From 2226efed8c8604a938d060d62565b611722e837c Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 20 Jul 2023 23:01:58 +0800 Subject: ... --- FrontEnd/src/common.ts | 1 + FrontEnd/src/locales/en/translation.json | 3 +- FrontEnd/src/locales/zh/translation.json | 2 +- FrontEnd/src/pages/setting/index.tsx | 279 +++++++++++------------- FrontEnd/src/views/common/Card.tsx | 2 +- FrontEnd/src/views/common/button/Button.tsx | 4 +- FrontEnd/src/views/common/button/FlatButton.tsx | 4 +- FrontEnd/src/views/common/common.ts | 2 +- 8 files changed, 133 insertions(+), 164 deletions(-) diff --git a/FrontEnd/src/common.ts b/FrontEnd/src/common.ts index 965f9933..7c053140 100644 --- a/FrontEnd/src/common.ts +++ b/FrontEnd/src/common.ts @@ -6,5 +6,6 @@ export class UiLogicError extends Error {} export const highlightTimelineUsername = "crupest"; export type { I18nText } from "./i18n"; +export type { I18nText as Text } from "./i18n"; export { c, convertI18nText } from "./i18n"; export { default as useC } from "./utilities/hooks/use-c"; diff --git a/FrontEnd/src/locales/en/translation.json b/FrontEnd/src/locales/en/translation.json index 95c722c9..a73472d2 100644 --- a/FrontEnd/src/locales/en/translation.json +++ b/FrontEnd/src/locales/en/translation.json @@ -176,7 +176,7 @@ "noAccount": "If you don't have an account and know a register code, then click <1>here to register." }, "settings": { - "subheaders": { + "subheader": { "account": "Account", "customization": "Customization" }, @@ -186,7 +186,6 @@ "logout": "Log out this account", "changeAvatar": "Change avatar", "changeNickname": "Change nickname", - "changeBookmarkVisibility": "Change bookmark visibility", "myRegisterCode": "My register code:", "myRegisterCodeDesc": "Click to create a new register code.", "renewRegisterCode": "Renew Register Code", diff --git a/FrontEnd/src/locales/zh/translation.json b/FrontEnd/src/locales/zh/translation.json index b7212128..8a2f628f 100644 --- a/FrontEnd/src/locales/zh/translation.json +++ b/FrontEnd/src/locales/zh/translation.json @@ -176,7 +176,7 @@ "noAccount": "如果你没有账号但有一个注册码,请点击<1>这里注册账号。" }, "settings": { - "subheaders": { + "subheader": { "account": "账户", "customization": "个性化" }, diff --git a/FrontEnd/src/pages/setting/index.tsx b/FrontEnd/src/pages/setting/index.tsx index 00503dcf..4e28585e 100644 --- a/FrontEnd/src/pages/setting/index.tsx +++ b/FrontEnd/src/pages/setting/index.tsx @@ -1,16 +1,21 @@ -import { useState, ReactNode } from "react"; -import { useNavigate } from "react-router-dom"; +import { + useState, + useEffect, + ReactNode, + ComponentPropsWithoutRef, +} from "react"; import { useTranslation } from "react-i18next"; +import { useNavigate } from "react-router-dom"; import classNames from "classnames"; -import { useC, I18nText } from "@/common"; +import { useC, Text } from "@/common"; import { useUser, userService } from "@/services/user"; import { getHttpUserClient } from "@/http/user"; import { TimelineVisibility } from "@/http/timeline"; -import ConfirmDialog from "../common/dialog/ConfirmDialog"; -import Card from "../common/Card"; -import Spinner from "../common/Spinner"; +import ConfirmDialog from "@/views/common/dialog/ConfirmDialog"; +import Card from "@/views/common/Card"; +import Spinner from "@/views/common/Spinner"; import ChangePasswordDialog from "./ChangePasswordDialog"; import ChangeAvatarDialog from "./ChangeAvatarDialog"; import ChangeNicknameDialog from "./ChangeNicknameDialog"; @@ -18,99 +23,94 @@ import ChangeNicknameDialog from "./ChangeNicknameDialog"; import "./index.css"; import { pushAlert } from "@/services/alert"; -interface SettingSectionProps { - title: I18nText; +interface SettingSectionProps + extends Omit, "title"> { + title: Text; children: ReactNode; } -function SettingSection({ title, children }: SettingSectionProps) { +function SettingSection({ + title, + className, + children, + ...otherProps +}: SettingSectionProps) { const c = useC(); return ( - -

{c(title)}

+ +

{c(title)}

{children}
); } -interface SettingItemContainerWithoutChildrenProps { - title: I18nText; - subtext?: I18nText; - first?: boolean; - danger?: boolean; - style?: React.CSSProperties; - className?: string; - onClick?: () => void; -} - interface SettingItemContainerProps - extends SettingItemContainerWithoutChildrenProps { - children?: React.ReactNode; + extends Omit, "title"> { + title: Text; + description?: Text; + danger?: boolean; + extraClassName?: string; } function SettingItemContainer({ title, - subtext, - first, + description, danger, - children, - style, + extraClassName, className, - onClick, -}: SettingItemContainerProps): JSX.Element { - const { t } = useTranslation(); + children, + ...otherProps +}: SettingItemContainerProps) { + const c = useC(); return (
-
-
- {convertI18nText(title, t)} -
- - {convertI18nText(subtext, t)} - +
+
{c(title)}
+ {c(description)}
-
{children}
+
{children}
); } -type ButtonSettingItemProps = SettingItemContainerWithoutChildrenProps; +type ButtonSettingItemProps = Omit; -const ButtonSettingItem: React.FC = ({ ...props }) => { - return ; -}; +function ButtonSettingItem(props: ButtonSettingItemProps) { + return ( + + ); +} interface SelectSettingItemProps - extends SettingItemContainerWithoutChildrenProps { + extends Omit { options: { value: string; - label: I18nText; + label: Text; }[]; - value?: string; + value?: string | null; onSelect: (value: string) => void; } -const SelectSettingsItem: React.FC = ({ +function SelectSettingsItem({ options, value, onSelect, - ...props -}) => { - const { t } = useTranslation(); + ...extraProps +}: SelectSettingItemProps) { + const c = useC(); return ( - + {value == null ? ( ) : ( @@ -122,53 +122,30 @@ const SelectSettingsItem: React.FC = ({ > {options.map(({ value, label }) => ( ))} )} ); -}; +} -const SettingsPage: React.FC = () => { - const { i18n } = useTranslation(); +function RegisterCodeSettingItem({ + openRenewDialog, +}: { + openRenewDialog: () => void; +}) { const user = useUser(); - const navigate = useNavigate(); - - const [dialog, setDialog] = useState< - | null - | "changepassword" - | "changeavatar" - | "changenickname" - | "logout" - | "renewregistercode" - >(null); - const [registerCode, setRegisterCode] = useState( - undefined, - ); - - const [bookmarkVisibility, setBookmarkVisibility] = - useState(); - - React.useEffect(() => { - if (user != null) { - void getHttpUserClient() - .getBookmarkVisibility(user.username) - .then(({ visibility }) => { - setBookmarkVisibility(visibility); - }); - } else { - setBookmarkVisibility(undefined); - } - }, [user]); + // undefined: loading + const [registerCode, setRegisterCode] = useState(); - React.useEffect(() => { + useEffect(() => { setRegisterCode(undefined); }, [user]); - React.useEffect(() => { + useEffect(() => { if (user != null && registerCode === undefined) { void getHttpUserClient() .getRegisterCode(user.username) @@ -178,87 +155,81 @@ const SettingsPage: React.FC = () => { } }, [user, registerCode]); + return ( + + {registerCode === undefined ? ( + + ) : registerCode === null ? ( + Noop + ) : ( + { + void navigator.clipboard.writeText(registerCode).then(() => { + pushAlert({ + type: "success", + message: "settings.myRegisterCodeCopied", + }); + }); + event.stopPropagation(); + }} + > + {registerCode} + + )} + + ); +} + +export default function SettingsPage() { + const c = useC(); + const { i18n } = useTranslation(); + const user = useUser(); + const navigate = useNavigate(); + + type DialogName = + | "change-password" + | "change-avatar" + | "change-nickname" + | "logout" + | "renew-register-code"; + + const [dialog, setDialog] = useState(null); + + function dialogOpener(name: DialogName): () => void { + return () => setDialog(name); + } + const language = i18n.language.slice(0, 2); return ( <>
{user ? ( - - setDialog("renewregistercode")} - > - {registerCode === undefined ? ( - - ) : registerCode === null ? ( - Noop - ) : ( - { - void navigator.clipboard - .writeText(registerCode) - .then(() => { - pushAlert({ - type: "success", - message: "settings.myRegisterCodeCopied", - }); - }); - event.stopPropagation(); - }} - > - {registerCode} - - )} - + + setDialog("changeavatar")} - first + onClick={dialogOpener("change-avatar")} /> setDialog("changenickname")} - /> - { - void getHttpUserClient() - .putBookmarkVisibility(user.username, { - visibility: value as TimelineVisibility, - }) - .then(() => { - setBookmarkVisibility(value as TimelineVisibility); - }); - }} + onClick={dialogOpener("change-nickname")} /> setDialog("changepassword")} + onClick={dialogOpener("change-password")} danger /> { - setDialog("logout"); - }} + onClick={dialogOpener("logout")} danger /> @@ -330,6 +301,4 @@ const SettingsPage: React.FC = () => { /> ); -}; - -export default SettingsPage; +} diff --git a/FrontEnd/src/views/common/Card.tsx b/FrontEnd/src/views/common/Card.tsx index 50632006..5ff89b61 100644 --- a/FrontEnd/src/views/common/Card.tsx +++ b/FrontEnd/src/views/common/Card.tsx @@ -4,7 +4,7 @@ import classNames from "classnames"; import "./Card.css"; interface CardProps extends ComponentPropsWithoutRef<"div"> { - containerRef: Ref; + containerRef?: Ref | null; } export default function Card({ diff --git a/FrontEnd/src/views/common/button/Button.tsx b/FrontEnd/src/views/common/button/Button.tsx index e1015f71..0f1bbf2b 100644 --- a/FrontEnd/src/views/common/button/Button.tsx +++ b/FrontEnd/src/views/common/button/Button.tsx @@ -1,13 +1,13 @@ import { ComponentPropsWithoutRef, Ref } from "react"; import classNames from "classnames"; -import { I18nText, useC, ThemeColor } from "../common"; +import { Text, useC, ThemeColor } from "../common"; import "./Button.css"; interface ButtonProps extends ComponentPropsWithoutRef<"button"> { color?: ThemeColor; - text?: I18nText; + text?: Text; outline?: boolean; buttonRef?: Ref | null; } diff --git a/FrontEnd/src/views/common/button/FlatButton.tsx b/FrontEnd/src/views/common/button/FlatButton.tsx index 7b268b6d..ed01f613 100644 --- a/FrontEnd/src/views/common/button/FlatButton.tsx +++ b/FrontEnd/src/views/common/button/FlatButton.tsx @@ -1,13 +1,13 @@ import { ComponentPropsWithoutRef, Ref } from "react"; import classNames from "classnames"; -import { I18nText, useC, ThemeColor } from "../common"; +import { Text, useC, ThemeColor } from "../common"; import "./FlatButton.css"; interface FlatButtonProps extends ComponentPropsWithoutRef<"button"> { color?: ThemeColor; - text?: I18nText; + text?: Text; buttonRef?: Ref | null; } diff --git a/FrontEnd/src/views/common/common.ts b/FrontEnd/src/views/common/common.ts index d3db9f93..4ad41edc 100644 --- a/FrontEnd/src/views/common/common.ts +++ b/FrontEnd/src/views/common/common.ts @@ -1,4 +1,4 @@ -export type { I18nText } from "@/common"; +export type { Text, I18nText } from "@/common"; export { c, convertI18nText, useC } from "@/common"; export const themeColors = [ -- cgit v1.2.3