feat: translate bookings page and components to English

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ivan
2026-03-01 21:22:55 +00:00
parent 0fb27b1825
commit 3e65974727
3 changed files with 52 additions and 52 deletions

View File

@@ -94,13 +94,13 @@ export function BookingCalendar({ siteId, onSlotClick }: BookingCalendarProps) {
const url = siteId ? `/api/courts?siteId=${siteId}` : "/api/courts";
const response = await fetch(url);
if (!response.ok) {
throw new Error("Error al cargar las canchas");
throw new Error("Error loading courts");
}
const data = await response.json();
setCourts(data);
return data as Court[];
} catch (err) {
setError(err instanceof Error ? err.message : "Error desconocido");
setError(err instanceof Error ? err.message : "Unknown error");
return [];
}
}, [siteId]);
@@ -113,7 +113,7 @@ export function BookingCalendar({ siteId, onSlotClick }: BookingCalendarProps) {
`/api/courts/${courtId}/availability?date=${dateStr}`
);
if (!response.ok) {
throw new Error(`Error al cargar disponibilidad`);
throw new Error(`Error loading availability`);
}
return (await response.json()) as CourtAvailability;
} catch (err) {
@@ -224,7 +224,7 @@ export function BookingCalendar({ siteId, onSlotClick }: BookingCalendarProps) {
fetchCourts();
}}
>
Reintentar
Retry
</Button>
</div>
</CardContent>
@@ -238,7 +238,7 @@ export function BookingCalendar({ siteId, onSlotClick }: BookingCalendarProps) {
<Card>
<CardHeader className="pb-4">
<div className="flex items-center justify-between">
<CardTitle className="text-lg">Calendario</CardTitle>
<CardTitle className="text-lg">Calendar</CardTitle>
<div className="flex items-center gap-2">
<Button variant="outline" size="sm" onClick={goToPrevDay}>
<svg
@@ -260,7 +260,7 @@ export function BookingCalendar({ siteId, onSlotClick }: BookingCalendarProps) {
size="sm"
onClick={goToToday}
>
Hoy
Today
</Button>
<Button variant="outline" size="sm" onClick={goToNextDay}>
<svg
@@ -286,12 +286,12 @@ export function BookingCalendar({ siteId, onSlotClick }: BookingCalendarProps) {
<div className="flex items-center justify-center p-12">
<div className="flex flex-col items-center gap-3">
<div className="h-8 w-8 animate-spin rounded-full border-4 border-primary-200 border-t-primary-600" />
<p className="text-sm text-primary-500">Cargando disponibilidad...</p>
<p className="text-sm text-primary-500">Loading availability...</p>
</div>
</div>
) : courts.length === 0 ? (
<div className="p-6 text-center text-primary-500">
<p>No hay canchas disponibles.</p>
<p>No courts available.</p>
</div>
) : (
<div className="overflow-x-auto">
@@ -316,7 +316,7 @@ export function BookingCalendar({ siteId, onSlotClick }: BookingCalendarProps) {
{court.name}
</h3>
<p className="text-xs text-primary-500 mt-1">
{court.type === "INDOOR" ? "Interior" : "Exterior"}
{court.type === "INDOOR" ? "Indoor" : "Outdoor"}
</p>
</div>
))}
@@ -347,7 +347,7 @@ export function BookingCalendar({ siteId, onSlotClick }: BookingCalendarProps) {
className="border-r border-primary-200 last:border-r-0 p-2"
>
<div className="rounded-md border border-primary-200 bg-primary-50 p-3 text-center text-xs text-primary-400">
No disponible
Not available
</div>
</div>
);
@@ -373,7 +373,7 @@ export function BookingCalendar({ siteId, onSlotClick }: BookingCalendarProps) {
{timeSlots.length === 0 && (
<div className="p-6 text-center text-primary-500">
<p>No hay horarios disponibles para este día.</p>
<p>No time slots available for this day.</p>
</div>
)}
</div>

View File

@@ -104,12 +104,12 @@ export function BookingDialog({
try {
const response = await fetch(`/api/bookings/${slot.bookingId}`);
if (!response.ok) {
throw new Error("Error al cargar la reserva");
throw new Error("Error loading booking");
}
const data = await response.json();
setBooking(data);
} catch (err) {
setError(err instanceof Error ? err.message : "Error desconocido");
setError(err instanceof Error ? err.message : "Unknown error");
} finally {
setLoadingBookingInfo(false);
}
@@ -128,7 +128,7 @@ export function BookingDialog({
`/api/clients?search=${encodeURIComponent(search)}&limit=10`
);
if (!response.ok) {
throw new Error("Error al buscar clientes");
throw new Error("Error searching players");
}
const data: ClientsResponse = await response.json();
setClients(data.data);
@@ -184,13 +184,13 @@ export function BookingDialog({
if (!response.ok) {
const data = await response.json();
throw new Error(data.error || "Error al crear la reserva");
throw new Error(data.error || "Error creating booking");
}
onBookingCreated?.();
onClose();
} catch (err) {
setError(err instanceof Error ? err.message : "Error al crear la reserva");
setError(err instanceof Error ? err.message : "Error creating booking");
} finally {
setCreatingBooking(false);
}
@@ -210,20 +210,20 @@ export function BookingDialog({
"Content-Type": "application/json",
},
body: JSON.stringify({
cancelReason: "Cancelada por el administrador",
cancelReason: "Cancelled by administrator",
}),
});
if (!response.ok) {
const data = await response.json();
throw new Error(data.error || "Error al cancelar la reserva");
throw new Error(data.error || "Error cancelling booking");
}
onBookingCancelled?.();
onClose();
} catch (err) {
setError(
err instanceof Error ? err.message : "Error al cancelar la reserva"
err instanceof Error ? err.message : "Error cancelling booking"
);
} finally {
setCancellingBooking(false);
@@ -246,7 +246,7 @@ export function BookingDialog({
<CardHeader className="pb-4">
<div className="flex items-center justify-between">
<CardTitle className="text-lg">
{slot.available ? "Nueva Reserva" : "Detalle de Reserva"}
{slot.available ? "New Booking" : "Booking Details"}
</CardTitle>
<button
onClick={onClose}
@@ -269,16 +269,16 @@ export function BookingDialog({
</div>
<div className="text-sm text-primary-600 space-y-1 mt-2">
<p>
<span className="font-medium">Cancha:</span> {slot.courtName}
<span className="font-medium">Court:</span> {slot.courtName}
</p>
<p>
<span className="font-medium">Fecha:</span> {formatDate(date)}
<span className="font-medium">Date:</span> {formatDate(date)}
</p>
<p>
<span className="font-medium">Hora:</span> {formatTime(slotDate)}
<span className="font-medium">Time:</span> {formatTime(slotDate)}
</p>
<p>
<span className="font-medium">Precio:</span>{" "}
<span className="font-medium">Price:</span>{" "}
{formatCurrency(slot.price)}
</p>
</div>
@@ -296,11 +296,11 @@ export function BookingDialog({
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-primary-700 mb-2">
Buscar Cliente
Search Player
</label>
<Input
type="text"
placeholder="Nombre, email o telefono..."
placeholder="Name, email or phone..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
autoFocus
@@ -317,7 +317,7 @@ export function BookingDialog({
{!loadingClients && searchQuery.length >= 2 && clients.length === 0 && (
<p className="text-sm text-primary-500 text-center py-4">
No se encontraron clientes.
No players found.
</p>
)}
@@ -341,7 +341,7 @@ export function BookingDialog({
{client.firstName} {client.lastName}
</p>
<p className="text-xs text-primary-500">
{client.email || client.phone || "Sin contacto"}
{client.email || client.phone || "No contact"}
</p>
</div>
{client.memberships.length > 0 && (
@@ -358,18 +358,18 @@ export function BookingDialog({
{selectedClient && (
<div className="mt-4 rounded-md border border-accent-200 bg-accent-50 p-3">
<p className="text-sm font-medium text-accent-800">
Cliente seleccionado:
Selected player:
</p>
<p className="text-sm text-accent-700">
{selectedClient.firstName} {selectedClient.lastName}
</p>
{selectedClient.memberships.length > 0 && (
<p className="text-xs text-accent-600 mt-1">
Membresia: {selectedClient.memberships[0].plan.name}
Membership: {selectedClient.memberships[0].plan.name}
{selectedClient.memberships[0].remainingHours !== null &&
selectedClient.memberships[0].remainingHours > 0 && (
<span className="ml-2">
({selectedClient.memberships[0].remainingHours}h restantes)
({selectedClient.memberships[0].remainingHours}h remaining)
</span>
)}
</p>
@@ -392,7 +392,7 @@ export function BookingDialog({
<div className="space-y-4">
<div className="rounded-md border border-primary-200 bg-primary-50 p-4 space-y-3">
<div>
<p className="text-xs text-primary-500">Cliente</p>
<p className="text-xs text-primary-500">Player</p>
<p className="font-medium text-primary-800">
{booking.client.firstName} {booking.client.lastName}
</p>
@@ -410,7 +410,7 @@ export function BookingDialog({
<div className="grid grid-cols-2 gap-3">
<div>
<p className="text-xs text-primary-500">Estado</p>
<p className="text-xs text-primary-500">Status</p>
<p
className={cn(
"text-sm font-medium",
@@ -419,21 +419,21 @@ export function BookingDialog({
booking.status === "CANCELLED" && "text-red-600"
)}
>
{booking.status === "CONFIRMED" && "Confirmada"}
{booking.status === "PENDING" && "Pendiente"}
{booking.status === "CANCELLED" && "Cancelada"}
{booking.status === "COMPLETED" && "Completada"}
{booking.status === "NO_SHOW" && "No asistio"}
{booking.status === "CONFIRMED" && "Confirmed"}
{booking.status === "PENDING" && "Pending"}
{booking.status === "CANCELLED" && "Cancelled"}
{booking.status === "COMPLETED" && "Completed"}
{booking.status === "NO_SHOW" && "No Show"}
</p>
</div>
<div>
<p className="text-xs text-primary-500">Tipo de Pago</p>
<p className="text-xs text-primary-500">Payment Type</p>
<p className="text-sm text-primary-800">
{booking.paymentType === "CASH" && "Efectivo"}
{booking.paymentType === "CARD" && "Tarjeta"}
{booking.paymentType === "TRANSFER" && "Transferencia"}
{booking.paymentType === "MEMBERSHIP" && "Membresia"}
{booking.paymentType === "FREE" && "Gratuito"}
{booking.paymentType === "CASH" && "Cash"}
{booking.paymentType === "CARD" && "Card"}
{booking.paymentType === "TRANSFER" && "Transfer"}
{booking.paymentType === "MEMBERSHIP" && "Membership"}
{booking.paymentType === "FREE" && "Free"}
</p>
</div>
</div>
@@ -450,7 +450,7 @@ export function BookingDialog({
{!loadingBookingInfo && !booking && (
<div className="text-center py-4 text-primary-500">
<p>No se pudo cargar la informacion de la reserva.</p>
<p>Could not load booking information.</p>
</div>
)}
</div>
@@ -460,7 +460,7 @@ export function BookingDialog({
<CardFooter className="border-t border-primary-200 bg-primary-50 pt-4">
<div className="flex w-full gap-3">
<Button variant="outline" onClick={onClose} className="flex-1">
Cerrar
Close
</Button>
{slot.available && (
@@ -473,10 +473,10 @@ export function BookingDialog({
{creatingBooking ? (
<span className="flex items-center gap-2">
<div className="h-4 w-4 animate-spin rounded-full border-2 border-white/30 border-t-white" />
Creando...
Creating...
</span>
) : (
"Crear Reserva"
"Create Booking"
)}
</Button>
)}
@@ -491,10 +491,10 @@ export function BookingDialog({
{cancellingBooking ? (
<span className="flex items-center gap-2">
<div className="h-4 w-4 animate-spin rounded-full border-2 border-white/30 border-t-white" />
Cancelando...
Cancelling...
</span>
) : (
"Cancelar Reserva"
"Cancel Booking"
)}
</Button>
)}