diff --git a/apps/web/actions/slots.ts b/apps/web/actions/slots.ts index 2875c68..8934620 100644 --- a/apps/web/actions/slots.ts +++ b/apps/web/actions/slots.ts @@ -16,10 +16,10 @@ export async function addSlot(input: AddSlotInput) { return api.createSlot({ ...input, - date: formatDate(input.date), + date: formatDate(input.date).db(), master: customer?.documentId, - time_end: formatTime(input.time_end), - time_start: formatTime(input.time_start), + time_end: formatTime(input.time_end).db(), + time_start: formatTime(input.time_start).db(), }); } diff --git a/apps/web/app/(main)/profile/schedule/slot/[documentId]/page.tsx b/apps/web/app/(main)/profile/schedule/slot/[documentId]/page.tsx new file mode 100644 index 0000000..34be423 --- /dev/null +++ b/apps/web/app/(main)/profile/schedule/slot/[documentId]/page.tsx @@ -0,0 +1,25 @@ +import { getSlot } from '@/actions/slots'; +import { PageHeader } from '@/components/navigation'; +import { TimeCard } from '@/components/schedule'; +import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'; + +type Props = { params: Promise<{ documentId: string }> }; + +export default async function ProfilePage(props: Readonly) { + const parameters = await props.params; + const { documentId } = parameters; + + const queryClient = new QueryClient(); + + await queryClient.prefetchQuery({ + queryFn: () => getSlot({ documentId }), + queryKey: ['schedule', 'slots', 'get', documentId], + }); + + return ( + + + + + ); +} diff --git a/apps/web/components/schedule/index.ts b/apps/web/components/schedule/index.ts index 01500b8..45948a4 100644 --- a/apps/web/components/schedule/index.ts +++ b/apps/web/components/schedule/index.ts @@ -1,2 +1,3 @@ export * from './calendar'; +export * from './time-card'; export * from './time-slots'; diff --git a/apps/web/components/schedule/time-card.tsx b/apps/web/components/schedule/time-card.tsx new file mode 100644 index 0000000..326699e --- /dev/null +++ b/apps/web/components/schedule/time-card.tsx @@ -0,0 +1,22 @@ +'use client'; +import { type SlotProps } from './types'; +import { useSlotQuery } from '@/hooks/slots'; +import { formatDate, formatTime } from '@/utils/date'; + +export function TimeCard({ documentId }: Readonly) { + const { data } = useSlotQuery({ documentId }); + + if (!data?.slot) return null; + + return ( +
+ {formatDate(data?.slot?.date).user()} + + {formatTime(data?.slot?.time_start).user()} + + + {formatTime(data?.slot?.time_end).user()} + +
+ ); +} diff --git a/apps/web/components/schedule/time-slots/components/slot-card.tsx b/apps/web/components/schedule/time-slots/components/slot-card.tsx index d84976b..a3cd6e6 100644 --- a/apps/web/components/schedule/time-slots/components/slot-card.tsx +++ b/apps/web/components/schedule/time-slots/components/slot-card.tsx @@ -1,6 +1,6 @@ 'use client'; +import { type SlotProps } from '../../types'; import { ContextProvider } from '../context'; -import { type SlotProps } from '../types'; import { ReadonlyTimeRange } from './time-pair'; import { useSlotQuery } from '@/hooks/slots'; import { withContext } from '@/utils/context'; diff --git a/apps/web/components/schedule/time-slots/components/time-pair.tsx b/apps/web/components/schedule/time-slots/components/time-pair.tsx index 3cc822d..8ebb8b6 100644 --- a/apps/web/components/schedule/time-slots/components/time-pair.tsx +++ b/apps/web/components/schedule/time-slots/components/time-pair.tsx @@ -1,9 +1,10 @@ 'use client'; +import { type Slot } from '../../types'; import { Context, type ContextType } from '../context'; -import { type Slot } from '../types'; import { useSlotAdd } from '@/hooks/slots'; -import { parseTime } from '@/utils/date'; +import { formatTime } from '@/utils/date'; import { Input } from '@repo/ui/components/ui/input'; +import { cn } from '@repo/ui/lib/utils'; import { use } from 'react'; type TimePairProps = Pick & { @@ -25,12 +26,16 @@ export function AddTimePair() { ); } -export function ReadonlyTimeRange({ time_end, time_start }: Readonly) { +export function ReadonlyTimeRange({ + className, + time_end, + time_start, +}: Readonly & { readonly className?: string }) { return ( -
- {parseTime(time_start)} +
+ {formatTime(time_start).user()} {' - '} - {parseTime(time_end)} + {formatTime(time_end).user()}
); } diff --git a/apps/web/components/schedule/time-slots/types.tsx b/apps/web/components/schedule/types.tsx similarity index 100% rename from apps/web/components/schedule/time-slots/types.tsx rename to apps/web/components/schedule/types.tsx diff --git a/apps/web/hooks/slots/index.ts b/apps/web/hooks/slots/index.ts index 075fa1e..ee56049 100644 --- a/apps/web/hooks/slots/index.ts +++ b/apps/web/hooks/slots/index.ts @@ -18,7 +18,7 @@ export const useSlots = () => { getSlots({ filters: { date: { - eq: formatDate(selectedDate), + eq: formatDate(selectedDate).db(), }, }, }), diff --git a/apps/web/utils/date/index.ts b/apps/web/utils/date/index.ts index 3f51b73..afc96dc 100644 --- a/apps/web/utils/date/index.ts +++ b/apps/web/utils/date/index.ts @@ -1,4 +1,6 @@ +/* eslint-disable import/no-unassigned-import */ import dayjs from 'dayjs'; +import 'dayjs/locale/ru'; export function combineDateTime(date: Date, time: string) { const [hours = '00', minutes = '00'] = time.split(':'); @@ -12,16 +14,22 @@ export function combineDateTime(date: Date, time: string) { ); } -export function formatDate(date: Date) { - return dayjs(date).format('YYYY-MM-DD'); +export function formatDate(date: Date | string) { + return { + db: () => dayjs(date).format('YYYY-MM-DD'), + user: () => { + const lang = document.documentElement.lang || 'ru'; + dayjs.locale(lang); + return dayjs(date).format('D MMMM YYYY'); + }, + }; } export function formatTime(time: string) { - return `${time}:00`; -} - -export function parseTime(time: string) { const [hours = '00', minutes = '00'] = time.split(':'); - return `${hours}:${minutes}`; + return { + db: () => `${hours}:${minutes}:00`, + user: () => `${hours}:${minutes}`, + }; }