42ce5fa0fe
Replace hardcoded "Coffee Project / Projects" with a BreadcrumbsContext that each page registers into via useBreadcrumbs(). The Header reads breadcrumb items dynamically, renders links for items with href, and makes "Coffee Project" clickable to open the navigation drawer. Also removes the unused currentScreenName from Redux appState. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
102 lines
2.5 KiB
TypeScript
102 lines
2.5 KiB
TypeScript
"use client"
|
||
|
||
import type { JSX } from "react"
|
||
|
||
import moment from "moment"
|
||
import { FunctionComponent } from "react"
|
||
|
||
import {
|
||
AvatarUpload,
|
||
ChangePasswordForm,
|
||
EditProfileForm,
|
||
LogoutButton,
|
||
} from "@features/profile"
|
||
import api from "@shared/api"
|
||
import { useBreadcrumbs } from "@shared/context/BreadcrumbsContext"
|
||
import { StaticLoader } from "@shared/ui/Loader"
|
||
import { Card } from "@shared/ui"
|
||
|
||
import { IProfilePageProps } from "./ProfilePage.d"
|
||
import styles from "./ProfilePage.module.scss"
|
||
|
||
export const ProfilePage: FunctionComponent<
|
||
IProfilePageProps
|
||
> = (): JSX.Element => {
|
||
useBreadcrumbs([{ label: "Profile" }])
|
||
|
||
const {
|
||
data: user,
|
||
isLoading,
|
||
refetch,
|
||
} = api.useQuery("get", "/api/users/me/")
|
||
|
||
const { mutate: updateUser } = api.useMutation(
|
||
"patch",
|
||
"/api/users/{user_id}/",
|
||
)
|
||
|
||
const handleAvatarChange = (url: string) => {
|
||
if (!user) return
|
||
updateUser(
|
||
{
|
||
params: { path: { user_id: user.id } },
|
||
body: { avatar: url },
|
||
},
|
||
{ onSuccess: () => refetch() },
|
||
)
|
||
}
|
||
|
||
if (isLoading) return <StaticLoader fullscreen />
|
||
|
||
if (!user) {
|
||
return (
|
||
<div className={styles.root} data-testid="ProfilePage">
|
||
<p>Не удалось загрузить данные пользователя</p>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<div className={styles.root} data-testid="ProfilePage">
|
||
<div className={styles.container}>
|
||
<AvatarUpload
|
||
currentAvatarUrl={user.avatar}
|
||
onAvatarChange={handleAvatarChange}
|
||
/>
|
||
|
||
<Card className={styles.section}>
|
||
<EditProfileForm user={user} />
|
||
</Card>
|
||
|
||
<Card className={styles.section}>
|
||
<ChangePasswordForm />
|
||
</Card>
|
||
|
||
<Card className={styles.section}>
|
||
<h3 className={styles.sectionTitle}>Аккаунт</h3>
|
||
<div className={styles.infoList}>
|
||
<div className={styles.infoRow}>
|
||
<span className={styles.infoLabel}>Логин</span>
|
||
<span className={styles.infoValue}>{user.username}</span>
|
||
</div>
|
||
<div className={styles.infoRow}>
|
||
<span className={styles.infoLabel}>Дата регистрации</span>
|
||
<span className={styles.infoValue}>
|
||
{moment(user.date_joined).format("DD.MM.YYYY")}
|
||
</span>
|
||
</div>
|
||
<div className={styles.infoRow}>
|
||
<span className={styles.infoLabel}>Статус</span>
|
||
<span className={styles.infoValue}>
|
||
{user.is_active ? "Активен" : "Неактивен"}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
|
||
<LogoutButton />
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|