lint
This commit is contained in:
@@ -531,8 +531,8 @@
|
||||
"AiTranslate": "AI translate",
|
||||
"cambridgeDictionary": "Cambridge dictionary",
|
||||
"customizeShortcuts": "Customize shortcuts",
|
||||
"customizeShortcutsTip":"Click to change",
|
||||
"customizeShortcutsRecordingTip":"Recording new shortcut",
|
||||
"customizeShortcutsTip": "Click to change",
|
||||
"customizeShortcutsRecordingTip": "Recording new shortcut",
|
||||
"customizeShortcutsInvalidToast": "Your shortcut should only have one modifier (Ctrl, Alt, Shift, or Meta) and one key, like 'Ctrl+C'.",
|
||||
"customizeShortcutsConflictToast": "{{input}} conflicts with the existing {{otherHotkeyName}} shortcut.",
|
||||
"customizeShortcutsUpdated": "Changes saved",
|
||||
|
||||
@@ -530,9 +530,9 @@
|
||||
"AiTranslate": "智能翻译",
|
||||
"cambridgeDictionary": "剑桥词典",
|
||||
"customizeShortcuts": "自定义快捷键",
|
||||
"customizeShortcutsTip":"点击重新录制",
|
||||
"customizeShortcutsRecordingTip":"正在录制快捷键",
|
||||
"customizeShortcutsInvalidToast":"快捷键应最多含一个修饰键(Ctrl, Alt, Shift 或 Meta)和一个键,如 'Ctrl+C'",
|
||||
"customizeShortcutsTip": "点击重新录制",
|
||||
"customizeShortcutsRecordingTip": "正在录制快捷键",
|
||||
"customizeShortcutsInvalidToast": "快捷键应最多含一个修饰键(Ctrl, Alt, Shift 或 Meta)和一个键,如 'Ctrl+C'",
|
||||
"customizeShortcutsConflictToast": "{{input}} 和已有 {{otherHotkeyName}} 的键位冲突了",
|
||||
"customizeShortcutsUpdated": "设置成功",
|
||||
"following": "关注中",
|
||||
|
||||
@@ -17,7 +17,7 @@ export const EmailSettings = () => {
|
||||
const { user, login, webApi } = useContext(AppSettingsProviderContext);
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [email, setEmail] = useState(user.email);
|
||||
const [code, setCode] = useState('');
|
||||
const [code, setCode] = useState("");
|
||||
const [codeSent, setCodeSent] = useState<boolean>(false);
|
||||
const [countdown, setCountdown] = useState<number>(0);
|
||||
|
||||
@@ -38,7 +38,7 @@ export const EmailSettings = () => {
|
||||
|
||||
return () => {
|
||||
if (timeout) clearTimeout(timeout);
|
||||
}
|
||||
};
|
||||
}, [countdown]);
|
||||
|
||||
if (!user) return null;
|
||||
@@ -47,78 +47,89 @@ export const EmailSettings = () => {
|
||||
<div className="flex items-start justify-between py-4">
|
||||
<div className="">
|
||||
<div className="mb-2">{t("email")}</div>
|
||||
<div className="text-sm text-muted-foreground mb-2">{user.email || '-'}</div>
|
||||
<div className="text-sm text-muted-foreground mb-2">
|
||||
{user.email || "-"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog open={editing} onOpenChange={(value) => setEditing(value)}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="secondary" size="sm">
|
||||
{t('edit')}
|
||||
{t("edit")}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{t('editEmail')}
|
||||
</DialogTitle>
|
||||
<DialogTitle>{t("editEmail")}</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="w-full max-w-sm mx-auto py-6">
|
||||
<div className="grid gap-4 mb-6">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">{t('email')}</Label>
|
||||
<Label htmlFor="email">{t("email")}</Label>
|
||||
<Input
|
||||
id="email"
|
||||
required
|
||||
value={email}
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
placeholder="m@example.com" />
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="m@example.com"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="code">{t('verificationCode')}</Label>
|
||||
<Label htmlFor="code">{t("verificationCode")}</Label>
|
||||
<Input
|
||||
id="code"
|
||||
required
|
||||
value={code}
|
||||
onChange={e => setCode(e.target.value)}
|
||||
placeholder={t('verificationCode')}
|
||||
onChange={(e) => setCode(e.target.value)}
|
||||
placeholder={t("verificationCode")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Button variant="secondary" disabled={!email} onClick={() => {
|
||||
webApi
|
||||
.loginCode({ email })
|
||||
.then(() => {
|
||||
toast.success(t("codeSent"));
|
||||
setCodeSent(true);
|
||||
setCountdown(120);
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.message);
|
||||
});
|
||||
}}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={!email}
|
||||
onClick={() => {
|
||||
webApi
|
||||
.loginCode({ email })
|
||||
.then(() => {
|
||||
toast.success(t("codeSent"));
|
||||
setCodeSent(true);
|
||||
setCountdown(120);
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.message);
|
||||
});
|
||||
}}
|
||||
>
|
||||
{countdown > 0 && <span className="mr-2">{countdown}</span>}
|
||||
<span>{codeSent ? t("resend") : t("sendCode")}</span>
|
||||
</Button>
|
||||
|
||||
<Button disabled={!code} onClick={() => {
|
||||
webApi.updateProfile(user.id, {
|
||||
email,
|
||||
code
|
||||
})
|
||||
.then(() => {
|
||||
toast.success(t("emailUpdated"));
|
||||
refreshProfile();
|
||||
setEditing(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.message);
|
||||
});
|
||||
}}>{t("confirm")}</Button>
|
||||
<Button
|
||||
disabled={!code}
|
||||
onClick={() => {
|
||||
webApi
|
||||
.updateProfile(user.id, {
|
||||
email,
|
||||
code,
|
||||
})
|
||||
.then(() => {
|
||||
toast.success(t("emailUpdated"));
|
||||
refreshProfile();
|
||||
setEditing(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.message);
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("confirm")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
|
||||
@@ -27,7 +27,9 @@ import { useContext, useState } from "react";
|
||||
import { redirect } from "react-router-dom";
|
||||
|
||||
export const UserSettings = () => {
|
||||
const { user, login, logout, webApi } = useContext(AppSettingsProviderContext);
|
||||
const { user, login, logout, webApi } = useContext(
|
||||
AppSettingsProviderContext
|
||||
);
|
||||
const [name, setName] = useState(user.name);
|
||||
const [editing, setEditing] = useState(false);
|
||||
|
||||
@@ -66,12 +68,12 @@ export const UserSettings = () => {
|
||||
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('editUserName')}</DialogTitle>
|
||||
<DialogTitle>{t("editUserName")}</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="w-full max-w-sm mx-auto py-6">
|
||||
<div className="grid gap-2 mb-6">
|
||||
<Label htmlFor="name">{t('userName')}</Label>
|
||||
<Label htmlFor="name">{t("userName")}</Label>
|
||||
<Input
|
||||
id="name"
|
||||
value={name}
|
||||
@@ -79,17 +81,23 @@ export const UserSettings = () => {
|
||||
/>
|
||||
</div>
|
||||
<div className="">
|
||||
<Button className="w-full" onClick={() => {
|
||||
webApi
|
||||
.updateProfile(user.id, { name })
|
||||
.then(() => {
|
||||
toast.success('profileUpdated')
|
||||
setEditing(false);
|
||||
refreshProfile();
|
||||
}).catch(err => {
|
||||
toast.error(err.message);
|
||||
})
|
||||
}}>{t('save')}</Button>
|
||||
<Button
|
||||
className="w-full"
|
||||
onClick={() => {
|
||||
webApi
|
||||
.updateProfile(user.id, { name })
|
||||
.then(() => {
|
||||
toast.success("profileUpdated");
|
||||
setEditing(false);
|
||||
refreshProfile();
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.message);
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("save")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
@@ -97,7 +105,11 @@ export const UserSettings = () => {
|
||||
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="secondary" className="text-destructive" size="sm">
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="text-destructive"
|
||||
size="sm"
|
||||
>
|
||||
{t("logout")}
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
|
||||
Reference in New Issue
Block a user