PersonalDropdown.jsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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 followOsCheckboxModifiedHandler = (bool) => {
  20. // reset user preference
  21. if (bool) {
  22. appContainer.setColorSchemePreference(null);
  23. }
  24. // set preferDarkModeByMediaQuery as users preference
  25. else {
  26. appContainer.setColorSchemePreference(appContainer.state.preferDarkModeByMediaQuery);
  27. }
  28. };
  29. const userPreferenceSwitchModifiedHandler = (bool) => {
  30. appContainer.setColorSchemePreference(bool);
  31. };
  32. /*
  33. * render
  34. */
  35. const { preferDarkModeByMediaQuery, preferDarkModeByUser } = appContainer.state;
  36. const isUserPreferenceExists = preferDarkModeByUser != null;
  37. const isDarkMode = () => {
  38. if (isUserPreferenceExists) {
  39. return preferDarkModeByUser;
  40. }
  41. return preferDarkModeByMediaQuery;
  42. };
  43. return (
  44. <>
  45. {/* Button */}
  46. {/* remove .dropdown-toggle for hide caret */}
  47. {/* See https://stackoverflow.com/a/44577512/13183572 */}
  48. <a className="nav-link waves-effect waves-light" data-toggle="dropdown">
  49. <UserPicture user={user} noLink noTooltip /><span className="d-none d-sm-inline-block">&nbsp;{user.name}</span>
  50. </a>
  51. {/* Menu */}
  52. <div className="dropdown-menu dropdown-menu-right">
  53. <div className="px-4 pt-3 pb-2 text-center">
  54. <UserPicture user={user} size="lg" noLink noTooltip />
  55. <h5 className="mt-2">
  56. {user.name}
  57. </h5>
  58. <div className="my-2">
  59. <i className="icon-user icon-fw"></i>{user.username}<br />
  60. <i className="icon-envelope icon-fw"></i><span className="grw-email-sm">{user.email}</span>
  61. </div>
  62. <div className="btn-group btn-block mt-2" role="group">
  63. <a className="btn btn-sm btn-outline-secondary" href={`/user/${user.username}`}><i className="icon-fw icon-home"></i>{ t('Home') }</a>
  64. <a className="btn btn-sm btn-outline-secondary" href="/me"><i className="icon-fw icon-wrench"></i>{ t('Settings') }</a>
  65. </div>
  66. </div>
  67. <div className="dropdown-divider"></div>
  68. <h6 className="dropdown-header">Color Scheme</h6>
  69. <form className="px-4">
  70. <div className="form-row align-items-center">
  71. <div className="form-group col-auto">
  72. <div className="custom-control custom-checkbox">
  73. <input
  74. id="cbFollowOs"
  75. className="custom-control-input"
  76. type="checkbox"
  77. checked={!isUserPreferenceExists}
  78. onChange={e => followOsCheckboxModifiedHandler(e.target.checked)}
  79. />
  80. <label className="custom-control-label text-nowrap" htmlFor="cbFollowOs">Use OS Setting</label>
  81. </div>
  82. </div>
  83. </div>
  84. <div className="form-row align-items-center">
  85. <div className="form-group col-auto mb-0 d-flex">
  86. <span className={isUserPreferenceExists ? '' : 'text-muted'}>Light</span>
  87. <div className="custom-control custom-switch custom-checkbox-secondary ml-2">
  88. <input
  89. id="swUserPreference"
  90. className="custom-control-input"
  91. type="checkbox"
  92. checked={isDarkMode()}
  93. disabled={!isUserPreferenceExists}
  94. onChange={e => userPreferenceSwitchModifiedHandler(e.target.checked)}
  95. />
  96. <label className="custom-control-label" htmlFor="swUserPreference"></label>
  97. </div>
  98. <span className={isUserPreferenceExists ? '' : 'text-muted'}>Dark</span>
  99. </div>
  100. </div>
  101. </form>
  102. <div className="dropdown-divider"></div>
  103. <button type="button" className="dropdown-item" onClick={logoutHandler}><i className="icon-fw icon-power"></i>{ t('Sign out') }</button>
  104. </div>
  105. </>
  106. );
  107. };
  108. /**
  109. * Wrapper component for using unstated
  110. */
  111. const PersonalDropdownWrapper = (props) => {
  112. return createSubscribedElement(PersonalDropdown, props, [AppContainer]);
  113. };
  114. PersonalDropdown.propTypes = {
  115. t: PropTypes.func.isRequired, // i18next
  116. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  117. };
  118. export default withTranslation()(PersonalDropdownWrapper);