mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 12:25:22 +02:00
Optimize Forecast View performance and implement WOC filter across views
This commit is contained in:
@@ -23,6 +23,8 @@ interface ForecastViewProps {
|
||||
onStockFilterChange: (newFilters: string[]) => void;
|
||||
vendorStockFilter: string[];
|
||||
onVendorStockFilterChange: (newFilters: string[]) => void;
|
||||
wocFilter: string[];
|
||||
onWocFilterChange: (newFilters: string[]) => void;
|
||||
}
|
||||
|
||||
const MONTH_ORDER = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
@@ -169,10 +171,20 @@ const ForecastView: React.FC<ForecastViewProps> = ({
|
||||
onStockFilterChange,
|
||||
vendorStockFilter,
|
||||
onVendorStockFilterChange,
|
||||
wocFilter,
|
||||
onWocFilterChange,
|
||||
top50Mode
|
||||
}) => {
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const debouncedSearch = useMemo(() => searchTerm.toLowerCase(), [searchTerm]);
|
||||
const [debouncedSearch, setDebouncedSearch] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setDebouncedSearch(searchTerm.toLowerCase());
|
||||
}, 300);
|
||||
return () => clearTimeout(timer);
|
||||
}, [searchTerm]);
|
||||
|
||||
const [showOnlyTop50, setShowOnlyTop50] = useState(false);
|
||||
const [displayCount, setDisplayCount] = useState(50);
|
||||
const [sortConfig, setSortConfig] = useState<{ key: string; direction: 'asc' | 'desc' }>({ key: 'actualUnits', direction: 'desc' });
|
||||
@@ -232,8 +244,8 @@ const ForecastView: React.FC<ForecastViewProps> = ({
|
||||
return Array.from(dataMap.values());
|
||||
}, [baseFilteredData]);
|
||||
|
||||
const processedData = useMemo(() => {
|
||||
let result = baseFilteredData.map(item => {
|
||||
const calculatedData = useMemo(() => {
|
||||
return baseFilteredData.map(item => {
|
||||
const forecastPeriod = activeMonths.reduce((sum, month) => {
|
||||
return sum + (item.monthlyData?.[month]?.forecastUnits || 0);
|
||||
}, 0);
|
||||
@@ -247,6 +259,10 @@ const ForecastView: React.FC<ForecastViewProps> = ({
|
||||
fcAchievement
|
||||
};
|
||||
});
|
||||
}, [baseFilteredData, activeMonths]);
|
||||
|
||||
const processedData = useMemo(() => {
|
||||
let result = [...calculatedData];
|
||||
|
||||
if (showOnlyTop50 && top50Ranking) {
|
||||
const currentRankMap = top50Mode === 'eu' ? top50Ranking.eu : top50Ranking.uk;
|
||||
@@ -261,6 +277,33 @@ const ForecastView: React.FC<ForecastViewProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
// Apply WOC Filter
|
||||
if (wocFilter && wocFilter.length > 0 && vendorStockMap) {
|
||||
result = result.filter(p => {
|
||||
const asin = p.asin.trim().toUpperCase();
|
||||
const stockData = vendorStockMap.get(asin);
|
||||
if (!stockData) return false;
|
||||
|
||||
const stock = top50Mode === 'uk' ? stockData.uk : stockData.eu;
|
||||
const velocity = p.avgWeeklySales || 0;
|
||||
|
||||
let woc: number = 0;
|
||||
if (velocity > 0) {
|
||||
woc = stock / velocity;
|
||||
} else if (stock > 0) {
|
||||
woc = 999;
|
||||
}
|
||||
|
||||
return wocFilter.some(f => {
|
||||
if (f === '< 4 Weeks') return woc < 4;
|
||||
if (f === '> 4 Weeks') return woc >= 4;
|
||||
if (f === 'Out of Stock') return woc === 0;
|
||||
if (f === 'Infinite Cover') return woc === 999;
|
||||
return true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Apply Sorting
|
||||
const { key, direction } = sortConfig;
|
||||
result.sort((a: any, b: any) => {
|
||||
@@ -276,7 +319,7 @@ const ForecastView: React.FC<ForecastViewProps> = ({
|
||||
});
|
||||
|
||||
return result;
|
||||
}, [baseFilteredData, debouncedSearch, showOnlyTop50, top50Ranking, top50Mode, sortConfig, activeMonths]);
|
||||
}, [calculatedData, debouncedSearch, showOnlyTop50, top50Ranking, top50Mode, sortConfig]);
|
||||
|
||||
const paginatedData = useMemo(() => processedData.slice(0, displayCount), [processedData, displayCount]);
|
||||
|
||||
@@ -393,6 +436,17 @@ const ForecastView: React.FC<ForecastViewProps> = ({
|
||||
className="bg-slate-950 border border-white/10 rounded-xl px-4 py-2 text-sm text-white focus:outline-none w-64"
|
||||
/>
|
||||
<button onClick={handleExportExcel} className="p-2 bg-slate-800 hover:bg-slate-700 text-white rounded-xl border border-white/5 transition-all"><DownloadIcon /></button>
|
||||
<InColumnStockFilter
|
||||
currentFilters={wocFilter}
|
||||
onFilterChange={onWocFilterChange}
|
||||
title="Week Coverage"
|
||||
options={[
|
||||
'< 4 Weeks',
|
||||
'> 4 Weeks',
|
||||
'Out of Stock',
|
||||
'Infinite Cover'
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user