From b14cfe00f0c780a8515940e9d3360d5eb0523b24 Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Thu, 23 Apr 2026 14:53:43 +0200 Subject: [PATCH] feat: fullscreen mode for all tabs + fix Dropbox/Supabase sync priority --- api/dropbox-sync.js | 2 +- src/App.tsx | 17 ++++++++------- src/components/ArticleDetails.tsx | 27 ++++++++++++++++++++---- src/components/DimensionsView.tsx | 21 ++++++++++++++++-- src/components/HistoryView.tsx | 20 ++++++++++++++++-- src/components/MatrixView.tsx | 21 ++++++++++++++++-- src/components/MissingDataView.tsx | 21 ++++++++++++++++-- src/components/PendingValidationView.tsx | 23 +++++++++++++++++--- src/components/ProductDescriptions.tsx | 18 +++++++++++++++- 9 files changed, 145 insertions(+), 25 deletions(-) diff --git a/api/dropbox-sync.js b/api/dropbox-sync.js index 28ae667..f3b3fb7 100644 --- a/api/dropbox-sync.js +++ b/api/dropbox-sync.js @@ -61,7 +61,7 @@ export default async function handler(req, res) { .from('products') .upsert(productsToUpsert, { onConflict: 'product_id', - ignoreDuplicates: true + ignoreDuplicates: true // Keep this: will be overwritten by App.tsx logic if there are pending edits }); if (error) { diff --git a/src/App.tsx b/src/App.tsx index 9909c12..fd305d3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -163,19 +163,20 @@ export default function App() { const articleNo = String(row[articleNoIdx]); const synced = syncedData[articleNo]; - const finalRow = [...row]; - if (synced) { - // Smart Merge: Only overlay fields we logically "own" via this app's editors + // Start with Dropbox values (default) + let finalRow = [...row]; + + // Only preserve Supabase values if there's a PENDING edit for this article + if (synced && synced.status === 'pending') { + // Keep the manually edited values from Supabase editableColumns.forEach(idx => { if (synced.data[idx] !== undefined && synced.data[idx] !== null) { - finalRow[idx] = synced.data[idx]; + finalRow[idx] = synced.data[idx]; } }); - - if (synced.status === 'pending') { - setRowStatuses(prev => ({ ...prev, [articleNo]: 'pending' })); - } + setRowStatuses(prev => ({ ...prev, [articleNo]: 'pending' })); } + // Otherwise use Dropbox values (don't merge, just process formatting) return finalRow.map((val: any, idx: number) => { if (val === undefined || val === null || val === '') return val; diff --git a/src/components/ArticleDetails.tsx b/src/components/ArticleDetails.tsx index d3510d0..5b085cf 100644 --- a/src/components/ArticleDetails.tsx +++ b/src/components/ArticleDetails.tsx @@ -1,7 +1,7 @@ import React, { useState, useMemo } from 'react'; import { ExcelRow } from '../types'; import { useColumns } from '../contexts/ColumnsContext'; -import { Search, Filter, Edit2, ChevronDown, ChevronUp, Info, Package, X } from 'lucide-react'; +import { Search, Filter, Edit2, ChevronDown, ChevronUp, Info, Package, X, Maximize2 } from 'lucide-react'; import { cn } from '../lib/utils'; import { ColumnFilterPopover } from './ColumnFilterPopover'; @@ -24,6 +24,7 @@ export function ArticleDetails({ data, onEdit, rowStatuses }: ArticleDetailsProp const [page, setPage] = useState(1); const [columnFilters, setColumnFilters] = useState>({}); const [openFilterCol, setOpenFilterCol] = useState(null); + const [isFullscreen, setIsFullscreen] = useState(false); const [columnWidths, setColumnWidths] = useState>({ [COLUMNS.ARTICLE_NO]: 100, [COLUMNS.ARTICLE_NAME]: 200, @@ -161,9 +162,19 @@ export function ArticleDetails({ data, onEdit, rowStatuses }: ArticleDetailsProp ]; return ( -
-
- {tabs.map(tab => ( +
+ {isFullscreen && ( + + )} +
+
+ {tabs.map(tab => ( ))} +
+
diff --git a/src/components/DimensionsView.tsx b/src/components/DimensionsView.tsx index 0ef2143..2dc4767 100644 --- a/src/components/DimensionsView.tsx +++ b/src/components/DimensionsView.tsx @@ -1,7 +1,7 @@ import React, { useState, useMemo } from 'react'; import { ExcelRow } from '../types'; import { useColumns } from '../contexts/ColumnsContext'; -import { AlertTriangle, CheckCircle2, ChevronDown, ChevronRight, Edit2, Package, Boxes, Scale, Loader2, RefreshCw, Layers, Link2, Search, Filter, X, Undo2 } from 'lucide-react'; +import { AlertTriangle, CheckCircle2, ChevronDown, ChevronRight, Edit2, Package, Boxes, Scale, Loader2, RefreshCw, Layers, Link2, Search, Filter, X, Undo2, Maximize2 } from 'lucide-react'; import { cn } from '../lib/utils'; import { ConfirmModal } from './ConfirmModal'; import { ColumnFilterPopover } from './ColumnFilterPopover'; @@ -63,6 +63,7 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat const [lastClickedIndex, setLastClickedIndex] = useState(null); const [activeClusterKey, setActiveClusterKey] = useState(null); const [openDropdown, setOpenDropdown] = useState<{ rowIndex: number; field: 'outer' | 'units' | 'moq' } | null>(null); + const [isFullscreen, setIsFullscreen] = useState(false); const isDraggingRef = React.useRef(false); const dragStartRef = React.useRef(null); @@ -414,7 +415,16 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat }; return ( -
+
+ {isFullscreen && ( + + )}
@@ -509,6 +519,13 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat /> Show only inconsistent +
{groups.filter(g => g.isInconsistent).length} ISSUES
diff --git a/src/components/HistoryView.tsx b/src/components/HistoryView.tsx index 0333d1a..190243b 100644 --- a/src/components/HistoryView.tsx +++ b/src/components/HistoryView.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { History, RotateCcw, ChevronDown, ChevronRight, User, Calendar, Tag, Search, X, Edit2 } from 'lucide-react'; +import { History, RotateCcw, ChevronDown, ChevronRight, User, Calendar, Tag, Search, X, Edit2, Maximize2 } from 'lucide-react'; import { getHistory, deleteHistoryEntry, HistoryEntry } from '../lib/supabase'; import { ExcelRow } from '../types'; import { useColumns } from '../contexts/ColumnsContext'; @@ -18,6 +18,7 @@ export function HistoryView({ headers, data, onRevert, onEdit }: HistoryViewProp const [loading, setLoading] = useState(true); const [expandedId, setExpandedId] = useState(null); const [search, setSearch] = useState(''); + const [isFullscreen, setIsFullscreen] = useState(false); useEffect(() => { loadHistory(); @@ -87,7 +88,15 @@ export function HistoryView({ headers, data, onRevert, onEdit }: HistoryViewProp } return ( -
+
+ {isFullscreen && ( + + )}

@@ -122,6 +131,13 @@ export function HistoryView({ headers, data, onRevert, onEdit }: HistoryViewProp Refresh +

diff --git a/src/components/MatrixView.tsx b/src/components/MatrixView.tsx index 3f47ade..3c34672 100644 --- a/src/components/MatrixView.tsx +++ b/src/components/MatrixView.tsx @@ -1,6 +1,6 @@ import React, { useState, useMemo } from 'react'; import { ExcelRow } from '../types'; -import { Search, Filter, ChevronDown, ChevronUp, X } from 'lucide-react'; +import { Search, Filter, ChevronDown, ChevronUp, X, Maximize2 } from 'lucide-react'; import { cn } from '../lib/utils'; import { ColumnFilterPopover } from './ColumnFilterPopover'; @@ -18,6 +18,7 @@ export function MatrixView({ data, headers, rowStatuses }: MatrixViewProps) { const [openFilterCol, setOpenFilterCol] = useState(null); const [sortCol, setSortCol] = useState(null); const [sortDesc, setSortDesc] = useState(false); + const [isFullscreen, setIsFullscreen] = useState(false); const filteredData = useMemo(() => { let result = data.map((row, index) => ({ row, index })); @@ -177,7 +178,16 @@ export function MatrixView({ data, headers, rowStatuses }: MatrixViewProps) { const totalPages = Math.ceil(filteredData.length / pageSize); return ( -
+
+ {isFullscreen && ( + + )}

Matrix View

@@ -214,6 +224,13 @@ export function MatrixView({ data, headers, rowStatuses }: MatrixViewProps) { Clear All Column Filters )} +
diff --git a/src/components/MissingDataView.tsx b/src/components/MissingDataView.tsx index 7ecb77b..828df7d 100644 --- a/src/components/MissingDataView.tsx +++ b/src/components/MissingDataView.tsx @@ -1,7 +1,7 @@ import React, { useState, useMemo } from 'react'; import { ExcelRow } from '../types'; import { useColumns } from '../contexts/ColumnsContext'; -import { Search, ChevronDown, ChevronUp, X, Edit2, Save } from 'lucide-react'; +import { Search, ChevronDown, ChevronUp, X, Edit2, Save, Maximize2 } from 'lucide-react'; import { cn } from '../lib/utils'; import { ColumnFilterPopover } from './ColumnFilterPopover'; import { DateFilterPopover } from './DateFilterPopover'; @@ -76,6 +76,7 @@ export function MissingDataView({ data, headers, onSaveRow, onCaptureState }: Mi const [columnFilters, setColumnFilters] = useState>({}); const [dateFilters, setDateFilters] = useState>({}); const [openFilter, setOpenFilter] = useState(null); + const [isFullscreen, setIsFullscreen] = useState(false); const pageSize = 100; const launchDateCol = useMemo(() => { @@ -304,7 +305,16 @@ export function MissingDataView({ data, headers, onSaveRow, onCaptureState }: Mi const editingRow = editing ? data[editing.rowIndex] : null; return ( -
+
+ {isFullscreen && ( + + )}
{tabs.map(tab => (
diff --git a/src/components/PendingValidationView.tsx b/src/components/PendingValidationView.tsx index 91d14d6..bd09a03 100644 --- a/src/components/PendingValidationView.tsx +++ b/src/components/PendingValidationView.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { ExcelRow } from '../types'; import { useColumns } from '../contexts/ColumnsContext'; -import { Clock, Undo2, Package, Box, DollarSign, FileText, Search, Filter, X } from 'lucide-react'; +import { Clock, Undo2, Package, Box, DollarSign, FileText, Search, Filter, X, Maximize2 } from 'lucide-react'; import { cn } from '../lib/utils'; interface PendingValidationViewProps { @@ -15,6 +15,7 @@ interface PendingValidationViewProps { export function PendingValidationView({ data, pendingRows, rowStatuses, onRevertRow, onEdit }: PendingValidationViewProps) { const COLUMNS = useColumns(); const [search, setSearch] = useState(''); + const [isFullscreen, setIsFullscreen] = useState(false); const pendingEntries = Object.entries(pendingRows); @@ -66,7 +67,16 @@ export function PendingValidationView({ data, pendingRows, rowStatuses, onRevert }; return ( -
+
+ {isFullscreen && ( + + )}
@@ -94,6 +104,13 @@ export function PendingValidationView({ data, pendingRows, rowStatuses, onRevert )}
+
@@ -164,4 +181,4 @@ export function PendingValidationView({ data, pendingRows, rowStatuses, onRevert )}
); -} +} \ No newline at end of file diff --git a/src/components/ProductDescriptions.tsx b/src/components/ProductDescriptions.tsx index 9041716..e5059ce 100644 --- a/src/components/ProductDescriptions.tsx +++ b/src/components/ProductDescriptions.tsx @@ -223,7 +223,16 @@ export function ProductDescriptions({ data, headers, asinColumnIndex, onEdit, ro ]; return ( -
+
+ {isFullscreen && ( + + )}
{tabs.map(tab => (