DisplaySwitcher.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import React, { useCallback, useEffect, useMemo } from 'react';
  2. import dynamic from 'next/dynamic';
  3. import { SocketEventName } from '~/interfaces/websocket';
  4. import {
  5. useCurrentPageId,
  6. useIsEditable,
  7. } from '~/stores/context';
  8. import { useIsHackmdDraftUpdatingInRealtime } from '~/stores/hackmd';
  9. import { useSetRemoteLatestPageData } from '~/stores/remote-latest-page';
  10. import { EditorMode, useEditorMode } from '~/stores/ui';
  11. import { useGlobalSocket } from '~/stores/websocket';
  12. import CustomTabContent from '../CustomNavigation/CustomTabContent';
  13. import { Page } from '../Page';
  14. const PageEditor = dynamic(() => import('../PageEditor'), { ssr: false });
  15. const PageEditorByHackmd = dynamic(() => import('../PageEditorByHackmd').then(mod => mod.PageEditorByHackmd), { ssr: false });
  16. const EditorNavbarBottom = dynamic(() => import('../PageEditor/EditorNavbarBottom'), { ssr: false });
  17. const HashChanged = dynamic(() => import('../EventListeneres/HashChanged'), { ssr: false });
  18. const DisplaySwitcher = React.memo((): JSX.Element => {
  19. const { data: currentPageId } = useCurrentPageId();
  20. const { data: editorMode = EditorMode.View } = useEditorMode();
  21. const { data: isEditable } = useIsEditable();
  22. const { setRemoteLatestPageData } = useSetRemoteLatestPageData();
  23. const { mutate: mutateIsHackmdDraftUpdatingInRealtime } = useIsHackmdDraftUpdatingInRealtime();
  24. const { data: socket } = useGlobalSocket();
  25. const isViewMode = editorMode === EditorMode.View;
  26. const setLatestRemotePageData = useCallback((data) => {
  27. const { s2cMessagePageUpdated } = data;
  28. const remoteData = {
  29. remoteRevisionId: s2cMessagePageUpdated.revisionId,
  30. remoteRevisionBody: s2cMessagePageUpdated.revisionBody,
  31. remoteRevisionLastUpdateUser: s2cMessagePageUpdated.remoteLastUpdateUser,
  32. remoteRevisionLastUpdatedAt: s2cMessagePageUpdated.revisionUpdateAt,
  33. revisionIdHackmdSynced: s2cMessagePageUpdated.revisionIdHackmdSynced,
  34. hasDraftOnHackmd: s2cMessagePageUpdated.hasDraftOnHackmd,
  35. };
  36. setRemoteLatestPageData(remoteData);
  37. }, [setRemoteLatestPageData]);
  38. const setIsHackmdDraftUpdatingInRealtime = useCallback((data) => {
  39. const { s2cMessagePageUpdated } = data;
  40. if (s2cMessagePageUpdated.pageId === currentPageId) {
  41. mutateIsHackmdDraftUpdatingInRealtime(true);
  42. }
  43. }, [currentPageId, mutateIsHackmdDraftUpdatingInRealtime]);
  44. // listen socket for someone updating this page
  45. useEffect(() => {
  46. if (socket == null) { return }
  47. socket.on(SocketEventName.PageUpdated, setLatestRemotePageData);
  48. return () => {
  49. socket.off(SocketEventName.PageUpdated, setLatestRemotePageData);
  50. };
  51. }, [setLatestRemotePageData, socket]);
  52. // listen socket for hackmd saved
  53. useEffect(() => {
  54. if (socket == null) { return }
  55. socket.on(SocketEventName.EditingWithHackmd, setIsHackmdDraftUpdatingInRealtime);
  56. return () => {
  57. socket.off(SocketEventName.EditingWithHackmd, setIsHackmdDraftUpdatingInRealtime);
  58. };
  59. }, [setIsHackmdDraftUpdatingInRealtime, socket]);
  60. const navTabMapping = useMemo(() => {
  61. return {
  62. [EditorMode.View]: {
  63. Content: () => (
  64. <div data-testid="page-view" id="page-view">
  65. <Page />
  66. </div>
  67. ),
  68. },
  69. [EditorMode.Editor]: {
  70. Content: () => (
  71. isEditable
  72. ? (
  73. <div data-testid="page-editor" id="page-editor">
  74. <PageEditor />
  75. </div>
  76. )
  77. : <></>
  78. ),
  79. },
  80. [EditorMode.HackMD]: {
  81. Content: () => (
  82. isEditable
  83. ? (
  84. <div id="page-editor-with-hackmd">
  85. <PageEditorByHackmd />
  86. </div>
  87. )
  88. : <></>
  89. ),
  90. },
  91. };
  92. }, [isEditable]);
  93. return (
  94. <>
  95. <CustomTabContent activeTab={editorMode} navTabMapping={navTabMapping} />
  96. { isEditable && !isViewMode && <EditorNavbarBottom /> }
  97. { isEditable && <HashChanged></HashChanged> }
  98. </>
  99. );
  100. });
  101. DisplaySwitcher.displayName = 'DisplaySwitcher';
  102. export default DisplaySwitcher;