mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 13:35:24 +02:00
feat: integrate Amazon Vendor Stock data across all views and fix local data loading
This commit is contained in:
@@ -6,7 +6,7 @@ import FilterBar from './components/FilterBar';
|
||||
import AIChat from './components/AIChat';
|
||||
import CrazeLogo from './components/CrazeLogo';
|
||||
import { SalesRecord, FilterState, AggregatedData, AdsRecord, TrafficRecord, ForecastRecord, ProductForecastData } from './types';
|
||||
import { processCSV, filterData, filterAdsData, aggregateData, getUniqueValues, processAdsCSV, processAdsExcel, processTrafficExcel, mergeSalesAndAdsData, processForecastExcel, calculateForecastViewData, processStockExcel } from './services/dataProcessor';
|
||||
import { processCSV, filterData, filterAdsData, aggregateData, getUniqueValues, processAdsCSV, processAdsExcel, processTrafficExcel, mergeSalesAndAdsData, processForecastExcel, calculateForecastViewData, processStockExcel, processVendorStockExcel } from './services/dataProcessor';
|
||||
import { queryGemini } from './services/geminiService';
|
||||
import { ChartIcon, TableIcon, UploadIcon, DownloadIcon, CloseIcon, TrendingIcon, MegaphoneIcon } from './components/Icons';
|
||||
import { loadSalesData, saveSalesData, clearSalesData, loadAdsData, saveAdsData, clearAdsData } from './services/storage';
|
||||
@@ -49,6 +49,7 @@ const App: React.FC = () => {
|
||||
const [activeUrl, setActiveUrl] = useState<string | null>(() => localStorage.getItem('craze_csv_url') || PERMANENT_DROPBOX_URL);
|
||||
const [lastUpdated, setLastUpdated] = useState<string | null>(null);
|
||||
const [stockMap, setStockMap] = useState<Map<string, number>>(new Map());
|
||||
const [vendorStockMap, setVendorStockMap] = useState<Map<string, { eu: number; uk: number }>>(new Map());
|
||||
|
||||
// Modal State
|
||||
const [isDataModalOpen, setIsDataModalOpen] = useState(false);
|
||||
@@ -143,8 +144,8 @@ const App: React.FC = () => {
|
||||
|
||||
const handleStockFetch = useCallback(async () => {
|
||||
try {
|
||||
console.log('[App] Fetching stock from /api/fetch-stock...');
|
||||
const response = await fetch('/api/fetch-stock');
|
||||
console.log('[App] Fetching stock from /Item Availability.xlsx...');
|
||||
const response = await fetch('/Item Availability.xlsx');
|
||||
if (!response.ok) throw new Error(`Failed to fetch stock: ${response.status}`);
|
||||
|
||||
const buffer = await response.arrayBuffer();
|
||||
@@ -156,6 +157,21 @@ const App: React.FC = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleVendorStockFetch = useCallback(async () => {
|
||||
try {
|
||||
console.log('[App] Fetching vendor stock from /Vendor Stock.xlsx...');
|
||||
const response = await fetch('/Vendor Stock.xlsx');
|
||||
if (!response.ok) throw new Error(`Failed to fetch vendor stock: ${response.status}`);
|
||||
|
||||
const buffer = await response.arrayBuffer();
|
||||
const data = await processVendorStockExcel(buffer);
|
||||
setVendorStockMap(data);
|
||||
console.log('[App] Successfully loaded vendor stock for', data.size, 'ASINs');
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch/parse Vendor Stock", error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
const handleForecastFetch = useCallback(async (sales: SalesRecord[], globalSales: SalesRecord[], activeFilters: FilterState) => {
|
||||
try {
|
||||
@@ -283,6 +299,7 @@ const App: React.FC = () => {
|
||||
// 1d. Always fetch Stock data
|
||||
console.log("Fetching Stock data...");
|
||||
handleStockFetch();
|
||||
handleVendorStockFetch();
|
||||
|
||||
// 1e. Fetch Forecast data
|
||||
handleForecastFetch(cachedData || [], cachedData || [], filters);
|
||||
@@ -528,7 +545,7 @@ const App: React.FC = () => {
|
||||
<div className="flex items-center gap-6">
|
||||
{/* Force Sync Action */}
|
||||
<button
|
||||
onClick={() => { handleDataFetch(); handleAdsFetch(); handleTrafficFetch(); }}
|
||||
onClick={() => { handleDataFetch(); handleAdsFetch(); handleTrafficFetch(); handleVendorStockFetch(); }}
|
||||
disabled={syncing}
|
||||
className={`flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-black uppercase tracking-widest transition-all
|
||||
${syncing
|
||||
@@ -609,6 +626,7 @@ const App: React.FC = () => {
|
||||
hasCustomerFilter={filters.customer.length > 0}
|
||||
adsData={filteredAdsData}
|
||||
stockMap={stockMap}
|
||||
vendorStockMap={vendorStockMap}
|
||||
top50Ranking={top50Ranking2025}
|
||||
top50Mode={filters.customer.includes('Amazon UK') ? 'uk' : 'eu'}
|
||||
/>
|
||||
@@ -620,6 +638,7 @@ const App: React.FC = () => {
|
||||
data={combinedAdsData}
|
||||
onDrillDown={handleSkuDrillDown}
|
||||
stockMap={stockMap}
|
||||
vendorStockMap={vendorStockMap}
|
||||
stockFilter={filters.stock}
|
||||
onStockFilterChange={(s) => setFilters(prev => ({ ...prev, stock: s }))}
|
||||
customerFilters={filters.customer}
|
||||
@@ -640,6 +659,7 @@ const App: React.FC = () => {
|
||||
filters={filters}
|
||||
top50Ranking={top50Ranking2025}
|
||||
stockMap={stockMap}
|
||||
vendorStockMap={vendorStockMap}
|
||||
stockFilter={filters.stock}
|
||||
onStockFilterChange={(s) => setFilters(prev => ({ ...prev, stock: s }))}
|
||||
top50Mode={filters.customer.includes('Amazon UK') ? 'uk' : 'eu'}
|
||||
@@ -653,6 +673,7 @@ const App: React.FC = () => {
|
||||
filters={filters}
|
||||
top50Ranking={top50Ranking2025}
|
||||
stockMap={stockMap}
|
||||
vendorStockMap={vendorStockMap}
|
||||
stockFilter={filters.stock}
|
||||
onStockFilterChange={(s) => setFilters(prev => ({ ...prev, stock: s }))}
|
||||
top50Mode={filters.customer.includes('Amazon UK') ? 'uk' : 'eu'}
|
||||
|
||||
Reference in New Issue
Block a user