mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 11:45:23 +02:00
feat: remove MKT and Experiments tabs and all related code
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
9f9c0c2975
commit
76d901fcde
@@ -6,14 +6,10 @@ 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, processBSRExcel, filterBsrData, isAllowedCustomer, isRealSale } from './services/dataProcessor';
|
||||
import { SalesRecord, FilterState, AggregatedData, AdsRecord, TrafficRecord, ForecastRecord, ProductForecastData, ActiveExperiment, BSRRecord } from './types';
|
||||
import { SalesRecord, FilterState, AggregatedData, AdsRecord, TrafficRecord, ForecastRecord, ProductForecastData, BSRRecord } from './types';
|
||||
import { queryGemini } from './services/geminiService';
|
||||
import { ChartIcon, TableIcon, CloseIcon, TrendingIcon, MegaphoneIcon } from './components/Icons';
|
||||
import { loadSalesData, saveSalesData, clearSalesData, loadAdsData, saveAdsData, clearAdsData } from './services/storage';
|
||||
import {
|
||||
listExperiments,
|
||||
getActiveExperiments,
|
||||
} from './services/experiments';
|
||||
|
||||
// Lazy load heavy components for better initial performance
|
||||
const DataGrid = lazy(() => import('./components/DataGrid'));
|
||||
@@ -21,9 +17,6 @@ const WeeklyGrid = lazy(() => import('./components/WeeklyGrid'));
|
||||
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 MktDataView = lazy(() => import('./components/mkt/MktDataView'));
|
||||
|
||||
|
||||
// Loading fallback component
|
||||
const LoadingSpinner = () => (
|
||||
@@ -51,7 +44,7 @@ const App: React.FC = () => {
|
||||
const [trafficData, setTrafficData] = useState<TrafficRecord[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [syncing, setSyncing] = useState(false);
|
||||
const [view, setView] = useState<'dashboard' | 'table' | 'weekly' | 'ads' | 'forecast' | 'vendor' | 'experiments' | 'mkt'>('dashboard');
|
||||
const [view, setView] = useState<'dashboard' | 'table' | 'weekly' | 'ads' | 'forecast' | 'vendor'>('dashboard');
|
||||
const [forecastData, setForecastData] = useState<ProductForecastData[]>([]);
|
||||
const [isChatOpen, setIsChatOpen] = useState(false);
|
||||
const [activeUrl, setActiveUrl] = useState<string | null>(() => localStorage.getItem('craze_csv_url') || PERMANENT_DROPBOX_URL);
|
||||
@@ -63,10 +56,6 @@ const App: React.FC = () => {
|
||||
const [buyBoxLostMap, setBuyBoxLostMap] = useState<Map<string, { countries: string[]; reasons: Record<string, string> }>>(new Map());
|
||||
const [bsrData, setBsrData] = useState<BSRRecord[]>([]);
|
||||
|
||||
// Experiments state
|
||||
const [experimentMap, setExperimentMap] = useState<Map<string, ActiveExperiment[]>>(new Map());
|
||||
// Experiment modal state removed — detail/create are now inline in ExperimentsView
|
||||
|
||||
// Modal State
|
||||
const [isDataModalOpen, setIsDataModalOpen] = useState(false);
|
||||
|
||||
@@ -266,17 +255,6 @@ const App: React.FC = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleExperimentsFetch = useCallback(async () => {
|
||||
try {
|
||||
const expMap = await getActiveExperiments(rawData);
|
||||
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 {
|
||||
const isUK = activeFilters.customer.includes('Amazon UK');
|
||||
@@ -356,11 +334,6 @@ const App: React.FC = () => {
|
||||
setView('ads');
|
||||
}, []);
|
||||
|
||||
// Create experiment for a specific line — now handled inline by ExperimentsView
|
||||
const handleCreateExperimentForLine = useCallback((_line: string) => {
|
||||
setView('experiments');
|
||||
}, []);
|
||||
|
||||
// 1. Initial Load from Cache (IndexedDB) or Auto-Fetch Permanent URL
|
||||
useEffect(() => {
|
||||
const initApp = async () => {
|
||||
@@ -418,7 +391,6 @@ const App: React.FC = () => {
|
||||
handleStockFetch(),
|
||||
handleVendorStockFetch(),
|
||||
handleBuyBoxFetch(),
|
||||
handleExperimentsFetch(),
|
||||
handleBSRFetch()
|
||||
]).catch(e => console.warn("Background fetch failed", e));
|
||||
|
||||
@@ -550,15 +522,6 @@ const App: React.FC = () => {
|
||||
const filteredAdsData = useMemo(() => filterAdsData(adsData, deferredFilters, globalAsinMetadata, stockMap, vendorStockMap, top50Mode), [adsData, deferredFilters, globalAsinMetadata, stockMap, vendorStockMap, top50Mode]);
|
||||
console.timeEnd('filteredAdsData');
|
||||
|
||||
const mktAdsData = useMemo(() => adsData.filter(ad => {
|
||||
const countryMatch = deferredFilters.customer.length === 0
|
||||
? true
|
||||
: deferredFilters.customer.some(c => c.toUpperCase() === ad.country.toUpperCase());
|
||||
const yearMatch = deferredFilters.year.length === 0 || deferredFilters.year.includes(ad.year.toString());
|
||||
const weekMatch = deferredFilters.week.length === 0 || deferredFilters.week.includes(`W${ad.week}`);
|
||||
return countryMatch && yearMatch && weekMatch;
|
||||
}), [adsData, deferredFilters.customer, deferredFilters.year, deferredFilters.week]);
|
||||
|
||||
console.time('aggregatedData');
|
||||
const aggregatedData = useMemo(() => aggregateData(filteredData), [filteredData]);
|
||||
console.timeEnd('aggregatedData');
|
||||
@@ -796,13 +759,6 @@ const App: React.FC = () => {
|
||||
>
|
||||
<TrendingIcon /> <span className="hidden lg:inline">Weekly Sales</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setView('mkt')}
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-all
|
||||
${view === 'mkt' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white hover:bg-slate-800/50'}`}
|
||||
>
|
||||
<ChartIcon /> <span className="hidden lg:inline">MKT</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setView('ads')}
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-all
|
||||
@@ -824,14 +780,6 @@ const App: React.FC = () => {
|
||||
>
|
||||
<ChartIcon /> <span className="hidden lg:inline">BSR</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setView('experiments')}
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-all
|
||||
${view === 'experiments' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white hover:bg-slate-800/50'}`}
|
||||
>
|
||||
<span className="text-lg">🧪</span> <span className="hidden lg:inline">Experiments</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -901,8 +849,6 @@ const App: React.FC = () => {
|
||||
top50Ranking={top50Ranking2025}
|
||||
velocityMap={velocityMap}
|
||||
buyBoxLostMap={buyBoxLostMap}
|
||||
experimentMap={experimentMap}
|
||||
onOpenExperiment={() => setView('experiments')}
|
||||
/>
|
||||
</div>
|
||||
</Suspense>
|
||||
@@ -964,30 +910,6 @@ const App: React.FC = () => {
|
||||
</div>
|
||||
</Suspense>
|
||||
|
||||
<Suspense fallback={<LoadingSpinner />}>
|
||||
<div className={view === 'experiments' ? '' : 'hidden'}>
|
||||
<ExperimentsView
|
||||
salesData={unfilteredCombinedData}
|
||||
onExperimentsFetch={handleExperimentsFetch}
|
||||
/>
|
||||
</div>
|
||||
</Suspense>
|
||||
|
||||
<Suspense fallback={<LoadingSpinner />}>
|
||||
<div className={view === 'mkt' ? '' : 'hidden'}>
|
||||
<MktDataView
|
||||
rawData={filteredData}
|
||||
adsData={mktAdsData}
|
||||
stockMap={stockMap}
|
||||
vendorStockMap={vendorStockMap}
|
||||
top50Mode={filters.customer.includes('Amazon UK') ? 'uk' : 'eu'}
|
||||
velocityMap={velocityMap}
|
||||
buyBoxLostMap={buyBoxLostMap}
|
||||
top50Ranking={top50Ranking2025}
|
||||
/>
|
||||
</div>
|
||||
</Suspense>
|
||||
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -998,16 +920,14 @@ const App: React.FC = () => {
|
||||
|
||||
{/* Mobile Bottom Navigation */}
|
||||
<nav className="fixed bottom-0 left-0 right-0 z-50 bg-slate-950/95 backdrop-blur border-t border-border md:hidden pb-safe">
|
||||
<div className="grid grid-cols-8 gap-0">
|
||||
<div className="grid grid-cols-6 gap-0">
|
||||
{([
|
||||
{ key: 'dashboard' as const, icon: <ChartIcon />, label: 'Home' },
|
||||
{ key: 'table' as const, icon: <TableIcon />, label: 'Grid' },
|
||||
{ key: 'weekly' as const, icon: <TrendingIcon />, label: 'Weekly' },
|
||||
{ key: 'ads' as const, icon: <MegaphoneIcon />, label: 'Ads' },
|
||||
{ key: 'forecast' as const, icon: <ChartIcon />, label: 'Fc 26' },
|
||||
{ key: 'mkt' as const, icon: <ChartIcon />, label: 'MKT' },
|
||||
{ key: 'vendor' as const, icon: <ChartIcon />, label: 'BSR' },
|
||||
{ key: 'experiments' as const, icon: <span className="text-lg">🧪</span>, label: 'Exp' },
|
||||
]).map(({ key, icon, label }) => (
|
||||
<button
|
||||
key={key}
|
||||
@@ -1051,8 +971,6 @@ const App: React.FC = () => {
|
||||
)
|
||||
}
|
||||
|
||||
{/* Experiment modals removed — detail/create are now inline in ExperimentsView */}
|
||||
|
||||
</div >
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user