RecipeTimelineContextMenu script setup and no emit mutation

This commit is contained in:
Kuchenpirat 2025-06-19 10:26:59 +00:00
commit 4a2d248c43

View file

@ -6,12 +6,12 @@
:icon="$globals.icons.edit" :icon="$globals.icons.edit"
can-submit can-submit
:submit-text="$t('general.save')" :submit-text="$t('general.save')"
@submit="$emit('update')" @submit="submitEdit"
> >
<v-card-text> <v-card-text>
<v-form ref="domMadeThisForm"> <v-form ref="domEditEventForm">
<v-text-field v-model="event.subject" :label="$t('general.subject')" /> <v-text-field v-model="localEvent.subject" :label="$t('general.subject')" />
<v-textarea v-model="event.eventMessage" :label="$t('general.message')" rows="4" /> <v-textarea v-model="localEvent.eventMessage" :label="$t('general.message')" rows="4" />
</v-form> </v-form>
</v-card-text> </v-card-text>
</BaseDialog> </BaseDialog>
@ -25,30 +25,30 @@
@confirm="$emit('delete')" @confirm="$emit('delete')"
> >
<v-card-text> <v-card-text>
{{ $t("events.event-delete-confirmation") }} {{ $t('events.event-delete-confirmation') }}
</v-card-text> </v-card-text>
</BaseDialog> </BaseDialog>
<v-menu <v-menu
offset-y offset-y
start start
:bottom="!menuTop" :bottom="!props.menuTop"
:nudge-bottom="!menuTop ? '5' : '0'" :nudge-bottom="!props.menuTop ? '5' : '0'"
:top="menuTop" :top="props.menuTop"
:nudge-top="menuTop ? '5' : '0'" :nudge-top="props.menuTop ? '5' : '0'"
allow-overflow allow-overflow
close-delay="125" close-delay="125"
:open-on-hover="!useMobileFormat" :open-on-hover="!props.useMobileFormat"
content-class="d-print-none" content-class="d-print-none"
> >
<template #activator="{ props }"> <template #activator="{ props: btnProps }">
<v-btn <v-btn
:class="{ 'rounded-circle': fab }" :class="{ 'rounded-circle': props.fab }"
:x-small="fab" :x-small="props.fab"
:elevation="elevation" :elevation="props.elevation ?? undefined"
:color="color" :color="props.color"
:icon="!fab" :icon="!props.fab"
v-bind="props" v-bind="btnProps"
@click.prevent @click.prevent
> >
<v-icon>{{ icon }}</v-icon> <v-icon>{{ icon }}</v-icon>
@ -72,7 +72,8 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { useI18n, useNuxtApp } from "#imports";
import type { RecipeTimelineEventOut } from "~/lib/api/types/recipe"; import type { RecipeTimelineEventOut } from "~/lib/api/types/recipe";
export interface TimelineContextMenuIncludes { export interface TimelineContextMenuIncludes {
@ -87,71 +88,30 @@ export interface ContextMenuItem {
event: string; event: string;
} }
export default defineNuxtComponent({ const props = defineProps<{
props: { useItems?: TimelineContextMenuIncludes;
useItems: { appendItems?: ContextMenuItem[];
type: Object as () => TimelineContextMenuIncludes, leadingItems?: ContextMenuItem[];
default: () => ({ menuTop?: boolean;
edit: true, fab?: boolean;
delete: true, elevation?: number | null;
}), color?: string;
}, event: RecipeTimelineEventOut;
// Append items are added at the end of the useItems list menuIcon?: string | null;
appendItems: { useMobileFormat?: boolean;
type: Array as () => ContextMenuItem[], }>();
default: () => [],
},
// Append items are added at the beginning of the useItems list
leadingItems: {
type: Array as () => ContextMenuItem[],
default: () => [],
},
menuTop: {
type: Boolean,
default: true,
},
fab: {
type: Boolean,
default: false,
},
elevation: {
type: Number,
default: null,
},
color: {
type: String,
default: "primary",
},
event: {
type: Object as () => RecipeTimelineEventOut,
required: true,
},
menuIcon: {
type: String,
default: null,
},
useMobileFormat: {
type: Boolean,
default: true,
},
},
emits: ["delete", "update"],
setup(props, context) {
const domEditEventForm = ref<VForm>();
const state = reactive({
recipeEventEditDialog: false,
recipeEventDeleteDialog: false,
loading: false,
menuItems: [] as ContextMenuItem[],
});
const i18n = useI18n(); const emit = defineEmits(["delete", "update"]);
const { $globals } = useNuxtApp();
// =========================================================================== const domEditEventForm = ref();
// Context Menu Setup const recipeEventEditDialog = ref(false);
const recipeEventDeleteDialog = ref(false);
const loading = ref(false);
const defaultItems: { [key: string]: ContextMenuItem } = { const i18n = useI18n();
const { $globals } = useNuxtApp();
const defaultItems: { [key: string]: ContextMenuItem } = {
edit: { edit: {
title: i18n.t("general.edit"), title: i18n.t("general.edit"),
icon: $globals.icons.edit, icon: $globals.icons.edit,
@ -164,55 +124,54 @@ export default defineNuxtComponent({
color: "error", color: "error",
event: "delete", event: "delete",
}, },
}; };
// Get Default Menu Items Specified in Props const menuItems = computed(() => {
for (const [key, value] of Object.entries(props.useItems)) { const items: ContextMenuItem[] = [];
const useItems = props.useItems ?? { edit: true, delete: true };
for (const [key, value] of Object.entries(useItems)) {
if (value) { if (value) {
const item = defaultItems[key]; const item = defaultItems[key];
if (item) { if (item) items.push(item);
state.menuItems.push(item);
}
} }
} }
return [
...items,
...(props.leadingItems ?? []),
...(props.appendItems ?? []),
];
});
// Add Leading and Appending Items const icon = computed(() => props.menuIcon || $globals.icons.dotsVertical);
state.menuItems = [...state.menuItems, ...props.leadingItems, ...props.appendItems];
const icon = props.menuIcon || $globals.icons.dotsVertical; const localEvent = ref({ ...props.event });
watch(() => props.event, (val) => {
localEvent.value = { ...val };
});
// =========================================================================== function openEditDialog() {
// Context Menu Event Handler localEvent.value = { ...props.event };
recipeEventEditDialog.value = true;
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type }
const eventHandlers: { [key: string]: () => void | Promise<any> } = { function openDeleteDialog() {
edit: () => { recipeEventDeleteDialog.value = true;
state.recipeEventEditDialog = true; }
}, function contextMenuEventHandler(eventKey: string) {
delete: () => { if (eventKey === "edit") {
state.recipeEventDeleteDialog = true; openEditDialog();
}, loading.value = false;
};
function contextMenuEventHandler(eventKey: string) {
const handler = eventHandlers[eventKey];
if (handler && typeof handler === "function") {
handler();
state.loading = false;
return; return;
} }
if (eventKey === "delete") {
context.emit(eventKey); openDeleteDialog();
state.loading = false; loading.value = false;
return;
} }
emit(eventKey as "delete" | "update");
return { loading.value = false;
...toRefs(state), }
contextMenuEventHandler, function submitEdit() {
domEditEventForm, emit("update", { ...localEvent.value });
icon, recipeEventEditDialog.value = false;
}; }
},
});
</script> </script>