refactor(profile): streamline profile and slot pages by integrating session user retrieval and updating booking logic with BookButton component
This commit is contained in:
parent
b5626a0a58
commit
6e91315647
@ -1,35 +1,55 @@
|
||||
import { getCustomer } from '@/actions/api/customers';
|
||||
import { getSessionUser } from '@/actions/session';
|
||||
import { Container } from '@/components/layout';
|
||||
import { PageHeader } from '@/components/navigation';
|
||||
import {
|
||||
BookContactButton,
|
||||
ContactDataCard,
|
||||
PersonCard,
|
||||
ProfileOrdersList,
|
||||
} from '@/components/profile';
|
||||
import { ContactDataCard, PersonCard, ProfileOrdersList } from '@/components/profile';
|
||||
import { BookButton } from '@/components/shared/book-button';
|
||||
import { isCustomerMaster } from '@repo/utils/customer';
|
||||
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query';
|
||||
|
||||
// Тип параметров страницы
|
||||
type Props = { params: Promise<{ telegramId: string }> };
|
||||
|
||||
export default async function ProfilePage(props: Readonly<Props>) {
|
||||
const parameters = await props.params;
|
||||
const telegramId = Number.parseInt(parameters.telegramId, 10);
|
||||
|
||||
const { telegramId } = await props.params;
|
||||
const contactTelegramId = Number(telegramId);
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
await queryClient.prefetchQuery({
|
||||
queryFn: () => getCustomer({ telegramId }),
|
||||
queryKey: ['customer', telegramId],
|
||||
// Получаем профиль контакта
|
||||
const { customer: profile } = await queryClient.fetchQuery({
|
||||
queryFn: () => getCustomer({ telegramId: contactTelegramId }),
|
||||
queryKey: ['customer', contactTelegramId],
|
||||
});
|
||||
|
||||
// Получаем текущего пользователя
|
||||
const sessionUser = await getSessionUser();
|
||||
const { customer: currentUser } = await queryClient.fetchQuery({
|
||||
queryFn: () => getCustomer({ telegramId: sessionUser.telegramId }),
|
||||
queryKey: ['customer', sessionUser.telegramId],
|
||||
});
|
||||
|
||||
// Проверка наличия данных
|
||||
if (!profile || !currentUser) return null;
|
||||
|
||||
// Определяем роли и id
|
||||
const isMaster = isCustomerMaster(currentUser);
|
||||
const masterId = isMaster ? currentUser.documentId : profile.documentId;
|
||||
const clientId = isMaster ? profile.documentId : currentUser.documentId;
|
||||
|
||||
return (
|
||||
<HydrationBoundary state={dehydrate(queryClient)}>
|
||||
<PageHeader title="Профиль контакта" />
|
||||
<Container className="px-0">
|
||||
<PersonCard telegramId={telegramId} />
|
||||
<ContactDataCard telegramId={telegramId} />
|
||||
<ProfileOrdersList telegramId={telegramId} />
|
||||
<BookContactButton telegramId={telegramId} />
|
||||
<PersonCard telegramId={contactTelegramId} />
|
||||
<ContactDataCard telegramId={contactTelegramId} />
|
||||
<ProfileOrdersList telegramId={contactTelegramId} />
|
||||
{masterId && clientId && (
|
||||
<BookButton
|
||||
clientId={clientId}
|
||||
label={isMaster ? 'Записать' : 'Записаться'}
|
||||
masterId={masterId}
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
</HydrationBoundary>
|
||||
);
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import { getCustomer } from '@/actions/api/customers';
|
||||
import { getSlot } from '@/actions/api/slots';
|
||||
import { getSessionUser } from '@/actions/session';
|
||||
import { Container } from '@/components/layout';
|
||||
import { PageHeader } from '@/components/navigation';
|
||||
import { SlotButtons, SlotDateTime, SlotOrdersList } from '@/components/schedule';
|
||||
import { type SlotPageParameters } from '@/components/schedule/types';
|
||||
import { BookButton } from '@/components/shared/book-button';
|
||||
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query';
|
||||
|
||||
type Props = { params: Promise<SlotPageParameters> };
|
||||
@ -18,12 +21,22 @@ export default async function SlotPage(props: Readonly<Props>) {
|
||||
queryKey: ['slot', documentId],
|
||||
});
|
||||
|
||||
// Получаем текущего пользователя
|
||||
const sessionUser = await getSessionUser();
|
||||
const { customer: currentUser } = await queryClient.fetchQuery({
|
||||
queryFn: () => getCustomer({ telegramId: sessionUser.telegramId }),
|
||||
queryKey: ['customer', sessionUser.telegramId],
|
||||
});
|
||||
|
||||
const masterId = currentUser?.documentId;
|
||||
|
||||
return (
|
||||
<HydrationBoundary state={dehydrate(queryClient)}>
|
||||
<PageHeader title="Слот" />
|
||||
<Container>
|
||||
<SlotDateTime {...parameters} />
|
||||
<SlotOrdersList {...parameters} />
|
||||
{masterId && <BookButton label="Создать запись" masterId={masterId} />}
|
||||
<div className="pb-24" />
|
||||
<SlotButtons {...parameters} />
|
||||
</Container>
|
||||
|
||||
@ -4,62 +4,6 @@ import { OrderCard } from '../shared/order-card';
|
||||
import { type ProfileProps } from './types';
|
||||
import { useCustomerQuery, useIsMaster } from '@/hooks/api/customers';
|
||||
import { useOrdersQuery } from '@/hooks/api/orders';
|
||||
import { usePushWithData } from '@/hooks/url';
|
||||
import { CalendarPlus } from 'lucide-react';
|
||||
|
||||
export function BookContactButton({ telegramId }: Readonly<ProfileProps>) {
|
||||
const { data: { customer } = {}, isLoading: isCustomerLoading } = useCustomerQuery();
|
||||
const isMaster = useIsMaster();
|
||||
|
||||
const { data: { customer: profile } = {}, isLoading: isProfileLoading } = useCustomerQuery({
|
||||
telegramId,
|
||||
});
|
||||
|
||||
const push = usePushWithData();
|
||||
|
||||
const handleBook = () => {
|
||||
if (!profile || !customer) return;
|
||||
|
||||
if (isMaster) {
|
||||
push('/orders/add', {
|
||||
client: {
|
||||
documentId: profile.documentId,
|
||||
},
|
||||
slot: {
|
||||
master: {
|
||||
documentId: customer.documentId,
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
push('/orders/add', {
|
||||
client: {
|
||||
documentId: customer.documentId,
|
||||
},
|
||||
slot: {
|
||||
master: {
|
||||
documentId: profile.documentId,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (isCustomerLoading || isProfileLoading || !profile || !customer) return null;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<button
|
||||
className="flex items-center justify-center gap-2 self-center rounded-xl bg-primary/5 px-6 py-2 font-semibold text-primary shadow-sm transition-colors hover:bg-primary/10"
|
||||
onClick={handleBook}
|
||||
type="button"
|
||||
>
|
||||
<CalendarPlus className="size-5 text-primary" />
|
||||
<span>{isMaster ? 'Записать' : 'Записаться'}</span>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ProfileOrdersList({ telegramId }: Readonly<ProfileProps>) {
|
||||
const { data: { customer } = {} } = useCustomerQuery();
|
||||
|
||||
46
apps/web/components/shared/book-button.tsx
Normal file
46
apps/web/components/shared/book-button.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
'use client';
|
||||
|
||||
import { usePushWithData } from '@/hooks/url';
|
||||
import { CalendarPlus } from 'lucide-react';
|
||||
|
||||
type BookButtonProps = {
|
||||
clientId?: string;
|
||||
disabled?: boolean;
|
||||
label: string;
|
||||
masterId: string;
|
||||
onBooked?: () => void;
|
||||
};
|
||||
|
||||
export function BookButton({
|
||||
clientId,
|
||||
disabled,
|
||||
label,
|
||||
masterId,
|
||||
onBooked,
|
||||
}: Readonly<BookButtonProps>) {
|
||||
const push = usePushWithData();
|
||||
|
||||
const handleBook = () => {
|
||||
push('/orders/add', {
|
||||
...(clientId && { client: { documentId: clientId } }),
|
||||
slot: { master: { documentId: masterId } },
|
||||
});
|
||||
onBooked?.();
|
||||
};
|
||||
|
||||
if (!masterId && !clientId) return null;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<button
|
||||
className="flex items-center justify-center gap-2 self-center rounded-xl bg-primary/5 px-6 py-2 font-semibold text-primary shadow-sm transition-colors hover:bg-primary/10"
|
||||
disabled={disabled}
|
||||
onClick={handleBook}
|
||||
type="button"
|
||||
>
|
||||
<CalendarPlus className="size-5 text-primary" />
|
||||
<span>{label}</span>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user