diff --git a/components/VendorDataView.tsx b/components/VendorDataView.tsx index b707e9b..4fb9493 100644 --- a/components/VendorDataView.tsx +++ b/components/VendorDataView.tsx @@ -15,8 +15,9 @@ interface VendorDataViewProps { bsrData: BSRRecord[]; } -interface WeeklyChartPoint { - weekLabel: string; +interface ChartPoint { + label: string; + sortKey: string; [key: string]: number | string | null; } @@ -73,30 +74,48 @@ const VendorDataView: React.FC = ({ bsrData }) => { return Array.from(m).sort(); }, [filteredData]); - // Aggregate Data for Charts + // Determine if daily resolution is available (>= half the records have a date) + const useDailyResolution = useMemo(() => { + const withDate = filteredData.filter(r => r.date).length; + return withDate > filteredData.length / 2; + }, [filteredData]); + + // Aggregate Data for Charts — daily if dates available, else weekly const { topBsrChartData, detailBsrChartData, ratingChartData } = useMemo(() => { - const byWeek = new Map(); + // Group by date string (YYYY-MM-DD) or by week number + const byBucket = new Map(); + filteredData.forEach(r => { - if (!byWeek.has(r.week)) byWeek.set(r.week, []); - byWeek.get(r.week)!.push(r); + const key = useDailyResolution && r.date ? r.date : `W${String(r.week).padStart(2, '0')}`; + if (!byBucket.has(key)) byBucket.set(key, []); + byBucket.get(key)!.push(r); }); - const sortedWeeks = Array.from(byWeek.keys()).sort((a, b) => a - b); + const sortedKeys = Array.from(byBucket.keys()).sort(); - const topBsrChartData: WeeklyChartPoint[] = []; - const detailBsrChartData: WeeklyChartPoint[] = []; - const ratingChartData: WeeklyChartPoint[] = []; + const topBsrChartData: ChartPoint[] = []; + const detailBsrChartData: ChartPoint[] = []; + const ratingChartData: ChartPoint[] = []; - sortedWeeks.forEach(week => { - const row = byWeek.get(week)!; - const weekLabel = `Week ${week}`; + sortedKeys.forEach(key => { + const rows = byBucket.get(key)!; - const topPoint: WeeklyChartPoint = { weekLabel }; - const detailPoint: WeeklyChartPoint = { weekLabel }; - const ratingPoint: WeeklyChartPoint = { weekLabel }; + // Human-readable label + let label: string; + if (useDailyResolution && key.includes('-')) { + // YYYY-MM-DD → "DD MMM" + const d = new Date(key + 'T12:00:00Z'); + label = d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short' }); + } else { + label = key; // e.g. "W08" + } + + const topPoint: ChartPoint = { label, sortKey: key }; + const detailPoint: ChartPoint = { label, sortKey: key }; + const ratingPoint: ChartPoint = { label, sortKey: key }; activeMarkets.forEach(m => { - const marketRows = row.filter(r => r.market === m); + const marketRows = rows.filter(r => r.market === m); // Top BSR const topBsrRows = marketRows.filter(r => r.topLevelBSR != null); @@ -123,7 +142,7 @@ const VendorDataView: React.FC = ({ bsrData }) => { }); return { topBsrChartData, detailBsrChartData, ratingChartData }; - }, [filteredData, activeMarkets]); + }, [filteredData, activeMarkets, useDailyResolution]); if (bsrData.length === 0) { return ( @@ -141,6 +160,8 @@ const VendorDataView: React.FC = ({ bsrData }) => { ); } + const resolutionLabel = useDailyResolution ? 'Daily Avg' : 'Weekly Avg'; + return (
{/* Filters */} @@ -188,12 +209,12 @@ const VendorDataView: React.FC = ({ bsrData }) => { {/* Top Level BSR Trend Chart */}
-

Top Level BSR Trend (Weekly Avg)

+

Top Level BSR Trend ({resolutionLabel})

Lower rank = better position. Averaged across filtered ASINs per market.

- + = ({ bsrData }) => { {/* Detail Level BSR Trend Chart */}
-

Detail Level BSR Trend (Weekly Avg)

+

Detail Level BSR Trend ({resolutionLabel})

Lower rank = better position. Averaged across filtered ASINs per market.

- + = ({ bsrData }) => { {/* Average Rating Chart */}
-

Average Rating (Weekly Avg)

+

Average Rating ({resolutionLabel})

Averaged across filtered ASINs per market.

- + 1000) { + // Excel serial date: days since 1899-12-30 + d = new Date((dateNum - 25569) * 86400 * 1000); + } else { + d = new Date(dateRaw); + } + if (!isNaN(d.getTime())) { + isoDate = d.toISOString().slice(0, 10); // "YYYY-MM-DD" + if (!week) { // ISO week number const tmp = new Date(d); tmp.setHours(0, 0, 0, 0); @@ -704,6 +714,7 @@ export const processBSRExcel = async (fileOrBuffer: File | ArrayBuffer): Promise allData.push({ week, + date: isoDate, market: String(marketRaw).trim(), asin: String(asinRaw).trim(), topLevelBSR: parseIntSafe(getColumnValue(row, [ diff --git a/types.ts b/types.ts index 82bd006..7f2393a 100644 --- a/types.ts +++ b/types.ts @@ -282,6 +282,7 @@ export interface VendorCSVRow { export interface BSRRecord { week: number; + date?: string; // ISO date string (YYYY-MM-DD) when available — enables daily resolution charts market: string; asin: string; topLevelBSR: number | null;