PersonalDropdown.jsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import { createSubscribedElement } from '../UnstatedUtils';
  5. import AppContainer from '../../services/AppContainer';
  6. import UserPicture from '../User/UserPicture';
  7. const PersonalDropdown = (props) => {
  8. const { t, appContainer } = props;
  9. const user = appContainer.currentUser || {};
  10. const logoutHandler = () => {
  11. const { interceptorManager } = appContainer;
  12. const context = {
  13. user,
  14. currentPagePath: decodeURIComponent(window.location.pathname),
  15. };
  16. interceptorManager.process('logout', context);
  17. window.location.href = '/logout';
  18. };
  19. const preferDrawerModeSwitchModifiedHandler = (bool) => {
  20. appContainer.setDrawerModePreference(bool);
  21. };
  22. const followOsCheckboxModifiedHandler = (bool) => {
  23. // reset user preference
  24. if (bool) {
  25. appContainer.setColorSchemePreference(null);
  26. }
  27. // set preferDarkModeByMediaQuery as users preference
  28. else {
  29. appContainer.setColorSchemePreference(appContainer.state.preferDarkModeByMediaQuery);
  30. }
  31. };
  32. const userPreferenceSwitchModifiedHandler = (bool) => {
  33. appContainer.setColorSchemePreference(bool);
  34. };
  35. /*
  36. * render
  37. */
  38. const { preferDarkModeByMediaQuery, preferDarkModeByUser, preferDrawerModeByUser } = appContainer.state;
  39. const isUserPreferenceExists = preferDarkModeByUser != null;
  40. const isDarkMode = () => {
  41. if (isUserPreferenceExists) {
  42. return preferDarkModeByUser;
  43. }
  44. return preferDarkModeByMediaQuery;
  45. };
  46. return (
  47. <>
  48. {/* Button */}
  49. {/* remove .dropdown-toggle for hide caret */}
  50. {/* See https://stackoverflow.com/a/44577512/13183572 */}
  51. <a className="nav-link waves-effect waves-light" data-toggle="dropdown">
  52. <UserPicture user={user} noLink noTooltip /><span className="d-none d-sm-inline-block">&nbsp;{user.name}</span>
  53. </a>
  54. {/* Menu */}
  55. <div className="dropdown-menu dropdown-menu-right">
  56. <div className="px-4 pt-3 pb-2 text-center">
  57. <UserPicture user={user} size="lg" noLink noTooltip />
  58. <h5 className="mt-2">
  59. {user.name}
  60. </h5>
  61. <div className="my-2">
  62. <i className="icon-user icon-fw"></i>{user.username}<br />
  63. <i className="icon-envelope icon-fw"></i><span className="grw-email-sm">{user.email}</span>
  64. </div>
  65. <div className="btn-group btn-block mt-2" role="group">
  66. <a className="btn btn-sm btn-outline-secondary" href={`/user/${user.username}`}>
  67. <i className="icon-fw icon-home"></i>{ t('personal_dropdown.home') }
  68. </a>
  69. <a className="btn btn-sm btn-outline-secondary" href="/me">
  70. <i className="icon-fw icon-wrench"></i>{ t('personal_dropdown.settings') }
  71. </a>
  72. </div>
  73. </div>
  74. <div className="dropdown-divider"></div>
  75. <h6 className="dropdown-header">{t('personal_dropdown.sidebar_mode')}</h6>
  76. <form className="px-4">
  77. <div className="form-row justify-content-center">
  78. <div className="form-group col-auto mb-0 d-flex align-items-center">
  79. <i className="icon-drawer"></i>
  80. <div className="custom-control custom-switch custom-checkbox-secondary ml-2">
  81. <input
  82. id="swSidebarMode"
  83. className="custom-control-input"
  84. type="checkbox"
  85. checked={!preferDrawerModeByUser}
  86. onChange={e => preferDrawerModeSwitchModifiedHandler(!e.target.checked)}
  87. />
  88. <label className="custom-control-label" htmlFor="swSidebarMode"></label>
  89. </div>
  90. <i className="ti-layout-sidebar-left"></i>
  91. </div>
  92. </div>
  93. </form>
  94. <h6 className="dropdown-header">{t('personal_dropdown.sidebar_mode_editor')}</h6>
  95. <form className="px-4">
  96. <div className="form-row justify-content-center">
  97. <div className="form-group col-auto mb-0 d-flex align-items-center">
  98. <i className="icon-drawer"></i>
  99. <div className="custom-control custom-switch custom-checkbox-secondary ml-2">
  100. <input
  101. id="swSidebarModeOnEditor"
  102. className="custom-control-input"
  103. type="checkbox"
  104. // checked={}
  105. // onChange={}
  106. />
  107. <label className="custom-control-label" htmlFor="swSidebarModeOnEditor"></label>
  108. </div>
  109. <i className="ti-layout-sidebar-left"></i>
  110. </div>
  111. </div>
  112. </form>
  113. <div className="dropdown-divider"></div>
  114. <h6 className="dropdown-header">{t('personal_dropdown.color_mode')}</h6>
  115. <form className="px-4">
  116. <div className="form-row">
  117. <div className="form-group col-auto">
  118. <div className="custom-control custom-checkbox">
  119. <input
  120. id="cbFollowOs"
  121. className="custom-control-input"
  122. type="checkbox"
  123. checked={!isUserPreferenceExists}
  124. onChange={e => followOsCheckboxModifiedHandler(e.target.checked)}
  125. />
  126. <label className="custom-control-label text-nowrap" htmlFor="cbFollowOs">{t('personal_dropdown.use_os_settings')}</label>
  127. </div>
  128. </div>
  129. </div>
  130. <div className="form-row justify-content-center">
  131. <div className="form-group col-auto mb-0 d-flex align-items-center">
  132. <span className={isUserPreferenceExists ? '' : 'text-muted'}>Light</span>
  133. <div className="custom-control custom-switch custom-checkbox-secondary ml-2">
  134. <input
  135. id="swUserPreference"
  136. className="custom-control-input"
  137. type="checkbox"
  138. checked={isDarkMode()}
  139. disabled={!isUserPreferenceExists}
  140. onChange={e => userPreferenceSwitchModifiedHandler(e.target.checked)}
  141. />
  142. <label className="custom-control-label" htmlFor="swUserPreference"></label>
  143. </div>
  144. <span className={isUserPreferenceExists ? '' : 'text-muted'}>Dark</span>
  145. </div>
  146. </div>
  147. </form>
  148. <div className="dropdown-divider"></div>
  149. <button type="button" className="dropdown-item" onClick={logoutHandler}><i className="icon-fw icon-power"></i>{ t('Sign out') }</button>
  150. </div>
  151. </>
  152. );
  153. };
  154. /**
  155. * Wrapper component for using unstated
  156. */
  157. const PersonalDropdownWrapper = (props) => {
  158. return createSubscribedElement(PersonalDropdown, props, [AppContainer]);
  159. };
  160. PersonalDropdown.propTypes = {
  161. t: PropTypes.func.isRequired, // i18next
  162. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  163. };
  164. export default withTranslation()(PersonalDropdownWrapper);