fix: enhance localization messages and improve account settings UI
- Added new success and failure messages for password updates in English and Chinese localization files. - Updated `UpdateAvatarCard`, `UpdateNameCard`, and `UpdatePasswordCard` components to improve error handling and user feedback with toast notifications. - Enhanced styling for the user avatar fallback icon in `UpdateAvatarCard` for better visual consistency.
This commit is contained in:
parent
c258cc7d0d
commit
d51a22e030
@ -324,7 +324,9 @@
|
||||
"newMinLength": "Password must be at least 8 characters",
|
||||
"hint": "Please use at least 8 characters for password",
|
||||
"showPassword": "Show password",
|
||||
"hidePassword": "Hide password"
|
||||
"hidePassword": "Hide password",
|
||||
"success": "Password updated successfully",
|
||||
"fail": "Failed to update password"
|
||||
},
|
||||
"save": "Save",
|
||||
"saving": "Saving..."
|
||||
|
||||
@ -319,7 +319,9 @@
|
||||
"newMinLength": "密码必须至少包含 8 个字符",
|
||||
"hint": "请使用至少 8 个字符",
|
||||
"showPassword": "显示密码",
|
||||
"hidePassword": "隐藏密码"
|
||||
"hidePassword": "隐藏密码",
|
||||
"success": "密码更新成功",
|
||||
"fail": "更新密码失败"
|
||||
},
|
||||
"save": "保存",
|
||||
"saving": "保存中..."
|
||||
|
||||
@ -75,7 +75,7 @@ export function UpdateAvatarCard() {
|
||||
<Avatar className="h-16 w-16 border">
|
||||
<AvatarImage src={avatarUrl ?? ''} alt={user.name} />
|
||||
<AvatarFallback>
|
||||
<User2Icon className="h-8 w-8" />
|
||||
<User2Icon className="h-8 w-8 text-muted-foreground" />
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { FormError } from '@/components/shared/form-error';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Card,
|
||||
@ -30,12 +31,15 @@ import { z } from 'zod';
|
||||
*
|
||||
* NOTICE: we update username instead of name in user table
|
||||
*
|
||||
* TODO: by default, username is empty, how can we show the username in user-button?
|
||||
*
|
||||
* https://www.better-auth.com/docs/plugins/username
|
||||
*/
|
||||
export function UpdateNameCard() {
|
||||
const t = useTranslations('Dashboard.sidebar.settings.items.account');
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const { data: session, refetch, error } = authClient.useSession();
|
||||
const [error, setError] = useState<string | undefined>('');
|
||||
const { data: session, refetch } = authClient.useSession();
|
||||
|
||||
// Create a schema for name validation
|
||||
const formSchema = z.object({
|
||||
@ -81,6 +85,7 @@ export function UpdateNameCard() {
|
||||
onRequest: (ctx) => {
|
||||
// console.log('update name, request:', ctx.url);
|
||||
setIsSaving(true);
|
||||
setError('');
|
||||
},
|
||||
onResponse: (ctx) => {
|
||||
// console.log('update name, response:', ctx.response);
|
||||
@ -91,10 +96,12 @@ export function UpdateNameCard() {
|
||||
// console.log("update name, success:", ctx.data);
|
||||
toast.success(t('name.success'));
|
||||
refetch();
|
||||
form.reset();
|
||||
},
|
||||
onError: (ctx) => {
|
||||
// update name fail, display the error message
|
||||
console.error('update name, error:', ctx.error);
|
||||
setError(`${ctx.error.status}: ${ctx.error.message}`);
|
||||
toast.error(t('name.fail'));
|
||||
},
|
||||
});
|
||||
@ -126,6 +133,7 @@ export function UpdateNameCard() {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormError message={error} />
|
||||
</CardContent>
|
||||
<CardFooter className="px-6 py-4 flex justify-between items-center bg-muted">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { FormError } from '@/components/shared/form-error';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Card,
|
||||
@ -18,20 +19,29 @@ import {
|
||||
FormMessage
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { useLocaleRouter } from '@/i18n/navigation';
|
||||
import { authClient } from '@/lib/auth-client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { EyeIcon, EyeOffIcon } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* update user password
|
||||
*
|
||||
* https://www.better-auth.com/docs/authentication/email-password#update-password
|
||||
*/
|
||||
export function UpdatePasswordCard() {
|
||||
const router = useLocaleRouter();
|
||||
const t = useTranslations('Dashboard.sidebar.settings.items.account');
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [showCurrentPassword, setShowCurrentPassword] = useState(false);
|
||||
const [showNewPassword, setShowNewPassword] = useState(false);
|
||||
const { data: session, error } = authClient.useSession();
|
||||
const [error, setError] = useState<string | undefined>('');
|
||||
const { data: session } = authClient.useSession();
|
||||
|
||||
// Create a schema for password validation
|
||||
const formSchema = z.object({
|
||||
@ -58,17 +68,41 @@ export function UpdatePasswordCard() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: if user account provider is not credential, we should not allow user to update password
|
||||
|
||||
// Handle form submission
|
||||
const onSubmit = async (values: z.infer<typeof formSchema>) => {
|
||||
setIsSaving(true);
|
||||
|
||||
// Here you would typically send the data to your server
|
||||
// For now, we're just simulating the request
|
||||
setTimeout(() => {
|
||||
setIsSaving(false);
|
||||
form.reset();
|
||||
// In a real implementation, you would handle the response from your server
|
||||
}, 1000);
|
||||
const { data, error } = await authClient.changePassword(
|
||||
{
|
||||
currentPassword: values.currentPassword,
|
||||
newPassword: values.newPassword,
|
||||
revokeOtherSessions: true,
|
||||
},
|
||||
{
|
||||
onRequest: (ctx) => {
|
||||
// console.log('update password, request:', ctx.url);
|
||||
setIsSaving(true);
|
||||
setError('');
|
||||
},
|
||||
onResponse: (ctx) => {
|
||||
// console.log('update password, response:', ctx.response);
|
||||
setIsSaving(false);
|
||||
},
|
||||
onSuccess: (ctx) => {
|
||||
// update password success, user information stored in ctx.data
|
||||
// console.log("update password, success:", ctx.data);
|
||||
toast.success(t('password.success'));
|
||||
router.refresh();
|
||||
form.reset();
|
||||
},
|
||||
onError: (ctx) => {
|
||||
// update password fail, display the error message
|
||||
// { "message": "Invalid password", "code": "INVALID_PASSWORD", "status": 400, "statusText": "BAD_REQUEST" }
|
||||
console.error('update password, error:', ctx.error);
|
||||
setError(`${ctx.error.status}: ${ctx.error.message}`);
|
||||
toast.error(t('password.fail'));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@ -154,6 +188,7 @@ export function UpdatePasswordCard() {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormError message={error} />
|
||||
</CardContent>
|
||||
<CardFooter className="px-6 py-4 flex justify-between items-center bg-muted">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
|
||||
@ -8,6 +8,8 @@ import { drizzleAdapter } from 'better-auth/adapters/drizzle';
|
||||
import { admin, username } from 'better-auth/plugins';
|
||||
|
||||
/**
|
||||
* TODO: init username when user signup
|
||||
*
|
||||
* https://www.better-auth.com/docs/reference/options
|
||||
*/
|
||||
export const auth = betterAuth({
|
||||
@ -102,6 +104,12 @@ export const auth = betterAuth({
|
||||
username({
|
||||
minUsernameLength: 3,
|
||||
maxUsernameLength: 30,
|
||||
usernameValidator: (username) => {
|
||||
if (username === "admin" || username === "administrator") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}),
|
||||
// https://www.better-auth.com/docs/plugins/admin
|
||||
admin(),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user