New booking panel
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
import { CalendarDays, Download, Drill, ShieldCheck, UsersRound } from 'lucide-react';
|
||||
import { useBooking } from '../booking-provider';
|
||||
import { formatBookingDate, toIsoDateLocal } from '../lib/booking-time';
|
||||
|
||||
export function BookingDaySummary() {
|
||||
const { selectedDate, summary } = useBooking();
|
||||
|
||||
return (
|
||||
<section className="rounded-lg border bg-card/85 p-5 shadow-sm xl:col-span-3">
|
||||
<div className="mb-4">
|
||||
<h2 className="text-base font-semibold">Resumen del día</h2>
|
||||
<p className="mt-1 text-sm capitalize text-muted-foreground">
|
||||
{formatBookingDate(selectedDate, { year: 'numeric' })}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 md:grid-cols-4">
|
||||
<SummaryCard
|
||||
label="Total de bloques"
|
||||
value={summary.totalReservations}
|
||||
icon={CalendarDays}
|
||||
className="border-border bg-background/45"
|
||||
/>
|
||||
<SummaryCard
|
||||
label="Libres"
|
||||
value={summary.freeSlots}
|
||||
detail={`${summary.freePercent}% del total`}
|
||||
icon={UsersRound}
|
||||
className="border-primary/30 bg-primary/10 text-primary"
|
||||
/>
|
||||
<SummaryCard
|
||||
label="Reservados"
|
||||
value={summary.reservedSlots}
|
||||
detail={`${summary.reservedPercent}% del total`}
|
||||
icon={ShieldCheck}
|
||||
className="border-reserved/35 bg-reserved/10 text-reserved"
|
||||
/>
|
||||
<SummaryCard
|
||||
label="Mantenimiento"
|
||||
value={summary.maintenanceSlots}
|
||||
detail={`${summary.maintenancePercent}% del total`}
|
||||
icon={Drill}
|
||||
className="border-maintenance/35 bg-maintenance/10 text-maintenance"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
interface SummaryCardProps {
|
||||
label: string;
|
||||
value: number;
|
||||
detail?: string;
|
||||
icon: typeof CalendarDays;
|
||||
className: string;
|
||||
}
|
||||
|
||||
function SummaryCard({ label, value, detail, icon: Icon, className }: SummaryCardProps) {
|
||||
return (
|
||||
<article className={`rounded-lg border p-4 ${className}`}>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex size-10 shrink-0 items-center justify-center rounded-md bg-transparent">
|
||||
<Icon className="size-5" />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className="truncate text-sm text-muted-foreground">{label}</p>
|
||||
<p className="text-2xl font-semibold leading-tight">{value}</p>
|
||||
{detail && <p className="mt-1 truncate text-xs text-muted-foreground">{detail}</p>}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
export function BookingQuickActions() {
|
||||
const { selectedDate, selectedStatus, setSelectedDate, setSelectedStatus, exportDayReport } =
|
||||
useBooking();
|
||||
const todayIso = toIsoDateLocal(new Date());
|
||||
const isViewingTodayReservations = selectedDate === todayIso && selectedStatus === 'reserved';
|
||||
const isViewingMaintenance = selectedStatus === 'maintenance';
|
||||
|
||||
return (
|
||||
<section className="rounded-lg border bg-card/85 p-5 shadow-sm">
|
||||
<h2 className="text-base font-semibold">Acciones rápidas</h2>
|
||||
<div className="mt-3 grid gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setSelectedDate(todayIso);
|
||||
setSelectedStatus(isViewingTodayReservations ? 'all' : 'reserved');
|
||||
}}
|
||||
aria-pressed={isViewingTodayReservations}
|
||||
className="flex h-10 items-center gap-3 rounded-md border bg-background/45 px-3 text-left text-sm transition-colors hover:bg-muted aria-pressed:border-reserved/50 aria-pressed:bg-reserved/10"
|
||||
>
|
||||
<CalendarDays className="size-4 text-muted-foreground" />
|
||||
{isViewingTodayReservations ? 'Ver todos los estados' : 'Ver reservas de hoy'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSelectedStatus(isViewingMaintenance ? 'all' : 'maintenance')}
|
||||
aria-pressed={isViewingMaintenance}
|
||||
className="flex h-10 items-center gap-3 rounded-md border bg-background/45 px-3 text-left text-sm transition-colors hover:bg-muted aria-pressed:border-maintenance/50 aria-pressed:bg-maintenance/10"
|
||||
>
|
||||
<Drill className="size-4 text-maintenance" />
|
||||
{isViewingMaintenance ? 'Ver todos los estados' : 'Ver mantenimiento'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={exportDayReport}
|
||||
className="flex h-10 items-center gap-3 rounded-md border bg-background/45 px-3 text-left text-sm transition-colors hover:bg-muted"
|
||||
>
|
||||
<Download className="size-4 text-primary" />
|
||||
Exportar reporte
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user