Files
CrazeAnalytix/components/TopMoversPage.tsx
T

92 lines
4.2 KiB
TypeScript
Raw Normal View History

import React, { useState, useMemo } from 'react';
import { SalesRecord } from '../types';
import { calculateItemMovers, getUniqueValues, generateItemMoversCSV } from '../services/dataProcessor'; // Import generateItemMoversCSV
import ItemGrowthTable from './ItemGrowthTable';
import { ExpandableCard } from './Dashboard'; // Re-use ExpandableCard from Dashboard
interface TopMoversPageProps {
filteredData: SalesRecord[]; // Data already filtered by global customer, year, month, etc.
}
const TopMoversPage: React.FC<TopMoversPageProps> = ({ filteredData }) => {
// Local state for the specific comparison year, initially null for auto-selection
const [selectedComparisonYear, setSelectedComparisonYear] = useState<string | null>(null);
// Derive available years from the *currently filtered data* for the comparison year dropdown
const availableYearsForComparisonDropdown = useMemo(() => {
const yearsInFilteredData = getUniqueValues(filteredData, 'year');
// Sort descending for the dropdown
return yearsInFilteredData.sort((a,b) => parseInt(b) - parseInt(a));
}, [filteredData]);
// Derive top/bottom movers based on selections
const { topMovers, bottomMovers, comparisonPeriods } = useMemo(() => {
const comparisonYearNum = selectedComparisonYear ? parseInt(selectedComparisonYear) : null;
// Pass the globally filtered data. The global filter bar now handles customer/line/sku/etc filtering.
// We pass null for the local customer override as it is no longer used.
return calculateItemMovers(filteredData, null, comparisonYearNum);
}, [filteredData, selectedComparisonYear]);
// Handlers for export
const handleExportGainers = () => {
generateItemMoversCSV(topMovers, comparisonPeriods, 'Gainers');
};
const handleExportLosers = () => {
generateItemMoversCSV(bottomMovers, comparisonPeriods, 'Losers');
};
return (
<div className="p-6 space-y-6 max-w-7xl mx-auto animate-fade-in pb-24">
<div className="flex flex-wrap justify-between items-center gap-4 mb-6">
<h2 className="text-2xl font-bold text-white">Top Item Movers</h2>
<div className="bg-slate-900 border border-border rounded-xl px-4 py-2 flex items-center gap-3">
<label className="text-xs font-semibold text-slate-400 uppercase tracking-wider whitespace-nowrap">Comparison Year</label>
<select
value={selectedComparisonYear || ''}
onChange={(e) => setSelectedComparisonYear(e.target.value || null)}
className="bg-surface border border-border hover:border-slate-600 text-sm rounded-lg py-1.5 px-3 focus:outline-none focus:ring-2 focus:ring-primary/50 transition-colors text-white"
>
<option value="">Auto (Latest 2 Years)</option>
{availableYearsForComparisonDropdown.map(year => (
<option key={year} value={year}>{year}</option>
))}
</select>
</div>
</div>
{/* Top 20 Gainers Table */}
<ExpandableCard
title={`Top 20 Gainers (${comparisonPeriods.current} vs ${comparisonPeriods.previous})`}
className="h-[500px]"
onExport={handleExportGainers} // Pass export handler
exportFileName={`Top_20_Gainers_${comparisonPeriods.current}_vs_${comparisonPeriods.previous}`}
>
<ItemGrowthTable
title={`Top 20 Gainers (${comparisonPeriods.current} vs ${comparisonPeriods.previous})`}
data={topMovers}
type="growth"
periods={comparisonPeriods}
/>
</ExpandableCard>
{/* Top 20 Losers Table */}
<ExpandableCard
title={`Top 20 Losers (${comparisonPeriods.current} vs ${comparisonPeriods.previous})`}
className="h-[500px]"
onExport={handleExportLosers} // Pass export handler
exportFileName={`Top_20_Losers_${comparisonPeriods.current}_vs_${comparisonPeriods.previous}`}
>
<ItemGrowthTable
title={`Top 20 Losers (${comparisonPeriods.current} vs ${comparisonPeriods.previous})`}
data={bottomMovers}
type="decline"
periods={comparisonPeriods}
/>
</ExpandableCard>
</div>
);
};
export default TopMoversPage;