From be65f2330e9148b035d639d95b40fd23e9b53030 Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 22 May 2026 12:08:41 +0500 Subject: [PATCH] refactor(client): remove avatarType, add auth effects, simplify UserAvatar --- .../src/features/order-chat/ui/OrderChat.tsx | 2 - .../order-detail/ui/OrderDetailContent.tsx | 2 - .../product-review/ui/ProductReviewsList.tsx | 1 - .../features/user/user-menu/ui/UserMenu.tsx | 1 - .../admin-settings/ui/AdminSettingsPage.tsx | 29 +------------- .../pages/admin-users/ui/AdminUsersPage.tsx | 1 - .../src/pages/me/ui/sections/MessagesPage.tsx | 2 - .../src/pages/me/ui/sections/SettingsPage.tsx | 25 +----------- client/src/shared/model/auth.ts | 36 +++++++++++++++++- client/src/shared/ui/UserAvatar.tsx | 5 +-- .../widgets/reviews-block/ui/ReviewsBlock.tsx | 1 - server/prisma/prisma/dev.db | Bin 364544 -> 364544 bytes 12 files changed, 40 insertions(+), 65 deletions(-) diff --git a/client/src/features/order-chat/ui/OrderChat.tsx b/client/src/features/order-chat/ui/OrderChat.tsx index 27d1c8a..65eac11 100644 --- a/client/src/features/order-chat/ui/OrderChat.tsx +++ b/client/src/features/order-chat/ui/OrderChat.tsx @@ -56,7 +56,6 @@ export function OrderChat({ messages, isPending, onSend }: Props) { @@ -64,7 +63,6 @@ export function OrderChat({ messages, isPending, onSend }: Props) { diff --git a/client/src/features/order-detail/ui/OrderDetailContent.tsx b/client/src/features/order-detail/ui/OrderDetailContent.tsx index 721c478..36f5b0c 100644 --- a/client/src/features/order-detail/ui/OrderDetailContent.tsx +++ b/client/src/features/order-detail/ui/OrderDetailContent.tsx @@ -175,7 +175,6 @@ export function OrderDetailContent({ detail, orderId }: { detail: AdminOrderDeta @@ -184,7 +183,6 @@ export function OrderDetailContent({ detail, orderId }: { detail: AdminOrderDeta diff --git a/client/src/features/product-review/ui/ProductReviewsList.tsx b/client/src/features/product-review/ui/ProductReviewsList.tsx index ed03e3d..a7f05e4 100644 --- a/client/src/features/product-review/ui/ProductReviewsList.tsx +++ b/client/src/features/product-review/ui/ProductReviewsList.tsx @@ -22,7 +22,6 @@ function ReviewItem({ rv }: { rv: PublicProductReviewItem }) { diff --git a/client/src/features/user/user-menu/ui/UserMenu.tsx b/client/src/features/user/user-menu/ui/UserMenu.tsx index ab661c3..44b7828 100644 --- a/client/src/features/user/user-menu/ui/UserMenu.tsx +++ b/client/src/features/user/user-menu/ui/UserMenu.tsx @@ -46,7 +46,6 @@ export function UserMenu({ user, isAdmin = false, onNavigate, onLogout }: Props) diff --git a/client/src/pages/admin-settings/ui/AdminSettingsPage.tsx b/client/src/pages/admin-settings/ui/AdminSettingsPage.tsx index 41adb80..b4da721 100644 --- a/client/src/pages/admin-settings/ui/AdminSettingsPage.tsx +++ b/client/src/pages/admin-settings/ui/AdminSettingsPage.tsx @@ -56,9 +56,7 @@ export function AdminSettingsPage() { mode: 'onChange', }) - const hasOAuthAvatar = Boolean(user?.avatar && user.avatarType !== 'generated') - const useOAuth = user?.avatarType === 'oauth' - const useGenerated = user?.avatarType === 'generated' + const hasAvatar = Boolean(user?.avatar) const [selectedStyle, setSelectedStyle] = useState(user?.avatarStyle || DEFAULT_STYLE_ID) const [previewSrc, setPreviewSrc] = useState(null) @@ -70,14 +68,12 @@ export function AdminSettingsPage() { mutationFn: (params: { displayName: string | null avatar?: string | null - avatarType?: string | null avatarStyle?: string | null }) => apiClient.patch('admin/profile', params), onSuccess: (_data, variables) => { const p: UpdateProfileParams = { displayName: variables.displayName ?? null } if (variables.avatar !== undefined) { p.avatar = variables.avatar - p.avatarType = variables.avatarType ?? null p.avatarStyle = variables.avatarStyle ?? null } updateProfileFx(p) @@ -144,7 +140,6 @@ export function AdminSettingsPage() { - {hasUnsavedPreview ? 'Предпросмотр' : useOAuth ? 'Сохранён' : useGenerated ? 'Сохранён' : 'Авто'} + {hasUnsavedPreview ? 'Предпросмотр' : hasAvatar ? 'Сохранён' : 'Авто'} {hasUnsavedPreview && ( @@ -161,7 +156,6 @@ export function AdminSettingsPage() { )} - - {hasOAuthAvatar && !hasUnsavedPreview && ( - - )} diff --git a/client/src/pages/admin-users/ui/AdminUsersPage.tsx b/client/src/pages/admin-users/ui/AdminUsersPage.tsx index 6e5d85b..cabc230 100644 --- a/client/src/pages/admin-users/ui/AdminUsersPage.tsx +++ b/client/src/pages/admin-users/ui/AdminUsersPage.tsx @@ -195,7 +195,6 @@ export function AdminUsersPage() { diff --git a/client/src/pages/me/ui/sections/MessagesPage.tsx b/client/src/pages/me/ui/sections/MessagesPage.tsx index 220753d..f225f78 100644 --- a/client/src/pages/me/ui/sections/MessagesPage.tsx +++ b/client/src/pages/me/ui/sections/MessagesPage.tsx @@ -181,7 +181,6 @@ export function MessagesPage() { @@ -189,7 +188,6 @@ export function MessagesPage() { diff --git a/client/src/pages/me/ui/sections/SettingsPage.tsx b/client/src/pages/me/ui/sections/SettingsPage.tsx index 2b0e403..54cb98e 100644 --- a/client/src/pages/me/ui/sections/SettingsPage.tsx +++ b/client/src/pages/me/ui/sections/SettingsPage.tsx @@ -56,9 +56,7 @@ export function SettingsPage() { const emailErrorMsg = getApiErrorMessage(errorEmailReq) ?? getApiErrorMessage(errorEmailVerify) const profileErrorMsg = getApiErrorMessage(errorProfile) - const hasOAuthAvatar = Boolean(user?.avatar && user.avatarType !== 'generated') - const useOAuth = user?.avatarType === 'oauth' - const useGenerated = user?.avatarType === 'generated' + const hasAvatar = Boolean(user?.avatar) const [selectedStyle, setSelectedStyle] = useState(user?.avatarStyle || DEFAULT_STYLE_ID) const [previewSrc, setPreviewSrc] = useState(null) @@ -128,7 +126,6 @@ export function SettingsPage() { - {hasUnsavedPreview ? 'Предпросмотр' : useOAuth ? 'Сохранён' : useGenerated ? 'Сохранён' : 'Авто'} + {hasUnsavedPreview ? 'Предпросмотр' : hasAvatar ? 'Сохранён' : 'Авто'} {hasUnsavedPreview && ( @@ -145,7 +142,6 @@ export function SettingsPage() { )} - - {hasOAuthAvatar && !hasUnsavedPreview && ( - - )} diff --git a/client/src/shared/model/auth.ts b/client/src/shared/model/auth.ts index 6761582..0e4e96d 100644 --- a/client/src/shared/model/auth.ts +++ b/client/src/shared/model/auth.ts @@ -11,11 +11,15 @@ export type AuthUser = { lastName?: string | null gender?: string | null avatar?: string | null - avatarType?: string | null avatarStyle?: string | null isAdmin?: boolean } +export type AuthMethod = { + type: 'password' | 'vk' | 'yandex' + active: boolean +} + export const tokenSet = createEvent() export const logout = createEvent() @@ -72,7 +76,6 @@ export const verifyEmailChangeFx = createEffect(async (params: { newEmail: strin export type UpdateProfileParams = { displayName: string | null avatar?: string | null - avatarType?: string | null avatarStyle?: string | null } @@ -81,6 +84,35 @@ export const updateProfileFx = createEffect(async (params: UpdateProfileParams) return data.user }) +// ----- Auth effects ----- + +export const loginFx = createEffect(async (params: { email: string; password: string }) => { + const { data } = await apiClient.post<{ token: string; user: AuthUser }>('auth/login', params) + tokenSet(data.token) + return data.user +}) + +export const registerFx = createEffect( + async (params: { email: string; password: string; displayName?: string }) => { + const { data } = await apiClient.post<{ token: string; user: AuthUser }>('auth/register', params) + tokenSet(data.token) + return data.user + }, +) + +export const fetchAuthMethodsFx = createEffect(async () => { + const { data } = await apiClient.get<{ methods: AuthMethod[] }>('me/auth-methods') + return data.methods +}) + +export const setPasswordFx = createEffect(async (password: string) => { + await apiClient.post('me/password', { password }) +}) + +export const unlinkOAuthFx = createEffect(async (provider: 'vk' | 'yandex') => { + await apiClient.delete(`me/oauth/${provider}`) +}) + // ----- Error stores ----- export const $requestEmailChangeCodeError = createErrorStore(requestEmailChangeCodeFx).$error diff --git a/client/src/shared/ui/UserAvatar.tsx b/client/src/shared/ui/UserAvatar.tsx index bc3eecf..7dd1fbe 100644 --- a/client/src/shared/ui/UserAvatar.tsx +++ b/client/src/shared/ui/UserAvatar.tsx @@ -7,20 +7,19 @@ import { DEFAULT_STYLE_ID, getStyleById } from '@/shared/lib/avatar-styles' type UserAvatarProps = { userId: string avatarUrl?: string | null - avatarType?: string | null avatarStyle?: string | null size?: number sx?: SxProps } -export function UserAvatar({ userId, avatarUrl, avatarType, avatarStyle, size = 40, sx }: UserAvatarProps) { +export function UserAvatar({ userId, avatarUrl, avatarStyle, size = 40, sx }: UserAvatarProps) { const generatedSrc = useMemo(() => { const styleDef = getStyleById(avatarStyle || DEFAULT_STYLE_ID) const avatar = createAvatar(styleDef.style, { seed: userId }) return avatar.toDataUri() }, [userId, avatarStyle]) - const src = avatarType && avatarUrl ? avatarUrl : generatedSrc + const src = avatarUrl || generatedSrc return ( diff --git a/client/src/widgets/reviews-block/ui/ReviewsBlock.tsx b/client/src/widgets/reviews-block/ui/ReviewsBlock.tsx index 4e5cb76..2a2f622 100644 --- a/client/src/widgets/reviews-block/ui/ReviewsBlock.tsx +++ b/client/src/widgets/reviews-block/ui/ReviewsBlock.tsx @@ -104,7 +104,6 @@ export function ReviewsBlock() { diff --git a/server/prisma/prisma/dev.db b/server/prisma/prisma/dev.db index e8e8ce5498e9b3fb8a44fca779fbea1701b91a6d..037559b852858d29f809986b677af85cf89195b2 100644 GIT binary patch delta 1478 zcma)6&rj1(9BzuCT-&|MCf+1kD@0>!oy?XyNi=U3*#f`LO?J2x#afYDd8E1j@iQIs=}N_$l@(x zAKi(y*VhvlZktE94I;`6;B>>_Wt+06P&O)lUsBU$U@ktkg*rq+#|ga2%Rntw2_ zn|EPjZZ?-T28kwdNSmhFOCiNCC4lJ2HHFni42 vfjjh^*i}{pluAW~R^_o&1v_@^cyb6SRVaC=rL=Sa94F4xv6GtC_R>rY zT_{twwgU?SiAP(Pk%5hXIx&<5b%f5W;kT1WMKR(ZE|TxlcX!`+m&VR;V`q5t0_^+! zd^8H;yT>n|A>Z+%-J!@UJU)TMp{kOTg<@rjWLb`;NSdR9BooncE82BYk>RUXkQA2B zX;Z3T^e}9Q4wFtfPS zYn_$^I=jLG7Q$qy5>a9~nV{F;QH1Z+VCo<#gfv;B^PI?rGWyd)$U20vaY)@AA|$-2 zw&7?ZI+M;UB#N;@MUBng4kz?Gw-)Xz$)&r+B3oWuS_n=p7M9JqB{0V9+Uup|8!^%{en}jO`TS~pWpJMM`PE3>0A($mTW_w zFnU=#X9Z^S4giLw?}_SEv<1O@3Vx%0|_p5$R%GUMU+{wU)8na9syzEB@p7 zVJF6+Gdzzu&+F|D$>^XX(e5Z4uI3p*F?xx<-EsOG*l>O}tOnZRBks+d7Nej4T+jK} z_%c{R3ST$jvphEz2n6D`O-_ALH1nV_A_Y?5tMj@kH?P6@nou7}jU??M2&uAam}RDD vm_=fK4&YLMF-Bdl@xRw@>(Jsm(K