import { useCallback, useMemo } from 'react'; import type { IAttachmentHasId, IPageToDeleteWithMeta, IPageToRenameWithMeta, IUserGroupHasId, } from '@growi/core'; import { useSWRStatic } from '@growi/core/dist/swr'; import { MarkdownTable } from '@growi/editor'; import type { SWRResponse } from 'swr'; import type { BookmarkFolderItems } from '~/interfaces/bookmark-info'; import type { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction, OnPutBackedFunction, onDeletedBookmarkFolderFunction, OnSelectedFunction, } from '~/interfaces/ui'; import loggerFactory from '~/utils/logger'; 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 = useSWRStatic('pageCreateModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: (path?: string) => swrResponse.mutate({ isOpened: true, path }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /* * GrantedGroupsInheritanceSelectModal */ type GrantedGroupsInheritanceSelectModalStatus = { isOpened: boolean, onCreateBtnClick?: (onlyInheritUserRelatedGrantedGroups?: boolean) => Promise, } type GrantedGroupsInheritanceSelectModalStatusUtils = { open(onCreateBtnClick?: (onlyInheritUserRelatedGrantedGroups?: boolean) => Promise): Promise close(): Promise } export const useGrantedGroupsInheritanceSelectModal = ( status?: GrantedGroupsInheritanceSelectModalStatus, ): SWRResponse & GrantedGroupsInheritanceSelectModalStatusUtils => { const initialData: GrantedGroupsInheritanceSelectModalStatus = { isOpened: false }; const swrResponse = useSWRStatic( 'grantedGroupsInheritanceSelectModalStatus', status, { fallbackData: initialData }, ); const { mutate } = swrResponse; return { ...swrResponse, open: useCallback( (onCreateBtnClick?: (onlyInheritUserRelatedGrantedGroups?: boolean) => Promise) => mutate({ isOpened: true, onCreateBtnClick }), [mutate], ), close: useCallback(() => mutate({ isOpened: false }), [mutate]), }; }; /* * 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 = useSWRStatic('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 = useSWRStatic('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 = useSWRStatic('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 = useSWRStatic('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 = useSWRStatic('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 = useSWRStatic('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 = useSWRStatic('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 = useSWRStatic('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 selectContents(activatedContents: PageAccessoriesModalContents): void } export const usePageAccessoriesModal = (): SWRResponse & PageAccessoriesModalUtils => { const initialStatus = { isOpened: false }; const swrResponse = useSWRStatic('pageAccessoriesModalStatus', undefined, { fallbackData: initialStatus }); const { data, mutate } = swrResponse; return Object.assign(swrResponse, { open: useCallback((activatedContents) => { if (data == null) { return; } mutate({ isOpened: true, activatedContents, }); }, [data, mutate]), close: useCallback(() => { if (data == null) { return; } mutate({ isOpened: false }); }, [data, mutate]), selectContents: useCallback((activatedContents) => { if (data == null) { return; } mutate({ isOpened: data.isOpened, activatedContents, }); }, [data, mutate]), }); }; /* * 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 = useSWRStatic('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 = useSWRStatic('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 = useSWRStatic('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, autoFormatMarkdownTable?: boolean, // onSave is passed only when editing table directly from the page. onSave?: HandsonTableModalSaveHandler } type HandsontableModalStatusUtils = { open( table: MarkdownTable, 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(), autoFormatMarkdownTable: false, }; const swrResponse = useSWRStatic('handsontableModalStatus', status, { fallbackData: initialData }); const { mutate } = swrResponse; const open = useCallback((table: MarkdownTable, autoFormatMarkdownTable?: boolean, onSave?: HandsonTableModalSaveHandler): void => { mutate({ isOpened: true, table, autoFormatMarkdownTable, onSave, }); }, [mutate]); const close = useCallback((): void => { mutate({ isOpened: false, table: defaultMarkdownTable(), autoFormatMarkdownTable: false, onSave: undefined, }); }, [mutate]); return { ...swrResponse, open, close, }; }; /* * ConflictDiffModal */ type ResolveConflictHandler = (newMarkdown: string) => Promise | void; type ConflictDiffModalStatus = { isOpened: boolean, requestRevisionBody?: string, onResolve?: ResolveConflictHandler } type ConflictDiffModalUtils = { open(requestRevisionBody: string, onResolveConflict: ResolveConflictHandler): void, close(): void, } export const useConflictDiffModal = (): SWRResponse & ConflictDiffModalUtils => { const initialStatus: ConflictDiffModalStatus = { isOpened: false }; const swrResponse = useSWRStatic('conflictDiffModal', undefined, { fallbackData: initialStatus }); const { mutate } = swrResponse; const open = useCallback((requestRevisionBody: string, onResolve: ResolveConflictHandler) => { mutate({ isOpened: true, requestRevisionBody, onResolve }); }, [mutate]); const close = useCallback(() => { mutate({ isOpened: false }); }, [mutate]); return { ...swrResponse, open, close, }; }; /* * 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 = useSWRStatic('deleteBookmarkFolderModalStatus', status, { fallbackData: initialData }); return { ...swrResponse, open: ( bookmarkFolder?: BookmarkFolderItems, opts?: IDeleteBookmarkFolderModalOption, ) => swrResponse.mutate({ isOpened: true, bookmarkFolder, opts, }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /** * DeleteAttachmentModal */ type Remove = (body: { attachment_id: string; }) => Promise type DeleteAttachmentModalStatus = { isOpened: boolean, attachment?: IAttachmentHasId, remove?: Remove, } type DeleteAttachmentModalUtils = { open( attachment: IAttachmentHasId, remove: Remove, ): void, close(): void, } export const useDeleteAttachmentModal = (): SWRResponse & DeleteAttachmentModalUtils => { const initialStatus: DeleteAttachmentModalStatus = { isOpened: false, attachment: undefined, remove: undefined, }; const swrResponse = useSWRStatic('deleteAttachmentModal', undefined, { fallbackData: initialStatus }); const { mutate } = swrResponse; const open = useCallback((attachment: IAttachmentHasId, remove: Remove) => { mutate({ isOpened: true, attachment, remove }); }, [mutate]); const close = useCallback(() => { mutate({ isOpened: false }); }, [mutate]); return { ...swrResponse, open, close, }; }; /* * PageSelectModal */ type IPageSelectModalOption = { isHierarchicalSelectionMode?: boolean, onSelected?: OnSelectedFunction, } type PageSelectModalStatus = { isOpened: boolean opts?: IPageSelectModalOption } type PageSelectModalStatusUtils = { open(opts?: IPageSelectModalOption): void close(): void } export const usePageSelectModal = ( status?: PageSelectModalStatus, ): SWRResponse & PageSelectModalStatusUtils => { const initialStatus = { isOpened: false }; const swrResponse = useSWRStatic('PageSelectModal', status, { fallbackData: initialStatus }); return { ...swrResponse, open: ( opts?: IPageSelectModalOption, ) => swrResponse.mutate({ isOpened: true, opts, }), close: () => swrResponse.mutate({ isOpened: false }), }; }; /* * TagEditModal */ export type TagEditModalStatus = { isOpen: boolean, tags: string[], pageId: string, revisionId: string, } type TagEditModalUtils = { open(tags: string[], pageId: string, revisionId: string): Promise, close(): Promise, } export const useTagEditModal = (): SWRResponse & TagEditModalUtils => { const initialStatus: TagEditModalStatus = useMemo(() => { return { isOpen: false, tags: [], pageId: '', revisionId: '', }; }, []); const swrResponse = useSWRStatic('TagEditModal', undefined, { fallbackData: initialStatus }); const { mutate } = swrResponse; const open = useCallback(async(tags: string[], pageId: string, revisionId: string) => { mutate({ isOpen: true, tags, pageId, revisionId, }); }, [mutate]); const close = useCallback(async() => { mutate(initialStatus); }, [initialStatus, mutate]); return { ...swrResponse, open, close, }; };