feat: translate settings page to English

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ivan
2026-03-01 21:24:52 +00:00
parent 0498844b4f
commit 3aeda8c2fb

View File

@@ -129,7 +129,7 @@ export default function SettingsPage() {
setLoading(true);
// Simulate save
await new Promise((resolve) => setTimeout(resolve, 500));
setMessage({ type: "success", text: "Configuración guardada correctamente" });
setMessage({ type: "success", text: "Settings saved successfully" });
setLoading(false);
setTimeout(() => setMessage(null), 3000);
};
@@ -147,15 +147,15 @@ export default function SettingsPage() {
});
if (res.ok) {
setMessage({ type: "success", text: editingSite ? "Sede actualizada" : "Sede creada" });
setMessage({ type: "success", text: editingSite ? "Site updated" : "Site created" });
fetchSites();
setShowSiteForm(false);
setEditingSite(null);
} else {
setMessage({ type: "error", text: "Error al guardar la sede" });
setMessage({ type: "error", text: "Error saving site" });
}
} catch (error) {
setMessage({ type: "error", text: "Error de conexión" });
setMessage({ type: "error", text: "Connection error" });
} finally {
setLoading(false);
setTimeout(() => setMessage(null), 3000);
@@ -175,15 +175,15 @@ export default function SettingsPage() {
});
if (res.ok) {
setMessage({ type: "success", text: editingCourt ? "Cancha actualizada" : "Cancha creada" });
setMessage({ type: "success", text: editingCourt ? "Court updated" : "Court created" });
fetchCourts();
setShowCourtForm(false);
setEditingCourt(null);
} else {
setMessage({ type: "error", text: "Error al guardar la cancha" });
setMessage({ type: "error", text: "Error saving court" });
}
} catch (error) {
setMessage({ type: "error", text: "Error de conexión" });
setMessage({ type: "error", text: "Connection error" });
} finally {
setLoading(false);
setTimeout(() => setMessage(null), 3000);
@@ -191,18 +191,18 @@ export default function SettingsPage() {
};
const handleDeleteCourt = async (courtId: string) => {
if (!confirm("¿Estás seguro de eliminar esta cancha?")) return;
if (!confirm("Are you sure you want to delete this court?")) return;
try {
const res = await fetch(`/api/courts/${courtId}`, { method: "DELETE" });
if (res.ok) {
setMessage({ type: "success", text: "Cancha eliminada" });
setMessage({ type: "success", text: "Court deleted" });
fetchCourts();
} else {
setMessage({ type: "error", text: "Error al eliminar la cancha" });
setMessage({ type: "error", text: "Error deleting court" });
}
} catch (error) {
setMessage({ type: "error", text: "Error de conexión" });
setMessage({ type: "error", text: "Connection error" });
}
setTimeout(() => setMessage(null), 3000);
};
@@ -211,8 +211,8 @@ export default function SettingsPage() {
<div className="space-y-6">
{/* Header */}
<div>
<h1 className="text-2xl font-bold text-primary-800">Configuración</h1>
<p className="text-primary-600">Administra la configuración del sistema</p>
<h1 className="text-2xl font-bold text-primary-800">Settings</h1>
<p className="text-primary-600">Manage system settings</p>
</div>
{/* Message */}
@@ -233,19 +233,19 @@ export default function SettingsPage() {
<TabsList className="grid w-full grid-cols-4 lg:w-auto lg:inline-grid">
<TabsTrigger value="organization" className="gap-2">
<Building2 className="h-4 w-4" />
<span className="hidden sm:inline">Organización</span>
<span className="hidden sm:inline">Organization</span>
</TabsTrigger>
<TabsTrigger value="sites" className="gap-2">
<MapPin className="h-4 w-4" />
<span className="hidden sm:inline">Sedes</span>
<span className="hidden sm:inline">Sites</span>
</TabsTrigger>
<TabsTrigger value="courts" className="gap-2">
<Clock className="h-4 w-4" />
<span className="hidden sm:inline">Canchas</span>
<span className="hidden sm:inline">Courts</span>
</TabsTrigger>
<TabsTrigger value="users" className="gap-2">
<Users className="h-4 w-4" />
<span className="hidden sm:inline">Usuarios</span>
<span className="hidden sm:inline">Users</span>
</TabsTrigger>
</TabsList>
@@ -253,34 +253,34 @@ export default function SettingsPage() {
<TabsContent value="organization" className="space-y-6">
<Card>
<CardHeader>
<CardTitle>Información de la Organización</CardTitle>
<CardTitle>Organization Information</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid gap-4 md:grid-cols-2">
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">
Nombre de la organización
Organization name
</label>
<Input
value={orgName}
onChange={(e) => setOrgName(e.target.value)}
placeholder="Nombre"
placeholder="Name"
/>
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">
Email de contacto
Contact email
</label>
<Input
type="email"
value={orgEmail}
onChange={(e) => setOrgEmail(e.target.value)}
placeholder="email@ejemplo.com"
placeholder="email@example.com"
/>
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">
Teléfono
Phone
</label>
<Input
value={orgPhone}
@@ -290,28 +290,28 @@ export default function SettingsPage() {
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">
Moneda
Currency
</label>
<select
value={currency}
onChange={(e) => setCurrency(e.target.value)}
className="w-full rounded-lg border border-primary-200 bg-white px-3 py-2 text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary"
>
<option value="MXN">MXN - Peso Mexicano</option>
<option value="USD">USD - lar</option>
<option value="MXN">MXN - Mexican Peso</option>
<option value="USD">USD - US Dollar</option>
<option value="EUR">EUR - Euro</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">
Zona horaria
Timezone
</label>
<select
value={timezone}
onChange={(e) => setTimezone(e.target.value)}
className="w-full rounded-lg border border-primary-200 bg-white px-3 py-2 text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary"
>
<option value="America/Mexico_City">Ciudad de México</option>
<option value="America/Mexico_City">Mexico City</option>
<option value="America/Monterrey">Monterrey</option>
<option value="America/Tijuana">Tijuana</option>
<option value="America/Cancun">Cancún</option>
@@ -322,7 +322,7 @@ export default function SettingsPage() {
<div className="pt-4">
<Button onClick={handleSaveOrganization} disabled={loading}>
<Save className="h-4 w-4 mr-2" />
{loading ? "Guardando..." : "Guardar cambios"}
{loading ? "Saving..." : "Save changes"}
</Button>
</div>
</CardContent>
@@ -330,31 +330,31 @@ export default function SettingsPage() {
<Card>
<CardHeader>
<CardTitle>Configuración de Reservas</CardTitle>
<CardTitle>Booking Settings</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid gap-4 md:grid-cols-2">
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">
Duración por defecto (minutos)
Default duration (minutes)
</label>
<Input type="number" defaultValue={60} min={30} step={30} />
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">
Anticipación mínima (horas)
Minimum notice (hours)
</label>
<Input type="number" defaultValue={2} min={0} />
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">
Anticipación máxima (días)
Maximum advance (days)
</label>
<Input type="number" defaultValue={14} min={1} />
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">
Horas para cancelar
Cancellation window (hours)
</label>
<Input type="number" defaultValue={24} min={0} />
</div>
@@ -363,7 +363,7 @@ export default function SettingsPage() {
<div className="pt-4">
<Button onClick={handleSaveOrganization} disabled={loading}>
<Save className="h-4 w-4 mr-2" />
{loading ? "Guardando..." : "Guardar cambios"}
{loading ? "Saving..." : "Save changes"}
</Button>
</div>
</CardContent>
@@ -373,10 +373,10 @@ export default function SettingsPage() {
{/* Sites Tab */}
<TabsContent value="sites" className="space-y-6">
<div className="flex justify-between items-center">
<h2 className="text-lg font-semibold text-primary-800">Sedes</h2>
<h2 className="text-lg font-semibold text-primary-800">Sites</h2>
<Button onClick={() => { setEditingSite(null); setShowSiteForm(true); }}>
<Plus className="h-4 w-4 mr-2" />
Nueva Sede
New Site
</Button>
</div>
@@ -423,7 +423,7 @@ export default function SettingsPage() {
: "bg-gray-100 text-gray-600"
}`}
>
{site.isActive ? "Activa" : "Inactiva"}
{site.isActive ? "Active" : "Inactive"}
</span>
</div>
</CardContent>
@@ -446,10 +446,10 @@ export default function SettingsPage() {
{/* Courts Tab */}
<TabsContent value="courts" className="space-y-6">
<div className="flex justify-between items-center">
<h2 className="text-lg font-semibold text-primary-800">Canchas</h2>
<h2 className="text-lg font-semibold text-primary-800">Courts</h2>
<Button onClick={() => { setEditingCourt(null); setShowCourtForm(true); }}>
<Plus className="h-4 w-4 mr-2" />
Nueva Cancha
New Court
</Button>
</div>
@@ -468,12 +468,12 @@ export default function SettingsPage() {
<table className="w-full">
<thead className="bg-primary-50 border-b border-primary-100">
<tr>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Cancha</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Sede</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Tipo</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Precio/hora</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Estado</th>
<th className="text-right px-4 py-3 text-sm font-medium text-primary-700">Acciones</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Court</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Site</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Type</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Price/hour</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Status</th>
<th className="text-right px-4 py-3 text-sm font-medium text-primary-700">Actions</th>
</tr>
</thead>
<tbody>
@@ -493,7 +493,7 @@ export default function SettingsPage() {
: "bg-gray-100 text-gray-600"
}`}
>
{court.status === "active" ? "Activa" : court.status === "maintenance" ? "Mantenimiento" : "Inactiva"}
{court.status === "active" ? "Active" : court.status === "maintenance" ? "Maintenance" : "Inactive"}
</span>
</td>
<td className="px-4 py-3 text-right">
@@ -533,10 +533,10 @@ export default function SettingsPage() {
{/* Users Tab */}
<TabsContent value="users" className="space-y-6">
<div className="flex justify-between items-center">
<h2 className="text-lg font-semibold text-primary-800">Usuarios</h2>
<h2 className="text-lg font-semibold text-primary-800">Users</h2>
<Button>
<Plus className="h-4 w-4 mr-2" />
Nuevo Usuario
New User
</Button>
</div>
@@ -555,12 +555,12 @@ export default function SettingsPage() {
<table className="w-full">
<thead className="bg-primary-50 border-b border-primary-100">
<tr>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Usuario</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">User</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Email</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Rol</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Sede</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Estado</th>
<th className="text-right px-4 py-3 text-sm font-medium text-primary-700">Acciones</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Role</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Site</th>
<th className="text-left px-4 py-3 text-sm font-medium text-primary-700">Status</th>
<th className="text-right px-4 py-3 text-sm font-medium text-primary-700">Actions</th>
</tr>
</thead>
<tbody>
@@ -573,11 +573,11 @@ export default function SettingsPage() {
<td className="px-4 py-3">
<span className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-primary-100 text-primary-700">
{user.role === "super_admin" ? "Super Admin" :
user.role === "site_admin" ? "Admin Sede" :
user.role === "site_admin" ? "Site Admin" :
user.role === "staff" ? "Staff" : user.role}
</span>
</td>
<td className="px-4 py-3 text-primary-600">{user.site?.name || "Todas"}</td>
<td className="px-4 py-3 text-primary-600">{user.site?.name || "All"}</td>
<td className="px-4 py-3">
<span
className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${
@@ -586,7 +586,7 @@ export default function SettingsPage() {
: "bg-gray-100 text-gray-600"
}`}
>
{user.isActive ? "Activo" : "Inactivo"}
{user.isActive ? "Active" : "Inactive"}
</span>
</td>
<td className="px-4 py-3 text-right">
@@ -636,7 +636,7 @@ function SiteFormModal({
<div className="bg-white rounded-xl shadow-xl w-full max-w-md mx-4">
<div className="flex items-center justify-between p-4 border-b">
<h3 className="text-lg font-semibold text-primary-800">
{site ? "Editar Sede" : "Nueva Sede"}
{site ? "Edit Site" : "New Site"}
</h3>
<button onClick={onClose} className="text-primary-500 hover:text-primary-700">
<X className="h-5 w-5" />
@@ -644,24 +644,24 @@ function SiteFormModal({
</div>
<form onSubmit={handleSubmit} className="p-4 space-y-4">
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Nombre</label>
<label className="block text-sm font-medium text-primary-700 mb-1">Name</label>
<Input value={name} onChange={(e) => setName(e.target.value)} required />
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Dirección</label>
<label className="block text-sm font-medium text-primary-700 mb-1">Address</label>
<Input value={address} onChange={(e) => setAddress(e.target.value)} required />
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Teléfono</label>
<label className="block text-sm font-medium text-primary-700 mb-1">Phone</label>
<Input value={phone} onChange={(e) => setPhone(e.target.value)} />
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Hora apertura</label>
<label className="block text-sm font-medium text-primary-700 mb-1">Opening time</label>
<Input type="time" value={openTime} onChange={(e) => setOpenTime(e.target.value)} />
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Hora cierre</label>
<label className="block text-sm font-medium text-primary-700 mb-1">Closing time</label>
<Input type="time" value={closeTime} onChange={(e) => setCloseTime(e.target.value)} />
</div>
</div>
@@ -673,14 +673,14 @@ function SiteFormModal({
onChange={(e) => setIsActive(e.target.checked)}
className="rounded border-primary-300"
/>
<label htmlFor="isActive" className="text-sm text-primary-700">Sede activa</label>
<label htmlFor="isActive" className="text-sm text-primary-700">Site active</label>
</div>
<div className="flex gap-3 pt-4">
<Button type="button" variant="outline" onClick={onClose} className="flex-1">
Cancelar
Cancel
</Button>
<Button type="submit" disabled={loading} className="flex-1">
{loading ? "Guardando..." : "Guardar"}
{loading ? "Saving..." : "Save"}
</Button>
</div>
</form>
@@ -727,7 +727,7 @@ function CourtFormModal({
<div className="bg-white rounded-xl shadow-xl w-full max-w-md mx-4">
<div className="flex items-center justify-between p-4 border-b">
<h3 className="text-lg font-semibold text-primary-800">
{court ? "Editar Cancha" : "Nueva Cancha"}
{court ? "Edit Court" : "New Court"}
</h3>
<button onClick={onClose} className="text-primary-500 hover:text-primary-700">
<X className="h-5 w-5" />
@@ -735,11 +735,11 @@ function CourtFormModal({
</div>
<form onSubmit={handleSubmit} className="p-4 space-y-4">
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Nombre</label>
<Input value={name} onChange={(e) => setName(e.target.value)} placeholder="Cancha 1" required />
<label className="block text-sm font-medium text-primary-700 mb-1">Name</label>
<Input value={name} onChange={(e) => setName(e.target.value)} placeholder="Court 1" required />
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Sede</label>
<label className="block text-sm font-medium text-primary-700 mb-1">Site</label>
<select
value={siteId}
onChange={(e) => setSiteId(e.target.value)}
@@ -752,7 +752,7 @@ function CourtFormModal({
</select>
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Tipo</label>
<label className="block text-sm font-medium text-primary-700 mb-1">Type</label>
<select
value={type}
onChange={(e) => setType(e.target.value)}
@@ -760,12 +760,12 @@ function CourtFormModal({
>
<option value="indoor">Indoor</option>
<option value="outdoor">Outdoor</option>
<option value="covered">Techada</option>
<option value="covered">Covered</option>
</select>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Precio/hora</label>
<label className="block text-sm font-medium text-primary-700 mb-1">Price/hour</label>
<Input
type="number"
value={hourlyRate}
@@ -775,34 +775,34 @@ function CourtFormModal({
/>
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Precio hora pico</label>
<label className="block text-sm font-medium text-primary-700 mb-1">Peak hour price</label>
<Input
type="number"
value={peakHourlyRate}
onChange={(e) => setPeakHourlyRate(e.target.value)}
min="0"
placeholder="Opcional"
placeholder="Optional"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-primary-700 mb-1">Estado</label>
<label className="block text-sm font-medium text-primary-700 mb-1">Status</label>
<select
value={status}
onChange={(e) => setStatus(e.target.value)}
className="w-full rounded-lg border border-primary-200 bg-white px-3 py-2 text-sm"
>
<option value="active">Activa</option>
<option value="maintenance">Mantenimiento</option>
<option value="inactive">Inactiva</option>
<option value="active">Active</option>
<option value="maintenance">Maintenance</option>
<option value="inactive">Inactive</option>
</select>
</div>
<div className="flex gap-3 pt-4">
<Button type="button" variant="outline" onClick={onClose} className="flex-1">
Cancelar
Cancel
</Button>
<Button type="submit" disabled={loading} className="flex-1">
{loading ? "Guardando..." : "Guardar"}
{loading ? "Saving..." : "Save"}
</Button>
</div>
</form>