slot page: replace buttons with floating panel
This commit is contained in:
parent
2ba56c5949
commit
4ed010056a
@ -23,8 +23,8 @@ export default async function SlotPage(props: Readonly<Props>) {
|
||||
<PageHeader title="Слот" />
|
||||
<Container>
|
||||
<SlotDateTime {...parameters} />
|
||||
<SlotButtons {...parameters} />
|
||||
<SlotOrdersList {...parameters} />
|
||||
<SlotButtons {...parameters} />
|
||||
</Container>
|
||||
</HydrationBoundary>
|
||||
);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export * from '../shared/action-panel';
|
||||
export * from './order-contacts';
|
||||
export * from './order-datetime';
|
||||
export * from './order-form';
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
/* eslint-disable canonical/id-match */
|
||||
'use client';
|
||||
|
||||
import FloatingActionPanel from '../shared/action-panel';
|
||||
import { type SlotComponentProps } from './types';
|
||||
import { useSlotDelete, useSlotMutation, useSlotQuery } from '@/hooks/api/slots';
|
||||
import { Enum_Slot_State } from '@repo/graphql/types';
|
||||
import { Button } from '@repo/ui/components/ui/button';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
export function SlotButtons({ documentId }: Readonly<SlotComponentProps>) {
|
||||
@ -38,33 +37,13 @@ export function SlotButtons({ documentId }: Readonly<SlotComponentProps>) {
|
||||
const hasOrders = Boolean(slot?.orders.length);
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-[2fr_1fr]">
|
||||
{isOpened && (
|
||||
<Button
|
||||
className="rounded-l-2xl rounded-r-none bg-orange-100 p-6 text-orange-500 dark:bg-yellow-700 dark:text-orange-100"
|
||||
onClick={handleCloseSlot}
|
||||
variant="ghost"
|
||||
>
|
||||
Закрыть
|
||||
</Button>
|
||||
)}
|
||||
{isClosed && (
|
||||
<Button
|
||||
className="rounded-l-2xl rounded-r-none bg-green-100 p-6 text-green-500 dark:bg-green-700 dark:text-green-100"
|
||||
onClick={handleOpenSlot}
|
||||
variant="ghost"
|
||||
>
|
||||
Открыть
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
className="rounded-l-none rounded-r-2xl bg-red-100 p-6 text-red-500 dark:bg-red-700 dark:text-red-100"
|
||||
disabled={hasOrders}
|
||||
onClick={handleDeleteSlot}
|
||||
variant="ghost"
|
||||
>
|
||||
Удалить
|
||||
</Button>
|
||||
</div>
|
||||
<FloatingActionPanel
|
||||
isOpen={isOpened}
|
||||
onDelete={hasOrders ? undefined : () => handleDeleteSlot()}
|
||||
onToggle={() => {
|
||||
if (isOpened) handleCloseSlot();
|
||||
if (isClosed) handleOpenSlot();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
91
apps/web/components/shared/action-panel.tsx
Normal file
91
apps/web/components/shared/action-panel.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@repo/ui/components/ui/button';
|
||||
import { Card } from '@repo/ui/components/ui/card';
|
||||
import { Ban, Check, Lock, Trash2, Unlock } from 'lucide-react';
|
||||
|
||||
type FloatingActionPanelProps = {
|
||||
readonly isOpen?: boolean;
|
||||
readonly onCancel?: () => void;
|
||||
readonly onConfirm?: () => void;
|
||||
readonly onDelete?: () => void;
|
||||
readonly onToggle?: () => void;
|
||||
};
|
||||
|
||||
export default function FloatingActionPanel({
|
||||
isOpen,
|
||||
onCancel,
|
||||
onConfirm,
|
||||
onDelete,
|
||||
onToggle,
|
||||
}: FloatingActionPanelProps) {
|
||||
return (
|
||||
<Card className="fixed inset-x-4 bottom-4 rounded-3xl border-0 bg-background/95 p-4 shadow-2xl backdrop-blur-sm dark:bg-primary/5 md:bottom-6 md:left-auto md:right-6 md:p-6">
|
||||
<div className="flex flex-col items-center gap-2 sm:flex-row sm:gap-4">
|
||||
{/* Кнопка закрыть/открыть */}
|
||||
{onToggle && (
|
||||
<Button
|
||||
className={`
|
||||
w-full rounded-2xl text-sm transition-all duration-200 sm:w-auto
|
||||
${
|
||||
isOpen
|
||||
? 'bg-blue-100 text-blue-700 hover:bg-blue-200 dark:bg-blue-950/70 dark:text-blue-300 dark:hover:bg-blue-900/70'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-900/70 dark:text-gray-300 dark:hover:bg-gray-800/70'
|
||||
}
|
||||
`}
|
||||
onClick={onToggle}
|
||||
size="sm"
|
||||
>
|
||||
{isOpen ? (
|
||||
<>
|
||||
<Lock className="mr-2 size-4" />
|
||||
<span>Закрыть</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Unlock className="mr-2 size-4" />
|
||||
<span>Открыть</span>
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Кнопка удалить */}
|
||||
{onDelete && (
|
||||
<Button
|
||||
className="w-full rounded-2xl bg-orange-100 text-sm text-orange-700 transition-all duration-200 hover:bg-orange-200 dark:bg-orange-950/70 dark:text-orange-300 dark:hover:bg-orange-900/70 sm:w-auto"
|
||||
onClick={onDelete}
|
||||
size="sm"
|
||||
>
|
||||
<Trash2 className="mr-2 size-4" />
|
||||
<span>Удалить</span>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Кнопка отменить */}
|
||||
{onCancel && (
|
||||
<Button
|
||||
className="w-full rounded-2xl bg-red-100 text-sm text-red-700 transition-all duration-200 hover:bg-red-200 dark:bg-red-950/70 dark:text-red-300 dark:hover:bg-red-900/70 sm:w-auto"
|
||||
onClick={onCancel}
|
||||
size="sm"
|
||||
>
|
||||
<Ban className="mr-2 size-4" />
|
||||
<span>Отменить</span>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Кнопка подтверд<D180><D0B4>ть */}
|
||||
{onConfirm && (
|
||||
<Button
|
||||
className="w-full rounded-2xl bg-green-600 text-sm text-white shadow-lg transition-all duration-200 hover:bg-green-700 dark:bg-green-700 dark:hover:bg-green-600 sm:w-auto"
|
||||
onClick={onConfirm}
|
||||
size="sm"
|
||||
>
|
||||
<Check className="mr-2 size-4" />
|
||||
<span>Подтвердить</span>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user