210 lines
5.4 KiB
Vue
210 lines
5.4 KiB
Vue
|
<script setup lang="ts">
|
||
|
import draggable from "vuedraggable";
|
||
|
import { v4 } from "uuid";
|
||
|
import lmove from "lodash-move";
|
||
|
import {
|
||
|
Field,
|
||
|
Form as veeForm,
|
||
|
FieldArray,
|
||
|
FieldEntry,
|
||
|
useForm,
|
||
|
} from "vee-validate";
|
||
|
import { storySchema } from "@client/storyFormSchema";
|
||
|
import {
|
||
|
FormChapter,
|
||
|
FormStory,
|
||
|
defaultChapter,
|
||
|
} from "@client/types/form/story";
|
||
|
import {
|
||
|
autoEdit,
|
||
|
autoSave,
|
||
|
debouncedAutoEdit,
|
||
|
debouncedAutoSave,
|
||
|
} from "@client/utils";
|
||
|
|
||
|
import findUser from "~/components/findUser.vue";
|
||
|
|
||
|
import singleChapter from "./singleChapter.vue";
|
||
|
import icon from "~/components/icon.vue";
|
||
|
|
||
|
const props = defineProps<{
|
||
|
data: FormStory;
|
||
|
canDraft?: boolean;
|
||
|
endpoint: string;
|
||
|
endpointMethod: "put" | "post";
|
||
|
submitText?: string;
|
||
|
}>();
|
||
|
let drag = false;
|
||
|
let acData = ref(props.data);
|
||
|
const expandos = ref<string[]>([]);
|
||
|
|
||
|
function logSubmit(values, actions) {
|
||
|
console.debug("VALUE");
|
||
|
console.debug(values);
|
||
|
console.debug(actions);
|
||
|
}
|
||
|
const otherBtnInvoked = ref<boolean>(false);
|
||
|
async function onSubmit(values, actions) {
|
||
|
logSubmit(values, actions);
|
||
|
if (props.canDraft) {
|
||
|
if (otherBtnInvoked.value) {
|
||
|
otherBtnInvoked.value = false;
|
||
|
await autoSave(values);
|
||
|
} else {
|
||
|
await useApiFetch(`/story/new`, {
|
||
|
method: "post",
|
||
|
body: values,
|
||
|
});
|
||
|
}
|
||
|
} else {
|
||
|
await autoEdit(values, props.endpoint, props.endpointMethod);
|
||
|
}
|
||
|
}
|
||
|
function inval({ values, errors, results }) {
|
||
|
logSubmit(values, undefined);
|
||
|
}
|
||
|
const { values, setFieldValue, handleSubmit } = useForm({
|
||
|
keepValuesOnUnmount: true,
|
||
|
validationSchema: storySchema,
|
||
|
initialValues: props.data,
|
||
|
});
|
||
|
const subCb = handleSubmit(onSubmit);
|
||
|
</script>
|
||
|
<template>
|
||
|
<!-- <vee-form
|
||
|
: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"> -->
|
||
|
<Field name="title" v-slot="{ value, field, errorMessage }">
|
||
|
<a-form-item
|
||
|
label="Title"
|
||
|
:help="errorMessage"
|
||
|
:validate-status="!!errorMessage ? 'error' : ''"
|
||
|
>
|
||
|
<a-input v-bind="field" :value="value" />
|
||
|
</a-form-item>
|
||
|
</Field>
|
||
|
<a-form-item label="Co-author (optional)">
|
||
|
<find-user :initial-option="null" fieldName="coAuthor" :multi="false" />
|
||
|
</a-form-item>
|
||
|
<Field
|
||
|
:unchecked-value="false"
|
||
|
:value="true"
|
||
|
type="checkbox"
|
||
|
name="completed"
|
||
|
v-slot="{ value, field, errorMessage }"
|
||
|
>
|
||
|
<a-checkbox v-bind="field"> Complete </a-checkbox>
|
||
|
</Field>
|
||
|
<a-divider />
|
||
|
<!-- <test1/> -->
|
||
|
<field-array name="chapters" v-slot="{ fields, push, remove, move }">
|
||
|
<draggable
|
||
|
:component-data="{ type: 'transtion-group' }"
|
||
|
@start="drag = true"
|
||
|
@end="drag = false"
|
||
|
v-model="values.chapters"
|
||
|
tag="div"
|
||
|
item-key="uuidKey"
|
||
|
@change="
|
||
|
(e) => {
|
||
|
if (e.moved) {
|
||
|
// log.debug(e.moved);
|
||
|
move(e.moved.oldIndex, e.moved.newIndex);
|
||
|
acData.chapters = lmove(
|
||
|
acData.chapters,
|
||
|
e.moved.oldIndex,
|
||
|
e.moved.newIndex,
|
||
|
);
|
||
|
// log.debug(toRaw(acData.chapters.map((a) => toRaw(a))));
|
||
|
}
|
||
|
}
|
||
|
"
|
||
|
>
|
||
|
<template #item="{ element, index }">
|
||
|
<a-collapse v-model:active-key="expandos" collapsible="icon">
|
||
|
<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);
|
||
|
acData.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 #footer>
|
||
|
<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);
|
||
|
acData.chapters.push(newChapter);
|
||
|
}
|
||
|
"
|
||
|
>
|
||
|
Add chapter
|
||
|
</a-button>
|
||
|
</template>
|
||
|
</draggable>
|
||
|
</field-array>
|
||
|
<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>
|
||
|
</form>
|
||
|
<!-- </vee-form> -->
|
||
|
</template>
|