109 lines
3.4 KiB
TypeScript
109 lines
3.4 KiB
TypeScript
import { Button } from '@/components/ui/button';
|
|
import type { Court } from '@repo/api-contract';
|
|
import { formatCurrency, summarizeAvailability } from '../lib/court.utils';
|
|
|
|
type CourtListSectionProps = {
|
|
courts: Court[];
|
|
isLoading: boolean;
|
|
isError: boolean;
|
|
onDuplicateCourt: (court: Court) => void;
|
|
onEditCourt: (court: Court) => void;
|
|
};
|
|
|
|
export function CourtListSection({
|
|
courts,
|
|
isLoading,
|
|
isError,
|
|
onDuplicateCourt,
|
|
onEditCourt,
|
|
}: CourtListSectionProps) {
|
|
return (
|
|
<section className="rounded-xl border bg-card p-3 text-card-foreground shadow-sm sm:p-5">
|
|
<h3 className="text-lg font-semibold">Canchas configuradas</h3>
|
|
|
|
{isLoading && <p className="mt-3 text-sm text-muted-foreground">Cargando canchas...</p>}
|
|
|
|
{isError && (
|
|
<p className="mt-3 text-sm text-destructive">
|
|
No se pudieron cargar las canchas del complejo.
|
|
</p>
|
|
)}
|
|
|
|
{!isLoading && courts.length === 0 && (
|
|
<p className="mt-3 text-sm text-muted-foreground">
|
|
Aún no hay canchas. Crea la primera usando el formulario.
|
|
</p>
|
|
)}
|
|
|
|
<div className="mt-4 space-y-3">
|
|
{courts.map((court) => (
|
|
<article key={court.id} className="rounded-lg border p-3 sm:p-4">
|
|
<div className="flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between">
|
|
<div>
|
|
<p className="font-medium">{court.name}</p>
|
|
<p className="text-sm text-muted-foreground">
|
|
{court.sport.name} · {court.slotDurationMinutes} min ·{' '}
|
|
{formatCurrency(court.basePrice)}
|
|
</p>
|
|
</div>
|
|
<div className="hidden w-full flex-col gap-2 sm:flex sm:w-auto sm:flex-row">
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
className="w-full sm:w-auto"
|
|
onClick={() => {
|
|
onDuplicateCourt(court);
|
|
}}
|
|
>
|
|
Duplicar cancha
|
|
</Button>
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
className="w-full sm:w-auto"
|
|
onClick={() => {
|
|
onEditCourt(court);
|
|
}}
|
|
>
|
|
Editar
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-3 flex flex-wrap gap-2 text-xs text-muted-foreground">
|
|
{summarizeAvailability(court.availability).map((summary) => (
|
|
<span key={`${court.id}-${summary}`} className="rounded-md border px-2 py-1">
|
|
{summary}
|
|
</span>
|
|
))}
|
|
</div>
|
|
|
|
<div className="mt-3 flex w-full flex-col gap-2 sm:hidden">
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
className="w-full"
|
|
onClick={() => {
|
|
onDuplicateCourt(court);
|
|
}}
|
|
>
|
|
Duplicar cancha
|
|
</Button>
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
className="w-full"
|
|
onClick={() => {
|
|
onEditCourt(court);
|
|
}}
|
|
>
|
|
Editar
|
|
</Button>
|
|
</div>
|
|
</article>
|
|
))}
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|