refactor(components): update story form
add `draftData` prop to distinguish whether we're editing a draft or a published story actually renumber chapter indexes after reordering use draftData prop in form change callback
This commit is contained in:
parent
4838b7b624
commit
6016813f4c
@ -5,7 +5,7 @@
|
|||||||
import { Field, FieldArray, useForm, useFieldArray } from "vee-validate";
|
import { Field, FieldArray, useForm, useFieldArray } from "vee-validate";
|
||||||
import { ASpin } from "#components";
|
import { ASpin } from "#components";
|
||||||
import { storySchema } from "@client/storyFormSchema";
|
import { storySchema } from "@client/storyFormSchema";
|
||||||
import { FormStory, defaultChapter } from "@client/types/form/story";
|
import { FormStory, defaultChapter, FormChapter } from "@client/types/form/story";
|
||||||
import { autoEdit, autoSave, debouncedAutoEdit, debouncedAutoSave } from "@client/utils";
|
import { autoEdit, autoSave, debouncedAutoEdit, debouncedAutoSave } from "@client/utils";
|
||||||
|
|
||||||
import findUser from "~/components/findUser.vue";
|
import findUser from "~/components/findUser.vue";
|
||||||
@ -20,17 +20,16 @@
|
|||||||
endpoint: string;
|
endpoint: string;
|
||||||
endpointMethod: "put" | "post";
|
endpointMethod: "put" | "post";
|
||||||
submitText?: string;
|
submitText?: string;
|
||||||
|
draftData?: {
|
||||||
|
endpoint: string;
|
||||||
|
endpointMethod: "put" | "post";
|
||||||
|
};
|
||||||
}>();
|
}>();
|
||||||
let w;
|
|
||||||
onMounted(() => {
|
|
||||||
w = window;
|
|
||||||
});
|
|
||||||
const dc = defaultChapter;
|
const dc = defaultChapter;
|
||||||
// data: FormStory;
|
|
||||||
const sdata = defineModel<FormStory>("data", {
|
const sdata = defineModel<FormStory>("data", {
|
||||||
required: true,
|
required: true,
|
||||||
});
|
});
|
||||||
let drag = false;
|
let drag: boolean = false;
|
||||||
const expandos = ref<string[]>([]);
|
const expandos = ref<string[]>([]);
|
||||||
|
|
||||||
function logSubmit(values, actions) {
|
function logSubmit(values, actions) {
|
||||||
@ -46,27 +45,32 @@
|
|||||||
otherBtnInvoked.value = false;
|
otherBtnInvoked.value = false;
|
||||||
await autoSave(values);
|
await autoSave(values);
|
||||||
} else {
|
} else {
|
||||||
const { data: dat } = await useApiFetch(`/story/new`, {
|
const { data: dat } = await useApiFetch<any>(`/story/new`, {
|
||||||
method: "post",
|
method: "post",
|
||||||
body: values,
|
body: values,
|
||||||
});
|
});
|
||||||
if (dat.success) {
|
if (dat.value.success) {
|
||||||
await router.push(`/story/${dat.story._id}/1`);
|
await router.push(`/story/${dat.value.story._id}/1`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await autoEdit(values, props.endpoint, props.endpointMethod);
|
await autoEdit(values, props.endpoint, props.endpointMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function inval({ values, errors, results }) {
|
|
||||||
logSubmit(values, undefined);
|
|
||||||
}
|
|
||||||
const { values, setFieldValue, handleSubmit } = useForm<FormStory>({
|
const { values, setFieldValue, handleSubmit } = useForm<FormStory>({
|
||||||
keepValuesOnUnmount: true,
|
keepValuesOnUnmount: true,
|
||||||
validationSchema: storySchema,
|
validationSchema: storySchema,
|
||||||
initialValues: sdata.value,
|
initialValues: sdata.value,
|
||||||
});
|
});
|
||||||
// const { push, remove, move, fields } = useFieldArray<FormChapter>("chapters");
|
function renumber(update: (idx: number, value: FormChapter) => void) {
|
||||||
|
for (let i = 0; i < values.chapters.length; i++) {
|
||||||
|
const nv = values.chapters[i];
|
||||||
|
nv.index = i + 1;
|
||||||
|
update(i, nv);
|
||||||
|
sdata.value.chapters[i].index = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
const subCb = handleSubmit(onSubmit);
|
const subCb = handleSubmit(onSubmit);
|
||||||
|
|
||||||
const pushHOF = (push) => (e) => {
|
const pushHOF = (push) => (e) => {
|
||||||
@ -96,7 +100,18 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<form data-testid="storyform" @submit="subCb" @change="() => (canDraft ? debouncedAutoSave(values) : debouncedAutoEdit(values, endpoint, endpointMethod))">
|
<form
|
||||||
|
data-testid="storyform"
|
||||||
|
@submit="subCb"
|
||||||
|
@change="
|
||||||
|
() =>
|
||||||
|
canDraft
|
||||||
|
? draftData
|
||||||
|
? debouncedAutoSave(values, draftData.endpoint, draftData.endpointMethod)
|
||||||
|
: debouncedAutoSave(values)
|
||||||
|
: debouncedAutoEdit(values, endpoint, endpointMethod)
|
||||||
|
"
|
||||||
|
>
|
||||||
<!-- <a-form v-bind:model="acData"> -->
|
<!-- <a-form v-bind:model="acData"> -->
|
||||||
|
|
||||||
<Field name="title" v-slot="{ value, field, errorMessage }">
|
<Field name="title" v-slot="{ value, field, errorMessage }">
|
||||||
@ -112,30 +127,26 @@
|
|||||||
</Field>
|
</Field>
|
||||||
<a-divider />
|
<a-divider />
|
||||||
<!-- <test1/> -->
|
<!-- <test1/> -->
|
||||||
<field-array name="chapters" v-slot="{ fields, push, remove, move }">
|
<field-array name="chapters" v-slot="{ fields, push, remove, move, update }">
|
||||||
<client-only :fallback="h(ASpin)">
|
<client-only :fallback="h(ASpin)">
|
||||||
<div>
|
<div>
|
||||||
<div v-for="(element, index) in data.chapters">
|
<div v-for="(element, index) in values.chapters">
|
||||||
<client-only>
|
<client-only>
|
||||||
<Teleport :to="`#chapter-\\[${element.uuidKey}\\]`">
|
<Teleport :to="`#chapter-\\[${element.uuidKey}\\]`">
|
||||||
<a-collapse v-model:active-key="expandos" collapsible="icon">
|
<a-collapse v-model:active-key="expandos" collapsible="icon">
|
||||||
<template #expandIcon="{ isActive }">
|
<template #expandIcon="{ isActive }">
|
||||||
<span :data-testid="`storyform.chapters[${index}].collapse`"> <RightOutlined :rotate="isActive ? 90 : undefined" /></span>
|
<span :data-testid="`storyform.chapters[${index}].collapse`"> <RightOutlined :rotate="isActive ? 90 : undefined" /></span>
|
||||||
</template>
|
</template>
|
||||||
<a-collapse-panel :key="`${element.uuidKey}`">
|
<a-collapse-panel :key="`${element.uuidKey}`" :data-testid="`storyform.chapters[${index}].outer`">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div :data-testid="`storyform.chapters[${index}].header`" style="display: flex; justify-content: space-between">
|
<div :data-testid="`storyform.chapters[${index}].header`" style="display: flex; align-items: center; justify-content: space-between">
|
||||||
<span :data-testid="`storyform.chapters[${index}].titleEl`">{{ values.chapters[index]?.chapterTitle || "Untitled" }}</span>
|
<span :data-testid="`storyform.chapters[${index}].titleEl`">{{ values.chapters[index]?.chapterTitle || "Untitled" }}</span>
|
||||||
<a-button
|
<a-button
|
||||||
@click="
|
@click="
|
||||||
(e) => {
|
(e) => {
|
||||||
// let localFields = toRaw(fields);
|
|
||||||
// log.debug(`${index} | ${element.index}`);
|
|
||||||
// log.debug('fields->', localFields);
|
|
||||||
data.chapters.splice(index, 1);
|
data.chapters.splice(index, 1);
|
||||||
remove(index);
|
remove(index);
|
||||||
// todo renumber
|
renumber(update);
|
||||||
// renumber()
|
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
@ -172,6 +183,7 @@
|
|||||||
console.debug(e.moved);
|
console.debug(e.moved);
|
||||||
move(e.moved.oldIndex, e.moved.newIndex);
|
move(e.moved.oldIndex, e.moved.newIndex);
|
||||||
data.chapters = lmove(data.chapters, e.moved.oldIndex, e.moved.newIndex);
|
data.chapters = lmove(data.chapters, e.moved.oldIndex, e.moved.newIndex);
|
||||||
|
renumber(update);
|
||||||
// w.tinymce.remove();
|
// w.tinymce.remove();
|
||||||
// log.debug(toRaw(acData.chapters.map((a) => toRaw(a))));
|
// log.debug(toRaw(acData.chapters.map((a) => toRaw(a))));
|
||||||
}
|
}
|
||||||
@ -191,3 +203,11 @@
|
|||||||
<a-button html-type="submit" v-if="canDraft" @click="() => (otherBtnInvoked = true)"> Save for Later </a-button>
|
<a-button html-type="submit" v-if="canDraft" @click="() => (otherBtnInvoked = true)"> Save for Later </a-button>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
<style>
|
||||||
|
.ant-collapse-item > .ant-collapse-header {
|
||||||
|
align-items: center !important;
|
||||||
|
}
|
||||||
|
.ant-collapse-header.ant-collapse-icon-collapsible-only {
|
||||||
|
align-items: center !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user