From 84d02913604392f19090a12f0c4f4be27a8f5a14 Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Sat, 17 Jan 2026 11:12:39 +0100 Subject: [PATCH] refactor: simplified data loading with direct fetch endpoint --- App.tsx | 60 ++++++-------- api/dropbox/[...path].ts | 67 ---------------- api/fetch-data.ts | 32 ++++++++ components/FileUpload.tsx | 164 +++++++++++++++----------------------- vite.config.ts | 6 +- 5 files changed, 122 insertions(+), 207 deletions(-) delete mode 100644 api/dropbox/[...path].ts create mode 100644 api/fetch-data.ts diff --git a/App.tsx b/App.tsx index 6552758..ad2b0f2 100644 --- a/App.tsx +++ b/App.tsx @@ -49,49 +49,35 @@ const App: React.FC = () => { title: [], }); - // Handle URL Fetch (Auto/Manual) - const handleUrlFetch = useCallback(async (url: string) => { + // Handle Data Fetch (Simplified) + const handleDataFetch = useCallback(async () => { setSyncing(true); try { - let directUrl = url; - // Create a direct download link for Dropbox if it's a share link. - if (url.includes('dropbox.com/') && !url.includes('dl.dropboxusercontent.com')) { - const urlObject = new URL(url); - urlObject.searchParams.set('dl', '1'); - directUrl = urlObject.toString(); + console.log('[App] Fetching data from /api/fetch-data...'); + const response = await fetch('/api/fetch-data'); + + if (!response.ok) { + throw new Error(`Failed to fetch CSV: ${response.status} ${response.statusText}`); } - - // Unified Fetch Logic for Local (Vite) and Production (Vercel Function) - // Both environments now support the /api/dropbox/... path. - // - Local: Vite proxies /api/dropbox -> https://www.dropbox.com - // - Vercel: api/dropbox.js handles the request -> https://www.dropbox.com - - const urlObj = new URL(directUrl); - const searchParams = urlObj.search; - // Construct path relative to root: /api/dropbox/scl/fi/... - const fetchUrl = `/api/dropbox${urlObj.pathname}${searchParams}`; - - const response = await fetch(fetchUrl); - if (!response.ok) throw new Error(`Failed to fetch CSV from URL: ${response.status} ${response.statusText}`); - const csvText = await response.text(); const data = await processCSV(csvText); await saveSalesData(data); initializeData(data); - setActiveUrl(url); // Store the original user-facing URL + setActiveUrl(PERMANENT_DROPBOX_URL); const now = new Date().toISOString(); setLastUpdated(now); localStorage.setItem('craze_last_updated', now); - localStorage.setItem('craze_csv_url', url); - setIsDataModalOpen(false); // Close modal on success + localStorage.setItem('craze_csv_url', PERMANENT_DROPBOX_URL); + setIsDataModalOpen(false); + + console.log('[App] Successfully loaded', data.length, 'rows'); } catch (error) { - console.error("Failed to fetch/parse CSV from URL", error); - // Don't alert on auto-fetch to avoid spamming the user on startup if offline - // alert("Error syncing data. Please check the URL."); - throw error; // re-throw to be caught by caller + console.error("Failed to fetch/parse CSV", error); + alert("Error loading data. Please refresh the page."); + throw error; } finally { setSyncing(false); setLoading(false); @@ -144,13 +130,13 @@ const App: React.FC = () => { setLoading(false); } else { console.log("Fetching fresh data from Permanent URL..."); - handleUrlFetch(PERMANENT_DROPBOX_URL).catch(e => { + handleDataFetch().catch(e => { console.error("Initial fetch failed."); }); } }; initApp(); - }, [handleUrlFetch]); + }, [handleDataFetch]); // Handle uploaded Sales file (Manual) const handleSalesUpload = async (file: File) => { @@ -196,7 +182,7 @@ const App: React.FC = () => { // Refresh if it's after 7 AM and we haven't refreshed today if (now.getHours() >= 7 && lastRefreshDate !== today) { console.log("Triggering daily data refresh..."); - handleUrlFetch(PERMANENT_DROPBOX_URL).then(() => { + handleDataFetch().then(() => { localStorage.setItem('craze_last_refresh_date', today); console.log("Daily refresh successful."); }).catch(err => { @@ -212,7 +198,7 @@ const App: React.FC = () => { const interval = setInterval(checkAndRefresh, 15 * 60 * 1000); return () => clearInterval(interval); - }, [handleUrlFetch]); + }, [handleDataFetch]); // Derive Data @@ -322,7 +308,7 @@ const App: React.FC = () => { {/* NEW REFRESH BUTTON */} - - - - - {isLoading && !activeUrl && ( -
-
- Processing data... +
+
- )} + +
+ +
+
); }; diff --git a/vite.config.ts b/vite.config.ts index ac20200..36f8ac4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -9,10 +9,10 @@ export default defineConfig(({ mode }) => { port: 3000, host: '0.0.0.0', proxy: { - '/api/dropbox': { - target: 'https://www.dropbox.com', + '/api/fetch-data': { + target: 'https://www.dropbox.com/scl/fi/b9zxn4z5i7sxwfakk5g5y/Amazon-Sell-Out-2023-2025.csv?rlkey=uoto6v0mm99py8nszy8ldtez8&st=pzn1zkrg&dl=1', changeOrigin: true, - rewrite: (path) => path.replace(/^\/api\/dropbox/, ''), + rewrite: () => '', // Replace entire path with empty string (target has full URL) followRedirects: true } }