| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  | <template> | 
					
						
							|  |  |  |   <div> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |     <v-dialog | 
					
						
							|  |  |  |       v-model="dialog" | 
					
						
							|  |  |  |       width="500" | 
					
						
							|  |  |  |     > | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  |       <v-card> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |         <v-app-bar | 
					
						
							|  |  |  |           density="compact" | 
					
						
							|  |  |  |           dark | 
					
						
							|  |  |  |           color="primary mb-2 position-relative left-0 top-0 w-100 pl-3" | 
					
						
							|  |  |  |         > | 
					
						
							|  |  |  |           <v-icon | 
					
						
							|  |  |  |             size="large" | 
					
						
							|  |  |  |             start | 
					
						
							|  |  |  |             class="mt-1" | 
					
						
							|  |  |  |           > | 
					
						
							|  |  |  |             {{ itemType === Organizer.Tool ? $globals.icons.potSteam | 
					
						
							|  |  |  |               : itemType === Organizer.Category ? $globals.icons.categories | 
					
						
							|  |  |  |                 : $globals.icons.tags }} | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  |           </v-icon> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           <v-toolbar-title class="headline"> | 
					
						
							|  |  |  |             {{ properties.title }} | 
					
						
							|  |  |  |           </v-toolbar-title> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           <v-spacer /> | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  |         </v-app-bar> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |         <v-card-title /> | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  |         <v-form @submit.prevent="select"> | 
					
						
							|  |  |  |           <v-card-text> | 
					
						
							|  |  |  |             <v-text-field | 
					
						
							|  |  |  |               v-model="name" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |               density="compact" | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  |               :label="properties.label" | 
					
						
							|  |  |  |               :rules="[rules.required]" | 
					
						
							|  |  |  |               autofocus | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             /> | 
					
						
							|  |  |  |             <v-checkbox | 
					
						
							|  |  |  |               v-if="itemType === Organizer.Tool" | 
					
						
							|  |  |  |               v-model="onHand" | 
					
						
							|  |  |  |               :label="$t('tool.on-hand')" | 
					
						
							|  |  |  |             /> | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  |           </v-card-text> | 
					
						
							|  |  |  |           <v-card-actions> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <BaseButton | 
					
						
							|  |  |  |               cancel | 
					
						
							|  |  |  |               @click="dialog = false" | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |             <v-spacer /> | 
					
						
							|  |  |  |             <BaseButton | 
					
						
							|  |  |  |               type="submit" | 
					
						
							|  |  |  |               create | 
					
						
							|  |  |  |               :disabled="!name" | 
					
						
							|  |  |  |             /> | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  |           </v-card-actions> | 
					
						
							|  |  |  |         </v-form> | 
					
						
							|  |  |  |       </v-card> | 
					
						
							|  |  |  |     </v-dialog> | 
					
						
							|  |  |  |   </div> | 
					
						
							|  |  |  | </template> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-30 20:37:02 +02:00
										 |  |  | <script setup lang="ts"> | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  | import { useUserApi } from "~/composables/api"; | 
					
						
							|  |  |  | import { useCategoryStore, useTagStore, useToolStore } from "~/composables/store"; | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | import { type RecipeOrganizer, Organizer } from "~/lib/api/types/non-generated"; | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const CREATED_ITEM_EVENT = "created-item"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-30 20:37:02 +02:00
										 |  |  | interface Props { | 
					
						
							|  |  |  |   color?: string | null; | 
					
						
							|  |  |  |   tagDialog?: boolean; | 
					
						
							|  |  |  |   itemType?: RecipeOrganizer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | const props = withDefaults(defineProps<Props>(), { | 
					
						
							|  |  |  |   color: null, | 
					
						
							|  |  |  |   tagDialog: true, | 
					
						
							|  |  |  |   itemType: "category" as RecipeOrganizer, | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const emit = defineEmits<{ | 
					
						
							|  |  |  |   "created-item": [item: any]; | 
					
						
							|  |  |  | }>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const dialog = defineModel<boolean>({ default: false }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const i18n = useI18n(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const name = ref(""); | 
					
						
							|  |  |  | const onHand = ref(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | watch( | 
					
						
							|  |  |  |   dialog, | 
					
						
							|  |  |  |   (val: boolean) => { | 
					
						
							|  |  |  |     if (!val) name.value = ""; | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  |   }, | 
					
						
							| 
									
										
										
										
											2025-07-30 20:37:02 +02:00
										 |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const userApi = useUserApi(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const store = (() => { | 
					
						
							|  |  |  |   switch (props.itemType) { | 
					
						
							|  |  |  |     case Organizer.Tag: | 
					
						
							|  |  |  |       return useTagStore(); | 
					
						
							|  |  |  |     case Organizer.Tool: | 
					
						
							|  |  |  |       return useToolStore(); | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return useCategoryStore(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | })(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const properties = computed(() => { | 
					
						
							|  |  |  |   switch (props.itemType) { | 
					
						
							|  |  |  |     case Organizer.Tag: | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         title: i18n.t("tag.create-a-tag"), | 
					
						
							|  |  |  |         label: i18n.t("tag.tag-name"), | 
					
						
							|  |  |  |         api: userApi.tags, | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     case Organizer.Tool: | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         title: i18n.t("tool.create-a-tool"), | 
					
						
							|  |  |  |         label: i18n.t("tool.tool-name"), | 
					
						
							|  |  |  |         api: userApi.tools, | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         title: i18n.t("category.create-a-category"), | 
					
						
							|  |  |  |         label: i18n.t("category.category-name"), | 
					
						
							|  |  |  |         api: userApi.categories, | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2025-07-30 20:37:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | const rules = { | 
					
						
							|  |  |  |   required: (val: string) => !!val || (i18n.t("general.a-name-is-required") as string), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function select() { | 
					
						
							|  |  |  |   if (store) { | 
					
						
							|  |  |  |     // @ts-expect-error the same state is used for different organizer types, which have different requirements
 | 
					
						
							|  |  |  |     await store.actions.createOne({ name: name.value, onHand: onHand.value }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const newItem = store.store.value.find(item => item.name === name.value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   emit(CREATED_ITEM_EVENT, newItem); | 
					
						
							|  |  |  |   dialog.value = false; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-06-03 20:12:32 -08:00
										 |  |  | </script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <style></style> |