diff --git a/App.tsx b/App.tsx index 43dcf7a..0e9fc12 100644 --- a/App.tsx +++ b/App.tsx @@ -6,10 +6,11 @@ import FilterBar from './components/FilterBar'; import AIChat from './components/AIChat'; import CrazeLogo from './components/CrazeLogo'; import { processCSV, processExcel, filterData, aggregateData, processAdsCSV, processAdsExcel, mergeSalesAndAdsData, processTrafficExcel, processStockExcel, filterAdsData, calculateForecastViewData, processVendorStockExcel, processUKInventoryExcel, calculateVelocityMap, getUniqueValues, processForecastExcel, processBuyBoxExcel, processVendorCSV } from './services/dataProcessor'; -import { SalesRecord, FilterState, AggregatedData, AdsRecord, TrafficRecord, ForecastRecord, ProductForecastData } from './types'; +import { SalesRecord, FilterState, AggregatedData, AdsRecord, TrafficRecord, ForecastRecord, ProductForecastData, ActiveExperiment } from './types'; 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'; +import { getActiveExperimentsForASINs } from './services/experiments'; // Lazy load heavy components for better initial performance const DataGrid = lazy(() => import('./components/DataGrid')); @@ -18,6 +19,9 @@ const TopMovers = lazy(() => import('./components/TopMovers')); const AdsPerformance = lazy(() => import('./components/AdsPerformance')); const ForecastView = lazy(() => import('./components/ForecastView')); const VendorDataView = lazy(() => import('./components/VendorDataView')); +const ExperimentsView = lazy(() => import('./components/ExperimentsView')); +const ExperimentDetail = lazy(() => import('./components/ExperimentDetail')); +const ExperimentForm = lazy(() => import('./components/ExperimentForm')); // Loading fallback component const LoadingSpinner = () => ( @@ -44,7 +48,7 @@ const App: React.FC = () => { const [trafficData, setTrafficData] = useState([]); const [loading, setLoading] = useState(true); const [syncing, setSyncing] = useState(false); - const [view, setView] = useState<'dashboard' | 'table' | 'weekly' | 'movers' | 'ads' | 'forecast' | 'vendor'>('dashboard'); + const [view, setView] = useState<'dashboard' | 'table' | 'weekly' | 'movers' | 'ads' | 'forecast' | 'vendor' | 'experiments'>('dashboard'); const [forecastData, setForecastData] = useState([]); const [isChatOpen, setIsChatOpen] = useState(false); const [activeUrl, setActiveUrl] = useState(() => localStorage.getItem('craze_csv_url') || PERMANENT_DROPBOX_URL); @@ -54,6 +58,13 @@ const App: React.FC = () => { const [cachedForecastRecords, setCachedForecastRecords] = useState([]); const [lastForecastFile, setLastForecastFile] = useState(null); const [buyBoxLostMap, setBuyBoxLostMap] = useState }>>(new Map()); + + // Experiments state + const [experimentMap, setExperimentMap] = useState>(new Map()); + const [selectedExperimentId, setSelectedExperimentId] = useState(null); + const [showCreateExperiment, setShowCreateExperiment] = useState(false); + const [preselectedAsins, setPreselectedAsins] = useState([]); + const [preselectedMarketplace, setPreselectedMarketplace] = useState(''); // Modal State const [isDataModalOpen, setIsDataModalOpen] = useState(false); @@ -238,6 +249,17 @@ const App: React.FC = () => { } }, []); + const handleExperimentsFetch = useCallback(async () => { + try { + const allAsins = Array.from(new Set(rawData.map(r => r.asin.toUpperCase()))); + const expMap = await getActiveExperimentsForASINs(allAsins); + setExperimentMap(expMap); + console.log('[App] Loaded experiments for', expMap.size, 'ASINs'); + } catch (error) { + console.error("Failed to fetch experiments", error); + } + }, [rawData]); + const handleForecastFetch = useCallback(async (sales: SalesRecord[], globalSales: SalesRecord[], activeFilters: FilterState) => { try { @@ -379,7 +401,11 @@ const App: React.FC = () => { handleVendorStockFetch(); handleBuyBoxFetch(); - // 1e. Fetch Forecast data + // 1e. Fetch Experiments data + console.log("Fetching Experiments data..."); + handleExperimentsFetch(); + + // 1f. Fetch Forecast data handleForecastFetch(cachedData || [], cachedData || [], filters); }; initApp(); @@ -793,6 +819,13 @@ const App: React.FC = () => { > Vendor + @@ -851,6 +884,8 @@ const App: React.FC = () => { top50Ranking={top50Ranking2025} velocityMap={velocityMap} buyBoxLostMap={buyBoxLostMap} + experimentMap={experimentMap} + onOpenExperiment={(id) => setSelectedExperimentId(id)} /> @@ -906,6 +941,19 @@ const App: React.FC = () => { + + }> +
+ setSelectedExperimentId(id)} + onOpenCreate={() => { + setPreselectedAsins([]); + setPreselectedMarketplace(filters.customer[0] || ''); + setShowCreateExperiment(true); + }} + /> +
+
)} @@ -916,7 +964,7 @@ const App: React.FC = () => { {/* Mobile Bottom Navigation */}