fix: QueryFilter Hydration & script setup (#5839)

This commit is contained in:
Kuchenpirat 2025-07-29 23:43:13 +02:00 committed by GitHub
commit eefe613aaf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 534 additions and 658 deletions

View file

@ -44,36 +44,20 @@
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import type { ReadCookBook } from "~/lib/api/types/cookbook";
import { Organizer } from "~/lib/api/types/non-generated"; import { Organizer } from "~/lib/api/types/non-generated";
import QueryFilterBuilder from "~/components/Domain/QueryFilterBuilder.vue"; import QueryFilterBuilder from "~/components/Domain/QueryFilterBuilder.vue";
import type { FieldDefinition } from "~/composables/use-query-filter-builder"; import type { FieldDefinition } from "~/composables/use-query-filter-builder";
import type { ReadCookBook } from "~/lib/api/types/cookbook";
export default defineNuxtComponent({ const modelValue = defineModel<ReadCookBook>({ required: true });
components: { QueryFilterBuilder }, const i18n = useI18n();
props: { const cookbook = toRef(modelValue);
modelValue: { function handleInput(value: string | undefined) {
type: Object as () => ReadCookBook,
required: true,
},
actions: {
type: Object as () => any,
required: true,
},
},
emits: ["update:modelValue"],
setup(props, { emit }) {
const i18n = useI18n();
const cookbook = toRef(() => props.modelValue);
function handleInput(value: string | undefined) {
cookbook.value.queryFilterString = value || ""; cookbook.value.queryFilterString = value || "";
emit("update:modelValue", cookbook.value); }
}
const fieldDefs: FieldDefinition[] = [ const fieldDefs: FieldDefinition[] = [
{ {
name: "recipe_category.id", name: "recipe_category.id",
label: i18n.t("category.categories"), label: i18n.t("category.categories"),
@ -109,13 +93,5 @@ export default defineNuxtComponent({
label: i18n.t("general.date-updated"), label: i18n.t("general.date-updated"),
type: "date", type: "date",
}, },
]; ];
return {
cookbook,
handleInput,
fieldDefs,
};
},
});
</script> </script>

View file

@ -17,7 +17,6 @@
<v-card-text> <v-card-text>
<CookbookEditor <CookbookEditor
v-model="editTarget" v-model="editTarget"
:actions="actions"
/> />
</v-card-text> </v-card-text>
</BaseDialog> </BaseDialog>
@ -65,7 +64,7 @@
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { useLazyRecipes } from "~/composables/recipes"; import { useLazyRecipes } from "~/composables/recipes";
import RecipeCardSection from "@/components/Domain/Recipe/RecipeCardSection.vue"; import RecipeCardSection from "@/components/Domain/Recipe/RecipeCardSection.vue";
import { useCookbookStore } from "~/composables/store/use-cookbook-store"; import { useCookbookStore } from "~/composables/store/use-cookbook-store";
@ -74,44 +73,40 @@ import { useLoggedInState } from "~/composables/use-logged-in-state";
import type { RecipeCookBook } from "~/lib/api/types/cookbook"; import type { RecipeCookBook } from "~/lib/api/types/cookbook";
import CookbookEditor from "~/components/Domain/Cookbook/CookbookEditor.vue"; import CookbookEditor from "~/components/Domain/Cookbook/CookbookEditor.vue";
export default defineNuxtComponent({ const $auth = useMealieAuth();
components: { RecipeCardSection, CookbookEditor }, const { isOwnGroup } = useLoggedInState();
setup() {
const $auth = useMealieAuth();
const { isOwnGroup } = useLoggedInState();
const route = useRoute(); const route = useRoute();
const groupSlug = computed(() => route.params.groupSlug as string || $auth.user.value?.groupSlug || ""); const groupSlug = computed(() => route.params.groupSlug as string || $auth.user.value?.groupSlug || "");
const { recipes, appendRecipes, assignSorted, removeRecipe, replaceRecipes } = useLazyRecipes(isOwnGroup.value ? null : groupSlug.value); const { recipes, appendRecipes, assignSorted, removeRecipe, replaceRecipes } = useLazyRecipes(isOwnGroup.value ? null : groupSlug.value);
const slug = route.params.slug as string; const slug = route.params.slug as string;
const { getOne } = useCookbook(isOwnGroup.value ? null : groupSlug.value); const { getOne } = useCookbook(isOwnGroup.value ? null : groupSlug.value);
const { actions } = useCookbookStore(); const { actions } = useCookbookStore();
const router = useRouter(); const router = useRouter();
const tab = ref(null); const book = getOne(slug);
const book = getOne(slug);
const isOwnHousehold = computed(() => { const isOwnHousehold = computed(() => {
if (!($auth.user.value && book.value?.householdId)) { if (!($auth.user.value && book.value?.householdId)) {
return false; return false;
} }
return $auth.user.value.householdId === book.value.householdId; return $auth.user.value.householdId === book.value.householdId;
}); });
const canEdit = computed(() => isOwnGroup.value && isOwnHousehold.value); const canEdit = computed(() => isOwnGroup.value && isOwnHousehold.value);
const dialogStates = reactive({ const dialogStates = reactive({
edit: false, edit: false,
}); });
const editTarget = ref<RecipeCookBook | null>(null); const editTarget = ref<RecipeCookBook | null>(null);
function handleEditCookbook() { function handleEditCookbook() {
dialogStates.edit = true; dialogStates.edit = true;
editTarget.value = book.value; editTarget.value = book.value;
} }
async function editCookbook() { async function editCookbook() {
if (!editTarget.value) { if (!editTarget.value) {
return; return;
} }
@ -127,28 +122,9 @@ export default defineNuxtComponent({
} }
dialogStates.edit = false; dialogStates.edit = false;
editTarget.value = null; editTarget.value = null;
} }
useSeoMeta({ useSeoMeta({
title: book?.value?.name || "Cookbook", title: book?.value?.name || "Cookbook",
});
return {
book,
slug,
tab,
appendRecipes,
assignSorted,
recipes,
removeRecipe,
replaceRecipes,
canEdit,
dialogStates,
editTarget,
handleEditCookbook,
editCookbook,
actions,
};
},
}); });
</script> </script>

View file

@ -163,14 +163,14 @@
max-width="290px" max-width="290px"
min-width="auto" min-width="auto"
> >
<template #activator="{ props }"> <template #activator="{ props: activatorProps }">
<v-text-field <v-text-field
v-model="field.value" v-model="field.value"
persistent-hint persistent-hint
:prepend-icon="$globals.icons.calendar" :prepend-icon="$globals.icons.calendar"
variant="underlined" variant="underlined"
color="primary" color="primary"
v-bind="props" v-bind="activatorProps"
readonly readonly
/> />
</template> </template>
@ -184,53 +184,48 @@
</v-menu> </v-menu>
<RecipeOrganizerSelector <RecipeOrganizerSelector
v-else-if="field.type === Organizer.Category" v-else-if="field.type === Organizer.Category"
:model-value="field.organizers" v-model="field.organizers"
:selector-type="Organizer.Category" :selector-type="Organizer.Category"
:show-add="false" :show-add="false"
:show-label="false" :show-label="false"
:show-icon="false" :show-icon="false"
variant="underlined" variant="underlined"
@update:model-value="setOrganizerValues(field, index, $event)"
/> />
<RecipeOrganizerSelector <RecipeOrganizerSelector
v-else-if="field.type === Organizer.Tag" v-else-if="field.type === Organizer.Tag"
:model-value="field.organizers" v-model="field.organizers"
:selector-type="Organizer.Tag" :selector-type="Organizer.Tag"
:show-add="false" :show-add="false"
:show-label="false" :show-label="false"
:show-icon="false" :show-icon="false"
variant="underlined" variant="underlined"
@update:model-value="setOrganizerValues(field, index, $event)"
/> />
<RecipeOrganizerSelector <RecipeOrganizerSelector
v-else-if="field.type === Organizer.Tool" v-else-if="field.type === Organizer.Tool"
:model-value="field.organizers" v-model="field.organizers"
:selector-type="Organizer.Tool" :selector-type="Organizer.Tool"
:show-add="false" :show-add="false"
:show-label="false" :show-label="false"
:show-icon="false" :show-icon="false"
variant="underlined" variant="underlined"
@update:model-value="setOrganizerValues(field, index, $event)"
/> />
<RecipeOrganizerSelector <RecipeOrganizerSelector
v-else-if="field.type === Organizer.Food" v-else-if="field.type === Organizer.Food"
:model-value="field.organizers" v-model="field.organizers"
:selector-type="Organizer.Food" :selector-type="Organizer.Food"
:show-add="false" :show-add="false"
:show-label="false" :show-label="false"
:show-icon="false" :show-icon="false"
variant="underlined" variant="underlined"
@update:model-value="setOrganizerValues(field, index, $event)"
/> />
<RecipeOrganizerSelector <RecipeOrganizerSelector
v-else-if="field.type === Organizer.Household" v-else-if="field.type === Organizer.Household"
:model-value="field.organizers" v-model="field.organizers"
:selector-type="Organizer.Household" :selector-type="Organizer.Household"
:show-add="false" :show-add="false"
:show-label="false" :show-label="false"
:show-icon="false" :show-icon="false"
variant="underlined" variant="underlined"
@update:model-value="setOrganizerValues(field, index, $event)"
/> />
</v-col> </v-col>
<!-- right parenthesis --> <!-- right parenthesis -->
@ -297,7 +292,7 @@
</v-card> </v-card>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { VueDraggable } from "vue-draggable-plus"; import { VueDraggable } from "vue-draggable-plus";
import { useDebounceFn } from "@vueuse/core"; import { useDebounceFn } from "@vueuse/core";
import { useHouseholdSelf } from "~/composables/use-households"; import { useHouseholdSelf } from "~/composables/use-households";
@ -307,12 +302,7 @@ import type { LogicalOperator, QueryFilterJSON, QueryFilterJSONPart, RelationalK
import { useCategoryStore, useFoodStore, useHouseholdStore, useTagStore, useToolStore } from "~/composables/store"; import { useCategoryStore, useFoodStore, useHouseholdStore, useTagStore, useToolStore } from "~/composables/store";
import { type Field, type FieldDefinition, type FieldValue, type OrganizerBase, useQueryFilterBuilder } from "~/composables/use-query-filter-builder"; import { type Field, type FieldDefinition, type FieldValue, type OrganizerBase, useQueryFilterBuilder } from "~/composables/use-query-filter-builder";
export default defineNuxtComponent({ const props = defineProps({
components: {
VueDraggable,
RecipeOrganizerSelector,
},
props: {
fieldDefs: { fieldDefs: {
type: Array as () => FieldDefinition[], type: Array as () => FieldDefinition[],
required: true, required: true,
@ -321,57 +311,62 @@ export default defineNuxtComponent({
type: Object as () => QueryFilterJSON | null, type: Object as () => QueryFilterJSON | null,
default: null, default: null,
}, },
}, });
emits: ["input", "inputJSON"],
setup(props, context) {
const { household } = useHouseholdSelf();
const { logOps, relOps, buildQueryFilterString, getFieldFromFieldDef, isOrganizerType } = useQueryFilterBuilder();
const firstDayOfWeek = computed(() => { const emit = defineEmits<{
(event: "input", value: string | undefined): void;
(event: "inputJSON", value: QueryFilterJSON | undefined): void;
}>();
const { household } = useHouseholdSelf();
const { logOps, relOps, buildQueryFilterString, getFieldFromFieldDef, isOrganizerType } = useQueryFilterBuilder();
const firstDayOfWeek = computed(() => {
return household.value?.preferences?.firstDayOfWeek || 0; return household.value?.preferences?.firstDayOfWeek || 0;
}); });
const state = reactive({ const state = reactive({
showAdvanced: false, showAdvanced: false,
qfValid: false, qfValid: false,
datePickers: [] as boolean[], datePickers: [] as boolean[],
drag: false, drag: false,
}); });
const { showAdvanced, datePickers, drag } = toRefs(state);
const storeMap = { const storeMap = {
[Organizer.Category]: useCategoryStore(), [Organizer.Category]: useCategoryStore(),
[Organizer.Tag]: useTagStore(), [Organizer.Tag]: useTagStore(),
[Organizer.Tool]: useToolStore(), [Organizer.Tool]: useToolStore(),
[Organizer.Food]: useFoodStore(), [Organizer.Food]: useFoodStore(),
[Organizer.Household]: useHouseholdStore(), [Organizer.Household]: useHouseholdStore(),
}; };
function onDragEnd(event: any) { function onDragEnd(event: any) {
state.drag = false; state.drag = false;
const oldIndex: number = event.oldIndex; const oldIndex: number = event.oldIndex;
const newIndex: number = event.newIndex; const newIndex: number = event.newIndex;
state.datePickers[oldIndex] = false; state.datePickers[oldIndex] = false;
state.datePickers[newIndex] = false; state.datePickers[newIndex] = false;
} }
// add id to fields to prevent reactivity issues // add id to fields to prevent reactivity issues
type FieldWithId = Field & { id: number }; type FieldWithId = Field & { id: number };
const fields = ref<FieldWithId[]>([]); const fields = ref<FieldWithId[]>([]);
const uid = ref(1); // init uid to pass to fields const uid = ref(1); // init uid to pass to fields
function useUid() { function useUid() {
return uid.value++; return uid.value++;
} }
function addField(field: FieldDefinition) { function addField(field: FieldDefinition) {
fields.value.push({ fields.value.push({
...getFieldFromFieldDef(field), ...getFieldFromFieldDef(field),
id: useUid(), id: useUid(),
}); });
state.datePickers.push(false); state.datePickers.push(false);
}; }
function setField(index: number, fieldLabel: string) { function setField(index: number, fieldLabel: string) {
state.datePickers[index] = false; state.datePickers[index] = false;
const fieldDef = props.fieldDefs.find(fieldDef => fieldDef.label === fieldLabel); const fieldDef = props.fieldDefs.find(fieldDef => fieldDef.label === fieldLabel);
if (!fieldDef) { if (!fieldDef) {
@ -388,48 +383,43 @@ export default defineNuxtComponent({
...getFieldFromFieldDef(updatedField, resetValue), ...getFieldFromFieldDef(updatedField, resetValue),
id: fields.value[index].id, // keep the id id: fields.value[index].id, // keep the id
}; };
} }
function setLeftParenthesisValue(field: FieldWithId, index: number, value: string) { function setLeftParenthesisValue(field: FieldWithId, index: number, value: string) {
fields.value[index].leftParenthesis = value; fields.value[index].leftParenthesis = value;
} }
function setRightParenthesisValue(field: FieldWithId, index: number, value: string) { function setRightParenthesisValue(field: FieldWithId, index: number, value: string) {
fields.value[index].rightParenthesis = value; fields.value[index].rightParenthesis = value;
} }
function setLogicalOperatorValue(field: FieldWithId, index: number, value: LogicalOperator | undefined) { function setLogicalOperatorValue(field: FieldWithId, index: number, value: LogicalOperator | undefined) {
if (!value) { if (!value) {
value = logOps.value.AND.value; value = logOps.value.AND.value;
} }
fields.value[index].logicalOperator = value ? logOps.value[value] : undefined; fields.value[index].logicalOperator = value ? logOps.value[value] : undefined;
} }
function setRelationalOperatorValue(field: FieldWithId, index: number, value: RelationalKeyword | RelationalOperator) { function setRelationalOperatorValue(field: FieldWithId, index: number, value: RelationalKeyword | RelationalOperator) {
fields.value[index].relationalOperatorValue = relOps.value[value]; fields.value[index].relationalOperatorValue = relOps.value[value];
} }
function setFieldValue(field: FieldWithId, index: number, value: FieldValue) { function setFieldValue(field: FieldWithId, index: number, value: FieldValue) {
state.datePickers[index] = false; state.datePickers[index] = false;
fields.value[index].value = value; fields.value[index].value = value;
} }
function setFieldValues(field: FieldWithId, index: number, values: FieldValue[]) { function setFieldValues(field: FieldWithId, index: number, values: FieldValue[]) {
fields.value[index].values = values; fields.value[index].values = values;
} }
function setOrganizerValues(field: FieldWithId, index: number, values: OrganizerBase[]) { function removeField(index: number) {
setFieldValues(field, index, values.map(value => value.id.toString()));
fields.value[index].organizers = values;
}
function removeField(index: number) {
fields.value.splice(index, 1); fields.value.splice(index, 1);
state.datePickers.splice(index, 1); state.datePickers.splice(index, 1);
}; }
const fieldsUpdater = useDebounceFn((/* newFields: typeof fields.value */) => { const fieldsUpdater = useDebounceFn((/* newFields: typeof fields.value */) => {
/* newFields.forEach((field, index) => { /* newFields.forEach((field, index) => {
const updatedField = getFieldFromFieldDef(field); const updatedField = getFieldFromFieldDef(field);
fields.value[index] = updatedField; // recursive!!! fields.value[index] = updatedField; // recursive!!!
@ -441,19 +431,17 @@ export default defineNuxtComponent({
} }
state.qfValid = !!qf; state.qfValid = !!qf;
context.emit("input", qf || undefined); emit("input", qf || undefined);
context.emit("inputJSON", qf ? buildQueryFilterJSON() : undefined); emit("inputJSON", qf ? buildQueryFilterJSON() : undefined);
}, 500); }, 500);
watch(fields, fieldsUpdater, { deep: true }); watch(fields, fieldsUpdater, { deep: true });
async function hydrateOrganizers(field: FieldWithId, index: number) { async function hydrateOrganizers(field: FieldWithId, _index: number) {
if (!field.values?.length || !isOrganizerType(field.type)) { if (!field.values?.length || !isOrganizerType(field.type)) {
return; return;
} }
field.organizers = [];
const { store, actions } = storeMap[field.type]; const { store, actions } = storeMap[field.type];
if (!store.value.length) { if (!store.value.length) {
await actions.refresh(); await actions.refresh();
@ -467,11 +455,12 @@ export default defineNuxtComponent({
} }
return organizer; return organizer;
}); });
field.organizers = organizers.filter(organizer => organizer !== undefined) as OrganizerBase[];
setOrganizerValues(field, index, field.organizers);
}
function initFieldsError(error = "") { field.organizers = organizers.filter(organizer => organizer !== undefined) as OrganizerBase[];
return field;
}
function initFieldsError(error = "") {
if (error) { if (error) {
console.error(error); console.error(error);
} }
@ -480,16 +469,17 @@ export default defineNuxtComponent({
if (props.fieldDefs.length) { if (props.fieldDefs.length) {
addField(props.fieldDefs[0]); addField(props.fieldDefs[0]);
} }
} }
function initializeFields() { async function initializeFields() {
if (!props.initialQueryFilter?.parts?.length) { if (!props.initialQueryFilter?.parts?.length) {
return initFieldsError(); return initFieldsError();
}; }
const initFields: FieldWithId[] = []; const initFields: FieldWithId[] = [];
let error = false; let error = false;
props.initialQueryFilter.parts.forEach((part: QueryFilterJSONPart, index: number) => {
for (const [index, part] of props.initialQueryFilter.parts.entries()) {
const fieldDef = props.fieldDefs.find(fieldDef => fieldDef.name === part.attributeName); const fieldDef = props.fieldDefs.find(fieldDef => fieldDef.name === part.attributeName);
if (!fieldDef) { if (!fieldDef) {
error = true; error = true;
@ -522,7 +512,7 @@ export default defineNuxtComponent({
} }
if (isOrganizerType(field.type)) { if (isOrganizerType(field.type)) {
hydrateOrganizers(field, index); await hydrateOrganizers(field, index);
} }
} }
else if (field.type === "boolean") { else if (field.type === "boolean") {
@ -553,7 +543,7 @@ export default defineNuxtComponent({
} }
initFields.push(field); initFields.push(field);
}); }
if (initFields.length && !error) { if (initFields.length && !error) {
fields.value = initFields; fields.value = initFields;
@ -561,16 +551,18 @@ export default defineNuxtComponent({
else { else {
initFieldsError(); initFieldsError();
} }
}; }
onMounted(async () => {
try { try {
initializeFields(); await initializeFields();
} }
catch (error) { catch (error) {
initFieldsError(`Error initializing fields: ${(error || "").toString()}`); initFieldsError(`Error initializing fields: ${(error || "").toString()}`);
} }
});
function buildQueryFilterJSON(): QueryFilterJSON { function buildQueryFilterJSON(): QueryFilterJSON {
const parts = fields.value.map((field) => { const parts = fields.value.map((field) => {
const part: QueryFilterJSONPart = { const part: QueryFilterJSONPart = {
attributeName: field.name, attributeName: field.name,
@ -596,9 +588,9 @@ export default defineNuxtComponent({
const qfJSON = { parts } as QueryFilterJSON; const qfJSON = { parts } as QueryFilterJSON;
console.debug(`Built query filter JSON: ${JSON.stringify(qfJSON)}`); console.debug(`Built query filter JSON: ${JSON.stringify(qfJSON)}`);
return qfJSON; return qfJSON;
} }
const config = computed(() => { const config = computed(() => {
const baseColMaxWidth = 55; const baseColMaxWidth = 55;
return { return {
col: { col: {
@ -642,30 +634,6 @@ export default defineNuxtComponent({
}, },
}, },
}; };
});
return {
Organizer,
...toRefs(state),
logOps,
relOps,
config,
firstDayOfWeek,
onDragEnd,
// Fields
fields,
addField,
setField,
setLeftParenthesisValue,
setRightParenthesisValue,
setLogicalOperatorValue,
setRelationalOperatorValue,
setFieldValue,
setFieldValues,
setOrganizerValues,
removeField,
};
},
}); });
</script> </script>

View file

@ -3,7 +3,7 @@
v-model="selected" v-model="selected"
v-bind="inputAttrs" v-bind="inputAttrs"
v-model:search="searchInput" v-model:search="searchInput"
:items="storeItem" :items="items"
:label="label" :label="label"
chips chips
closable-chips closable-chips
@ -46,78 +46,51 @@
</v-autocomplete> </v-autocomplete>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import type { IngredientFood, RecipeCategory, RecipeTag } from "~/lib/api/types/recipe"; import type { IngredientFood, RecipeCategory, RecipeTag } from "~/lib/api/types/recipe";
import type { RecipeTool } from "~/lib/api/types/admin"; import type { RecipeTool } from "~/lib/api/types/admin";
import { Organizer, type RecipeOrganizer } from "~/lib/api/types/non-generated"; import { Organizer, type RecipeOrganizer } from "~/lib/api/types/non-generated";
import type { HouseholdSummary } from "~/lib/api/types/household"; import type { HouseholdSummary } from "~/lib/api/types/household";
import { useCategoryStore, useFoodStore, useHouseholdStore, useTagStore, useToolStore } from "~/composables/store"; import { useCategoryStore, useFoodStore, useHouseholdStore, useTagStore, useToolStore } from "~/composables/store";
export default defineNuxtComponent({ interface Props {
props: { selectorType: RecipeOrganizer;
modelValue: { inputAttrs?: Record<string, any>;
type: Array as () => ( returnObject?: boolean;
showAdd?: boolean;
showLabel?: boolean;
showIcon?: boolean;
variant?: "filled" | "underlined" | "outlined" | "plain" | "solo" | "solo-inverted" | "solo-filled";
}
const props = withDefaults(defineProps<Props>(), {
inputAttrs: () => ({}),
returnObject: true,
showAdd: true,
showLabel: true,
showIcon: true,
variant: "outlined",
});
const selected = defineModel<(
| HouseholdSummary | HouseholdSummary
| RecipeTag | RecipeTag
| RecipeCategory | RecipeCategory
| RecipeTool | RecipeTool
| IngredientFood | IngredientFood
| string | string
)[] | undefined, )[] | undefined>({ required: true });
required: true,
},
/**
* The type of organizer to use.
*/
selectorType: {
type: String as () => RecipeOrganizer,
required: true,
},
inputAttrs: {
type: Object as () => Record<string, any>,
default: () => ({}),
},
returnObject: {
type: Boolean,
default: true,
},
showAdd: {
type: Boolean,
default: true,
},
showLabel: {
type: Boolean,
default: true,
},
showIcon: {
type: Boolean,
default: true,
},
variant: {
type: String as () => "filled" | "underlined" | "outlined" | "plain" | "solo" | "solo-inverted" | "solo-filled",
default: "outlined",
},
},
emits: ["update:modelValue"],
setup(props, context) { onMounted(() => {
const selected = computed({
get: () => props.modelValue,
set: (val) => {
context.emit("update:modelValue", val);
},
});
onMounted(() => {
if (selected.value === undefined) { if (selected.value === undefined) {
selected.value = []; selected.value = [];
} }
}); });
const i18n = useI18n(); const i18n = useI18n();
const { $globals } = useNuxtApp(); const { $globals } = useNuxtApp();
const label = computed(() => { const label = computed(() => {
if (!props.showLabel) { if (!props.showLabel) {
return ""; return "";
} }
@ -136,9 +109,9 @@ export default defineNuxtComponent({
default: default:
return i18n.t("general.organizer"); return i18n.t("general.organizer");
} }
}); });
const icon = computed(() => { const icon = computed(() => {
if (!props.showIcon) { if (!props.showIcon) {
return ""; return "";
} }
@ -157,69 +130,54 @@ export default defineNuxtComponent({
default: default:
return $globals.icons.tags; return $globals.icons.tags;
} }
}); });
// =========================================================================== // ===========================================================================
// Store & Items Setup // Store & Items Setup
const storeMap = { const storeMap = {
[Organizer.Category]: useCategoryStore(), [Organizer.Category]: useCategoryStore(),
[Organizer.Tag]: useTagStore(), [Organizer.Tag]: useTagStore(),
[Organizer.Tool]: useToolStore(), [Organizer.Tool]: useToolStore(),
[Organizer.Food]: useFoodStore(), [Organizer.Food]: useFoodStore(),
[Organizer.Household]: useHouseholdStore(), [Organizer.Household]: useHouseholdStore(),
}; };
const store = computed(() => { const store = computed(() => {
const { store } = storeMap[props.selectorType]; const { store } = storeMap[props.selectorType];
return store.value; return store.value;
}); });
const items = computed(() => { const items = computed(() => {
if (!props.returnObject) { if (!props.returnObject) {
return store.value.map(item => item.name); return store.value.map(item => item.name);
} }
return store.value; return store.value;
}); });
function removeByIndex(index: number) { function removeByIndex(index: number) {
if (selected.value === undefined) { if (selected.value === undefined) {
return; return;
} }
const newSelected = selected.value.filter((_, i) => i !== index); const newSelected = selected.value.filter((_, i) => i !== index);
selected.value = [...newSelected]; selected.value = [...newSelected];
} }
function appendCreated(item: any) { function appendCreated(item: any) {
if (selected.value === undefined) { if (selected.value === undefined) {
return; return;
} }
selected.value = [...selected.value, item]; selected.value = [...selected.value, item];
} }
const dialog = ref(false); const dialog = ref(false);
const searchInput = ref(""); const searchInput = ref("");
function resetSearchInput() { function resetSearchInput() {
searchInput.value = ""; searchInput.value = "";
} }
return {
Organizer,
appendCreated,
dialog,
storeItem: items,
label,
icon,
selected,
removeByIndex,
searchInput,
resetSearchInput,
};
},
});
</script> </script>
<style scoped> <style scoped>

View file

@ -16,7 +16,7 @@
@cancel="deleteCreateTarget()" @cancel="deleteCreateTarget()"
> >
<v-card-text> <v-card-text>
<CookbookEditor :key="createTargetKey" v-model="createTarget" :actions="actions" /> <CookbookEditor :key="createTargetKey" v-model="createTarget" />
</v-card-text> </v-card-text>
</BaseDialog> </BaseDialog>
@ -105,9 +105,7 @@
<v-expansion-panel-text> <v-expansion-panel-text>
<CookbookEditor <CookbookEditor
v-model="myCookbooks[index]" v-model="myCookbooks[index]"
:actions="actions"
:collapsable="false" :collapsable="false"
@delete="deleteEventHandler"
/> />
<v-card-actions> <v-card-actions>
<v-spacer /> <v-spacer />