From c1e3960a20bc059388d27aa6a9fef993574a519d Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Thu, 23 Apr 2026 19:07:38 +0200 Subject: [PATCH] fix: merge history data into rows when products table is empty --- src/App.tsx | 24 +++++++++++++++--------- src/lib/supabase.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index da1dbcd..dcf85e3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,7 +9,7 @@ import { TopBar } from './components/TopBar'; import { ProductDescriptions } from './components/ProductDescriptions'; import { MatrixView } from './components/MatrixView'; import { EditPanel } from './components/EditPanel'; -import { getAllSyncedRows, saveRowToSupabase, resetAllPendingRows, saveHistoryEntry, deleteHistoryEntry } from './lib/supabase'; +import { getAllSyncedRows, saveRowToSupabase, resetAllPendingRows, saveHistoryEntry, deleteHistoryEntry, getHistoryDataForMerge } from './lib/supabase'; import { getStoredSession, signOut, type AuthSession } from './lib/auth'; import { LoginPage } from './components/LoginPage'; import { DimensionsView } from './components/DimensionsView'; @@ -134,6 +134,9 @@ export default function App() { console.log('Fetching synced data from Supabase...'); const syncedData = await getAllSyncedRows(); + console.log('Fetching history data from Supabase for merge...'); + const historyData = await getHistoryDataForMerge(); + console.log('Supabase synced rows:', Object.keys(syncedData).length, '| History rows:', Object.keys(historyData).length); // Extend headers with virtual columns if the Excel is shorter than the saved data. // COLUMNS hardcoded indices (PRODUCT_TYPE=103, ITEM_TO_LOGISTIC=104, etc.) are used @@ -186,33 +189,36 @@ const articleNoIdx = resolvedCols.ARTICLE_NO; const processedRows = rows.map(row => { const articleNo = String(row[articleNoIdx]); const synced = syncedData[articleNo]; + const hist = historyData[articleNo]; // Start with fresh Dropbox values (prices from Excel) let finalRow = [...row]; - // Merge logic: Prioritize internal control columns and active session edits - if (synced && synced.data) { + // Merge logic: Prioritize internal control columns from syncedData or historyData + const sourceForInternal = synced?.data || hist; + + if (sourceForInternal) { // 1. ALWAYS restore Internal Control Columns (indices >= 100) // These are the "TYPE", "Item to Logistic", "Checking", etc. // We use hardcoded indices from COLUMNS to ensure they stay at the end. Object.values(COLUMNS).forEach(idx => { - if (idx >= 100 && synced.data[idx] !== undefined && synced.data[idx] !== null) { - finalRow[idx] = synced.data[idx]; + if (idx >= 100 && sourceForInternal[idx] !== undefined && sourceForInternal[idx] !== null) { + finalRow[idx] = sourceForInternal[idx]; } }); // 2. For Master Data (indices < 100, like UVP/SRP), only restore if it's an active edit (pending) // This protects against the "Column Shift" bug where old saved indices might be wrong. - if (synced.status === 'pending') { + if (synced?.status === 'pending') { editableColumns.forEach(idx => { - if (idx < 100 && synced.data[idx] !== undefined && synced.data[idx] !== null) { - finalRow[idx] = synced.data[idx]; + if (idx < 100 && sourceForInternal[idx] !== undefined && sourceForInternal[idx] !== null) { + finalRow[idx] = sourceForInternal[idx]; } }); } // Update row status in UI if it's not the default 'excel' - if (synced.status && synced.status !== 'excel') { + if (synced?.status && synced.status !== 'excel') { setRowStatuses(prev => ({ ...prev, [articleNo]: synced.status! })); } } diff --git a/src/lib/supabase.ts b/src/lib/supabase.ts index 87716b9..114122c 100644 --- a/src/lib/supabase.ts +++ b/src/lib/supabase.ts @@ -194,6 +194,35 @@ export async function getHistory(): Promise { } } +export async function getHistoryDataForMerge(): Promise> { + try { + const response = await safeFetch( + `${SUPABASE_URL}/rest/v1/products_history?select=product_id,new_data&order=changed_at.desc`, + { cache: 'no-store' } + ); + + if (!response.ok) { + console.error('[getHistoryDataForMerge] Error:', response.status); + return {}; + } + const entries: Array<{ product_id: string; new_data: ExcelRow }> = await response.json(); + + const result: Record = {}; + const seen = new Set(); + for (const entry of entries) { + if (seen.has(entry.product_id)) continue; + seen.add(entry.product_id); + if (entry.new_data && entry.new_data.length > 0) { + result[entry.product_id] = entry.new_data; + } + } + return result; + } catch (error: any) { + console.error('[getHistoryDataForMerge] Exception:', error.message); + return {}; + } +} + export async function deleteHistoryEntry(id: string): Promise { try { const response = await safeFetch(