From e305bf15ef78fbd1303c9105002b49f8de1814be Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 24 Jun 2025 01:56:26 +0100 Subject: [PATCH] refactor: replace button text changes with toast notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update all admin forms to use toast messages - Remove temporary "Saving..." button text changes - Remove inline error/success message displays - Keep buttons disabled during operations - Show loading, success, and error toasts appropriately Updated components: - AlbumForm: Save operations with descriptive messages - StatusDropdown: Remove loading text from buttons - MediaDetailsModal: Save, delete, and copy operations - ProjectForm: Create and update operations - EssayForm: Publish and save draft operations - SimplePostForm: Create and update posts - PhotoPostForm: Publish photo posts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/lib/components/admin/AlbumForm.svelte | 30 ++++------ src/lib/components/admin/EssayForm.svelte | 27 +++++---- .../components/admin/MediaDetailsModal.svelte | 55 ++++++------------- src/lib/components/admin/PhotoPostForm.svelte | 17 ++++-- src/lib/components/admin/ProjectForm.svelte | 25 ++++----- .../components/admin/SimplePostForm.svelte | 21 +++---- .../components/admin/StatusDropdown.svelte | 2 +- 7 files changed, 76 insertions(+), 101 deletions(-) diff --git a/src/lib/components/admin/AlbumForm.svelte b/src/lib/components/admin/AlbumForm.svelte index 2296b26..38cb243 100644 --- a/src/lib/components/admin/AlbumForm.svelte +++ b/src/lib/components/admin/AlbumForm.svelte @@ -10,6 +10,7 @@ import SmartImage from '../SmartImage.svelte' import EnhancedComposer from './EnhancedComposer.svelte' import { authenticatedFetch } from '$lib/admin-auth' + import { toast } from '$lib/stores/toast' import type { Album } from '@prisma/client' import type { JSONContent } from '@tiptap/core' @@ -34,8 +35,6 @@ // State let isLoading = $state(mode === 'edit') let isSaving = $state(false) - let error = $state('') - let successMessage = $state('') let validationErrors = $state>({}) let showBulkAlbumModal = $state(false) let albumMedia = $state([]) @@ -132,14 +131,14 @@ async function handleSave() { if (!validateForm()) { - error = 'Please fix the validation errors' + toast.error('Please fix the validation errors') return } + const loadingToastId = toast.loading(`${mode === 'edit' ? 'Saving' : 'Creating'} album...`) + try { isSaving = true - error = '' - successMessage = '' const payload = { title: formData.title, @@ -172,6 +171,9 @@ const savedAlbum = await response.json() + toast.dismiss(loadingToastId) + toast.success(`Album ${mode === 'edit' ? 'saved' : 'created'} successfully!`) + if (mode === 'create') { goto(`/admin/albums/${savedAlbum.id}/edit`) } else if (mode === 'edit' && album) { @@ -180,10 +182,12 @@ populateFormData(savedAlbum) } } catch (err) { - error = + toast.dismiss(loadingToastId) + toast.error( err instanceof Error ? err.message : `Failed to ${mode === 'edit' ? 'save' : 'create'} album` + ) console.error(err) } finally { isSaving = false @@ -252,10 +256,6 @@ {#if isLoading}
Loading album...
{:else} - {#if error} -
{error}
- {/if} -
@@ -464,16 +464,6 @@ color: $grey-40; } - .error-message { - background-color: #fee; - color: #d33; - padding: $unit-3x; - border-radius: $unit; - margin-bottom: $unit-4x; - max-width: 700px; - margin-left: auto; - margin-right: auto; - } .form-section { display: flex; diff --git a/src/lib/components/admin/EssayForm.svelte b/src/lib/components/admin/EssayForm.svelte index 4617cf3..32b07b1 100644 --- a/src/lib/components/admin/EssayForm.svelte +++ b/src/lib/components/admin/EssayForm.svelte @@ -5,6 +5,7 @@ import Editor from './Editor.svelte' import Button from './Button.svelte' import Input from './Input.svelte' + import { toast } from '$lib/stores/toast' import type { JSONContent } from '@tiptap/core' interface Props { @@ -24,8 +25,6 @@ // State let isLoading = $state(false) let isSaving = $state(false) - let error = $state('') - let successMessage = $state('') let activeTab = $state('metadata') let showPublishMenu = $state(false) @@ -80,14 +79,14 @@ } if (!title) { - error = 'Title is required' + toast.error('Title is required') return } + const loadingToastId = toast.loading(`${mode === 'edit' ? 'Saving' : 'Creating'} essay...`) + try { isSaving = true - error = '' - successMessage = '' const auth = localStorage.getItem('admin_auth') if (!auth) { @@ -121,16 +120,16 @@ } const savedPost = await response.json() - successMessage = `Essay ${mode === 'edit' ? 'saved' : 'created'} successfully!` + + toast.dismiss(loadingToastId) + toast.success(`Essay ${mode === 'edit' ? 'saved' : 'created'} successfully!`) - setTimeout(() => { - successMessage = '' - if (mode === 'create') { - goto(`/admin/posts/${savedPost.id}/edit`) - } - }, 1500) + if (mode === 'create') { + goto(`/admin/posts/${savedPost.id}/edit`) + } } catch (err) { - error = `Failed to ${mode === 'edit' ? 'save' : 'create'} essay` + toast.dismiss(loadingToastId) + toast.error(`Failed to ${mode === 'edit' ? 'save' : 'create'} essay`) console.error(err) } finally { isSaving = false @@ -196,7 +195,7 @@
@@ -1035,16 +1026,6 @@ display: flex; align-items: center; gap: $unit-2x; - - .error-text { - color: $red-60; - font-size: 0.875rem; - } - - .success-text { - color: #16a34a; // green-600 equivalent - font-size: 0.875rem; - } } } diff --git a/src/lib/components/admin/PhotoPostForm.svelte b/src/lib/components/admin/PhotoPostForm.svelte index 3e64088..58880fb 100644 --- a/src/lib/components/admin/PhotoPostForm.svelte +++ b/src/lib/components/admin/PhotoPostForm.svelte @@ -5,6 +5,7 @@ import Input from './Input.svelte' import ImageUploader from './ImageUploader.svelte' import Editor from './Editor.svelte' + import { toast } from '$lib/stores/toast' import type { JSONContent } from '@tiptap/core' import type { Media } from '@prisma/client' @@ -24,7 +25,6 @@ // State let isSaving = $state(false) - let error = $state('') let status = $state<'draft' | 'published'>(initialData?.status || 'draft') // Form data @@ -81,18 +81,19 @@ async function handleSave() { // Validate required fields if (!featuredImage) { - error = 'Please upload a photo for this post' + toast.error('Please upload a photo for this post') return } if (!title.trim()) { - error = 'Please enter a title for this post' + toast.error('Please enter a title for this post') return } + const loadingToastId = toast.loading(`${status === 'published' ? 'Publishing' : 'Saving'} photo post...`) + try { isSaving = true - error = '' // Get editor content let editorContent = content @@ -145,6 +146,9 @@ const savedPost = await response.json() + toast.dismiss(loadingToastId) + toast.success(`Photo post ${status === 'published' ? 'published' : 'saved'} successfully!`) + // Redirect to posts list or edit page if (mode === 'create') { goto(`/admin/posts/${savedPost.id}/edit`) @@ -152,7 +156,8 @@ goto('/admin/posts') } } catch (err) { - error = `Failed to ${mode === 'edit' ? 'update' : 'create'} photo post` + toast.dismiss(loadingToastId) + toast.error(`Failed to ${mode === 'edit' ? 'update' : 'create'} photo post`) console.error(err) } finally { isSaving = false @@ -192,7 +197,7 @@ onclick={handlePublish} disabled={!featuredImage || !title.trim()} > - {isSaving ? 'Publishing...' : 'Publish'} + Publish {/if}
diff --git a/src/lib/components/admin/ProjectForm.svelte b/src/lib/components/admin/ProjectForm.svelte index 68c8901..46a9395 100644 --- a/src/lib/components/admin/ProjectForm.svelte +++ b/src/lib/components/admin/ProjectForm.svelte @@ -11,6 +11,7 @@ import Button from './Button.svelte' import StatusDropdown from './StatusDropdown.svelte' import { projectSchema } from '$lib/schemas/project' + import { toast } from '$lib/stores/toast' import type { Project, ProjectFormData } from '$lib/types/project' import { defaultProjectFormData } from '$lib/types/project' @@ -24,8 +25,6 @@ // State let isLoading = $state(mode === 'edit') let isSaving = $state(false) - let error = $state('') - let successMessage = $state('') let activeTab = $state('metadata') let validationErrors = $state>({}) @@ -117,14 +116,14 @@ } if (!validateForm()) { - error = 'Please fix the validation errors' + toast.error('Please fix the validation errors') return } + const loadingToastId = toast.loading(`${mode === 'edit' ? 'Saving' : 'Creating'} project...`) + try { isSaving = true - error = '' - successMessage = '' const auth = localStorage.getItem('admin_auth') if (!auth) { @@ -173,16 +172,16 @@ } const savedProject = await response.json() - successMessage = `Project ${mode === 'edit' ? 'saved' : 'created'} successfully!` + + toast.dismiss(loadingToastId) + toast.success(`Project ${mode === 'edit' ? 'saved' : 'created'} successfully!`) - setTimeout(() => { - successMessage = '' - if (mode === 'create') { - goto(`/admin/projects/${savedProject.id}/edit`) - } - }, 1500) + if (mode === 'create') { + goto(`/admin/projects/${savedProject.id}/edit`) + } } catch (err) { - error = `Failed to ${mode === 'edit' ? 'save' : 'create'} project` + toast.dismiss(loadingToastId) + toast.error(`Failed to ${mode === 'edit' ? 'save' : 'create'} project`) console.error(err) } finally { isSaving = false diff --git a/src/lib/components/admin/SimplePostForm.svelte b/src/lib/components/admin/SimplePostForm.svelte index 2b1c0a5..5707cef 100644 --- a/src/lib/components/admin/SimplePostForm.svelte +++ b/src/lib/components/admin/SimplePostForm.svelte @@ -5,6 +5,7 @@ import Editor from './Editor.svelte' import Button from './Button.svelte' import Input from './Input.svelte' + import { toast } from '$lib/stores/toast' interface Props { postType: 'post' @@ -23,7 +24,6 @@ // State let isSaving = $state(false) - let error = $state('') let status = $state<'draft' | 'published'>(initialData?.status || 'draft') // Form data @@ -53,19 +53,20 @@ async function handleSave(publishStatus: 'draft' | 'published') { if (isOverLimit) { - error = 'Post is too long' + toast.error('Post is too long') return } // For link posts, URL is required if (linkUrl && !linkUrl.trim()) { - error = 'Link URL is required' + toast.error('Link URL is required') return } + const loadingToastId = toast.loading(`${publishStatus === 'published' ? 'Publishing' : 'Saving'} post...`) + try { isSaving = true - error = '' const auth = localStorage.getItem('admin_auth') if (!auth) { @@ -104,10 +105,14 @@ const savedPost = await response.json() + toast.dismiss(loadingToastId) + toast.success(`Post ${publishStatus === 'published' ? 'published' : 'saved'} successfully!`) + // Redirect back to posts list after creation goto('/admin/posts') } catch (err) { - error = `Failed to ${mode === 'edit' ? 'save' : 'create'} post` + toast.dismiss(loadingToastId) + toast.error(`Failed to ${mode === 'edit' ? 'save' : 'create'} post`) console.error(err) } finally { isSaving = false @@ -146,16 +151,12 @@ onclick={() => handleSave('published')} disabled={isSaving || !hasContent() || (postType === 'microblog' && isOverLimit)} > - {isSaving ? 'Posting...' : 'Post'} + Post
- {#if error} -
{error}
- {/if} -
{#if postType === 'microblog'}
diff --git a/src/lib/components/admin/StatusDropdown.svelte b/src/lib/components/admin/StatusDropdown.svelte index fc86556..43fc01e 100644 --- a/src/lib/components/admin/StatusDropdown.svelte +++ b/src/lib/components/admin/StatusDropdown.svelte @@ -76,7 +76,7 @@ onclick={handlePrimaryAction} disabled={disabled || isLoading} > - {isLoading ? `${primaryAction.label.replace(/e$/, 'ing')}...` : primaryAction.label} + {primaryAction.label} {#if hasDropdownContent}