import { useCallback, useMemo } from 'react'; import { SWRResponse } from 'swr'; import Linker from '~/client/models/Linker'; import MarkdownTable from '~/client/models/MarkdownTable'; import { BookmarkFolderItems } from '~/interfaces/bookmark-info'; import { IPageToDeleteWithMeta, IPageToRenameWithMeta } from '~/interfaces/page'; import { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction, OnPutBackedFunction, onDeletedBookmarkFolderFunction, } from '~/interfaces/ui'; import { IUserGroupHasId } from '~/interfaces/user'; import loggerFactory from '~/utils/logger'; import { useStaticSWR } from './use-static-swr'; const logger = loggerFactory('growi:stores:modal'); /* * PageCreateModal */ type CreateModalStatus = { isOpened: boolean, path?: string, } type CreateModalStatusUtils = { open(path?: string): Promise close(): Promise } export const usePageCreateModal = (status?: CreateModalStatus): SWRResponse & CreateModalStatusUtils => { const initialData: CreateModalStatus = { isOpened: false }; const swrResponse = useStaticSWR('pageCreateModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: (path?: string) => swrResponse.mutate({ isOpened: true, path }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /* * PageDeleteModal */ export type IDeleteModalOption = { onDeleted?: OnDeletedFunction, } type DeleteModalStatus = { isOpened: boolean, pages?: IPageToDeleteWithMeta[], opts?: IDeleteModalOption, } type DeleteModalStatusUtils = { open( pages?: IPageToDeleteWithMeta[], opts?: IDeleteModalOption, ): Promise, close(): Promise, } export const usePageDeleteModal = (status?: DeleteModalStatus): SWRResponse & DeleteModalStatusUtils => { const initialData: DeleteModalStatus = { isOpened: false, pages: [], }; const swrResponse = useStaticSWR('deleteModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: ( pages?: IPageToDeleteWithMeta[], opts?: IDeleteModalOption, ) => swrResponse.mutate({ isOpened: true, pages, opts, }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /* * EmptyTrashModal */ type IEmptyTrashModalOption = { onEmptiedTrash?: () => void, canDeleteAllPages: boolean, } type EmptyTrashModalStatus = { isOpened: boolean, pages?: IPageToDeleteWithMeta[], opts?: IEmptyTrashModalOption, } type EmptyTrashModalStatusUtils = { open( pages?: IPageToDeleteWithMeta[], opts?: IEmptyTrashModalOption, ): Promise, close(): Promise, } export const useEmptyTrashModal = (status?: EmptyTrashModalStatus): SWRResponse & EmptyTrashModalStatusUtils => { const initialData: EmptyTrashModalStatus = { isOpened: false, pages: [], }; const swrResponse = useStaticSWR('emptyTrashModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: ( pages?: IPageToDeleteWithMeta[], opts?: IEmptyTrashModalOption, ) => swrResponse.mutate({ isOpened: true, pages, opts, }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /* * PageDuplicateModal */ export type IPageForPageDuplicateModal = { pageId: string, path: string } export type IDuplicateModalOption = { onDuplicated?: OnDuplicatedFunction, } type DuplicateModalStatus = { isOpened: boolean, page?: IPageForPageDuplicateModal, opts?: IDuplicateModalOption, } type DuplicateModalStatusUtils = { open( page?: IPageForPageDuplicateModal, opts?: IDuplicateModalOption ): Promise close(): Promise } export const usePageDuplicateModal = (status?: DuplicateModalStatus): SWRResponse & DuplicateModalStatusUtils => { const initialData: DuplicateModalStatus = { isOpened: false }; const swrResponse = useStaticSWR('duplicateModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: ( page?: IPageForPageDuplicateModal, opts?: IDuplicateModalOption, ) => swrResponse.mutate({ isOpened: true, page, opts }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /* * PageRenameModal */ export type IRenameModalOption = { onRenamed?: OnRenamedFunction, } type RenameModalStatus = { isOpened: boolean, page?: IPageToRenameWithMeta, opts?: IRenameModalOption } type RenameModalStatusUtils = { open( page?: IPageToRenameWithMeta, opts?: IRenameModalOption ): Promise close(): Promise } export const usePageRenameModal = (status?: RenameModalStatus): SWRResponse & RenameModalStatusUtils => { const initialData: RenameModalStatus = { isOpened: false }; const swrResponse = useStaticSWR('renameModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: ( page?: IPageToRenameWithMeta, opts?: IRenameModalOption, ) => swrResponse.mutate({ isOpened: true, page, opts, }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /* * PutBackPageModal */ export type IPageForPagePutBackModal = { pageId: string, path: string } export type IPutBackPageModalOption = { onPutBacked?: OnPutBackedFunction, } type PutBackPageModalStatus = { isOpened: boolean, page?: IPageForPagePutBackModal, opts?: IPutBackPageModalOption, } type PutBackPageModalUtils = { open( page?: IPageForPagePutBackModal, opts?: IPutBackPageModalOption, ): Promise close(): Promise } export const usePutBackPageModal = (status?: PutBackPageModalStatus): SWRResponse & PutBackPageModalUtils => { const initialData: PutBackPageModalStatus = useMemo(() => ({ isOpened: false, page: { pageId: '', path: '' }, }), []); const swrResponse = useStaticSWR('putBackPageModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: ( page: IPageForPagePutBackModal, opts?: IPutBackPageModalOption, ) => swrResponse.mutate({ isOpened: true, page, opts, }), close: () => swrResponse.mutate({ isOpened: false, page: { pageId: '', path: '' } }), }; }; /* * PagePresentationModal */ type PresentationModalStatus = { isOpened: boolean, } type PresentationModalStatusUtils = { open(): Promise close(): Promise } export const usePagePresentationModal = ( status?: PresentationModalStatus, ): SWRResponse & PresentationModalStatusUtils => { const initialData: PresentationModalStatus = { isOpened: false, }; const swrResponse = useStaticSWR('presentationModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: () => swrResponse.mutate({ isOpened: true }, { revalidate: true }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /* * PrivateLegacyPagesMigrationModal */ export type ILegacyPrivatePage = { pageId: string, path: string }; export type PrivateLegacyPagesMigrationModalSubmitedHandler = (pages: ILegacyPrivatePage[], isRecursively?: boolean) => void; type PrivateLegacyPagesMigrationModalStatus = { isOpened: boolean, pages?: ILegacyPrivatePage[], onSubmited?: PrivateLegacyPagesMigrationModalSubmitedHandler, } type PrivateLegacyPagesMigrationModalStatusUtils = { open(pages: ILegacyPrivatePage[], onSubmited?: PrivateLegacyPagesMigrationModalSubmitedHandler): Promise, close(): Promise, } export const usePrivateLegacyPagesMigrationModal = ( status?: PrivateLegacyPagesMigrationModalStatus, ): SWRResponse & PrivateLegacyPagesMigrationModalStatusUtils => { const initialData: PrivateLegacyPagesMigrationModalStatus = { isOpened: false, pages: [], }; const swrResponse = useStaticSWR('privateLegacyPagesMigrationModal', status, { fallbackData: initialData }); return { ...swrResponse, open: (pages, onSubmited?) => swrResponse.mutate({ isOpened: true, pages, onSubmited, }), close: () => swrResponse.mutate({ isOpened: false, pages: [], onSubmited: undefined }), }; }; /* * DescendantsPageListModal */ type DescendantsPageListModalStatus = { isOpened: boolean, path?: string, } type DescendantsPageListUtils = { open(path: string): Promise close(): Promise } export const useDescendantsPageListModal = ( status?: DescendantsPageListModalStatus, ): SWRResponse & DescendantsPageListUtils => { const initialData: DescendantsPageListModalStatus = { isOpened: false }; const swrResponse = useStaticSWR('descendantsPageListModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: (path: string) => swrResponse.mutate({ isOpened: true, path }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /* * PageAccessoriesModal */ export const PageAccessoriesModalContents = { PageHistory: 'PageHistory', Attachment: 'Attachment', ShareLink: 'ShareLink', } as const; export type PageAccessoriesModalContents = typeof PageAccessoriesModalContents[keyof typeof PageAccessoriesModalContents]; type PageAccessoriesModalStatus = { isOpened: boolean, activatedContents?: PageAccessoriesModalContents, } type PageAccessoriesModalUtils = { open(activatedContents: PageAccessoriesModalContents): void close(): void } export const usePageAccessoriesModal = (): SWRResponse & PageAccessoriesModalUtils => { const initialStatus = { isOpened: false }; const swrResponse = useStaticSWR('pageAccessoriesModalStatus', undefined, { fallbackData: initialStatus }); return { ...swrResponse, open: (activatedContents: PageAccessoriesModalContents) => { if (swrResponse.data == null) { return; } swrResponse.mutate({ isOpened: true, activatedContents, }); }, close: () => { if (swrResponse.data == null) { return; } swrResponse.mutate({ isOpened: false }); }, }; }; /* * UpdateUserGroupConfirmModal */ type UpdateUserGroupConfirmModalStatus = { isOpened: boolean, targetGroup?: IUserGroupHasId, updateData?: Partial, onConfirm?: (targetGroup: IUserGroupHasId, updateData: Partial, forceUpdateParents: boolean) => any, } type UpdateUserGroupConfirmModalUtils = { open(targetGroup: IUserGroupHasId, updateData: Partial, onConfirm?: (...args: any[]) => any): Promise, close(): Promise, } export const useUpdateUserGroupConfirmModal = (): SWRResponse & UpdateUserGroupConfirmModalUtils => { const initialStatus: UpdateUserGroupConfirmModalStatus = { isOpened: false }; const swrResponse = useStaticSWR('updateParentConfirmModal', undefined, { fallbackData: initialStatus }); return { ...swrResponse, async open(targetGroup: IUserGroupHasId, updateData: Partial, onConfirm?: (...args: any[]) => any) { await swrResponse.mutate({ isOpened: true, targetGroup, updateData, onConfirm, }); }, async close() { await swrResponse.mutate({ isOpened: false }); }, }; }; /* * ShortcutsModal */ type ShortcutsModalStatus = { isOpened: boolean, } type ShortcutsModalUtils = { open(): void, close(): void, } export const useShortcutsModal = (): SWRResponse & ShortcutsModalUtils => { const initialStatus: ShortcutsModalStatus = { isOpened: false }; const swrResponse = useStaticSWR('shortcutsModal', undefined, { fallbackData: initialStatus }); return { ...swrResponse, open() { swrResponse.mutate({ isOpened: true }); }, close() { swrResponse.mutate({ isOpened: false }); }, }; }; /* * DrawioModal */ type DrawioModalSaveHandler = (drawioMxFile: string) => void; type DrawioModalStatus = { isOpened: boolean, drawioMxFile: string, onSave?: DrawioModalSaveHandler, } type DrawioModalStatusUtils = { open( drawioMxFile: string, onSave?: DrawioModalSaveHandler, ): void, close(): void, } export const useDrawioModal = (status?: DrawioModalStatus): SWRResponse & DrawioModalStatusUtils => { const initialData: DrawioModalStatus = { isOpened: false, drawioMxFile: '', }; const swrResponse = useStaticSWR('drawioModalStatus', status, { fallbackData: initialData }); const { mutate } = swrResponse; const open = useCallback((drawioMxFile: string, onSave?: DrawioModalSaveHandler): void => { mutate({ isOpened: true, drawioMxFile, onSave }); }, [mutate]); const close = useCallback((): void => { mutate({ isOpened: false, drawioMxFile: '', onSave: undefined }); }, [mutate]); return { ...swrResponse, open, close, }; }; /* * HandsonTableModal */ type HandsonTableModalSaveHandler = (table: MarkdownTable) => void; type HandsontableModalStatus = { isOpened: boolean, table: MarkdownTable, // TODO: Define editor type editor?: any, autoFormatMarkdownTable?: boolean, // onSave is passed only when editing table directly from the page. onSave?: HandsonTableModalSaveHandler } type HandsontableModalStatusUtils = { open( table: MarkdownTable, editor?: any, autoFormatMarkdownTable?: boolean, onSave?: HandsonTableModalSaveHandler ): void close(): void } const defaultMarkdownTable = () => { return new MarkdownTable( [ ['col1', 'col2', 'col3'], ['', '', ''], ['', '', ''], ], { align: ['', '', ''], }, ); }; export const useHandsontableModal = (status?: HandsontableModalStatus): SWRResponse & HandsontableModalStatusUtils => { const initialData: HandsontableModalStatus = { isOpened: false, table: defaultMarkdownTable(), editor: undefined, autoFormatMarkdownTable: false, }; const swrResponse = useStaticSWR('handsontableModalStatus', status, { fallbackData: initialData }); const { mutate } = swrResponse; const open = useCallback((table: MarkdownTable, editor?: any, autoFormatMarkdownTable?: boolean, onSave?: HandsonTableModalSaveHandler): void => { mutate({ isOpened: true, table, editor, autoFormatMarkdownTable, onSave, }); }, [mutate]); const close = useCallback((): void => { mutate({ isOpened: false, table: defaultMarkdownTable(), editor: undefined, autoFormatMarkdownTable: false, onSave: undefined, }); }, [mutate]); return { ...swrResponse, open, close, }; }; /* * ConflictDiffModal */ type ConflictDiffModalStatus = { isOpened: boolean, } type ConflictDiffModalUtils = { open(): void, close(): void, } export const useConflictDiffModal = (): SWRResponse & ConflictDiffModalUtils => { const initialStatus: ConflictDiffModalStatus = { isOpened: false }; const swrResponse = useStaticSWR('conflictDiffModal', undefined, { fallbackData: initialStatus }); return Object.assign(swrResponse, { open: () => { swrResponse.mutate({ isOpened: true }); }, close: () => { swrResponse.mutate({ isOpened: false }); }, }); }; /* * BookmarkFolderDeleteModal */ export type IDeleteBookmarkFolderModalOption = { onDeleted?: onDeletedBookmarkFolderFunction, } type DeleteBookmarkFolderModalStatus = { isOpened: boolean, bookmarkFolder?: BookmarkFolderItems, opts?: IDeleteBookmarkFolderModalOption, } type DeleteModalBookmarkFolderStatusUtils = { open( bookmarkFolder?: BookmarkFolderItems, opts?: IDeleteBookmarkFolderModalOption, ): Promise, close(): Promise, } export const useBookmarkFolderDeleteModal = (status?: DeleteBookmarkFolderModalStatus): SWRResponse & DeleteModalBookmarkFolderStatusUtils => { const initialData: DeleteBookmarkFolderModalStatus = { isOpened: false, }; const swrResponse = useStaticSWR('deleteBookmarkFolderModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: ( bookmarkFolder?: BookmarkFolderItems, opts?: IDeleteBookmarkFolderModalOption, ) => swrResponse.mutate({ isOpened: true, bookmarkFolder, opts, }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /* * TemplateModal */ type TemplateModalStatus = { isOpened: boolean, onSubmit?: (templateText: string) => void } type TemplateModalUtils = { open(onSubmit: (templateText: string) => void): void, close(): void, } export const useTemplateModal = (): SWRResponse & TemplateModalUtils => { const initialStatus: TemplateModalStatus = { isOpened: false }; const swrResponse = useStaticSWR('templateModal', undefined, { fallbackData: initialStatus }); return Object.assign(swrResponse, { open: (onSubmit: (templateText: string) => void) => { swrResponse.mutate({ isOpened: true, onSubmit }); }, close: () => { swrResponse.mutate({ isOpened: false }); }, }); }; /* * LinkEditModal */ type LinkEditModalStatus = { isOpened: boolean, defaultMarkdownLink?: Linker, onSave?: (linkText: string) => void } type LinkEditModalUtils = { open(defaultMarkdownLink: Linker, onSave: (linkText: string) => void): void, close(): void, } export const useLinkEditModal = (): SWRResponse & LinkEditModalUtils => { const initialStatus: LinkEditModalStatus = { isOpened: false }; const swrResponse = useStaticSWR('linkEditModal', undefined, { fallbackData: initialStatus }); return Object.assign(swrResponse, { open: (defaultMarkdownLink: Linker, onSave: (linkText: string) => void) => { swrResponse.mutate({ isOpened: true, defaultMarkdownLink, onSave }); }, close: () => { swrResponse.mutate({ isOpened: false }); }, }); };