From e4c2aa0dbcb90bf61afd87b908e269ac603e1635 Mon Sep 17 00:00:00 2001 From: Jaime Idolpx Date: Tue, 9 Jun 2026 05:42:01 -0400 Subject: [PATCH] feat(App, DevicesPage): implement toast notifications for save status and update DevicesPage UI --- src/app/App.tsx | 97 ++++++++---------------------- src/app/components/DevicesPage.tsx | 4 +- 2 files changed, 26 insertions(+), 75 deletions(-) diff --git a/src/app/App.tsx b/src/app/App.tsx index 7b65042..02777c1 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; -import { Cpu, Settings, Wifi, Network, HardDrive, Activity, Search, Wrench, User, LogOut, Bell, FileText, AppWindow, Folder, Edit, Eye, Database, Upload, Download, Code2, LayoutList, Image, ChevronLeft, Loader2, Check, AlertCircle, RefreshCw, Terminal, Link, Printer, Maximize2, Minimize2 } from 'lucide-react'; -import { Toaster } from 'sonner'; +import { Cpu, Settings, Wifi, Network, HardDrive, Activity, Search, Wrench, User, LogOut, Bell, FileText, AppWindow, Folder, Edit, Eye, Database, Upload, Download, Code2, LayoutList, Image, ChevronLeft, Loader2, Terminal, Link, Printer, Maximize2, Minimize2 } from 'lucide-react'; +import { Toaster, toast } from 'sonner'; import StatusPage from './components/StatusPage'; import DevicesPage from './components/DevicesPage'; import GeneralPage from './components/GeneralPage'; @@ -49,6 +49,28 @@ export default function App() { const [devicesOpenId, setDevicesOpenId] = useState(null); const [isFullscreen, setIsFullscreen] = useState(false); + useEffect(() => { + const id = 'save-status'; + switch (saveStatus) { + case 'idle': toast.dismiss(id); break; + case 'loading': toast.loading('Loading settings…', { id }); break; + case 'unsaved': + toast(`${pendingCount} unsaved change${pendingCount === 1 ? '' : 's'}`, { + id, duration: Infinity, + action: { label: 'Save', onClick: flushNow }, + }); + break; + case 'saving': toast.loading('Saving…', { id }); break; + case 'saved': toast.success('Settings saved', { id, duration: 2000 }); break; + case 'error': + toast.error('Save failed', { + id, duration: Infinity, + action: { label: 'Retry', onClick: reload }, + }); + break; + } + }, [saveStatus, pendingCount, flushNow, reload]); + useEffect(() => { const onChange = () => setIsFullscreen(!!document.fullscreenElement); document.addEventListener('fullscreenchange', onChange); @@ -231,7 +253,6 @@ function AppPage({ title, onBack }: { title: string; onBack: () => void }) { > -
- - ); - } - - if (status === 'saving') { - return ( - - Saving - - ); - } - - if (status === 'saved') { - return ( - - Saved - - ); - } - - // error - return ( - - ); -} \ No newline at end of file diff --git a/src/app/components/DevicesPage.tsx b/src/app/components/DevicesPage.tsx index fe7984f..52bf0ae 100644 --- a/src/app/components/DevicesPage.tsx +++ b/src/app/components/DevicesPage.tsx @@ -340,14 +340,14 @@ export default function DevicesPage({ config, setConfig, openDeviceId, onClearOp
-
+ {/*
updateSetting(['cassette', 'play_record'], e.target.value)} className="w-full px-3 py-2 border border-neutral-300 rounded-lg" />
updateSetting(['cassette', 'pulldown'], e.target.value)} className="w-full px-3 py-2 border border-neutral-300 rounded-lg" /> -
+
*/}
updateSetting(['cassette', 'url'], e.target.value)} className="w-full px-3 py-2 border border-neutral-300 rounded-lg" />