PronounsPage/components/PersistentForm.vue

81 lines
2.6 KiB
Vue

<template>
<form @submit.prevent="submit">
<div v-if="storedDraft !== undefined" class="alert alert-info d-flex flex-column flex-md-row">
<div class="p-2">
<Icon v="pencil-ruler" />
<T :params="{ time: $datetime(storedDraft.savedAt) }">form.persistent.present.question</T>
</div>
<div class="p-2 text-nowrap">
<button type="button" class="btn btn-primary" @click="load">
<Icon v="cloud-download" />
<T>form.persistent.present.load</T>
</button>
<button type="button" class="btn btn-outline-danger" @click="abandon">
<Icon v="trash" />
<T>form.persistent.present.abandon</T>
</button>
</div>
</div>
<slot></slot>
<p v-if="draftSaved" class="text-muted small">
<Icon v="pencil-ruler" />
<T :params="{ time: $datetime(draftSaved) }">form.persistent.saved</T>
</p>
</form>
</template>
<script lang="ts">
export default defineComponent({
props: {
modelValue: { required: true, type: Object },
uid: { required: true, type: String },
},
emits: ['update:modelValue', 'submit'],
data() {
return {
originalValue: JSON.stringify(this.modelValue),
storageKey: `persistent-form-draft--${this.uid}`,
storedDraft: undefined as { draft: any; savedAt: number } | undefined,
draftSaved: null as number | null,
};
},
watch: {
value: {
handler(newValue) {
this.draftSaved = Math.round(Date.now() / 1000);
localStorage.setItem(this.storageKey, JSON.stringify({ draft: newValue, savedAt: this.draftSaved }));
},
deep: true,
},
},
async mounted() {
const storedRaw = localStorage.getItem(this.storageKey);
if (!storedRaw) {
return;
}
const stored = JSON.parse(storedRaw);
if (stored && JSON.stringify(stored.draft) !== this.originalValue) {
this.storedDraft = stored;
}
},
methods: {
load() {
if (!this.storedDraft) {
return;
}
this.$emit('update:modelValue', this.storedDraft.draft);
this.storedDraft = undefined;
},
abandon() {
localStorage.removeItem(this.storageKey);
this.storedDraft = undefined;
},
submit(event: Event) {
this.abandon();
this.$emit('submit', event);
},
},
});
</script>