mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-31 02:03:35 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			174 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { computed, ComputedRef, ref, Ref, useContext } from "@nuxtjs/composition-api";
 | |
| import { UserOut } from "~/lib/api/types/user";
 | |
| import { useNavigationWarning } from "~/composables/use-navigation-warning";
 | |
| 
 | |
| export enum PageMode {
 | |
|   EDIT = "EDIT",
 | |
|   VIEW = "VIEW",
 | |
|   COOK = "COOK",
 | |
| }
 | |
| 
 | |
| export enum EditorMode {
 | |
|   JSON = "JSON",
 | |
|   FORM = "FORM",
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * PageState encapsulates the state of the recipe page the can be shared across components.
 | |
|  * It allows and facilitates the complex state management of the recipe page where many components
 | |
|  * need to share and communicate with each other and guarantee consistency.
 | |
|  *
 | |
|  * **Page Modes**
 | |
|  *
 | |
|  * are ComputedRefs so we can use a readonly reactive copy of the state of the page.
 | |
|  */
 | |
| interface PageState {
 | |
|   slug: Ref<string>;
 | |
|   imageKey: Ref<number>;
 | |
| 
 | |
|   pageMode: ComputedRef<PageMode>;
 | |
|   editMode: ComputedRef<EditorMode>;
 | |
| 
 | |
|   /**
 | |
|    * true is the page is in edit mode and the edit mode is in form mode.
 | |
|    */
 | |
|   isEditForm: ComputedRef<boolean>;
 | |
|   /**
 | |
|    * true is the page is in edit mode and the edit mode is in json mode.
 | |
|    */
 | |
|   isEditJSON: ComputedRef<boolean>;
 | |
|   /**
 | |
|    * true is the page is in view mode.
 | |
|    */
 | |
|   isEditMode: ComputedRef<boolean>;
 | |
|   /**
 | |
|    * true is the page is in cook mode.
 | |
|    */
 | |
|   isCookMode: ComputedRef<boolean>;
 | |
| 
 | |
|   setMode: (v: PageMode) => void;
 | |
|   setEditMode: (v: EditorMode) => void;
 | |
|   toggleEditMode: () => void;
 | |
|   toggleCookMode: () => void;
 | |
| }
 | |
| 
 | |
| type PageRefs = ReturnType<typeof pageRefs>;
 | |
| 
 | |
| const memo: Record<string, PageRefs> = {};
 | |
| 
 | |
| function pageRefs(slug: string) {
 | |
|   return {
 | |
|     slugRef: ref(slug),
 | |
|     pageModeRef: ref(PageMode.VIEW),
 | |
|     editModeRef: ref(EditorMode.FORM),
 | |
|     imageKey: ref(1),
 | |
|   };
 | |
| }
 | |
| 
 | |
| function pageState({ slugRef, pageModeRef, editModeRef, imageKey }: PageRefs): PageState {
 | |
|   const { activateNavigationWarning, deactivateNavigationWarning } = useNavigationWarning();
 | |
| 
 | |
|   const toggleEditMode = () => {
 | |
|     if (editModeRef.value === EditorMode.FORM) {
 | |
|       editModeRef.value = EditorMode.JSON;
 | |
|       return;
 | |
|     }
 | |
|     editModeRef.value = EditorMode.FORM;
 | |
|   };
 | |
| 
 | |
|   const toggleCookMode = () => {
 | |
|     if (pageModeRef.value === PageMode.COOK) {
 | |
|       pageModeRef.value = PageMode.VIEW;
 | |
|       return;
 | |
|     }
 | |
|     pageModeRef.value = PageMode.COOK;
 | |
|   };
 | |
| 
 | |
|   const setEditMode = (v: EditorMode) => {
 | |
|     editModeRef.value = v;
 | |
|   };
 | |
| 
 | |
|   const setMode = (toMode: PageMode) => {
 | |
|     const fromMode = pageModeRef.value;
 | |
| 
 | |
|     if (fromMode === PageMode.EDIT) {
 | |
|       if (toMode === PageMode.VIEW) {
 | |
|         setEditMode(EditorMode.FORM);
 | |
|       }
 | |
|       deactivateNavigationWarning();
 | |
|     } else if (toMode === PageMode.EDIT) {
 | |
|       activateNavigationWarning();
 | |
|     }
 | |
| 
 | |
|     pageModeRef.value = toMode;
 | |
|   };
 | |
| 
 | |
|   return {
 | |
|     slug: slugRef,
 | |
|     pageMode: computed(() => pageModeRef.value),
 | |
|     editMode: computed(() => editModeRef.value),
 | |
|     imageKey,
 | |
| 
 | |
|     toggleEditMode,
 | |
|     setMode,
 | |
|     setEditMode,
 | |
|     toggleCookMode,
 | |
| 
 | |
|     isEditForm: computed(() => {
 | |
|       return pageModeRef.value === PageMode.EDIT && editModeRef.value === EditorMode.FORM;
 | |
|     }),
 | |
|     isEditJSON: computed(() => {
 | |
|       return pageModeRef.value === PageMode.EDIT && editModeRef.value === EditorMode.JSON;
 | |
|     }),
 | |
|     isEditMode: computed(() => {
 | |
|       return pageModeRef.value === PageMode.EDIT;
 | |
|     }),
 | |
|     isCookMode: computed(() => {
 | |
|       return pageModeRef.value === PageMode.COOK;
 | |
|     }),
 | |
|   };
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * usePageState provides a common way to interact with shared state across the
 | |
|  * RecipePage component.
 | |
|  */
 | |
| export function usePageState(slug: string): PageState {
 | |
|   if (!memo[slug]) {
 | |
|     memo[slug] = pageRefs(slug);
 | |
|   }
 | |
| 
 | |
|   return pageState(memo[slug]);
 | |
| }
 | |
| 
 | |
| export function clearPageState(slug: string) {
 | |
|   delete memo[slug];
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * usePageUser provides a wrapper around $auth that provides a type-safe way to
 | |
|  * access the UserOut type from the context. If no user is logged in then an empty
 | |
|  * object with all properties set to their zero value is returned.
 | |
|  */
 | |
| export function usePageUser(): { user: UserOut } {
 | |
|   const { $auth } = useContext();
 | |
| 
 | |
|   if (!$auth.user) {
 | |
|     return {
 | |
|       user: {
 | |
|         id: "",
 | |
|         group: "",
 | |
|         groupId: "",
 | |
|         groupSlug: "",
 | |
|         household: "",
 | |
|         householdId: "",
 | |
|         householdSlug: "",
 | |
|         cacheKey: "",
 | |
|         email: "",
 | |
|       },
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   return { user: $auth.user };
 | |
| }
 |