PronounsPage/components/TermsSubmitForm.vue

200 lines
6.6 KiB
Vue

<template>
<section v-if="config.terminology.enabled && $user()" ref="section" class="px-md-3 scroll-mt-7">
<div v-if="afterSubmit" class="alert alert-success text-center">
<p>
<T>nouns.submit.thanks</T>
</p>
<p>
<button type="button" class="btn btn-success" @click="focus()">
<Icon v="plus" />
<T>nouns.submit.another</T>
</button>
</p>
</div>
<form v-else @submit.prevent="submit">
<div class="row">
<div class="col-12 col-lg-6">
<div class="form-group">
<label class="text-nowrap"><strong>
<T>terminology.term</T>
</strong></label>
<ListInput v-model="form.term" :maxlength="128" :minitems="1" />
</div>
</div>
<div class="col-12 col-lg-6">
<div class="form-group">
<label class="text-nowrap"><strong>
<T>terminology.original</T>
</strong></label>
<ListInput v-model="form.original" :maxlength="1024" />
</div>
</div>
</div>
<div class="form-group">
<label class="text-nowrap"><strong>
<T>terminology.definition</T>
</strong></label>
<textarea v-model="form.definition" class="form-control form-control-sm" required rows="6"></textarea>
</div>
<CategoriesSelector
v-model="form.categories"
:label="$t('terminology.category')"
:categories="config.terminology.categories"
/>
<div class="row">
<div class="col-12 col-lg-4">
<label for="key"><strong><T>sources.submit.key</T></strong></label>
<AutocompleteSelect v-model="form.key" :options="keys" maxlength="255" freeform />
<p class="small text-muted">
<T>sources.submit.keyInfo</T>
<T>sources.submit.keyInfoConvention</T>
</p>
</div>
<div class="col-12 col-lg-4">
<div class="form-group">
<label class="text-nowrap"><strong>
<T>profile.flags</T>
</strong></label>
<FlagList v-model="form.flags" />
</div>
</div>
<div class="col-12 col-lg-4">
<div class="form-group">
<label>
<strong><T>terminology.images</T></strong>
</label>
<ImageWidget v-model="form.images" multiple sizes="flag" small-size="flag" big-size="flag" />
</div>
</div>
</div>
<div v-if="form.base" class="alert alert-info">
<Icon v="info-circle" />
<T>nouns.editing</T>
<button type="button" class="btn btn-sm float-end" @click="form.base = null">
<Icon v="times" />
</button>
</div>
<button type="submit" class="btn btn-primary w-100" :disabled="submitting">
<template v-if="submitting">
<Icon v="circle-notch fa-spin" />
</template>
<template v-else>
<Icon v="plus" />
<T>nouns.submit.actionLong</T>
</template>
</button>
<p class="small text-muted mt-1">
<T>nouns.submit.moderation</T>
</p>
</form>
</section>
<section v-else ref="section" class="text-center">
<div class="alert alert-info">
<T>crud.loginRequired</T>
</div>
</section>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import useConfig from '../composables/useConfig.ts';
import useDialogue from '../composables/useDialogue.ts';
import type { TermsEntry } from '../src/classes.ts';
interface Data {
form: {
term: string[];
original: string[];
key: string | null;
definition: string;
categories: string[];
flags: string[];
images: string[];
base: string | null;
};
submitting: boolean;
afterSubmit: boolean;
}
export default defineComponent({
emits: ['submit'],
async setup() {
const dialogue = useDialogue();
const section = useTemplateRef<HTMLElement>('section');
const { data: keys } = await useFetch('/api/terms/keys', { lazy: true, default: () => ({}) });
return {
config: useConfig(),
dialogue,
section,
keys,
};
},
data(): Data {
return {
form: {
term: [''],
original: [],
key: '',
definition: '',
categories: [],
flags: [],
images: [],
base: null,
},
submitting: false,
afterSubmit: false,
};
},
methods: {
async submit(): Promise<void> {
this.submitting = true;
try {
await this.dialogue.postWithAlertOnError('/api/terms/submit', this.form);
this.afterSubmit = true;
this.form = {
term: [''],
original: [],
key: '',
definition: '',
categories: [],
flags: [],
images: [],
base: null,
};
this.focus(false);
this.$emit('submit');
} finally {
this.submitting = false;
}
},
edit(word: TermsEntry): void {
this.form = {
term: word.term,
original: word.original,
key: word.key,
definition: word.definition,
categories: word.categories,
flags: word.flags,
images: word.images,
base: word.id,
};
this.focus();
},
focus(editable = true): void {
if (editable) {
this.afterSubmit = false;
}
this.section?.scrollIntoView();
},
},
});
</script>