refactor(profile): split view/container and update nav state

Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
2026-01-31 18:30:34 +08:00
committed by Asai Neko
parent ff10fe10ce
commit 7ad479bc87
20 changed files with 173 additions and 73 deletions

View File

@@ -0,0 +1,15 @@
import type { ServiceUserUserInfoData } from '@/client';
import { useUpdateUser } from '@/hooks/data/useUpdateUser';
import { EditProfileDialogView } from './edit-profile.dialog.view';
export function EditProfileDialogContainer({ data }: { data: ServiceUserUserInfoData }) {
const { mutateAsync } = useUpdateUser();
return (
<EditProfileDialogView
user={data}
updateProfile={async (data) => {
await mutateAsync({ body: data });
}}
/>
);
}

View File

@@ -1,6 +1,9 @@
import type { ServiceUserUserInfoData } from '@/client';
import { useForm } from '@tanstack/react-form';
import { useState } from 'react';
import {
useEffect,
useState,
} from 'react';
import { toast } from 'sonner';
import z from 'zod';
import { Button } from '@/components/ui/button';
@@ -21,7 +24,6 @@ import {
import {
Input,
} from '@/components/ui/input';
import { useUpdateUser } from '@/hooks/data/useUpdateUser';
import { Switch } from '../ui/switch';
const formSchema = z.object({
@@ -31,9 +33,7 @@ const formSchema = z.object({
avatar: z.url().or(z.literal('')),
allow_public: z.boolean(),
});
export function EditProfileDialog({ user }: { user: ServiceUserUserInfoData }) {
const { mutateAsync } = useUpdateUser();
export function EditProfileDialogView({ user, updateProfile }: { user: ServiceUserUserInfoData; updateProfile: (data: ServiceUserUserInfoData) => Promise<void> }) {
const form = useForm({
defaultValues: {
avatar: user.avatar,
@@ -49,7 +49,7 @@ export function EditProfileDialog({ user }: { user: ServiceUserUserInfoData }) {
value,
}) => {
try {
await mutateAsync({ body: value });
await updateProfile(value);
toast.success('个人资料更新成功');
}
catch (error) {
@@ -61,11 +61,14 @@ export function EditProfileDialog({ user }: { user: ServiceUserUserInfoData }) {
const [open, setOpen] = useState(false);
if (!open) {
setTimeout(() => {
form.reset();
}, 200);
}
useEffect(() => {
if (!open) {
const id = setTimeout(() => {
form.reset();
}, 200);
return () => clearTimeout(id);
}
}, [open, form]);
return (
<Dialog open={open} onOpenChange={setOpen}>

View File

@@ -0,0 +1,17 @@
import { useUpdateUser } from '@/hooks/data/useUpdateUser';
import { useOtherUserInfo } from '@/hooks/data/useUserInfo';
import { utf8ToBase64 } from '@/lib/utils';
import { ProfileView } from './profile.view';
export function ProfileContainer({ userId }: { userId: string }) {
const { data } = useOtherUserInfo(userId);
const { mutateAsync } = useUpdateUser();
return (
<ProfileView
user={data.data!}
onSaveBio={async (bio) => {
await mutateAsync({ body: { bio: utf8ToBase64(bio) } });
}}
/>
);
}

View File

@@ -11,15 +11,13 @@ import { useMemo, useState } from 'react';
import Markdown from 'react-markdown';
import { toast } from 'sonner';
import { Avatar, AvatarImage } from '@/components/ui/avatar';
import { useUpdateUser } from '@/hooks/data/useUpdateUser';
import { base64ToUtf8, utf8ToBase64 } from '@/lib/utils';
import { base64ToUtf8 } from '@/lib/utils';
import { Button } from '../ui/button';
import { EditProfileDialog } from './edit-profile-dialog';
import { EditProfileDialogContainer } from './edit-profile.dialog.container';
export function Profile({ user }: { user: ServiceUserUserInfoData }) {
export function ProfileView({ user, onSaveBio }: { user: ServiceUserUserInfoData; onSaveBio: (bio: string) => Promise<void> }) {
const [bio, setBio] = useState<string | undefined>(() => base64ToUtf8(user.bio ?? ''));
const [enableBioEdit, setEnableBioEdit] = useState(false);
const { mutateAsync } = useUpdateUser();
const IdentIcon = useMemo(() => {
const avatar = createAvatar(identicon, {
@@ -48,7 +46,7 @@ export function Profile({ user }: { user: ServiceUserUserInfoData }) {
{user.email}
</div>
</div>
<EditProfileDialog user={user} />
<EditProfileDialogContainer data={user} />
</div>
</div>
<section className="relative rounded-md border border-muted w-full flex-1 lg:flex-auto min-h-72 lg:h-full mt-4 lg:mt-0 prose dark:prose-invert max-w-[1012px] self-center">
@@ -72,7 +70,7 @@ export function Profile({ user }: { user: ServiceUserUserInfoData }) {
else {
if (!isNil(bio)) {
try {
await mutateAsync({ body: { bio: utf8ToBase64(bio) } });
await onSaveBio(bio);
setEnableBioEdit(false);
}
catch (error) {