UserArea.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. Copyright (C) 2025 QuantumNous
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>.
  13. For commercial licensing, please contact support@quantumnous.com
  14. */
  15. import React from 'react';
  16. import { Link } from 'react-router-dom';
  17. import {
  18. Avatar,
  19. Button,
  20. Dropdown,
  21. Typography,
  22. } from '@douyinfe/semi-ui';
  23. import {
  24. IconChevronDown,
  25. IconExit,
  26. IconUserSetting,
  27. IconCreditCard,
  28. IconKey,
  29. } from '@douyinfe/semi-icons';
  30. import { stringToColor } from '../../../helpers/index.js';
  31. import SkeletonWrapper from './SkeletonWrapper.js';
  32. const UserArea = ({
  33. userState,
  34. isLoading,
  35. isMobile,
  36. isSelfUseMode,
  37. logout,
  38. navigate,
  39. t,
  40. }) => {
  41. if (isLoading) {
  42. return (
  43. <SkeletonWrapper
  44. loading={true}
  45. type="userArea"
  46. width={50}
  47. isMobile={isMobile}
  48. />
  49. );
  50. }
  51. if (userState.user) {
  52. return (
  53. <Dropdown
  54. position="bottomRight"
  55. render={
  56. <Dropdown.Menu className="!bg-semi-color-bg-overlay !border-semi-color-border !shadow-lg !rounded-lg dark:!bg-gray-700 dark:!border-gray-600">
  57. <Dropdown.Item
  58. onClick={() => {
  59. navigate('/console/personal');
  60. }}
  61. className="!px-3 !py-1.5 !text-sm !text-semi-color-text-0 hover:!bg-semi-color-fill-1 dark:!text-gray-200 dark:hover:!bg-blue-500 dark:hover:!text-white"
  62. >
  63. <div className="flex items-center gap-2">
  64. <IconUserSetting size="small" className="text-gray-500 dark:text-gray-400" />
  65. <span>{t('个人设置')}</span>
  66. </div>
  67. </Dropdown.Item>
  68. <Dropdown.Item
  69. onClick={() => {
  70. navigate('/console/token');
  71. }}
  72. className="!px-3 !py-1.5 !text-sm !text-semi-color-text-0 hover:!bg-semi-color-fill-1 dark:!text-gray-200 dark:hover:!bg-blue-500 dark:hover:!text-white"
  73. >
  74. <div className="flex items-center gap-2">
  75. <IconKey size="small" className="text-gray-500 dark:text-gray-400" />
  76. <span>{t('令牌管理')}</span>
  77. </div>
  78. </Dropdown.Item>
  79. <Dropdown.Item
  80. onClick={() => {
  81. navigate('/console/topup');
  82. }}
  83. className="!px-3 !py-1.5 !text-sm !text-semi-color-text-0 hover:!bg-semi-color-fill-1 dark:!text-gray-200 dark:hover:!bg-blue-500 dark:hover:!text-white"
  84. >
  85. <div className="flex items-center gap-2">
  86. <IconCreditCard size="small" className="text-gray-500 dark:text-gray-400" />
  87. <span>{t('钱包管理')}</span>
  88. </div>
  89. </Dropdown.Item>
  90. <Dropdown.Item onClick={logout} className="!px-3 !py-1.5 !text-sm !text-semi-color-text-0 hover:!bg-semi-color-fill-1 dark:!text-gray-200 dark:hover:!bg-red-500 dark:hover:!text-white">
  91. <div className="flex items-center gap-2">
  92. <IconExit size="small" className="text-gray-500 dark:text-gray-400" />
  93. <span>{t('退出')}</span>
  94. </div>
  95. </Dropdown.Item>
  96. </Dropdown.Menu>
  97. }
  98. >
  99. <Button
  100. theme="borderless"
  101. type="tertiary"
  102. className="flex items-center gap-1.5 !p-1 !rounded-full hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-700 !bg-semi-color-fill-0 dark:!bg-semi-color-fill-1 dark:hover:!bg-semi-color-fill-2"
  103. >
  104. <Avatar
  105. size="extra-small"
  106. color={stringToColor(userState.user.username)}
  107. className="mr-1"
  108. >
  109. {userState.user.username[0].toUpperCase()}
  110. </Avatar>
  111. <span className="hidden md:inline">
  112. <Typography.Text className="!text-xs !font-medium !text-semi-color-text-1 dark:!text-gray-300 mr-1">
  113. {userState.user.username}
  114. </Typography.Text>
  115. </span>
  116. <IconChevronDown className="text-xs text-semi-color-text-2 dark:text-gray-400" />
  117. </Button>
  118. </Dropdown>
  119. );
  120. } else {
  121. const showRegisterButton = !isSelfUseMode;
  122. const commonSizingAndLayoutClass = "flex items-center justify-center !py-[10px] !px-1.5";
  123. const loginButtonSpecificStyling = "!bg-semi-color-fill-0 dark:!bg-semi-color-fill-1 hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-700 transition-colors";
  124. let loginButtonClasses = `${commonSizingAndLayoutClass} ${loginButtonSpecificStyling}`;
  125. let registerButtonClasses = `${commonSizingAndLayoutClass}`;
  126. const loginButtonTextSpanClass = "!text-xs !text-semi-color-text-1 dark:!text-gray-300 !p-1.5";
  127. const registerButtonTextSpanClass = "!text-xs !text-white !p-1.5";
  128. if (showRegisterButton) {
  129. if (isMobile) {
  130. loginButtonClasses += " !rounded-full";
  131. } else {
  132. loginButtonClasses += " !rounded-l-full !rounded-r-none";
  133. }
  134. registerButtonClasses += " !rounded-r-full !rounded-l-none";
  135. } else {
  136. loginButtonClasses += " !rounded-full";
  137. }
  138. return (
  139. <div className="flex items-center">
  140. <Link to="/login" className="flex">
  141. <Button
  142. theme="borderless"
  143. type="tertiary"
  144. className={loginButtonClasses}
  145. >
  146. <span className={loginButtonTextSpanClass}>
  147. {t('登录')}
  148. </span>
  149. </Button>
  150. </Link>
  151. {showRegisterButton && (
  152. <div className="hidden md:block">
  153. <Link to="/register" className="flex -ml-px">
  154. <Button
  155. theme="solid"
  156. type="primary"
  157. className={registerButtonClasses}
  158. >
  159. <span className={registerButtonTextSpanClass}>
  160. {t('注册')}
  161. </span>
  162. </Button>
  163. </Link>
  164. </div>
  165. )}
  166. </div>
  167. );
  168. }
  169. };
  170. export default UserArea;