fix(components): make it so that reordering chapters in the story form no longer causes catastrophic state loss, rendering the tinymce components useless

all hail PORTALS!!!!!
This commit is contained in:
parent ec050390ad
commit 739cfb5eff
Signed by: tablet
GPG Key ID: 924A5F6AF051E87C
2 changed files with 88 additions and 71 deletions

@ -19,6 +19,12 @@
<tinymce-editor <tinymce-editor
v-bind="field" v-bind="field"
width="100%" width="100%"
@change="
(e) => {
console.debug(e);
setValue(e);
}
"
:initial-value="value" :initial-value="value"
v-model:model-value="field.value" v-model:model-value="field.value"
tinymce-script-src="/tinymce/tinymce.min.js" tinymce-script-src="/tinymce/tinymce.min.js"

@ -2,7 +2,7 @@
import draggable from "vuedraggable"; import draggable from "vuedraggable";
import { v4 } from "uuid"; import { v4 } from "uuid";
import lmove from "lodash-move"; import lmove from "lodash-move";
import { Field, FieldArray, useForm } from "vee-validate"; import { Field, FieldArray, useForm, useFieldArray } from "vee-validate";
import { storySchema } from "@client/storyFormSchema"; import { storySchema } from "@client/storyFormSchema";
import { FormStory, defaultChapter } from "@client/types/form/story"; import { FormStory, defaultChapter } from "@client/types/form/story";
import { autoEdit, autoSave, debouncedAutoEdit, debouncedAutoSave } from "@client/utils"; import { autoEdit, autoSave, debouncedAutoEdit, debouncedAutoSave } from "@client/utils";
@ -18,9 +18,13 @@
endpointMethod: "put" | "post"; endpointMethod: "put" | "post";
submitText?: string; submitText?: string;
}>(); }>();
let w;
onMounted(() => {
w = window;
});
const dc = defaultChapter; const dc = defaultChapter;
// data: FormStory; // data: FormStory;
const data = defineModel<FormStory>("data", { const sdata = defineModel<FormStory>("data", {
required: true, required: true,
}); });
let drag = false; let drag = false;
@ -54,114 +58,121 @@
const { values, setFieldValue, handleSubmit } = useForm<FormStory>({ const { values, setFieldValue, handleSubmit } = useForm<FormStory>({
keepValuesOnUnmount: true, keepValuesOnUnmount: true,
validationSchema: storySchema, validationSchema: storySchema,
initialValues: data.value, initialValues: sdata.value,
}); });
// const { push, remove, move, fields } = useFieldArray<FormChapter>("chapters");
const subCb = handleSubmit(onSubmit); const subCb = handleSubmit(onSubmit);
const pushHOF = (push) => (e) => {
if (!Array.isArray(values.chapters)) {
// noinspection TypeScriptValidateTypes
setFieldValue("chapters", []);
}
const chaps = [...toRaw(values.chapters)];
let lastIndex = chaps.length - 1;
if (lastIndex < 0) lastIndex = 0;
let lastChapter = chaps[lastIndex];
// log.debug('chaptrs->', chaps);
// log.debug('lastIndex->', lastIndex, lastChapter);
let newChapter = Object.assign({}, defaultChapter, {
summary: lastChapter?.summary || "",
index: (lastChapter?.index || 0) + 1,
bands: lastChapter?.bands || [],
characters: lastChapter?.characters || [],
relationships: lastChapter?.relationships || [],
uuidKey: v4(),
genre: lastChapter?.genre || [],
});
// console.debug("nc->", newChapter);
// console.debug("pushi -> ", push);
push(newChapter);
sdata.value.chapters.push(newChapter);
};
</script> </script>
<template> <template>
<!-- <vee-form <form data-testid="storyform" @submit="subCb" @change="() => (canDraft ? debouncedAutoSave(values) : debouncedAutoEdit(values, endpoint, endpointMethod))">
:keep-values="true"
v-slot="{ values, setFieldValue }"
:validation-schema="storySchema"
:initial-values="data"
@submit="onSubmit"
@invalid-submit="inval"
> -->
<form @submit="subCb" @change="() => (canDraft ? 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 }">
<a-form-item label="Title" :help="errorMessage" :validate-status="!!errorMessage ? 'error' : ''"> <a-form-item label="Title" :help="errorMessage" :validate-status="!!errorMessage ? 'error' : ''">
<a-input v-bind="field" :value="value" /> <a-input :data-testid="`storyform.${field.name}`" v-bind="field" :value="value" />
</a-form-item> </a-form-item>
</Field> </Field>
<a-form-item label="Co-author (optional)"> <a-form-item label="Co-author (optional)">
<find-user :initial-option="data.coAuthor" fieldName="coAuthor" :multi="false" /> <find-user data-testid="storyform.coauthor" :initial-option="sdata.coAuthor" fieldName="coAuthor" :multi="false" />
</a-form-item> </a-form-item>
<Field :unchecked-value="false" :value="true" type="checkbox" name="completed" v-slot="{ value, field, errorMessage }"> <Field :unchecked-value="false" :value="true" type="checkbox" name="completed" v-slot="{ value, field, errorMessage }">
<a-checkbox v-bind="field"> Complete </a-checkbox> <a-checkbox :data-testid="`storyform.${field.name}`" v-bind="field"> Complete </a-checkbox>
</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 }">
<div>
<div v-for="(element, index) in values.chapters">
<client-only>
<Teleport :to="`#chapter-\\[${element.uuidKey}\\]`">
<a-collapse v-model:active-key="expandos" collapsible="icon">
<template #expandIcon="{ isActive }">
<span :data-testid="`storyform.chapters[${index}].collapse`"> <RightOutlined :rotate="isActive ? 90 : undefined" /></span>
</template>
<a-collapse-panel :key="`${element.uuidKey}`">
<template #header>
<div :data-testid="`storyform.chapters[${index}].header`" style="display: flex; justify-content: space-between">
<span :data-testid="`storyform.chapters[${index}].titleEl`">{{ values.chapters[index]?.chapterTitle || "Untitled" }}</span>
<a-button
@click="
(e) => {
// let localFields = toRaw(fields);
// log.debug(`${index} | ${element.index}`);
// log.debug('fields->', localFields);
data.chapters.splice(index, 1);
remove(index);
// todo renumber
// renumber()
}
"
>
<icon istyle="regular" name="trash" />
</a-button>
</div>
</template>
<single-chapter :data="element" :name="`chapters[${index}]`" />
</a-collapse-panel>
</a-collapse>
</Teleport>
</client-only>
</div>
</div>
<draggable <draggable
:component-data="{ type: 'transtion-group' }" :component-data="{ type: 'transtion-group', 'data-testid': 'storyform.chapters' }"
@start="drag = true" @start="drag = true"
@end="drag = false" @end="drag = false"
v-model="values.chapters" v-model="values.chapters"
tag="div" tag="div"
data-testid="storyform.chapters"
item-key="uuidKey" item-key="uuidKey"
@change=" @change="
(e) => { (e) => {
console.log(e);
if (e.moved) { if (e.moved) {
// log.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);
// w.tinymce.remove();
// log.debug(toRaw(acData.chapters.map((a) => toRaw(a)))); // log.debug(toRaw(acData.chapters.map((a) => toRaw(a))));
} }
} }
" "
> >
<template #item="{ element, index }"> <template #item="{ element, index }">
<a-collapse v-model:active-key="expandos" collapsible="icon"> <div :id="`chapter-[${element.uuidKey}]`"></div>
<a-collapse-panel :key="`${element.uuidKey}`">
<template #header>
{{ values.chapters[index]?.chapterTitle || "Untitled" }}
<a-button
@click="
(e) => {
let localFields = toRaw(fields);
// log.debug(`${index} | ${element.index}`);
// log.debug('fields->', localFields);
data.chapters.splice(index, 1);
remove(index);
// todo renumber
// renumber()
}
"
>
<icon istyle="regular" name="trash" />
</a-button>
</template>
<single-chapter :data="element" :name="`chapters[${index}]`" />
</a-collapse-panel>
</a-collapse>
</template> </template>
<template #footer> <template #footer>
<a-button <a-button data-testid="storyform.addChapter" :onClick="pushHOF(push)"> Add chapter </a-button>
@click="
(e) => {
if (!Array.isArray(values.chapters)) {
// noinspection TypeScriptValidateTypes
setFieldValue('chapters', []);
}
const chaps = [...toRaw(values.chapters)];
let lastIndex = chaps.length - 1;
if (lastIndex < 0) lastIndex = 0;
let lastChapter = chaps[lastIndex];
// log.debug('chaptrs->', chaps);
// log.debug('lastIndex->', lastIndex, lastChapter);
let newChapter = Object.assign({}, defaultChapter, {
summary: lastChapter?.summary || '',
index: (lastChapter?.index || 0) + 1,
bands: lastChapter?.bands || [],
characters: lastChapter?.characters || [],
relationships: lastChapter?.relationships || [],
uuidKey: v4(),
genre: lastChapter?.genre || [],
});
// log.debug('nc->', newChapter);
push(newChapter);
data.chapters.push(newChapter);
}
"
>
Add chapter
</a-button>
</template> </template>
</draggable> </draggable>
</field-array> </field-array>
<a-button type="primary" html-type="submit">{{ submitText || "Post" }}</a-button> <a-button type="primary" html-type="submit">{{ submitText || "Post" }}</a-button>
<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>
<!-- </vee-form> -->
</template> </template>