From 06a00d07e426b3d1532d0e433e0094b383e282f8 Mon Sep 17 00:00:00 2001 From: Sosokker Date: Wed, 12 Mar 2025 16:01:50 +0700 Subject: [PATCH] ui: add ui placeholder for marketplace --- .../(sidebar)/marketplace/CustomTooltip.tsx | 22 + .../(sidebar)/marketplace/DemandAnalysis.tsx | 38 ++ .../marketplace/MarketComparisonTab.tsx | 95 +++++ .../marketplace/MarketOpportunity.tsx | 76 ++++ .../marketplace/MarketPriceTable.tsx | 88 ++++ .../(sidebar)/marketplace/MarketSummary.tsx | 64 +++ .../(sidebar)/marketplace/PriceAnalytics.tsx | 130 ++++++ .../marketplace/PriceAnalyticsCard.tsx | 114 +++++ .../marketplace/TopOpportunities.tsx | 78 ++++ frontend/app/(sidebar)/marketplace/page.tsx | 401 ++++-------------- frontend/lib/marketData.ts | 142 +++++++ 11 files changed, 936 insertions(+), 312 deletions(-) create mode 100644 frontend/app/(sidebar)/marketplace/CustomTooltip.tsx create mode 100644 frontend/app/(sidebar)/marketplace/DemandAnalysis.tsx create mode 100644 frontend/app/(sidebar)/marketplace/MarketComparisonTab.tsx create mode 100644 frontend/app/(sidebar)/marketplace/MarketOpportunity.tsx create mode 100644 frontend/app/(sidebar)/marketplace/MarketPriceTable.tsx create mode 100644 frontend/app/(sidebar)/marketplace/MarketSummary.tsx create mode 100644 frontend/app/(sidebar)/marketplace/PriceAnalytics.tsx create mode 100644 frontend/app/(sidebar)/marketplace/PriceAnalyticsCard.tsx create mode 100644 frontend/app/(sidebar)/marketplace/TopOpportunities.tsx create mode 100644 frontend/lib/marketData.ts diff --git a/frontend/app/(sidebar)/marketplace/CustomTooltip.tsx b/frontend/app/(sidebar)/marketplace/CustomTooltip.tsx new file mode 100644 index 0000000..60fdec8 --- /dev/null +++ b/frontend/app/(sidebar)/marketplace/CustomTooltip.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { Card } from "@/components/ui/card"; + +interface CustomTooltipProps { + active?: boolean; + payload?: { value: number }[]; + label?: string; +} + +export default function CustomTooltip({ active, payload, label }: CustomTooltipProps) { + if (active && payload && payload.length) { + return ( + +

{label}

+

Price: ${payload[0].value}

+ {payload[1] &&

Volume: {payload[1].value} units

} +
+ ); + } + return null; +} diff --git a/frontend/app/(sidebar)/marketplace/DemandAnalysis.tsx b/frontend/app/(sidebar)/marketplace/DemandAnalysis.tsx new file mode 100644 index 0000000..41cfd0d --- /dev/null +++ b/frontend/app/(sidebar)/marketplace/DemandAnalysis.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import { Progress } from "@/components/ui/progress"; +import MarketOpportunity from "./MarketOpportunity"; +import { IMarketComparison } from "@/lib/marketData"; + +interface DemandAnalysisProps { + selectedCrop: string; + marketComparison: IMarketComparison[]; +} + +export default function DemandAnalysis({ selectedCrop, marketComparison }: DemandAnalysisProps) { + return ( +
+ + + Demand Forecast + Projected demand for {selectedCrop} over the next 30 days + + +
+ {marketComparison.map((market) => ( +
+
+ {market.name} + {market.demand}% +
+ +
+ ))} +
+
+
+ +
+ ); +} diff --git a/frontend/app/(sidebar)/marketplace/MarketComparisonTab.tsx b/frontend/app/(sidebar)/marketplace/MarketComparisonTab.tsx new file mode 100644 index 0000000..95bfcb8 --- /dev/null +++ b/frontend/app/(sidebar)/marketplace/MarketComparisonTab.tsx @@ -0,0 +1,95 @@ +"use client"; + +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, Cell } from "recharts"; +import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import { Button } from "@/components/ui/button"; +import { ArrowUpRight, ArrowDownRight, ChevronRight } from "lucide-react"; +import { Progress } from "@/components/ui/progress"; +import { IMarketComparison } from "@/lib/marketData"; + +interface MarketComparisonTabProps { + marketComparison: IMarketComparison[]; + selectedCrop: string; + onSelectCrop: (crop: string) => void; +} + +export default function MarketComparisonTab({ + marketComparison, + selectedCrop, + onSelectCrop, +}: MarketComparisonTabProps) { + return ( + <> +
+ + + + + `$${value}`} /> + + + + {marketComparison.map((entry, index) => ( + item.price)) ? "#15803d" : "#16a34a"} + /> + ))} + + + +
+ +
+ + + Market comparison for {selectedCrop} as of {new Date().toLocaleDateString()} + + + + Market + Price + Demand + Price Difference + Action + + + + {marketComparison.map((market) => { + const avgPrice = marketComparison.reduce((sum, m) => sum + m.price, 0) / marketComparison.length; + const priceDiff = (((market.price - avgPrice) / avgPrice) * 100).toFixed(1); + const isPriceHigh = Number.parseFloat(priceDiff) > 0; + + return ( + onSelectCrop(market.name)}> + {market.name} + ${market.price.toFixed(2)} + +
+ + {market.demand}% +
+
+ +
+ {isPriceHigh ? : } + {priceDiff}% +
+
+ + + +
+ ); + })} +
+
+
+ + ); +} diff --git a/frontend/app/(sidebar)/marketplace/MarketOpportunity.tsx b/frontend/app/(sidebar)/marketplace/MarketOpportunity.tsx new file mode 100644 index 0000000..045f017 --- /dev/null +++ b/frontend/app/(sidebar)/marketplace/MarketOpportunity.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Progress } from "@/components/ui/progress"; +import { Separator } from "@/components/ui/separator"; +import { ArrowUpRight, ArrowDownRight, TrendingUp, MapPin, AlertCircle } from "lucide-react"; +import { IMarketComparison } from "@/lib/marketData"; + +interface MarketOpportunityProps { + crop: string; + data: IMarketComparison[]; +} + +export default function MarketOpportunity({ crop, data }: MarketOpportunityProps) { + const highestPrice = Math.max(...data.map((item) => item.price)); + const bestMarket = data.find((item) => item.price === highestPrice); + const highestDemand = Math.max(...data.map((item) => item.demand)); + const highDemandMarket = data.find((item) => item.demand === highestDemand); + + return ( + + + + + Sales Opportunity for {crop} + + Based on current market conditions + + +
+
+

Best Price Opportunity

+
+
+

${bestMarket?.price}

+

{bestMarket?.name}

+
+ + {Math.round((bestMarket!.price / (highestPrice - 1)) * 100)}% above average + +
+
+ + + +
+

Highest Demand

+
+
+

{highDemandMarket?.name}

+
+ + {highDemandMarket?.demand}% demand +
+
+ +
+
+ + + + Recommendation + + Consider selling your {crop} at {bestMarket?.name} within the next 7 days to maximize profit. + + +
+
+
+ ); +} diff --git a/frontend/app/(sidebar)/marketplace/MarketPriceTable.tsx b/frontend/app/(sidebar)/marketplace/MarketPriceTable.tsx new file mode 100644 index 0000000..593b8d3 --- /dev/null +++ b/frontend/app/(sidebar)/marketplace/MarketPriceTable.tsx @@ -0,0 +1,88 @@ +"use client"; + +import { Table, TableBody, TableHeader, TableRow, TableHead, TableCell } from "@/components/ui/table"; +import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; +import { ArrowUpRight, ArrowDownRight } from "lucide-react"; +import { IMarketData, ITrend } from "@/lib/marketData"; + +interface MarketPriceTableProps { + marketData: IMarketData[]; + isLoading: boolean; + onSelectCrop: (crop: string) => void; +} + +const getTrendColor = (trend: ITrend) => (trend.direction === "up" ? "text-green-600" : "text-red-600"); + +const getTrendIcon = (trend: ITrend) => + trend.direction === "up" ? ( + + ) : ( + + ); + +export default function MarketPriceTable({ marketData, isLoading, onSelectCrop }: MarketPriceTableProps) { + if (isLoading) { + return ( + + + Market Price Table + Comprehensive price data across all markets and crops + + +
+ + + + +
+
+
+ ); + } + + return ( + + + Market Price Table + Comprehensive price data across all markets and crops + + +
+ + + + Crop + {marketData[0]?.marketPrices.map((market) => ( + {market.market} + ))} + Average + Recommended + + + + {marketData.map((crop) => ( + onSelectCrop(crop.name)}> + {crop.name} + {crop.marketPrices.map((market) => ( + +
+ ${market.price.toFixed(2)} + {getTrendIcon(market.trend)} +
+
+ ))} + ${crop.averagePrice.toFixed(2)} + ${crop.recommendedPrice.toFixed(2)} +
+ ))} +
+
+
+
+
+ ); +} diff --git a/frontend/app/(sidebar)/marketplace/MarketSummary.tsx b/frontend/app/(sidebar)/marketplace/MarketSummary.tsx new file mode 100644 index 0000000..a558a28 --- /dev/null +++ b/frontend/app/(sidebar)/marketplace/MarketSummary.tsx @@ -0,0 +1,64 @@ +// components/MarketSummary.tsx +"use client"; + +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Skeleton } from "@/components/ui/skeleton"; +import { ArrowUpRight, ArrowDownRight } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { IMarketData } from "@/lib/marketData"; + +interface MarketSummaryProps { + marketData: IMarketData[]; + isLoading: boolean; + onSelectCrop: (crop: string) => void; +} + +export default function MarketSummary({ marketData, isLoading, onSelectCrop }: MarketSummaryProps) { + return ( + + + Market Summary + Today's market overview + + + {isLoading ? ( +
+ + + +
+ ) : ( + +
+ {marketData.slice(0, 5).map((crop) => ( +
+
+

{crop.name}

+
+ ${crop.averagePrice.toFixed(2)} + {crop.marketPrices[0].trend.direction === "up" ? ( + + + {crop.marketPrices[0].trend.value}% + + ) : ( + + + {crop.marketPrices[0].trend.value}% + + )} +
+
+ +
+ ))} +
+
+ )} +
+
+ ); +} diff --git a/frontend/app/(sidebar)/marketplace/PriceAnalytics.tsx b/frontend/app/(sidebar)/marketplace/PriceAnalytics.tsx new file mode 100644 index 0000000..9027c80 --- /dev/null +++ b/frontend/app/(sidebar)/marketplace/PriceAnalytics.tsx @@ -0,0 +1,130 @@ +"use client"; + +import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from "recharts"; +import { Card, CardContent } from "@/components/ui/card"; +import { RefreshCw, Leaf, Calendar } from "lucide-react"; +import CustomTooltip from "./CustomTooltip"; +import { Badge } from "@/components/ui/badge"; +import { Progress } from "@/components/ui/progress"; +import { IHistoricalData } from "@/lib/marketData"; + +interface PriceAnalyticsProps { + historicalData: IHistoricalData[]; + isLoading: boolean; + selectedCrop: string; +} + +export default function PriceAnalytics({ historicalData, isLoading, selectedCrop }: PriceAnalyticsProps) { + if (isLoading) { + return ( +
+
+ +

Loading market data...

+
+
+ ); + } + + const currentPrice = historicalData[historicalData.length - 1]?.price ?? 0; + const averagePrice = historicalData.reduce((sum, item) => sum + item.price, 0) / historicalData.length; + const recommendedPrice = currentPrice * 1.05; + + return ( + <> +
+ + + + { + const date = new Date(value); + return `${date.getMonth() + 1}/${date.getDate()}`; + }} + /> + `$${value}`} + domain={["dataMin - 0.5", "dataMax + 0.5"]} + /> + + } /> + + + + + +
+ +
+ + +
+
+

