PersonalDropdown.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import { useState } from 'react';
  2. import { pagePathUtils } from '@growi/core/dist/utils';
  3. import { UserPicture } from '@growi/ui/dist/components';
  4. import { useTranslation } from 'next-i18next';
  5. import dynamic from 'next/dynamic';
  6. import Link from 'next/link';
  7. import {
  8. UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem,
  9. } from 'reactstrap';
  10. import { apiv3Post } from '~/client/util/apiv3-client';
  11. import { toastError } from '~/client/util/toastr';
  12. import { useCurrentUser } from '~/stores/context';
  13. import { SkeletonItem } from './SkeletonItem';
  14. import styles from './PersonalDropdown.module.scss';
  15. const ProactiveQuestionnaireModal = dynamic(() => import('~/features/questionnaire/client/components/ProactiveQuestionnaireModal'), { ssr: false });
  16. export const PersonalDropdown = (): JSX.Element => {
  17. const { t } = useTranslation('commons');
  18. const { data: currentUser } = useCurrentUser();
  19. const [isQuestionnaireModalOpen, setQuestionnaireModalOpen] = useState(false);
  20. if (currentUser == null) {
  21. return <SkeletonItem />;
  22. }
  23. const logoutHandler = async() => {
  24. try {
  25. await apiv3Post('/logout');
  26. window.location.reload();
  27. }
  28. catch (err) {
  29. toastError(err);
  30. }
  31. };
  32. return (
  33. <>
  34. <UncontrolledDropdown
  35. direction="end"
  36. >
  37. <DropdownToggle
  38. className="btn btn-primary"
  39. data-testid="personal-dropdown-button"
  40. >
  41. <UserPicture user={currentUser} noLink noTooltip />
  42. </DropdownToggle>
  43. <DropdownMenu
  44. container="body"
  45. data-testid="personal-dropdown-menu"
  46. className={styles['personal-dropdown-menu']}
  47. >
  48. <DropdownItem className={styles['personal-dropdown-header']}>
  49. <div className="mt-2 mb-3">
  50. <UserPicture user={currentUser} size="lg" noLink noTooltip />
  51. </div>
  52. <div className="ms-1 fs-6">{currentUser.name}</div>
  53. <div className="d-flex align-items-center my-2">
  54. <small className="material-symbols-outlined me-1 pb-0 fs-6">person</small>
  55. <span>{currentUser.username}</span>
  56. </div>
  57. <div className="d-flex align-items-center">
  58. <span className="material-symbols-outlined me-1 pb-0 fs-6">mail</span>
  59. <span className="item-text-email">{currentUser.email}</span>
  60. </div>
  61. </DropdownItem>
  62. <DropdownItem className="my-3" divider />
  63. <DropdownItem className={`my-1 ${styles['personal-dropdown-item']}`}>
  64. <Link
  65. href={pagePathUtils.userHomepagePath(currentUser)}
  66. data-testid="grw-personal-dropdown-menu-user-home"
  67. >
  68. <span className="d-flex align-items-center">
  69. <span className="item-icon material-symbols-outlined me-2 pb-0 fs-6">home</span>
  70. <span className="item-text">{t('personal_dropdown.home')}</span>
  71. </span>
  72. </Link>
  73. </DropdownItem>
  74. <DropdownItem className={`my-1 ${styles['personal-dropdown-item']}`}>
  75. <Link
  76. href="/me"
  77. data-testid="grw-personal-dropdown-menu-user-settings"
  78. >
  79. <span className="d-flex align-items-center">
  80. <span className="item-icon material-symbols-outlined me-2 pb-0 fs-6">discover_tune</span>
  81. <span className="item-text">{t('personal_dropdown.settings')}</span>
  82. </span>
  83. </Link>
  84. </DropdownItem>
  85. <DropdownItem
  86. data-testid="grw-proactive-questionnaire-modal-toggle-btn"
  87. onClick={() => setQuestionnaireModalOpen(true)}
  88. className={`my-1 ${styles['personal-dropdown-item']}`}
  89. >
  90. <span className="d-flex align-items-center">
  91. <span className="item-icon material-symbols-outlined me-2 pb-0 fs-6">edit_note</span>
  92. <span className="item-text">{t('personal_dropdown.feedback')}</span>
  93. </span>
  94. </DropdownItem>
  95. <DropdownItem onClick={logoutHandler} className={`my-1 ${styles['personal-dropdown-item']}`}>
  96. <span className="d-flex align-items-center">
  97. <span className="item-icon material-symbols-outlined me-2 pb-0 fs-6">logout</span>
  98. <span className="item-text">{t('Sign out')}</span>
  99. </span>
  100. </DropdownItem>
  101. </DropdownMenu>
  102. </UncontrolledDropdown>
  103. <ProactiveQuestionnaireModal isOpen={isQuestionnaireModalOpen} onClose={() => setQuestionnaireModalOpen(false)} />
  104. </>
  105. );
  106. };