mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 13:45:23 +02:00
feat: Initialize Craze Analytix project structure
Sets up the project with Vite, React, Tailwind CSS, Gemini AI integration, and necessary dependencies for data analysis. Includes initial configuration for TypeScript, Tailwind, and project metadata.
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user