feat: entry editor at /content/:key/new and /content/:key/:id
This commit is contained in:
1 parent
91d916fb74
commit
fba20f83c5
94 files changed
+7116
-423
No files matched your search
@@ -0,0 +1,90 @@
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { t } from '@/i18n'
|
||||
import { useLocalizedToast } from '@/i18n/presentation'
|
||||
import { ApiError } from '@/composables/useApi'
|
||||
import { useEntries } from '@/composables/useEntries'
|
||||
import type { EntryDraft } from '@/composables/useEntryDraft'
|
||||
import { isGoneError } from '@/lib/entryServerError'
|
||||
import { contentPath } from '@/lib/routePaths'
|
||||
|
||||
const UNAUTHORIZED = 401
|
||||
const TOAST_ID = 'entry-deleted'
|
||||
|
||||
export type RemovalStage = 'closed' | 'confirm' | 'failed'
|
||||
|
||||
export function useEntryRemoval(editor: EntryDraft, typeName: () => string, title: () => string) {
|
||||
const router = useRouter()
|
||||
const toast = useLocalizedToast()
|
||||
const { deleteEntry } = useEntries()
|
||||
|
||||
const stage = ref<RemovalStage>('closed')
|
||||
const pending = ref(false)
|
||||
const done = ref(false)
|
||||
|
||||
function open() {
|
||||
if (!pending.value && !editor.saving.value && editor.entryId.value !== null) {
|
||||
stage.value = 'confirm'
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (!pending.value) {
|
||||
stage.value = 'closed'
|
||||
}
|
||||
}
|
||||
|
||||
function announce(deletedTitle: string) {
|
||||
toast.add(() => ({
|
||||
id: TOAST_ID,
|
||||
color: 'success',
|
||||
icon: 'i-lucide-circle-check',
|
||||
title: t('Entry deleted'),
|
||||
description: t('"{0}" was deleted from {1}.', [deletedTitle, typeName()]),
|
||||
}))
|
||||
}
|
||||
|
||||
function refuse(error: unknown) {
|
||||
if (error instanceof ApiError && error.status === UNAUTHORIZED) {
|
||||
return
|
||||
}
|
||||
if (isGoneError(error)) {
|
||||
stage.value = 'closed'
|
||||
editor.load.markGone(error)
|
||||
return
|
||||
}
|
||||
stage.value = 'failed'
|
||||
}
|
||||
|
||||
async function confirm() {
|
||||
const id = editor.entryId.value
|
||||
if (pending.value || id === null) {
|
||||
return
|
||||
}
|
||||
const deletedTitle = title()
|
||||
pending.value = true
|
||||
stage.value = 'confirm'
|
||||
try {
|
||||
await deleteEntry(editor.typeKey, id)
|
||||
} catch (error) {
|
||||
pending.value = false
|
||||
refuse(error)
|
||||
return
|
||||
}
|
||||
pending.value = false
|
||||
done.value = true
|
||||
stage.value = 'closed'
|
||||
announce(deletedTitle)
|
||||
const arrived = await router.replace(contentPath(editor.typeKey)).then(
|
||||
(failure) => !failure,
|
||||
() => false,
|
||||
)
|
||||
if (!arrived) {
|
||||
done.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return { stage, pending, done, open, close, confirm }
|
||||
}
|
||||
|
||||
export type EntryRemoval = ReturnType<typeof useEntryRemoval>
|
||||
Reference in new issue
Block a user