From aeb49c40ebe08ff811c103e38d00a25a82fea76d Mon Sep 17 00:00:00 2001 From: dhanabalan Date: Fri, 23 Jan 2026 12:57:18 +0530 Subject: [PATCH] Added rfq chart and rfq rank chart widgets page --- app/Filament/Widgets/RfqChart.php | 136 +++++++++++++++++ app/Filament/Widgets/RfqRankChart.php | 205 ++++++++++++++++++++++++++ 2 files changed, 341 insertions(+) create mode 100644 app/Filament/Widgets/RfqChart.php create mode 100644 app/Filament/Widgets/RfqRankChart.php diff --git a/app/Filament/Widgets/RfqChart.php b/app/Filament/Widgets/RfqChart.php new file mode 100644 index 0000000..ab14ce5 --- /dev/null +++ b/app/Filament/Widgets/RfqChart.php @@ -0,0 +1,136 @@ +where('transporter_name', $transporter) + // ->where('rfq_number', $rfqNumber) + // ->first(); + + // if (!$selectedRfq) { + // return [ + // Stat::make('Total Freight Charge', '-'), + // Stat::make('Rank', '-'), + // ]; + // } + + // $myAmount = (float) $selectedRfq->total_freight_charge; + + // $rank = RequestQuotation::query() + // ->whereRaw( + // 'CAST(total_freight_charge AS DECIMAL(10,2)) < ?', + // [$myAmount] + // ) + // ->selectRaw('CAST(total_freight_charge AS DECIMAL(10,2))') + // ->distinct() + // ->count() + 1; + + // $medal = match (true) { + // $rank == 1 => '🥇', + // $rank == 2 => '🥈', + // $rank == 3 => '🥉', + // default => '', + // }; + + // return [ + // Stat::make( + // 'Total Freight Charge', + // number_format($selectedRfq->total_freight_charge, 2) + // ) + // ->description('Transporter: ' . $selectedRfq->transporter_name) + // ->color($rank == 1 ? 'success' : 'primary'), + + // Stat::make( + // 'Rank', + // trim("{$medal} #{$rank}") + // ) + // ->description('Among all transporters') + // ->color( + // $rank == 1 ? 'success' : + // ($rank <= 3 ? 'warning' : 'gray') + // ), + // ]; + // } + + protected function getStats(): array + { + $transporter = session('transport_name'); + $rfqNumber = session('rfq_id'); + + if (!$transporter || !$rfqNumber) { + return [ + Stat::make('Total Freight Charge', '-'), + Stat::make('Rank', '-'), + ]; + } + + $selectedRfq = RfqTransporterBid::query() + ->where('transporter_name', $transporter) + ->where('request_quotation_id', $rfqNumber) + ->first(); + + if (!$selectedRfq) { + return [ + Stat::make('Total Freight Charge', '-'), + Stat::make('Rank', '-'), + ]; + } + + $myAmount = (float) $selectedRfq->total_freight_charge; + + $rank = RfqTransporterBid::query() + ->whereRaw( + 'CAST(total_freight_charge AS DECIMAL(10,2)) < ?', + [$myAmount] + ) + ->selectRaw('CAST(total_freight_charge AS DECIMAL(10,2))') + ->distinct() + ->count() + 1; + + $medal = match (true) { + $rank == 1 => '🥇', + $rank == 2 => '🥈', + $rank == 3 => '🥉', + default => '', + }; + + return [ + Stat::make( + 'Total Freight Charge', + number_format($selectedRfq->total_freight_charge, 2) + ) + ->description('Transporter: ' . $selectedRfq->transporter_name) + ->color($rank == 1 ? 'success' : 'primary'), + + Stat::make( + 'Rank', + trim("{$medal} #{$rank}") + ) + ->description('Among all transporters') + ->color( + $rank == 1 ? 'success' : + ($rank <= 3 ? 'warning' : 'gray') + ), + ]; + } +} diff --git a/app/Filament/Widgets/RfqRankChart.php b/app/Filament/Widgets/RfqRankChart.php new file mode 100644 index 0000000..104b595 --- /dev/null +++ b/app/Filament/Widgets/RfqRankChart.php @@ -0,0 +1,205 @@ + [], + // 'labels' => [], + // ]; + // } + + // // Get bids ordered by lowest freight charge + // $bids = RfqTransporterBid::query() + // ->where('request_quotation_id', $rfqId) + // ->orderByRaw('CAST(total_freight_charge AS DECIMAL(10,2)) ASC') + // ->get(); + + // // $labels = []; + // // $ranks = []; + + // // $rank = 1; + // // foreach ($bids as $bid) { + // // $labels[] = $bid->transporter_name; + // // $ranks[] = $rank++; + // // } + + // // return [ + // // 'datasets' => [ + // // [ + // // 'label' => 'Rank (Lower is Better)', + // // 'data' => $ranks, + // // 'fill' => false, + // // 'tension' => 0.3, + // // ], + // // ], + // // 'labels' => $labels, + // // ]; + // $labels = []; + // $ranks = []; + // $colors = []; + + // $rank = 1; + // foreach ($bids as $bid) { + // $labels[] = $bid->transporter_name; + // $ranks[] = $rank; + + // // Rank-based colors + // $colors[] = match ($rank) { + // 1 => '#FFD700', // Gold + // 2 => '#C0C0C0', // Silver + // 3 => '#CD7F32', // Bronze + // default => '#3B82F6', // Blue + // }; + + // $rank++; + // } + + // return [ + // 'datasets' => [ + // [ + // 'label' => 'Rank (1 = Best)', + // 'data' => $ranks, + + // // 🎨 Styling + // 'borderColor' => '#3B82F6', + // 'backgroundColor' => $colors, + // 'pointBackgroundColor' => $colors, + // 'pointBorderColor' => '#000', + // 'pointRadius' => 7, + // 'pointHoverRadius' => 10, + // 'borderWidth' => 3, + // 'tension' => 0.4, + // 'fill' => false, + // ], + // ], + // 'labels' => $labels, + // ]; + // } + + + + protected function getData(): array + { + $rfqId = session('rfq_id'); + + if (!$rfqId) { + return [ + 'datasets' => [], + 'labels' => [], + ]; + } + + /** + * STEP 1: Get bids sorted by freight charge (for ranking) + */ + $rankedBids = RfqTransporterBid::query() + ->where('request_quotation_id', $rfqId) + ->orderByRaw('CAST(total_freight_charge AS DECIMAL(10,2)) ASC') + ->get(); + + $rankMap = []; + $rank = 1; + + foreach ($rankedBids as $bid) { + $rankMap[$bid->id] = $rank++; + } + + /** + * STEP 2: Get bids in natural order (for wave effect) + * You can change orderBy to: + * - created_at + * - transporter_name + */ + $chartBids = RfqTransporterBid::query() + ->where('request_quotation_id', $rfqId) + ->orderBy('id') + ->get(); + + $labels = []; + $amounts = []; + $colors = []; + + $ranks = []; + + foreach ($chartBids as $bid) { + $labels[] = $bid->transporter_name; + $amounts[] = (float) $bid->total_freight_charge; + + $rank = $rankMap[$bid->id]; + $ranks[] = $rank; + + $colors[] = match ($rank) { + 1 => '#FFD700', + 2 => '#C0C0C0', + 3 => '#CD7F32', + default => '#2563EB', + }; + } + + + return [ + 'datasets' => [ + [ + 'label' => 'Freight Charge', + 'data' => $amounts, + 'rankData' => $ranks, + + 'borderColor' => '#2563EB', + 'backgroundColor' => $colors, + 'pointBackgroundColor' => $colors, + 'pointBorderColor' => '#000', + 'pointRadius' => 7, + 'pointHoverRadius' => 11, + 'borderWidth' => 3, + 'tension' => 0.45, + 'fill' => false, + ], + ], + 'labels' => $labels, + ]; + } + + protected function getOptions(): array + { + return [ + 'plugins' => [ + 'datalabels' => [ + 'anchor' => 'start', + 'align' => 'start', + 'offset' => -15, + 'color' => '#000', + 'font' => [ + 'weight' => 'bold', + ], + 'formatter' => Js::from("function(value) { return Number(value); }"), + ], + ], + 'scales' => [ + 'y' => [ + 'beginAtZero' => true, + 'ticks' => [ + 'stepSize' => 0.5, + ], + ], + ], + ]; + } + + protected function getType(): string + { + return 'bar'; + } +}