PrimaryItems.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { FC, memo, useCallback } from 'react';
  2. import dynamic from 'next/dynamic';
  3. import { scheduleToPut } from '~/client/services/user-ui-settings';
  4. import { SidebarContentsType, SidebarMode } from '~/interfaces/ui';
  5. import { useCollapsedContentsOpened, useCurrentSidebarContents, useSidebarMode } from '~/stores/ui';
  6. import styles from './PrimaryItems.module.scss';
  7. const InAppNotificationDropdown = dynamic(() => import('../../InAppNotification/InAppNotificationDropdown')
  8. .then(mod => mod.InAppNotificationDropdown), { ssr: false });
  9. /**
  10. * @returns String for className to switch the indicator is active or not
  11. */
  12. const useIndicator = (sidebarMode: SidebarMode, isSelected: boolean): string => {
  13. const { data: isCollapsedContentsOpened } = useCollapsedContentsOpened();
  14. if (sidebarMode === SidebarMode.COLLAPSED && !isCollapsedContentsOpened) {
  15. return '';
  16. }
  17. return isSelected ? 'active' : '';
  18. };
  19. type PrimaryItemProps = {
  20. contents: SidebarContentsType,
  21. label: string,
  22. iconName: string,
  23. sidebarMode: SidebarMode,
  24. onHover?: (contents: SidebarContentsType) => void,
  25. }
  26. const PrimaryItem: FC<PrimaryItemProps> = (props: PrimaryItemProps) => {
  27. const {
  28. contents, label, iconName, sidebarMode,
  29. onHover,
  30. } = props;
  31. const { data: currentContents, mutate: mutateContents } = useCurrentSidebarContents();
  32. const indicatorClass = useIndicator(sidebarMode, contents === currentContents);
  33. const selectThisItem = useCallback(() => {
  34. mutateContents(contents, false);
  35. scheduleToPut({ currentSidebarContents: contents });
  36. }, [contents, mutateContents]);
  37. const itemClickedHandler = useCallback(() => {
  38. // do nothing ONLY WHEN the collapse mode
  39. if (sidebarMode === SidebarMode.COLLAPSED) {
  40. return;
  41. }
  42. selectThisItem();
  43. }, [selectThisItem, sidebarMode]);
  44. const mouseEnteredHandler = useCallback(() => {
  45. // ignore other than collapsed mode
  46. if (sidebarMode !== SidebarMode.COLLAPSED) {
  47. return;
  48. }
  49. selectThisItem();
  50. onHover?.(contents);
  51. }, [contents, onHover, selectThisItem, sidebarMode]);
  52. const labelForTestId = label.toLowerCase().replace(' ', '-');
  53. return (
  54. <button
  55. type="button"
  56. data-testid={`grw-sidebar-nav-primary-${labelForTestId}`}
  57. className={`d-block btn btn-primary ${indicatorClass}`}
  58. onClick={itemClickedHandler}
  59. onMouseEnter={mouseEnteredHandler}
  60. >
  61. <i className="material-icons">{iconName}</i>
  62. </button>
  63. );
  64. };
  65. type Props = {
  66. onItemHover?: (contents: SidebarContentsType) => void,
  67. }
  68. export const PrimaryItems = memo((props: Props) => {
  69. const { onItemHover } = props;
  70. const { data: sidebarMode } = useSidebarMode();
  71. if (sidebarMode == null) {
  72. return <></>;
  73. }
  74. return (
  75. <div className={styles['grw-primary-items']}>
  76. <PrimaryItem sidebarMode={sidebarMode} contents={SidebarContentsType.TREE} label="Page Tree" iconName="format_list_bulleted" onHover={onItemHover} />
  77. <PrimaryItem sidebarMode={sidebarMode} contents={SidebarContentsType.CUSTOM} label="Custom Sidebar" iconName="code" onHover={onItemHover} />
  78. <PrimaryItem sidebarMode={sidebarMode} contents={SidebarContentsType.RECENT} label="Recent Changes" iconName="update" onHover={onItemHover} />
  79. <PrimaryItem sidebarMode={sidebarMode} contents={SidebarContentsType.BOOKMARKS} label="Bookmarks" iconName="bookmark" onHover={onItemHover} />
  80. <PrimaryItem sidebarMode={sidebarMode} contents={SidebarContentsType.TAG} label="Tags" iconName="local_offer" onHover={onItemHover} />
  81. <InAppNotificationDropdown />
  82. </div>
  83. );
  84. });