resolve merge conflict in AlbumForm

This commit is contained in:
Justin Edmund 2025-12-11 14:05:28 -08:00
commit 2555067837
4 changed files with 34 additions and 14 deletions

View file

@ -8,7 +8,7 @@ export interface AutoSaveStoreOptions<TPayload, TResponse = unknown> {
onSaved?: (res: TResponse, ctx: { prime: (payload: TPayload) => void }) => void
}
export interface AutoSaveStore<TPayload> {
export interface AutoSaveStore<TPayload, _TResponse = unknown> {
readonly status: AutoSaveStatus
readonly lastError: string | null
schedule: () => void
@ -36,7 +36,7 @@ export interface AutoSaveStore<TPayload> {
*/
export function createAutoSaveStore<TPayload, TResponse = unknown>(
opts: AutoSaveStoreOptions<TPayload, TResponse>
): AutoSaveStore<TPayload> {
): AutoSaveStore<TPayload, unknown> {
const debounceMs = opts.debounceMs ?? 2000
const idleResetMs = opts.idleResetMs ?? 2000
let timer: ReturnType<typeof setTimeout> | null = null

View file

@ -1,7 +1,7 @@
import { loadDraft, clearDraft, timeAgo } from '$lib/admin/draftStore'
export function useDraftRecovery<TPayload>(options: {
draftKey: string | null
draftKey: () => string | null
onRestore: (payload: TPayload) => void
enabled?: boolean
}) {
@ -17,9 +17,10 @@ export function useDraftRecovery<TPayload>(options: {
// Auto-detect draft on mount using $effect
$effect(() => {
if (!options.draftKey || options.enabled === false) return
const key = options.draftKey()
if (!key || options.enabled === false) return
const draft = loadDraft<TPayload>(options.draftKey)
const draft = loadDraft<TPayload>(key)
if (draft) {
showPrompt = true
draftTimestamp = draft.ts
@ -43,19 +44,21 @@ export function useDraftRecovery<TPayload>(options: {
draftTimeText,
restore() {
if (!options.draftKey) return
const draft = loadDraft<TPayload>(options.draftKey)
const key = options.draftKey()
if (!key) return
const draft = loadDraft<TPayload>(key)
if (!draft) return
options.onRestore(draft.payload)
showPrompt = false
clearDraft(options.draftKey)
clearDraft(key)
},
dismiss() {
if (!options.draftKey) return
const key = options.draftKey()
if (!key) return
showPrompt = false
clearDraft(options.draftKey)
clearDraft(key)
}
}
}

View file

@ -2,7 +2,9 @@ import { beforeNavigate } from '$app/navigation'
import { toast } from '$lib/stores/toast'
import type { AutoSaveStore } from '$lib/admin/autoSave.svelte'
export function useFormGuards(autoSave: AutoSaveStore<unknown, unknown> | null) {
export function useFormGuards<TPayload = unknown, _TResponse = unknown>(
autoSave: AutoSaveStore<TPayload, unknown> | null
) {
if (!autoSave) return // No guards needed for create mode
// Navigation guard: flush autosave before route change
@ -21,8 +23,12 @@ export function useFormGuards(autoSave: AutoSaveStore<unknown, unknown> | null)
// Warn before closing browser tab/window if unsaved changes
$effect(() => {
// Capture autoSave in closure to avoid non-null assertions
const store = autoSave
if (!store) return
function handleBeforeUnload(event: BeforeUnloadEvent) {
if (autoSave!.status !== 'saved') {
if (store.status !== 'saved') {
event.preventDefault()
event.returnValue = ''
}
@ -34,13 +40,17 @@ export function useFormGuards(autoSave: AutoSaveStore<unknown, unknown> | null)
// Cmd/Ctrl+S keyboard shortcut for immediate save
$effect(() => {
// Capture autoSave in closure to avoid non-null assertions
const store = autoSave
if (!store) return
function handleKeydown(event: KeyboardEvent) {
const key = event.key.toLowerCase()
const isModifier = event.metaKey || event.ctrlKey
if (isModifier && key === 's') {
event.preventDefault()
autoSave!.flush().catch((error) => {
store.flush().catch((error) => {
console.error('Autosave flush failed:', error)
toast.error('Failed to save changes')
})

View file

@ -104,10 +104,15 @@
}
// Autosave store (edit mode only)
// Initialized as null and created reactively when album data becomes available
let autoSave = $state<ReturnType<typeof createAutoSaveStore<ReturnType<typeof buildPayload>, Album>> | null>(null)
// INITIALIZATION ORDER:
// 1. This effect creates autoSave when album prop becomes available
// 2. useFormGuards is called immediately after creation (same effect)
// 3. Other effects check for autoSave existence before using it
$effect(() => {
// Create or update autoSave when album becomes available
// Create autoSave when album becomes available (only once)
if (mode === 'edit' && album && !autoSave) {
const albumId = album.id // Capture album ID to avoid null reference
autoSave = createAutoSaveStore({
@ -180,6 +185,8 @@
})
// Trigger autosave when form data changes
// Using `void` operator to explicitly track dependencies without using their values
// This effect re-runs whenever any of these form fields change
$effect(() => {
void formData.title
void formData.slug