From b36a53fd456409d4082b1436359a25cf4e5b7ef5 Mon Sep 17 00:00:00 2001 From: Ender Date: Fri, 24 Oct 2025 15:56:29 +0200 Subject: [PATCH] feat: add toast notifications for post save success/failure states --- apps/admin/src/components/EditorShell.tsx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/admin/src/components/EditorShell.tsx b/apps/admin/src/components/EditorShell.tsx index e744e03..7ca2683 100644 --- a/apps/admin/src/components/EditorShell.tsx +++ b/apps/admin/src/components/EditorShell.tsx @@ -1,4 +1,4 @@ -import { Box, Button, Stack, Typography, TextField, MenuItem } from '@mui/material'; +import { Box, Button, Stack, Typography, TextField, MenuItem, Snackbar, Alert } from '@mui/material'; import AdminLayout from '../layout/AdminLayout'; import Recorder from '../features/recorder/Recorder'; import RichEditor from './RichEditor'; @@ -14,6 +14,7 @@ export default function EditorShell({ onLogout, initialPostId, onBack }: { onLog const [meta, setMeta] = useState({ title: '', tagsText: '', canonicalUrl: '', featureImage: '' }); const [postClips, setPostClips] = useState>([]); const [postStatus, setPostStatus] = useState<'inbox' | 'editing' | 'ready_for_publish' | 'published' | 'archived'>('editing'); + const [toast, setToast] = useState<{ open: boolean; message: string; severity: 'success' | 'error' } | null>(null); useEffect(() => { const savedId = initialPostId || localStorage.getItem('voxblog_draft_id'); @@ -58,7 +59,7 @@ export default function EditorShell({ onLogout, initialPostId, onBack }: { onLog tags: meta.tagsText ? meta.tagsText.split(',').map(t => t.trim()).filter(Boolean) : undefined, featureImage: meta.featureImage || undefined, canonicalUrl: meta.canonicalUrl || undefined, - status: 'editing', + status: postStatus, }), }); if (res.ok) { @@ -67,14 +68,30 @@ export default function EditorShell({ onLogout, initialPostId, onBack }: { onLog setDraftId(data.id); localStorage.setItem('voxblog_draft_id', data.id); } + setToast({ open: true, message: 'Post saved', severity: 'success' }); + } else { + const text = await res.text(); + setToast({ open: true, message: `Save failed: ${text || res.status}`, severity: 'error' }); } - } catch {} + } catch (e: any) { + setToast({ open: true, message: `Save error: ${e?.message || 'unknown error'}` as string, severity: 'error' }); + } }; // No inline post switching here; selection happens on Posts page return ( + setToast(t => t ? { ...t, open: false } : null)} + anchorOrigin={{ vertical: 'top', horizontal: 'center' }} + > + setToast(t => t ? { ...t, open: false } : null)} severity={toast?.severity || 'success'} sx={{ width: '100%' }}> + {toast?.message || ''} + + Post