modal.tsx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. import { useCallback } from 'react';
  2. import { SWRResponse } from 'swr';
  3. import MarkdownTable from '~/client/models/MarkdownTable';
  4. import { IPageToDeleteWithMeta, IPageToRenameWithMeta } from '~/interfaces/page';
  5. import {
  6. OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction, OnPutBackedFunction,
  7. } from '~/interfaces/ui';
  8. import { IUserGroupHasId } from '~/interfaces/user';
  9. import { useStaticSWR } from './use-static-swr';
  10. /*
  11. * PageCreateModal
  12. */
  13. type CreateModalStatus = {
  14. isOpened: boolean,
  15. path?: string,
  16. }
  17. type CreateModalStatusUtils = {
  18. open(path?: string): Promise<CreateModalStatus | undefined>
  19. close(): Promise<CreateModalStatus | undefined>
  20. }
  21. export const usePageCreateModal = (status?: CreateModalStatus): SWRResponse<CreateModalStatus, Error> & CreateModalStatusUtils => {
  22. const initialData: CreateModalStatus = { isOpened: false };
  23. const swrResponse = useStaticSWR<CreateModalStatus, Error>('pageCreateModalStatus', status, { fallbackData: initialData });
  24. return {
  25. ...swrResponse,
  26. open: (path?: string) => swrResponse.mutate({ isOpened: true, path }),
  27. close: () => swrResponse.mutate({ isOpened: false }),
  28. };
  29. };
  30. /*
  31. * PageDeleteModal
  32. */
  33. export type IDeleteModalOption = {
  34. onDeleted?: OnDeletedFunction,
  35. }
  36. type DeleteModalStatus = {
  37. isOpened: boolean,
  38. pages?: IPageToDeleteWithMeta[],
  39. opts?: IDeleteModalOption,
  40. }
  41. type DeleteModalStatusUtils = {
  42. open(
  43. pages?: IPageToDeleteWithMeta[],
  44. opts?: IDeleteModalOption,
  45. ): Promise<DeleteModalStatus | undefined>,
  46. close(): Promise<DeleteModalStatus | undefined>,
  47. }
  48. export const usePageDeleteModal = (status?: DeleteModalStatus): SWRResponse<DeleteModalStatus, Error> & DeleteModalStatusUtils => {
  49. const initialData: DeleteModalStatus = {
  50. isOpened: false,
  51. pages: [],
  52. };
  53. const swrResponse = useStaticSWR<DeleteModalStatus, Error>('deleteModalStatus', status, { fallbackData: initialData });
  54. return {
  55. ...swrResponse,
  56. open: (
  57. pages?: IPageToDeleteWithMeta[],
  58. opts?: IDeleteModalOption,
  59. ) => swrResponse.mutate({
  60. isOpened: true, pages, opts,
  61. }),
  62. close: () => swrResponse.mutate({ isOpened: false }),
  63. };
  64. };
  65. /*
  66. * EmptyTrashModal
  67. */
  68. type IEmptyTrashModalOption = {
  69. onEmptiedTrash?: () => void,
  70. canDeleteAllPages: boolean,
  71. }
  72. type EmptyTrashModalStatus = {
  73. isOpened: boolean,
  74. pages?: IPageToDeleteWithMeta[],
  75. opts?: IEmptyTrashModalOption,
  76. }
  77. type EmptyTrashModalStatusUtils = {
  78. open(
  79. pages?: IPageToDeleteWithMeta[],
  80. opts?: IEmptyTrashModalOption,
  81. ): Promise<EmptyTrashModalStatus | undefined>,
  82. close(): Promise<EmptyTrashModalStatus | undefined>,
  83. }
  84. export const useEmptyTrashModal = (status?: EmptyTrashModalStatus): SWRResponse<EmptyTrashModalStatus, Error> & EmptyTrashModalStatusUtils => {
  85. const initialData: EmptyTrashModalStatus = {
  86. isOpened: false,
  87. pages: [],
  88. };
  89. const swrResponse = useStaticSWR<EmptyTrashModalStatus, Error>('emptyTrashModalStatus', status, { fallbackData: initialData });
  90. return {
  91. ...swrResponse,
  92. open: (
  93. pages?: IPageToDeleteWithMeta[],
  94. opts?: IEmptyTrashModalOption,
  95. ) => swrResponse.mutate({
  96. isOpened: true, pages, opts,
  97. }),
  98. close: () => swrResponse.mutate({ isOpened: false }),
  99. };
  100. };
  101. /*
  102. * PageDuplicateModal
  103. */
  104. export type IPageForPageDuplicateModal = {
  105. pageId: string,
  106. path: string
  107. }
  108. export type IDuplicateModalOption = {
  109. onDuplicated?: OnDuplicatedFunction,
  110. }
  111. type DuplicateModalStatus = {
  112. isOpened: boolean,
  113. page?: IPageForPageDuplicateModal,
  114. opts?: IDuplicateModalOption,
  115. }
  116. type DuplicateModalStatusUtils = {
  117. open(
  118. page?: IPageForPageDuplicateModal,
  119. opts?: IDuplicateModalOption
  120. ): Promise<DuplicateModalStatus | undefined>
  121. close(): Promise<DuplicateModalStatus | undefined>
  122. }
  123. export const usePageDuplicateModal = (status?: DuplicateModalStatus): SWRResponse<DuplicateModalStatus, Error> & DuplicateModalStatusUtils => {
  124. const initialData: DuplicateModalStatus = { isOpened: false };
  125. const swrResponse = useStaticSWR<DuplicateModalStatus, Error>('duplicateModalStatus', status, { fallbackData: initialData });
  126. return {
  127. ...swrResponse,
  128. open: (
  129. page?: IPageForPageDuplicateModal,
  130. opts?: IDuplicateModalOption,
  131. ) => swrResponse.mutate({ isOpened: true, page, opts }),
  132. close: () => swrResponse.mutate({ isOpened: false }),
  133. };
  134. };
  135. /*
  136. * PageRenameModal
  137. */
  138. export type IRenameModalOption = {
  139. onRenamed?: OnRenamedFunction,
  140. }
  141. type RenameModalStatus = {
  142. isOpened: boolean,
  143. page?: IPageToRenameWithMeta,
  144. opts?: IRenameModalOption
  145. }
  146. type RenameModalStatusUtils = {
  147. open(
  148. page?: IPageToRenameWithMeta,
  149. opts?: IRenameModalOption
  150. ): Promise<RenameModalStatus | undefined>
  151. close(): Promise<RenameModalStatus | undefined>
  152. }
  153. export const usePageRenameModal = (status?: RenameModalStatus): SWRResponse<RenameModalStatus, Error> & RenameModalStatusUtils => {
  154. const initialData: RenameModalStatus = { isOpened: false };
  155. const swrResponse = useStaticSWR<RenameModalStatus, Error>('renameModalStatus', status, { fallbackData: initialData });
  156. return {
  157. ...swrResponse,
  158. open: (
  159. page?: IPageToRenameWithMeta,
  160. opts?: IRenameModalOption,
  161. ) => swrResponse.mutate({
  162. isOpened: true, page, opts,
  163. }),
  164. close: () => swrResponse.mutate({ isOpened: false }),
  165. };
  166. };
  167. /*
  168. * PutBackPageModal
  169. */
  170. export type IPageForPagePutBackModal = {
  171. pageId: string,
  172. path: string
  173. }
  174. export type IPutBackPageModalOption = {
  175. onPutBacked?: OnPutBackedFunction,
  176. }
  177. type PutBackPageModalStatus = {
  178. isOpened: boolean,
  179. page?: IPageForPagePutBackModal,
  180. opts?: IPutBackPageModalOption,
  181. }
  182. type PutBackPageModalUtils = {
  183. open(
  184. page?: IPageForPagePutBackModal,
  185. opts?: IPutBackPageModalOption,
  186. ): Promise<PutBackPageModalStatus | undefined>
  187. close():Promise<PutBackPageModalStatus | undefined>
  188. }
  189. export const usePutBackPageModal = (status?: PutBackPageModalStatus): SWRResponse<PutBackPageModalStatus, Error> & PutBackPageModalUtils => {
  190. const initialData: PutBackPageModalStatus = {
  191. isOpened: false,
  192. page: { pageId: '', path: '' },
  193. };
  194. const swrResponse = useStaticSWR<PutBackPageModalStatus, Error>('putBackPageModalStatus', status, { fallbackData: initialData });
  195. return {
  196. ...swrResponse,
  197. open: (
  198. page: IPageForPagePutBackModal, opts?: IPutBackPageModalOption,
  199. ) => swrResponse.mutate({
  200. isOpened: true, page, opts,
  201. }),
  202. close: () => swrResponse.mutate({ isOpened: false, page: { pageId: '', path: '' } }),
  203. };
  204. };
  205. /*
  206. * PagePresentationModal
  207. */
  208. type PresentationModalStatus = {
  209. isOpened: boolean,
  210. href?: string
  211. }
  212. type PresentationModalStatusUtils = {
  213. open(href: string): Promise<PresentationModalStatus | undefined>
  214. close(): Promise<PresentationModalStatus | undefined>
  215. }
  216. export const usePagePresentationModal = (
  217. status?: PresentationModalStatus,
  218. ): SWRResponse<PresentationModalStatus, Error> & PresentationModalStatusUtils => {
  219. const initialData: PresentationModalStatus = {
  220. isOpened: false, href: '?presentation=1',
  221. };
  222. const swrResponse = useStaticSWR<PresentationModalStatus, Error>('presentationModalStatus', status, { fallbackData: initialData });
  223. return {
  224. ...swrResponse,
  225. open: (href: string) => swrResponse.mutate({ isOpened: true, href }),
  226. close: () => swrResponse.mutate({ isOpened: false }),
  227. };
  228. };
  229. /*
  230. * PrivateLegacyPagesMigrationModal
  231. */
  232. export type ILegacyPrivatePage = { pageId: string, path: string };
  233. export type PrivateLegacyPagesMigrationModalSubmitedHandler = (pages: ILegacyPrivatePage[], isRecursively?: boolean) => void;
  234. type PrivateLegacyPagesMigrationModalStatus = {
  235. isOpened: boolean,
  236. pages?: ILegacyPrivatePage[],
  237. onSubmited?: PrivateLegacyPagesMigrationModalSubmitedHandler,
  238. }
  239. type PrivateLegacyPagesMigrationModalStatusUtils = {
  240. open(pages: ILegacyPrivatePage[], onSubmited?: PrivateLegacyPagesMigrationModalSubmitedHandler): Promise<PrivateLegacyPagesMigrationModalStatus | undefined>,
  241. close(): Promise<PrivateLegacyPagesMigrationModalStatus | undefined>,
  242. }
  243. export const usePrivateLegacyPagesMigrationModal = (
  244. status?: PrivateLegacyPagesMigrationModalStatus,
  245. ): SWRResponse<PrivateLegacyPagesMigrationModalStatus, Error> & PrivateLegacyPagesMigrationModalStatusUtils => {
  246. const initialData: PrivateLegacyPagesMigrationModalStatus = {
  247. isOpened: false,
  248. pages: [],
  249. };
  250. const swrResponse = useStaticSWR<PrivateLegacyPagesMigrationModalStatus, Error>('privateLegacyPagesMigrationModal', status, { fallbackData: initialData });
  251. return {
  252. ...swrResponse,
  253. open: (pages, onSubmited?) => swrResponse.mutate({
  254. isOpened: true, pages, onSubmited,
  255. }),
  256. close: () => swrResponse.mutate({ isOpened: false, pages: [], onSubmited: undefined }),
  257. };
  258. };
  259. /*
  260. * DescendantsPageListModal
  261. */
  262. type DescendantsPageListModalStatus = {
  263. isOpened: boolean,
  264. path?: string,
  265. }
  266. type DescendantsPageListUtils = {
  267. open(path: string): Promise<DescendantsPageListModalStatus | undefined>
  268. close(): Promise<DuplicateModalStatus | undefined>
  269. }
  270. export const useDescendantsPageListModal = (
  271. status?: DescendantsPageListModalStatus,
  272. ): SWRResponse<DescendantsPageListModalStatus, Error> & DescendantsPageListUtils => {
  273. const initialData: DescendantsPageListModalStatus = { isOpened: false };
  274. const swrResponse = useStaticSWR<DescendantsPageListModalStatus, Error>('descendantsPageListModalStatus', status, { fallbackData: initialData });
  275. return {
  276. ...swrResponse,
  277. open: (path: string) => swrResponse.mutate({ isOpened: true, path }),
  278. close: () => swrResponse.mutate({ isOpened: false }),
  279. };
  280. };
  281. /*
  282. * PageAccessoriesModal
  283. */
  284. export const PageAccessoriesModalContents = {
  285. PageHistory: 'PageHistory',
  286. Attachment: 'Attachment',
  287. ShareLink: 'ShareLink',
  288. } as const;
  289. export type PageAccessoriesModalContents = typeof PageAccessoriesModalContents[keyof typeof PageAccessoriesModalContents];
  290. type PageAccessoriesModalStatus = {
  291. isOpened: boolean,
  292. onOpened?: (initialActivatedContents: PageAccessoriesModalContents) => void,
  293. }
  294. type PageAccessoriesModalUtils = {
  295. open(activatedContents: PageAccessoriesModalContents): void
  296. close(): void
  297. }
  298. export const usePageAccessoriesModal = (): SWRResponse<PageAccessoriesModalStatus, Error> & PageAccessoriesModalUtils => {
  299. const initialStatus = { isOpened: false };
  300. const swrResponse = useStaticSWR<PageAccessoriesModalStatus, Error>('pageAccessoriesModalStatus', undefined, { fallbackData: initialStatus });
  301. return {
  302. ...swrResponse,
  303. open: (activatedContents: PageAccessoriesModalContents) => {
  304. if (swrResponse.data == null) {
  305. return;
  306. }
  307. swrResponse.mutate({ isOpened: true });
  308. if (swrResponse.data.onOpened != null) {
  309. swrResponse.data.onOpened(activatedContents);
  310. }
  311. },
  312. close: () => {
  313. if (swrResponse.data == null) {
  314. return;
  315. }
  316. swrResponse.mutate({ isOpened: false });
  317. },
  318. };
  319. };
  320. /*
  321. * UpdateUserGroupConfirmModal
  322. */
  323. type UpdateUserGroupConfirmModalStatus = {
  324. isOpened: boolean,
  325. targetGroup?: IUserGroupHasId,
  326. updateData?: Partial<IUserGroupHasId>,
  327. onConfirm?: (targetGroup: IUserGroupHasId, updateData: Partial<IUserGroupHasId>, forceUpdateParents: boolean) => any,
  328. }
  329. type UpdateUserGroupConfirmModalUtils = {
  330. open(targetGroup: IUserGroupHasId, updateData: Partial<IUserGroupHasId>, onConfirm?: (...args: any[]) => any): Promise<void>,
  331. close(): Promise<void>,
  332. }
  333. export const useUpdateUserGroupConfirmModal = (): SWRResponse<UpdateUserGroupConfirmModalStatus, Error> & UpdateUserGroupConfirmModalUtils => {
  334. const initialStatus: UpdateUserGroupConfirmModalStatus = { isOpened: false };
  335. const swrResponse = useStaticSWR<UpdateUserGroupConfirmModalStatus, Error>('updateParentConfirmModal', undefined, { fallbackData: initialStatus });
  336. return {
  337. ...swrResponse,
  338. async open(targetGroup: IUserGroupHasId, updateData: Partial<IUserGroupHasId>, onConfirm?: (...args: any[]) => any) {
  339. await swrResponse.mutate({
  340. isOpened: true, targetGroup, updateData, onConfirm,
  341. });
  342. },
  343. async close() {
  344. await swrResponse.mutate({ isOpened: false });
  345. },
  346. };
  347. };
  348. /*
  349. * ShortcutsModal
  350. */
  351. type ShortcutsModalStatus = {
  352. isOpened: boolean,
  353. }
  354. type ShortcutsModalUtils = {
  355. open(): void,
  356. close(): void,
  357. }
  358. export const useShortcutsModal = (): SWRResponse<ShortcutsModalStatus, Error> & ShortcutsModalUtils => {
  359. const initialStatus: ShortcutsModalStatus = { isOpened: false };
  360. const swrResponse = useStaticSWR<ShortcutsModalStatus, Error>('shortcutsModal', undefined, { fallbackData: initialStatus });
  361. return {
  362. ...swrResponse,
  363. open() {
  364. swrResponse.mutate({ isOpened: true });
  365. },
  366. close() {
  367. swrResponse.mutate({ isOpened: false });
  368. },
  369. };
  370. };
  371. /*
  372. * DrawioModal
  373. */
  374. type DrawioModalSaveHandler = (drawioMxFile: string) => void;
  375. type DrawioModalStatus = {
  376. isOpened: boolean,
  377. drawioMxFile: string,
  378. onSave?: DrawioModalSaveHandler,
  379. }
  380. type DrawioModalStatusUtils = {
  381. open(
  382. drawioMxFile: string,
  383. onSave?: DrawioModalSaveHandler,
  384. ): void,
  385. close(): void,
  386. }
  387. export const useDrawioModal = (status?: DrawioModalStatus): SWRResponse<DrawioModalStatus, Error> & DrawioModalStatusUtils => {
  388. const initialData: DrawioModalStatus = {
  389. isOpened: false,
  390. drawioMxFile: '',
  391. };
  392. const swrResponse = useStaticSWR<DrawioModalStatus, Error>('drawioModalStatus', status, { fallbackData: initialData });
  393. const { mutate } = swrResponse;
  394. const open = useCallback((drawioMxFile: string, onSave?: DrawioModalSaveHandler): void => {
  395. mutate({ isOpened: true, drawioMxFile, onSave });
  396. }, [mutate]);
  397. const close = useCallback((): void => {
  398. mutate({ isOpened: false, drawioMxFile: '', onSave: undefined });
  399. }, [mutate]);
  400. return {
  401. ...swrResponse,
  402. open,
  403. close,
  404. };
  405. };
  406. /*
  407. * HandsonTableModal
  408. */
  409. type HandsonTableModalSaveHandler = (table: MarkdownTable) => void;
  410. type HandsontableModalStatus = {
  411. isOpened: boolean,
  412. table: MarkdownTable,
  413. // TODO: Define editor type
  414. editor?: any,
  415. autoFormatMarkdownTable?: boolean,
  416. // onSave is passed only when editing table directly from the page.
  417. onSave?: HandsonTableModalSaveHandler
  418. }
  419. type HandsontableModalStatusUtils = {
  420. open(
  421. table: MarkdownTable,
  422. editor?: any,
  423. autoFormatMarkdownTable?: boolean,
  424. onSave?: HandsonTableModalSaveHandler
  425. ): void
  426. close(): void
  427. }
  428. const defaultMarkdownTable = () => {
  429. return new MarkdownTable(
  430. [
  431. ['col1', 'col2', 'col3'],
  432. ['', '', ''],
  433. ['', '', ''],
  434. ],
  435. {
  436. align: ['', '', ''],
  437. },
  438. );
  439. };
  440. export const useHandsontableModal = (status?: HandsontableModalStatus): SWRResponse<HandsontableModalStatus, Error> & HandsontableModalStatusUtils => {
  441. const initialData: HandsontableModalStatus = {
  442. isOpened: false,
  443. table: defaultMarkdownTable(),
  444. editor: undefined,
  445. autoFormatMarkdownTable: false,
  446. };
  447. const swrResponse = useStaticSWR<HandsontableModalStatus, Error>('handsontableModalStatus', status, { fallbackData: initialData });
  448. const { mutate } = swrResponse;
  449. const open = useCallback((table: MarkdownTable, editor?: any, autoFormatMarkdownTable?: boolean, onSave?: HandsonTableModalSaveHandler): void => {
  450. mutate({
  451. isOpened: true, table, editor, autoFormatMarkdownTable, onSave,
  452. });
  453. }, [mutate]);
  454. const close = useCallback((): void => {
  455. mutate({
  456. isOpened: false, table: defaultMarkdownTable(), editor: undefined, autoFormatMarkdownTable: false, onSave: undefined,
  457. });
  458. }, [mutate]);
  459. return {
  460. ...swrResponse,
  461. open,
  462. close,
  463. };
  464. };