From a3fe14a53c8bb9d93aa0a4eafa304024a5058a0c Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Wed, 25 Jun 2025 14:24:11 +0300 Subject: [PATCH] fix badges & alerts --- apps/web/components/orders/order-status.tsx | 18 +- .../schedule/day-slots-list/slot-card.tsx | 34 +--- apps/web/components/shared/order-card.tsx | 7 +- apps/web/components/shared/status.tsx | 168 ++++++++++++++++++ apps/web/utils/components/order/index.ts | 1 - apps/web/utils/components/order/status.ts | 92 ---------- 6 files changed, 177 insertions(+), 143 deletions(-) create mode 100644 apps/web/components/shared/status.tsx delete mode 100644 apps/web/utils/components/order/index.ts delete mode 100644 apps/web/utils/components/order/status.ts diff --git a/apps/web/components/orders/order-status.tsx b/apps/web/components/orders/order-status.tsx index 92c895e..a4ed9d9 100644 --- a/apps/web/components/orders/order-status.tsx +++ b/apps/web/components/orders/order-status.tsx @@ -1,25 +1,11 @@ 'use client'; import { type OrderComponentProps } from './types'; +import { getAlert } from '@/components/shared/status'; import { useOrderQuery } from '@/hooks/api/orders'; -import { getAlertStyles, getBadgeText, getStatusIcon } from '@/utils/components/order'; -import { Alert, AlertTitle } from '@repo/ui/components/ui/alert'; export function OrderStatus({ documentId }: Readonly) { const { data: { order } = {} } = useOrderQuery({ documentId }); - const state = order?.state; - - if (!state) return null; - - const title = getBadgeText(state); - const styles = getAlertStyles(state); - const { icon: StatusIcon, iconStyles } = getStatusIcon(state); - - return ( - - - {title} - - ); + return order?.state && getAlert(order.state); } diff --git a/apps/web/components/schedule/day-slots-list/slot-card.tsx b/apps/web/components/schedule/day-slots-list/slot-card.tsx index 358f210..147aaef 100644 --- a/apps/web/components/schedule/day-slots-list/slot-card.tsx +++ b/apps/web/components/schedule/day-slots-list/slot-card.tsx @@ -1,22 +1,16 @@ -/* eslint-disable canonical/id-match */ 'use client'; -import { type SlotComponentProps } from '../types'; +import { getBadge } from '@/components/shared/status'; import { ReadonlyTimeRange } from '@/components/shared/time-range'; import { useSlotQuery } from '@/hooks/api/slots'; -import { Enum_Slot_State } from '@repo/graphql/types'; -import { Badge } from '@repo/ui/components/ui/badge'; +import type * as GQL from '@repo/graphql/types'; import { cn } from '@repo/ui/lib/utils'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; -const MAP_BADGE_TEXT: Record = { - closed: 'Закрыто', - open: 'Открыто', - reserved: 'Зарезервировано', -}; +type Props = GQL.SlotFieldsFragment; -export function SlotCard(props: Readonly) { +export function SlotCard(props: Readonly) { const pathname = usePathname(); const { documentId } = props; @@ -25,9 +19,6 @@ export function SlotCard(props: Readonly) { const ordersNumber = slot?.orders?.length; const hasOrders = Boolean(ordersNumber); - const isOpened = slot?.state === Enum_Slot_State.Open; - const isClosed = slot?.state === Enum_Slot_State.Closed; - return (
@@ -42,23 +33,8 @@ export function SlotCard(props: Readonly) { {hasOrders ? 'Есть записи' : 'Свободно'}
- {slot?.state && ( - - {getBadgeText(slot.state)} - - )} + {slot?.state && getBadge(slot.state)} ); } - -function getBadgeText(state: Enum_Slot_State) { - if (!state) return ''; - - return MAP_BADGE_TEXT[state]; -} diff --git a/apps/web/components/shared/order-card.tsx b/apps/web/components/shared/order-card.tsx index 67079d7..8c4ab2f 100644 --- a/apps/web/components/shared/order-card.tsx +++ b/apps/web/components/shared/order-card.tsx @@ -1,10 +1,9 @@ 'use client'; import { ReadonlyTimeRange } from './time-range/readonly'; -import { getBadgeStyles, getBadgeText } from '@/utils/components/order'; +import { getBadge } from '@/components/shared/status'; import type * as GQL from '@repo/graphql/types'; import { Avatar, AvatarFallback, AvatarImage } from '@repo/ui/components/ui/avatar'; -import { Badge } from '@repo/ui/components/ui/badge'; import Link from 'next/link'; type OrderClient = NonNullable['client']; @@ -26,9 +25,7 @@ export function OrderCard({ documentId, ...order }: Readonly{clientName} */} - {order?.state && ( - {getBadgeText(order.state)} - )} + {order?.state && getBadge(order.state)} ); diff --git a/apps/web/components/shared/status.tsx b/apps/web/components/shared/status.tsx new file mode 100644 index 0000000..7d7e819 --- /dev/null +++ b/apps/web/components/shared/status.tsx @@ -0,0 +1,168 @@ +import { Badge } from '@repo/ui/components/ui/badge'; +import { cn } from '@repo/ui/lib/utils'; +import { AlertCircle, Calendar, CheckCircle, FileText, Lock, Unlock, XCircle } from 'lucide-react'; +import { type JSX } from 'react'; + +const BADGE_BY_STATE: Record = { + approved: ( + + Подтверждено + + ), + cancelled: ( + + Отменено + + ), + cancelling: ( + + Отменяется + + ), + closed: ( + + Закрыто + + ), + completed: ( + + Завершено + + ), + created: ( + + Создано + + ), + open: ( + + Открыто + + ), + scheduled: ( + + Запланировано + + ), +}; + +export function getBadge(state: string) { + return BADGE_BY_STATE[state] ?? null; +} + +function Alert({ className, ...props }: JSX.IntrinsicElements['div']) { + return ( +
+ ); +} + +function AlertTitle({ className, ...props }: JSX.IntrinsicElements['span']) { + return ; +} + +const ALERT_BY_STATE: Record = { + approved: ( + + + Подтверждено + + ), + cancelled: ( + + + Отменено + + ), + cancelling: ( + + + Отменяется + + ), + closed: ( + + + Закрыто + + ), + completed: ( + + + Завершено + + ), + created: ( + + + Создано + + ), + opened: ( + + + Открыто + + ), + scheduled: ( + + + Запланировано + + ), +}; + +export function getAlert(state: string) { + return ALERT_BY_STATE[state] ?? null; +} diff --git a/apps/web/utils/components/order/index.ts b/apps/web/utils/components/order/index.ts deleted file mode 100644 index 420cc02..0000000 --- a/apps/web/utils/components/order/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './status'; diff --git a/apps/web/utils/components/order/status.ts b/apps/web/utils/components/order/status.ts deleted file mode 100644 index c1da0b5..0000000 --- a/apps/web/utils/components/order/status.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { type Enum_Order_State } from '@repo/graphql/types'; -import { AlertCircle, Calendar, CheckCircle, FileText, XCircle } from 'lucide-react'; - -const BADGE_TEXT: Record = { - approved: 'Подтверждено', - cancelled: 'Отменено', - cancelling: 'Отменяется', - completed: 'Завершено', - created: 'Создано', - scheduled: 'Запланировано', -}; - -const BADGE_STYLES: Record = { - approved: 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-100', - cancelled: 'bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-100', - cancelling: 'bg-orange-100 text-orange-700 dark:bg-orange-900 dark:text-orange-100', - completed: 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-100', - created: '', - scheduled: 'bg-purple-100 text-purple-700 dark:bg-purple-900 dark:text-purple-100', -}; - -const ALERT_STYLES: Record = { - approved: - 'border-blue-200 bg-blue-50 text-blue-800 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-200', - cancelled: - 'border-red-200 bg-red-50 text-red-800 dark:border-red-800 dark:bg-red-950 dark:text-red-200', - cancelling: - 'border-orange-200 bg-orange-50 text-orange-800 dark:border-orange-800 dark:bg-orange-950 dark:text-orange-200', - completed: - 'border-green-200 bg-green-50 text-green-800 dark:border-green-800 dark:bg-green-950 dark:text-green-200', - created: - 'border-gray-200 bg-gray-50 text-gray-800 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200', - scheduled: - 'border-purple-200 bg-purple-50 text-purple-800 dark:border-purple-800 dark:bg-purple-950 dark:text-purple-200', -}; - -const STATUS_ICONS: Record< - Enum_Order_State, - { - icon: React.ComponentType<{ className?: string }>; - iconStyles: string; - } -> = { - approved: { - icon: CheckCircle, - iconStyles: 'text-blue-600 dark:text-blue-400', - }, - cancelled: { - icon: XCircle, - iconStyles: 'text-red-600 dark:text-red-400', - }, - cancelling: { - icon: AlertCircle, - iconStyles: 'text-orange-600 dark:text-orange-400', - }, - completed: { - icon: CheckCircle, - iconStyles: 'text-green-600 dark:text-green-400', - }, - created: { - icon: FileText, - iconStyles: 'text-gray-600 dark:text-gray-400', - }, - scheduled: { - icon: Calendar, - iconStyles: 'text-purple-600 dark:text-purple-400', - }, -}; - -export function getAlertStyles(state: Enum_Order_State) { - if (!state) return ''; - - return ALERT_STYLES[state]; -} - -export function getBadgeStyles(state: Enum_Order_State) { - if (!state) return ''; - - return BADGE_STYLES[state]; -} - -export function getBadgeText(state: Enum_Order_State) { - if (!state) return ''; - - return BADGE_TEXT[state]; -} - -export function getStatusIcon(state: Enum_Order_State) { - if (!state) return { icon: () => null, iconStyles: '' }; - - return STATUS_ICONS[state]; -}