PrimaryItem.tsx 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { FC, useCallback } from 'react';
  2. import { SidebarContentsType, SidebarMode } from '~/interfaces/ui';
  3. import { useCollapsedContentsOpened, useCurrentSidebarContents } from '~/stores/ui';
  4. const useIndicator = (sidebarMode: SidebarMode, isSelected: boolean): string => {
  5. const { data: isCollapsedContentsOpened } = useCollapsedContentsOpened();
  6. if (sidebarMode === SidebarMode.COLLAPSED && !isCollapsedContentsOpened) {
  7. return '';
  8. }
  9. return isSelected ? 'active' : '';
  10. };
  11. export type Props = {
  12. contents: SidebarContentsType,
  13. label: string,
  14. iconName: string,
  15. sidebarMode: SidebarMode,
  16. badgeContents?: number,
  17. onHover?: (contents: SidebarContentsType) => void,
  18. onClick?: () => void,
  19. }
  20. export const PrimaryItem: FC<Props> = (props: Props) => {
  21. const {
  22. contents, label, iconName, sidebarMode, badgeContents,
  23. onClick, onHover,
  24. } = props;
  25. const { data: currentContents, mutateAndSave: mutateContents } = useCurrentSidebarContents();
  26. const indicatorClass = useIndicator(sidebarMode, contents === currentContents);
  27. const selectThisItem = useCallback(() => {
  28. mutateContents(contents, false);
  29. }, [contents, mutateContents]);
  30. const itemClickedHandler = useCallback(() => {
  31. // do nothing ONLY WHEN the collapse mode
  32. if (sidebarMode === SidebarMode.COLLAPSED) {
  33. return;
  34. }
  35. selectThisItem();
  36. onClick?.();
  37. }, [onClick, selectThisItem, sidebarMode]);
  38. const mouseEnteredHandler = useCallback(() => {
  39. // ignore other than collapsed mode
  40. if (sidebarMode !== SidebarMode.COLLAPSED) {
  41. return;
  42. }
  43. selectThisItem();
  44. onHover?.(contents);
  45. }, [contents, onHover, selectThisItem, sidebarMode]);
  46. const labelForTestId = label.toLowerCase().replace(' ', '-');
  47. return (
  48. <button
  49. type="button"
  50. data-testid={`grw-sidebar-nav-primary-${labelForTestId}`}
  51. className={`btn btn-primary ${indicatorClass}`}
  52. onClick={itemClickedHandler}
  53. onMouseEnter={mouseEnteredHandler}
  54. >
  55. <div className="position-relative">
  56. { badgeContents != null && (
  57. <span className="position-absolute badge rounded-pill bg-primary">{badgeContents}</span>
  58. )}
  59. <span className="material-symbols-outlined">{iconName}</span>
  60. </div>
  61. </button>
  62. );
  63. };