mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 16:35:24 +02:00
feat: show Save button always, disabled when no pending changes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
a7d8dad36e
commit
1b0b35d3bf
+69
-54
@@ -80,61 +80,76 @@ export function TopBar({ stats, onExport, hasData, hasUnsavedChanges, userEmail,
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{pendingCount > 0 && (
|
<div className="relative" ref={dropdownRef}>
|
||||||
<div className="relative" ref={dropdownRef}>
|
{/* Split button: Save All + dropdown toggle */}
|
||||||
{/* Split button: Save All + dropdown toggle */}
|
<div className={cn(
|
||||||
<div className="flex items-center rounded-md overflow-hidden shadow-lg shadow-green-900/30">
|
"flex items-center rounded-md overflow-hidden shadow-lg transition-all",
|
||||||
<button
|
pendingCount > 0 ? "shadow-green-900/30" : "shadow-none opacity-40"
|
||||||
onClick={onSaveAll}
|
)}>
|
||||||
disabled={isSavingAll}
|
<button
|
||||||
className="flex items-center gap-2 px-4 py-2 text-sm font-bold transition-all bg-green-600 hover:bg-green-500 disabled:opacity-60 text-white"
|
onClick={onSaveAll}
|
||||||
>
|
disabled={isSavingAll || pendingCount === 0}
|
||||||
{isSavingAll ? <Loader2 className="w-4 h-4 animate-spin" /> : <CloudUpload className="w-4 h-4" />}
|
className={cn(
|
||||||
{isSavingAll ? 'Saving...' : `Save ${pendingCount} change${pendingCount > 1 ? 's' : ''}`}
|
"flex items-center gap-2 px-4 py-2 text-sm font-bold transition-all text-white",
|
||||||
</button>
|
pendingCount > 0
|
||||||
<button
|
? "bg-green-600 hover:bg-green-500 disabled:opacity-60"
|
||||||
onClick={() => setShowPending(v => !v)}
|
: "bg-slate-700 cursor-not-allowed"
|
||||||
disabled={isSavingAll}
|
)}
|
||||||
className="flex items-center px-2 py-2 bg-green-700 hover:bg-green-600 disabled:opacity-60 text-white border-l border-green-500/40 transition-all"
|
>
|
||||||
title="View pending changes"
|
{isSavingAll ? <Loader2 className="w-4 h-4 animate-spin" /> : <CloudUpload className="w-4 h-4" />}
|
||||||
>
|
{isSavingAll
|
||||||
<ChevronDown className={cn("w-4 h-4 transition-transform", showPending && "rotate-180")} />
|
? 'Saving...'
|
||||||
</button>
|
: pendingCount > 0
|
||||||
</div>
|
? `Save ${pendingCount} change${pendingCount > 1 ? 's' : ''}`
|
||||||
|
: 'No pending changes'}
|
||||||
{/* Dropdown: list of pending changes */}
|
</button>
|
||||||
{showPending && (
|
<button
|
||||||
<div className="absolute right-0 top-full mt-2 w-80 bg-slate-800 border border-slate-700 rounded-lg shadow-2xl z-50 overflow-hidden">
|
onClick={() => pendingCount > 0 && setShowPending(v => !v)}
|
||||||
<div className="px-3 py-2 border-b border-slate-700 flex items-center justify-between">
|
disabled={isSavingAll || pendingCount === 0}
|
||||||
<span className="text-xs font-bold text-slate-400 uppercase tracking-wider">Pending changes</span>
|
className={cn(
|
||||||
<span className="text-xs text-slate-500">{pendingCount} unsaved</span>
|
"flex items-center px-2 py-2 text-white border-l transition-all",
|
||||||
</div>
|
pendingCount > 0
|
||||||
<div className="max-h-64 overflow-y-auto">
|
? "bg-green-700 hover:bg-green-600 border-green-500/40"
|
||||||
{Object.entries(pendingChanges).map(([articleNo, { articleName }]) => (
|
: "bg-slate-700 cursor-not-allowed border-slate-600"
|
||||||
<div
|
)}
|
||||||
key={articleNo}
|
title="View pending changes"
|
||||||
className="flex items-center gap-2 px-3 py-2.5 hover:bg-slate-700/50 border-b border-slate-700/50 last:border-0"
|
>
|
||||||
>
|
<ChevronDown className={cn("w-4 h-4 transition-transform", showPending && "rotate-180")} />
|
||||||
<div className="w-2 h-2 rounded-full bg-yellow-400 shrink-0" />
|
</button>
|
||||||
<div className="flex-1 min-w-0">
|
|
||||||
<p className="text-xs font-mono text-slate-400">{articleNo}</p>
|
|
||||||
<p className="text-sm text-white truncate">{articleName}</p>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={() => onRevertRow(articleNo)}
|
|
||||||
title="Discard this change"
|
|
||||||
className="shrink-0 flex items-center gap-1 px-2 py-1 text-xs text-red-400 hover:text-white hover:bg-red-600 rounded transition-colors"
|
|
||||||
>
|
|
||||||
<RotateCcw className="w-3 h-3" />
|
|
||||||
Revert
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
{/* Dropdown: list of pending changes */}
|
||||||
|
{showPending && pendingCount > 0 && (
|
||||||
|
<div className="absolute right-0 top-full mt-2 w-80 bg-slate-800 border border-slate-700 rounded-lg shadow-2xl z-50 overflow-hidden">
|
||||||
|
<div className="px-3 py-2 border-b border-slate-700 flex items-center justify-between">
|
||||||
|
<span className="text-xs font-bold text-slate-400 uppercase tracking-wider">Pending changes</span>
|
||||||
|
<span className="text-xs text-slate-500">{pendingCount} unsaved</span>
|
||||||
|
</div>
|
||||||
|
<div className="max-h-64 overflow-y-auto">
|
||||||
|
{Object.entries(pendingChanges).map(([articleNo, { articleName }]) => (
|
||||||
|
<div
|
||||||
|
key={articleNo}
|
||||||
|
className="flex items-center gap-2 px-3 py-2.5 hover:bg-slate-700/50 border-b border-slate-700/50 last:border-0"
|
||||||
|
>
|
||||||
|
<div className="w-2 h-2 rounded-full bg-yellow-400 shrink-0" />
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<p className="text-xs font-mono text-slate-400">{articleNo}</p>
|
||||||
|
<p className="text-sm text-white truncate">{articleName}</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => onRevertRow(articleNo)}
|
||||||
|
title="Discard this change"
|
||||||
|
className="shrink-0 flex items-center gap-1 px-2 py-1 text-xs text-red-400 hover:text-white hover:bg-red-600 rounded transition-colors"
|
||||||
|
>
|
||||||
|
<RotateCcw className="w-3 h-3" />
|
||||||
|
Revert
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{hasData && (
|
{hasData && (
|
||||||
<button
|
<button
|
||||||
|
|||||||
Reference in New Issue
Block a user