Current Price

+

${currentPrice.toFixed(2)}

+
+
+ +
+
+
+
+ + + +
+
+

30-Day Average

+

${averagePrice.toFixed(2)}

+
+
+ +
+
+
+
+ + + +
+
+

Recommended Price

+

${recommendedPrice.toFixed(2)}

+
+ + +5% margin + +
+
+
+
+ + ); +} diff --git a/frontend/app/(sidebar)/marketplace/PriceAnalyticsCard.tsx b/frontend/app/(sidebar)/marketplace/PriceAnalyticsCard.tsx new file mode 100644 index 0000000..d6e1efd --- /dev/null +++ b/frontend/app/(sidebar)/marketplace/PriceAnalyticsCard.tsx @@ -0,0 +1,114 @@ +// components/PriceAnalyticsCard.tsx +"use client"; + +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { RefreshCw } from "lucide-react"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import PriceAnalytics from "./PriceAnalytics"; +import MarketComparisonTab from "./MarketComparisonTab"; +import DemandAnalysis from "./DemandAnalysis"; + +interface PriceAnalyticsCardProps { + isLoading: boolean; + selectedCrop: string; + timeRange: string; + lastUpdated: Date; + onSelectCrop: (crop: string) => void; + onTimeRangeChange: (value: string) => void; + onRefresh: () => void; + historicalData: any; + marketComparison: any; +} + +export default function PriceAnalyticsCard({ + isLoading, + selectedCrop, + timeRange, + lastUpdated, + onSelectCrop, + onTimeRangeChange, + onRefresh, + historicalData, + marketComparison, +}: PriceAnalyticsCardProps) { + return ( + + +
+
+ Price Analytics + Track price trends and market movements +
+
+ + + +
+
+
+ + {isLoading ? ( +
+
+ +

Loading market data...

+
+
+ ) : ( + + + + Price Trend + + + Market Comparison + + + Demand Analysis + + + + + + + + + + + + + )} +
+
+ ); +} diff --git a/frontend/app/(sidebar)/marketplace/TopOpportunities.tsx b/frontend/app/(sidebar)/marketplace/TopOpportunities.tsx new file mode 100644 index 0000000..dcd2711 --- /dev/null +++ b/frontend/app/(sidebar)/marketplace/TopOpportunities.tsx @@ -0,0 +1,78 @@ +"use client"; + +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { TrendingUp } from "lucide-react"; +import { IMarketData } from "@/lib/marketData"; + +interface TopOpportunitiesProps { + marketData: IMarketData[]; + isLoading: boolean; + onSelectCrop: (crop: string) => void; +} + +export default function TopOpportunities({ marketData, isLoading, onSelectCrop }: TopOpportunitiesProps) { + if (isLoading) { + return ( + + + Top Opportunities + Best selling opportunities today + + +
+ + + +
+
+
+ ); + } + + return ( + + + Top Opportunities + Best selling opportunities today + + +
+ {marketData + .filter((crop) => crop.opportunity) + .slice(0, 3) + .map((crop) => { + const bestMarket = crop.marketPrices.reduce( + (best, current) => (current.price > best.price ? current : best), + crop.marketPrices[0] + ); + return ( +
+
+
+

{crop.name}

+

+ {bestMarket.market} - ${bestMarket.price.toFixed(2)} +

+
+ High Demand +
+
+
+ + Recommended +
+ +
+
+ ); + })} +
+
+
+ ); +} diff --git a/frontend/app/(sidebar)/marketplace/page.tsx b/frontend/app/(sidebar)/marketplace/page.tsx index 33b21f0..f72e42e 100644 --- a/frontend/app/(sidebar)/marketplace/page.tsx +++ b/frontend/app/(sidebar)/marketplace/page.tsx @@ -2,26 +2,9 @@ import { useState, useEffect } from "react"; import { useSearchParams } from "next/navigation"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle -} from "@/components/ui/card"; -import { - Tabs, - TabsContent, - TabsList, - TabsTrigger -} from "@/components/ui/tabs"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue -} from "@/components/ui/select"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { @@ -35,7 +18,7 @@ import { ResponsiveContainer, BarChart, Bar, - Cell + Cell, } from "recharts"; import { ArrowUpRight, @@ -49,26 +32,14 @@ import { Leaf, BarChart3, LineChartIcon, - PieChart + PieChart, } from "lucide-react"; import { Skeleton } from "@/components/ui/skeleton"; -import { - Table, - TableBody, - TableCaption, - TableCell, - TableHead, - TableHeader, - TableRow -} from "@/components/ui/table"; +import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Progress } from "@/components/ui/progress"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; -import { - Alert, - AlertDescription, - AlertTitle -} from "@/components/ui/alert"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; // Define types for market data @@ -121,26 +92,10 @@ interface MarketOpportunityProps { // Mock data for market prices const generateMarketData = (): IMarketData[] => { - const crops = [ - "Corn", - "Wheat", - "Soybeans", - "Rice", - "Potatoes", - "Tomatoes", - "Apples", - "Oranges" - ]; - const markets = [ - "National Market", - "Regional Hub", - "Local Market", - "Export Market", - "Wholesale Market" - ]; + const crops = ["Corn", "Wheat", "Soybeans", "Rice", "Potatoes", "Tomatoes", "Apples", "Oranges"]; + const markets = ["National Market", "Regional Hub", "Local Market", "Export Market", "Wholesale Market"]; - const getRandomPrice = (base: number) => - Number((base + Math.random() * 2).toFixed(2)); + const getRandomPrice = (base: number) => Number((base + Math.random() * 2).toFixed(2)); const getRandomDemand = () => Math.floor(Math.random() * 100); const getRandomTrend = (): ITrend => Math.random() > 0.5 @@ -172,21 +127,18 @@ const generateMarketData = (): IMarketData[] => { market, price: getRandomPrice(basePrice), demand: getRandomDemand(), - trend: getRandomTrend() + trend: getRandomTrend(), })), averagePrice: getRandomPrice(basePrice - 0.5), recommendedPrice: getRandomPrice(basePrice + 0.2), demandScore: getRandomDemand(), - opportunity: Math.random() > 0.7 + opportunity: Math.random() > 0.7, }; }); }; // Generate historical price data for a specific crop -const generateHistoricalData = ( - crop: string, - days = 30 -): IHistoricalData[] => { +const generateHistoricalData = (crop: string, days = 30): IHistoricalData[] => { const basePrice = crop === "Corn" ? 4 @@ -216,7 +168,7 @@ const generateHistoricalData = ( data.push({ date: date.toISOString().split("T")[0], price: Number(currentPrice.toFixed(2)), - volume: Math.floor(Math.random() * 1000) + 200 + volume: Math.floor(Math.random() * 1000) + 200, }); } @@ -224,16 +176,8 @@ const generateHistoricalData = ( }; // Generate market comparison data -const generateMarketComparisonData = ( - crop: string -): IMarketComparison[] => { - const markets = [ - "National Market", - "Regional Hub", - "Local Market", - "Export Market", - "Wholesale Market" - ]; +const generateMarketComparisonData = (crop: string): IMarketComparison[] => { + const markets = ["National Market", "Regional Hub", "Local Market", "Export Market", "Wholesale Market"]; const basePrice = crop === "Corn" ? 4 @@ -254,26 +198,18 @@ const generateMarketComparisonData = ( return markets.map((market) => ({ name: market, price: Number((basePrice + (Math.random() - 0.5) * 2).toFixed(2)), - demand: Math.floor(Math.random() * 100) + demand: Math.floor(Math.random() * 100), })); }; // Custom tooltip for the price chart -const CustomTooltip = ({ - active, - payload, - label -}: CustomTooltipProps) => { +const CustomTooltip = ({ active, payload, label }: CustomTooltipProps) => { if (active && payload && payload.length) { return (

{label}

Price: ${payload[0].value}

- {payload[1] && ( -

- Volume: {payload[1].value} units -

- )} + {payload[1] &&

Volume: {payload[1].value} units

}
); } @@ -285,9 +221,7 @@ const MarketOpportunity = ({ crop, data }: MarketOpportunityProps) => { const highestPrice = Math.max(...data.map((item) => item.price)); const bestMarket = data.find((item) => item.price === highestPrice); const highestDemand = Math.max(...data.map((item) => item.demand)); - const highDemandMarket = data.find( - (item) => item.demand === highestDemand - ); + const highDemandMarket = data.find((item) => item.demand === highestDemand); return ( @@ -296,28 +230,19 @@ const MarketOpportunity = ({ crop, data }: MarketOpportunityProps) => { Sales Opportunity for {crop} - - Based on current market conditions - + Based on current market conditions
-

- Best Price Opportunity -

+

Best Price Opportunity

-

- ${bestMarket?.price} -

-

- {bestMarket?.name} -

+

${bestMarket?.price}

+

{bestMarket?.name}

- {Math.round((bestMarket!.price / (highestPrice - 1)) * 100)}% - above average + {Math.round((bestMarket!.price / (highestPrice - 1)) * 100)}% above average
@@ -325,22 +250,13 @@ const MarketOpportunity = ({ crop, data }: MarketOpportunityProps) => {
-

- Highest Demand -

+

Highest Demand

-

- {highDemandMarket?.name} -

+

{highDemandMarket?.name}

- - - {highDemandMarket?.demand}% demand - + + {highDemandMarket?.demand}% demand
@@ -374,17 +287,14 @@ export default function MarketplacePage() { const [isLoading, setIsLoading] = useState(true); const [marketData, setMarketData] = useState([]); const [historicalData, setHistoricalData] = useState([]); - const [marketComparison, setMarketComparison] = - useState([]); + const [marketComparison, setMarketComparison] = useState([]); const [lastUpdated, setLastUpdated] = useState(new Date()); useEffect(() => { setIsLoading(true); const timer = setTimeout(() => { setMarketData(generateMarketData()); - setHistoricalData( - generateHistoricalData(selectedCrop, Number.parseInt(timeRange)) - ); + setHistoricalData(generateHistoricalData(selectedCrop, Number.parseInt(timeRange))); setMarketComparison(generateMarketComparisonData(selectedCrop)); setLastUpdated(new Date()); setIsLoading(false); @@ -397,9 +307,7 @@ export default function MarketplacePage() { setIsLoading(true); setTimeout(() => { setMarketData(generateMarketData()); - setHistoricalData( - generateHistoricalData(selectedCrop, Number.parseInt(timeRange)) - ); + setHistoricalData(generateHistoricalData(selectedCrop, Number.parseInt(timeRange))); setMarketComparison(generateMarketComparisonData(selectedCrop)); setLastUpdated(new Date()); setIsLoading(false); @@ -424,33 +332,18 @@ export default function MarketplacePage() {
-

- Marketplace Information -

+

Marketplace Information

- Make informed decisions with real-time market data and price - analytics + Make informed decisions with real-time market data and price analytics

- -
- Last updated: {lastUpdated.toLocaleTimeString()} -
+
Last updated: {lastUpdated.toLocaleTimeString()}
@@ -460,9 +353,7 @@ export default function MarketplacePage() {
Price Analytics - - Track price trends and market movements - + Track price trends and market movements