mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 12:25:23 +02:00
feat: fullscreen mode for all tabs + fix Dropbox/Supabase sync priority
This commit is contained in:
+1
-1
@@ -61,7 +61,7 @@ export default async function handler(req, res) {
|
|||||||
.from('products')
|
.from('products')
|
||||||
.upsert(productsToUpsert, {
|
.upsert(productsToUpsert, {
|
||||||
onConflict: 'product_id',
|
onConflict: 'product_id',
|
||||||
ignoreDuplicates: true
|
ignoreDuplicates: true // Keep this: will be overwritten by App.tsx logic if there are pending edits
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|||||||
+9
-8
@@ -163,19 +163,20 @@ export default function App() {
|
|||||||
const articleNo = String(row[articleNoIdx]);
|
const articleNo = String(row[articleNoIdx]);
|
||||||
const synced = syncedData[articleNo];
|
const synced = syncedData[articleNo];
|
||||||
|
|
||||||
const finalRow = [...row];
|
// Start with Dropbox values (default)
|
||||||
if (synced) {
|
let finalRow = [...row];
|
||||||
// Smart Merge: Only overlay fields we logically "own" via this app's editors
|
|
||||||
|
// 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 => {
|
editableColumns.forEach(idx => {
|
||||||
if (synced.data[idx] !== undefined && synced.data[idx] !== null) {
|
if (synced.data[idx] !== undefined && synced.data[idx] !== null) {
|
||||||
finalRow[idx] = synced.data[idx];
|
finalRow[idx] = synced.data[idx];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setRowStatuses(prev => ({ ...prev, [articleNo]: 'pending' }));
|
||||||
if (synced.status === 'pending') {
|
|
||||||
setRowStatuses(prev => ({ ...prev, [articleNo]: 'pending' }));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Otherwise use Dropbox values (don't merge, just process formatting)
|
||||||
|
|
||||||
return finalRow.map((val: any, idx: number) => {
|
return finalRow.map((val: any, idx: number) => {
|
||||||
if (val === undefined || val === null || val === '') return val;
|
if (val === undefined || val === null || val === '') return val;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useMemo } from 'react';
|
import React, { useState, useMemo } from 'react';
|
||||||
import { ExcelRow } from '../types';
|
import { ExcelRow } from '../types';
|
||||||
import { useColumns } from '../contexts/ColumnsContext';
|
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 { cn } from '../lib/utils';
|
||||||
import { ColumnFilterPopover } from './ColumnFilterPopover';
|
import { ColumnFilterPopover } from './ColumnFilterPopover';
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ export function ArticleDetails({ data, onEdit, rowStatuses }: ArticleDetailsProp
|
|||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [columnFilters, setColumnFilters] = useState<Record<number, string[]>>({});
|
const [columnFilters, setColumnFilters] = useState<Record<number, string[]>>({});
|
||||||
const [openFilterCol, setOpenFilterCol] = useState<number | null>(null);
|
const [openFilterCol, setOpenFilterCol] = useState<number | null>(null);
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
const [columnWidths, setColumnWidths] = useState<Record<number, number>>({
|
const [columnWidths, setColumnWidths] = useState<Record<number, number>>({
|
||||||
[COLUMNS.ARTICLE_NO]: 100,
|
[COLUMNS.ARTICLE_NO]: 100,
|
||||||
[COLUMNS.ARTICLE_NAME]: 200,
|
[COLUMNS.ARTICLE_NAME]: 200,
|
||||||
@@ -161,9 +162,19 @@ export function ArticleDetails({ data, onEdit, rowStatuses }: ArticleDetailsProp
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full">
|
<div className={isFullscreen ? "fixed inset-0 z-40 bg-[#041021] p-6 overflow-auto" : "flex flex-col h-full"}>
|
||||||
<div className="flex flex-wrap gap-2 mb-6">
|
{isFullscreen && (
|
||||||
{tabs.map(tab => (
|
<button
|
||||||
|
onClick={() => setIsFullscreen(false)}
|
||||||
|
className="fixed top-4 right-4 z-50 w-10 h-10 flex items-center justify-center bg-slate-800/90 backdrop-blur border border-slate-600 text-white rounded hover:bg-slate-700 hover:scale-105 transition-all"
|
||||||
|
title="Exit fullscreen"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<div className="flex items-center justify-between mb-6">
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{tabs.map(tab => (
|
||||||
<button
|
<button
|
||||||
key={tab.id}
|
key={tab.id}
|
||||||
onClick={() => { setActiveTab(tab.id); setPage(1); }}
|
onClick={() => { setActiveTab(tab.id); setPage(1); }}
|
||||||
@@ -177,6 +188,14 @@ export function ArticleDetails({ data, onEdit, rowStatuses }: ArticleDetailsProp
|
|||||||
{tab.label}
|
{tab.label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(true)}
|
||||||
|
className="p-2 text-slate-400 hover:text-white hover:bg-slate-700 rounded-md transition-colors"
|
||||||
|
title="Fullscreen"
|
||||||
|
>
|
||||||
|
<Maximize2 className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap gap-4 mb-6 bg-slate-800/50 p-4 rounded-xl border border-slate-700/50">
|
<div className="flex flex-wrap gap-4 mb-6 bg-slate-800/50 p-4 rounded-xl border border-slate-700/50">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useMemo } from 'react';
|
import React, { useState, useMemo } from 'react';
|
||||||
import { ExcelRow } from '../types';
|
import { ExcelRow } from '../types';
|
||||||
import { useColumns } from '../contexts/ColumnsContext';
|
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 { cn } from '../lib/utils';
|
||||||
import { ConfirmModal } from './ConfirmModal';
|
import { ConfirmModal } from './ConfirmModal';
|
||||||
import { ColumnFilterPopover } from './ColumnFilterPopover';
|
import { ColumnFilterPopover } from './ColumnFilterPopover';
|
||||||
@@ -63,6 +63,7 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat
|
|||||||
const [lastClickedIndex, setLastClickedIndex] = useState<number | null>(null);
|
const [lastClickedIndex, setLastClickedIndex] = useState<number | null>(null);
|
||||||
const [activeClusterKey, setActiveClusterKey] = useState<string | null>(null);
|
const [activeClusterKey, setActiveClusterKey] = useState<string | null>(null);
|
||||||
const [openDropdown, setOpenDropdown] = useState<{ rowIndex: number; field: 'outer' | 'units' | 'moq' } | null>(null);
|
const [openDropdown, setOpenDropdown] = useState<{ rowIndex: number; field: 'outer' | 'units' | 'moq' } | null>(null);
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
|
||||||
const isDraggingRef = React.useRef(false);
|
const isDraggingRef = React.useRef(false);
|
||||||
const dragStartRef = React.useRef<number | null>(null);
|
const dragStartRef = React.useRef<number | null>(null);
|
||||||
@@ -414,7 +415,16 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className={isFullscreen ? "fixed inset-0 z-40 bg-[#041021] p-6 overflow-auto" : "space-y-6"}>
|
||||||
|
{isFullscreen && (
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(false)}
|
||||||
|
className="fixed top-4 right-4 z-50 w-10 h-10 flex items-center justify-center bg-slate-800/90 backdrop-blur border border-slate-600 text-white rounded hover:bg-slate-700 hover:scale-105 transition-all"
|
||||||
|
title="Exit fullscreen"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<div className="flex flex-wrap items-center gap-4 bg-slate-800/50 p-4 rounded-lg border border-slate-700">
|
<div className="flex flex-wrap items-center gap-4 bg-slate-800/50 p-4 rounded-lg border border-slate-700">
|
||||||
<div className="relative flex-1 min-w-[250px]">
|
<div className="relative flex-1 min-w-[250px]">
|
||||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500" />
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500" />
|
||||||
@@ -509,6 +519,13 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat
|
|||||||
/>
|
/>
|
||||||
Show only inconsistent
|
Show only inconsistent
|
||||||
</label>
|
</label>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(true)}
|
||||||
|
className="p-2 text-slate-400 hover:text-white hover:bg-slate-700 rounded transition-colors ml-4"
|
||||||
|
title="Fullscreen"
|
||||||
|
>
|
||||||
|
<Maximize2 className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
<div className="text-[10px] font-bold text-amber-500 bg-amber-500/10 px-2 py-1 rounded border border-amber-500/20 whitespace-nowrap">
|
<div className="text-[10px] font-bold text-amber-500 bg-amber-500/10 px-2 py-1 rounded border border-amber-500/20 whitespace-nowrap">
|
||||||
{groups.filter(g => g.isInconsistent).length} ISSUES
|
{groups.filter(g => g.isInconsistent).length} ISSUES
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
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 { getHistory, deleteHistoryEntry, HistoryEntry } from '../lib/supabase';
|
||||||
import { ExcelRow } from '../types';
|
import { ExcelRow } from '../types';
|
||||||
import { useColumns } from '../contexts/ColumnsContext';
|
import { useColumns } from '../contexts/ColumnsContext';
|
||||||
@@ -18,6 +18,7 @@ export function HistoryView({ headers, data, onRevert, onEdit }: HistoryViewProp
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [expandedId, setExpandedId] = useState<string | null>(null);
|
const [expandedId, setExpandedId] = useState<string | null>(null);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadHistory();
|
loadHistory();
|
||||||
@@ -87,7 +88,15 @@ export function HistoryView({ headers, data, onRevert, onEdit }: HistoryViewProp
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6 animate-in fade-in slide-in-from-bottom-4 duration-500">
|
<div className={isFullscreen ? "fixed inset-0 z-40 bg-[#041021] p-6 overflow-auto" : "space-y-6 animate-in fade-in slide-in-from-bottom-4 duration-500"}>
|
||||||
|
{isFullscreen && (
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(false)}
|
||||||
|
className="fixed top-4 right-4 z-50 p-2 bg-slate-800 hover:bg-slate-700 text-slate-200 rounded-md transition-colors border border-slate-700"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold text-white flex items-center gap-3">
|
<h1 className="text-2xl font-bold text-white flex items-center gap-3">
|
||||||
@@ -122,6 +131,13 @@ export function HistoryView({ headers, data, onRevert, onEdit }: HistoryViewProp
|
|||||||
<RotateCcw className="w-4 h-4" />
|
<RotateCcw className="w-4 h-4" />
|
||||||
Refresh
|
Refresh
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(!isFullscreen)}
|
||||||
|
className="p-2 bg-slate-800 hover:bg-slate-700 text-slate-200 rounded-md transition-colors border border-slate-700"
|
||||||
|
title={isFullscreen ? "Exit fullscreen" : "Enter fullscreen"}
|
||||||
|
>
|
||||||
|
<Maximize2 className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useMemo } from 'react';
|
import React, { useState, useMemo } from 'react';
|
||||||
import { ExcelRow } from '../types';
|
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 { cn } from '../lib/utils';
|
||||||
import { ColumnFilterPopover } from './ColumnFilterPopover';
|
import { ColumnFilterPopover } from './ColumnFilterPopover';
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@ export function MatrixView({ data, headers, rowStatuses }: MatrixViewProps) {
|
|||||||
const [openFilterCol, setOpenFilterCol] = useState<number | null>(null);
|
const [openFilterCol, setOpenFilterCol] = useState<number | null>(null);
|
||||||
const [sortCol, setSortCol] = useState<number | null>(null);
|
const [sortCol, setSortCol] = useState<number | null>(null);
|
||||||
const [sortDesc, setSortDesc] = useState(false);
|
const [sortDesc, setSortDesc] = useState(false);
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
|
||||||
const filteredData = useMemo(() => {
|
const filteredData = useMemo(() => {
|
||||||
let result = data.map((row, index) => ({ row, index }));
|
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);
|
const totalPages = Math.ceil(filteredData.length / pageSize);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full bg-slate-800 rounded-xl border border-slate-700 shadow-xl overflow-hidden">
|
<div className={isFullscreen ? "fixed inset-0 z-40 bg-[#041021] p-6 overflow-auto" : "flex flex-col h-full bg-slate-800 rounded-xl border border-slate-700 shadow-xl overflow-hidden"}>
|
||||||
|
{isFullscreen && (
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(false)}
|
||||||
|
className="fixed top-4 right-4 z-50 w-10 h-10 flex items-center justify-center bg-slate-800/90 backdrop-blur border border-slate-600 text-white rounded hover:bg-slate-700 hover:scale-105 transition-all"
|
||||||
|
title="Exit fullscreen"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<div className="p-4 border-b border-slate-700 bg-slate-800/50 flex items-center justify-between">
|
<div className="p-4 border-b border-slate-700 bg-slate-800/50 flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold text-white">Matrix View</h2>
|
<h2 className="text-lg font-semibold text-white">Matrix View</h2>
|
||||||
@@ -214,6 +224,13 @@ export function MatrixView({ data, headers, rowStatuses }: MatrixViewProps) {
|
|||||||
Clear All Column Filters
|
Clear All Column Filters
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(true)}
|
||||||
|
className="p-2 text-slate-400 hover:text-white hover:bg-slate-700 rounded transition-colors"
|
||||||
|
title="Fullscreen"
|
||||||
|
>
|
||||||
|
<Maximize2 className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useMemo } from 'react';
|
import React, { useState, useMemo } from 'react';
|
||||||
import { ExcelRow } from '../types';
|
import { ExcelRow } from '../types';
|
||||||
import { useColumns } from '../contexts/ColumnsContext';
|
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 { cn } from '../lib/utils';
|
||||||
import { ColumnFilterPopover } from './ColumnFilterPopover';
|
import { ColumnFilterPopover } from './ColumnFilterPopover';
|
||||||
import { DateFilterPopover } from './DateFilterPopover';
|
import { DateFilterPopover } from './DateFilterPopover';
|
||||||
@@ -76,6 +76,7 @@ export function MissingDataView({ data, headers, onSaveRow, onCaptureState }: Mi
|
|||||||
const [columnFilters, setColumnFilters] = useState<Record<number, string[]>>({});
|
const [columnFilters, setColumnFilters] = useState<Record<number, string[]>>({});
|
||||||
const [dateFilters, setDateFilters] = useState<Record<number, { start: string; end: string }>>({});
|
const [dateFilters, setDateFilters] = useState<Record<number, { start: string; end: string }>>({});
|
||||||
const [openFilter, setOpenFilter] = useState<number | null>(null);
|
const [openFilter, setOpenFilter] = useState<number | null>(null);
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
const pageSize = 100;
|
const pageSize = 100;
|
||||||
|
|
||||||
const launchDateCol = useMemo(() => {
|
const launchDateCol = useMemo(() => {
|
||||||
@@ -304,7 +305,16 @@ export function MissingDataView({ data, headers, onSaveRow, onCaptureState }: Mi
|
|||||||
const editingRow = editing ? data[editing.rowIndex] : null;
|
const editingRow = editing ? data[editing.rowIndex] : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full">
|
<div className={isFullscreen ? "fixed inset-0 z-40 bg-[#041021] p-6 overflow-auto" : "flex flex-col h-full"}>
|
||||||
|
{isFullscreen && (
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(false)}
|
||||||
|
className="fixed top-4 right-4 z-50 w-10 h-10 flex items-center justify-center bg-slate-800/90 backdrop-blur border border-slate-600 text-white rounded hover:bg-slate-700 hover:scale-105 transition-all"
|
||||||
|
title="Exit fullscreen"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<div className="flex flex-wrap gap-2 mb-6">
|
<div className="flex flex-wrap gap-2 mb-6">
|
||||||
{tabs.map(tab => (
|
{tabs.map(tab => (
|
||||||
<button
|
<button
|
||||||
@@ -320,6 +330,13 @@ export function MissingDataView({ data, headers, onSaveRow, onCaptureState }: Mi
|
|||||||
{tab.label}
|
{tab.label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(true)}
|
||||||
|
className="ml-auto p-2 text-slate-400 hover:text-white hover:bg-slate-700 rounded transition-colors"
|
||||||
|
title="Fullscreen"
|
||||||
|
>
|
||||||
|
<Maximize2 className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap gap-4 mb-6 bg-slate-800/50 p-4 rounded-xl border border-slate-700/50">
|
<div className="flex flex-wrap gap-4 mb-6 bg-slate-800/50 p-4 rounded-xl border border-slate-700/50">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { ExcelRow } from '../types';
|
import { ExcelRow } from '../types';
|
||||||
import { useColumns } from '../contexts/ColumnsContext';
|
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';
|
import { cn } from '../lib/utils';
|
||||||
|
|
||||||
interface PendingValidationViewProps {
|
interface PendingValidationViewProps {
|
||||||
@@ -15,6 +15,7 @@ interface PendingValidationViewProps {
|
|||||||
export function PendingValidationView({ data, pendingRows, rowStatuses, onRevertRow, onEdit }: PendingValidationViewProps) {
|
export function PendingValidationView({ data, pendingRows, rowStatuses, onRevertRow, onEdit }: PendingValidationViewProps) {
|
||||||
const COLUMNS = useColumns();
|
const COLUMNS = useColumns();
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
|
||||||
const pendingEntries = Object.entries(pendingRows);
|
const pendingEntries = Object.entries(pendingRows);
|
||||||
|
|
||||||
@@ -66,7 +67,16 @@ export function PendingValidationView({ data, pendingRows, rowStatuses, onRevert
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-1 flex flex-col h-full overflow-hidden">
|
<div className={isFullscreen ? "fixed inset-0 z-40 bg-[#041021] p-6 overflow-auto" : "flex-1 flex flex-col h-full overflow-hidden"}>
|
||||||
|
{isFullscreen && (
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(false)}
|
||||||
|
className="fixed top-4 right-4 z-50 w-10 h-10 flex items-center justify-center bg-slate-800/90 backdrop-blur border border-slate-600 text-white rounded hover:bg-slate-700 hover:scale-105 transition-all"
|
||||||
|
title="Exit fullscreen"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<div className="flex items-center justify-between p-4 border-b border-slate-700">
|
<div className="flex items-center justify-between p-4 border-b border-slate-700">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Clock className="w-5 h-5 text-yellow-500" />
|
<Clock className="w-5 h-5 text-yellow-500" />
|
||||||
@@ -94,6 +104,13 @@ export function PendingValidationView({ data, pendingRows, rowStatuses, onRevert
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(true)}
|
||||||
|
className="p-2 text-slate-400 hover:text-white hover:bg-slate-700 rounded transition-colors"
|
||||||
|
title="Fullscreen"
|
||||||
|
>
|
||||||
|
<Maximize2 className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -164,4 +181,4 @@ export function PendingValidationView({ data, pendingRows, rowStatuses, onRevert
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -223,7 +223,16 @@ export function ProductDescriptions({ data, headers, asinColumnIndex, onEdit, ro
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full">
|
<div className={isFullscreen ? "fixed inset-0 z-40 bg-[#041021] p-6 overflow-auto" : "flex flex-col h-full"}>
|
||||||
|
{isFullscreen && (
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(false)}
|
||||||
|
className="fixed top-4 right-4 z-50 w-10 h-10 flex items-center justify-center bg-slate-800/90 backdrop-blur border border-slate-600 text-white rounded hover:bg-slate-700 hover:scale-105 transition-all"
|
||||||
|
title="Exit fullscreen"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<div className="flex flex-wrap gap-2 mb-6">
|
<div className="flex flex-wrap gap-2 mb-6">
|
||||||
{tabs.map(tab => (
|
{tabs.map(tab => (
|
||||||
<button
|
<button
|
||||||
@@ -239,6 +248,13 @@ export function ProductDescriptions({ data, headers, asinColumnIndex, onEdit, ro
|
|||||||
{tab.label}
|
{tab.label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFullscreen(true)}
|
||||||
|
className="ml-auto p-2 text-slate-400 hover:text-white hover:bg-slate-700 rounded transition-colors"
|
||||||
|
title="Fullscreen"
|
||||||
|
>
|
||||||
|
<Maximize2 className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap gap-4 mb-6 bg-slate-800 p-4 rounded-xl border border-slate-700 shadow-sm">
|
<div className="flex flex-wrap gap-4 mb-6 bg-slate-800 p-4 rounded-xl border border-slate-700 shadow-sm">
|
||||||
|
|||||||
Reference in New Issue
Block a user