feat: translate API error messages to English

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ivan
2026-03-01 21:24:54 +00:00
parent 3aeda8c2fb
commit d3419a8cc5
9 changed files with 84 additions and 84 deletions

View File

@@ -12,7 +12,7 @@ interface RouteContext {
// Validation schema for payment
const paymentSchema = z.object({
paymentType: z.enum(['CASH', 'CARD', 'TRANSFER', 'MEMBERSHIP', 'FREE']),
amount: z.number().positive('El monto debe ser mayor a 0').optional(),
amount: z.number().positive('Amount must be greater than 0').optional(),
reference: z.string().max(100).optional(),
notes: z.string().max(500).optional(),
cashRegisterId: z.string().uuid().optional(),
@@ -28,7 +28,7 @@ export async function POST(
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -51,7 +51,7 @@ export async function POST(
if (!existingBooking) {
return NextResponse.json(
{ error: 'Reserva no encontrada' },
{ error: 'Booking not found' },
{ status: 404 }
);
}
@@ -59,7 +59,7 @@ export async function POST(
// If user is SITE_ADMIN, verify they have access to this site
if (session.user.role === 'SITE_ADMIN' && session.user.siteId !== existingBooking.siteId) {
return NextResponse.json(
{ error: 'No tiene permiso para procesar pagos en esta reserva' },
{ error: 'You do not have permission to process payments for this booking' },
{ status: 403 }
);
}
@@ -67,7 +67,7 @@ export async function POST(
// Check if booking is already cancelled
if (existingBooking.status === 'CANCELLED') {
return NextResponse.json(
{ error: 'No se puede procesar el pago de una reserva cancelada' },
{ error: 'Cannot process payment for a cancelled booking' },
{ status: 400 }
);
}
@@ -81,7 +81,7 @@ export async function POST(
if (totalPaid >= totalPrice) {
return NextResponse.json(
{ error: 'La reserva ya está completamente pagada' },
{ error: 'The booking is already fully paid' },
{ status: 400 }
);
}
@@ -93,7 +93,7 @@ export async function POST(
if (!validationResult.success) {
return NextResponse.json(
{
error: 'Datos de pago inválidos',
error: 'Invalid payment data',
details: validationResult.error.flatten().fieldErrors,
},
{ status: 400 }
@@ -108,7 +108,7 @@ export async function POST(
if (paymentAmount <= 0) {
return NextResponse.json(
{ error: 'El monto del pago debe ser mayor a 0' },
{ error: 'Payment amount must be greater than 0' },
{ status: 400 }
);
}
@@ -125,7 +125,7 @@ export async function POST(
if (!cashRegister) {
return NextResponse.json(
{ error: 'Caja registradora no encontrada o no está abierta' },
{ error: 'Cash register not found or is not open' },
{ status: 400 }
);
}
@@ -211,8 +211,8 @@ export async function POST(
return NextResponse.json({
message: result.isFullyPaid
? 'Pago completado. La reserva ha sido confirmada.'
: 'Pago parcial registrado exitosamente.',
? 'Payment completed. The booking has been confirmed.'
: 'Partial payment recorded successfully.',
booking: result.booking,
payment: result.payment,
remainingAmount: Math.max(0, totalPrice - (totalPaid + paymentAmount)),
@@ -220,7 +220,7 @@ export async function POST(
} catch (error) {
console.error('Error processing payment:', error);
return NextResponse.json(
{ error: 'Error al procesar el pago' },
{ error: 'Error processing payment' },
{ status: 500 }
);
}

View File

@@ -26,7 +26,7 @@ export async function GET(
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -99,7 +99,7 @@ export async function GET(
if (!booking) {
return NextResponse.json(
{ error: 'Reserva no encontrada' },
{ error: 'Booking not found' },
{ status: 404 }
);
}
@@ -108,7 +108,7 @@ export async function GET(
} catch (error) {
console.error('Error fetching booking:', error);
return NextResponse.json(
{ error: 'Error al obtener la reserva' },
{ error: 'Error fetching booking' },
{ status: 500 }
);
}
@@ -124,7 +124,7 @@ export async function PUT(
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -146,7 +146,7 @@ export async function PUT(
if (!existingBooking) {
return NextResponse.json(
{ error: 'Reserva no encontrada' },
{ error: 'Booking not found' },
{ status: 404 }
);
}
@@ -154,7 +154,7 @@ export async function PUT(
// If user is SITE_ADMIN, verify they have access to this site
if (session.user.role === 'SITE_ADMIN' && session.user.siteId !== existingBooking.siteId) {
return NextResponse.json(
{ error: 'No tiene permiso para modificar esta reserva' },
{ error: 'You do not have permission to modify this booking' },
{ status: 403 }
);
}
@@ -166,7 +166,7 @@ export async function PUT(
if (!validationResult.success) {
return NextResponse.json(
{
error: 'Datos de actualización inválidos',
error: 'Invalid update data',
details: validationResult.error.flatten().fieldErrors,
},
{ status: 400 }
@@ -239,7 +239,7 @@ export async function PUT(
} catch (error) {
console.error('Error updating booking:', error);
return NextResponse.json(
{ error: 'Error al actualizar la reserva' },
{ error: 'Error updating booking' },
{ status: 500 }
);
}
@@ -255,7 +255,7 @@ export async function DELETE(
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -277,7 +277,7 @@ export async function DELETE(
if (!existingBooking) {
return NextResponse.json(
{ error: 'Reserva no encontrada' },
{ error: 'Booking not found' },
{ status: 404 }
);
}
@@ -285,7 +285,7 @@ export async function DELETE(
// If user is SITE_ADMIN, verify they have access to this site
if (session.user.role === 'SITE_ADMIN' && session.user.siteId !== existingBooking.siteId) {
return NextResponse.json(
{ error: 'No tiene permiso para cancelar esta reserva' },
{ error: 'You do not have permission to cancel this booking' },
{ status: 403 }
);
}
@@ -294,7 +294,7 @@ export async function DELETE(
const hasPayments = existingBooking.payments.length > 0;
// Parse optional cancel reason from query params or body
let cancelReason = 'Cancelada por el administrador';
let cancelReason = 'Cancelled by administrator';
try {
const body = await request.json();
if (body.cancelReason) {
@@ -316,9 +316,9 @@ export async function DELETE(
});
return NextResponse.json({
message: 'Reserva cancelada exitosamente',
message: 'Booking cancelled successfully',
booking,
note: 'La reserva tiene pagos asociados, por lo que fue cancelada en lugar de eliminada',
note: 'The booking has associated payments, so it was cancelled instead of deleted',
});
} else {
// If no payments, allow hard delete for pending bookings only
@@ -328,7 +328,7 @@ export async function DELETE(
});
return NextResponse.json({
message: 'Reserva eliminada exitosamente',
message: 'Booking deleted successfully',
});
} else {
// For non-pending bookings, soft delete
@@ -342,7 +342,7 @@ export async function DELETE(
});
return NextResponse.json({
message: 'Reserva cancelada exitosamente',
message: 'Booking cancelled successfully',
booking,
});
}
@@ -350,7 +350,7 @@ export async function DELETE(
} catch (error) {
console.error('Error deleting booking:', error);
return NextResponse.json(
{ error: 'Error al cancelar la reserva' },
{ error: 'Error cancelling booking' },
{ status: 500 }
);
}

View File

@@ -20,7 +20,7 @@ export async function GET(request: NextRequest) {
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -138,7 +138,7 @@ export async function GET(request: NextRequest) {
} catch (error) {
console.error('Error fetching bookings:', error);
return NextResponse.json(
{ error: 'Error al obtener las reservas' },
{ error: 'Error fetching bookings' },
{ status: 500 }
);
}
@@ -151,7 +151,7 @@ export async function POST(request: NextRequest) {
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -163,7 +163,7 @@ export async function POST(request: NextRequest) {
if (!validationResult.success) {
return NextResponse.json(
{
error: 'Datos de reserva inválidos',
error: 'Invalid booking data',
details: validationResult.error.flatten().fieldErrors,
},
{ status: 400 }
@@ -193,14 +193,14 @@ export async function POST(request: NextRequest) {
if (!court) {
return NextResponse.json(
{ error: 'Cancha no encontrada o no pertenece a su organización' },
{ error: 'Court not found or does not belong to your organization' },
{ status: 404 }
);
}
if (court.status !== 'AVAILABLE' || !court.isActive) {
return NextResponse.json(
{ error: 'La cancha no está disponible para reservas' },
{ error: 'The court is not available for bookings' },
{ status: 400 }
);
}
@@ -232,7 +232,7 @@ export async function POST(request: NextRequest) {
if (!client) {
return NextResponse.json(
{ error: 'Cliente no encontrado o no pertenece a su organización' },
{ error: 'Client not found or does not belong to your organization' },
{ status: 404 }
);
}
@@ -269,7 +269,7 @@ export async function POST(request: NextRequest) {
if (existingBooking) {
return NextResponse.json(
{ error: 'Ya existe una reserva en ese horario. Por favor, seleccione otro horario.' },
{ error: 'A booking already exists for that time slot. Please select another time.' },
{ status: 409 }
);
}
@@ -391,7 +391,7 @@ export async function POST(request: NextRequest) {
} catch (error) {
console.error('Error creating booking:', error);
return NextResponse.json(
{ error: 'Error al crear la reserva' },
{ error: 'Error creating booking' },
{ status: 500 }
);
}

View File

@@ -10,11 +10,11 @@ interface RouteContext {
// Validation schema for updating client
const updateClientSchema = z.object({
firstName: z.string().min(1, 'El nombre es requerido').optional(),
lastName: z.string().min(1, 'El apellido es requerido').optional(),
email: z.string().email('Email invalido').nullable().optional(),
firstName: z.string().min(1, 'First name is required').optional(),
lastName: z.string().min(1, 'Last name is required').optional(),
email: z.string().email('Invalid email').nullable().optional(),
phone: z.string().nullable().optional(),
avatar: z.string().url('URL invalida').nullable().optional(),
avatar: z.string().url('Invalid URL').nullable().optional(),
dateOfBirth: z.string().nullable().optional(),
address: z.string().nullable().optional(),
notes: z.string().nullable().optional(),
@@ -32,7 +32,7 @@ export async function GET(
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -79,7 +79,7 @@ export async function GET(
if (!client) {
return NextResponse.json(
{ error: 'Cliente no encontrado' },
{ error: 'Client not found' },
{ status: 404 }
);
}
@@ -122,7 +122,7 @@ export async function GET(
} catch (error) {
console.error('Error fetching client:', error);
return NextResponse.json(
{ error: 'Error al obtener el cliente' },
{ error: 'Error fetching client' },
{ status: 500 }
);
}
@@ -138,7 +138,7 @@ export async function PUT(
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -155,7 +155,7 @@ export async function PUT(
if (!existingClient) {
return NextResponse.json(
{ error: 'Cliente no encontrado' },
{ error: 'Client not found' },
{ status: 404 }
);
}
@@ -167,7 +167,7 @@ export async function PUT(
if (!validationResult.success) {
return NextResponse.json(
{
error: 'Datos de actualizacion invalidos',
error: 'Invalid update data',
details: validationResult.error.flatten().fieldErrors,
},
{ status: 400 }
@@ -201,7 +201,7 @@ export async function PUT(
if (emailExists) {
return NextResponse.json(
{ error: 'Ya existe un cliente con este email' },
{ error: 'A client with this email already exists' },
{ status: 409 }
);
}
@@ -262,13 +262,13 @@ export async function PUT(
// Check for unique constraint violation
if (error instanceof Error && error.message.includes('Unique constraint')) {
return NextResponse.json(
{ error: 'Ya existe un cliente con este email o DNI' },
{ error: 'A client with this email or ID number already exists' },
{ status: 409 }
);
}
return NextResponse.json(
{ error: 'Error al actualizar el cliente' },
{ error: 'Error updating client' },
{ status: 500 }
);
}
@@ -284,7 +284,7 @@ export async function DELETE(
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -318,7 +318,7 @@ export async function DELETE(
if (!existingClient) {
return NextResponse.json(
{ error: 'Cliente no encontrado' },
{ error: 'Client not found' },
{ status: 404 }
);
}
@@ -327,7 +327,7 @@ export async function DELETE(
if (existingClient.memberships.length > 0) {
return NextResponse.json(
{
error: 'No se puede desactivar un cliente con membresia activa',
error: 'Cannot deactivate a client with an active membership',
details: {
activeMemberships: existingClient.memberships.length,
},
@@ -340,7 +340,7 @@ export async function DELETE(
if (existingClient.bookings.length > 0) {
return NextResponse.json(
{
error: 'No se puede desactivar un cliente con reservas pendientes',
error: 'Cannot deactivate a client with pending bookings',
details: {
pendingBookings: existingClient.bookings.length,
},
@@ -364,13 +364,13 @@ export async function DELETE(
});
return NextResponse.json({
message: 'Cliente desactivado exitosamente',
message: 'Client deactivated successfully',
client,
});
} catch (error) {
console.error('Error deleting client:', error);
return NextResponse.json(
{ error: 'Error al desactivar el cliente' },
{ error: 'Error deactivating client' },
{ status: 500 }
);
}

View File

@@ -11,7 +11,7 @@ export async function GET(request: NextRequest) {
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -123,7 +123,7 @@ export async function GET(request: NextRequest) {
} catch (error) {
console.error('Error fetching clients:', error);
return NextResponse.json(
{ error: 'Error al obtener los clientes' },
{ error: 'Error fetching clients' },
{ status: 500 }
);
}
@@ -136,7 +136,7 @@ export async function POST(request: NextRequest) {
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -148,7 +148,7 @@ export async function POST(request: NextRequest) {
if (!validationResult.success) {
return NextResponse.json(
{
error: 'Datos del cliente inválidos',
error: 'Invalid client data',
details: validationResult.error.flatten().fieldErrors,
},
{ status: 400 }
@@ -181,7 +181,7 @@ export async function POST(request: NextRequest) {
if (existingClient) {
return NextResponse.json(
{ error: 'Ya existe un cliente con este correo electrónico en su organización' },
{ error: 'A client with this email already exists in your organization' },
{ status: 409 }
);
}
@@ -224,13 +224,13 @@ export async function POST(request: NextRequest) {
// Check for unique constraint violation
if (error instanceof Error && error.message.includes('Unique constraint')) {
return NextResponse.json(
{ error: 'Ya existe un cliente con este correo electrónico o DNI' },
{ error: 'A client with this email or ID number already exists' },
{ status: 409 }
);
}
return NextResponse.json(
{ error: 'Error al crear el cliente' },
{ error: 'Error creating client' },
{ status: 500 }
);
}

View File

@@ -10,7 +10,7 @@ export async function GET(request: NextRequest) {
if (!session?.user) {
return NextResponse.json(
{ error: 'No autorizado' },
{ error: 'Unauthorized' },
{ status: 401 }
);
}
@@ -315,7 +315,7 @@ export async function GET(request: NextRequest) {
} catch (error) {
console.error('Error fetching dashboard stats:', error);
return NextResponse.json(
{ error: 'Error al obtener estadísticas del dashboard' },
{ error: 'Error fetching dashboard statistics' },
{ status: 500 }
);
}

View File

@@ -35,14 +35,14 @@ export async function GET(
});
if (!site) {
return NextResponse.json({ error: 'Sede no encontrada' }, { status: 404 });
return NextResponse.json({ error: 'Site not found' }, { status: 404 });
}
return NextResponse.json({ data: site });
} catch (error) {
console.error('Error fetching site:', error);
return NextResponse.json(
{ error: 'Error al obtener sede' },
{ error: 'Error fetching site' },
{ status: 500 }
);
}
@@ -61,7 +61,7 @@ export async function PUT(
}
if (!['super_admin', 'site_admin'].includes(session.user.role)) {
return NextResponse.json({ error: 'Sin permisos' }, { status: 403 });
return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });
}
const body = await request.json();
@@ -76,7 +76,7 @@ export async function PUT(
});
if (!existingSite) {
return NextResponse.json({ error: 'Sede no encontrada' }, { status: 404 });
return NextResponse.json({ error: 'Site not found' }, { status: 404 });
}
const updateData: any = {};
@@ -102,7 +102,7 @@ export async function PUT(
} catch (error) {
console.error('Error updating site:', error);
return NextResponse.json(
{ error: 'Error al actualizar sede' },
{ error: 'Error updating site' },
{ status: 500 }
);
}
@@ -121,7 +121,7 @@ export async function DELETE(
}
if (session.user.role !== 'super_admin') {
return NextResponse.json({ error: 'Sin permisos' }, { status: 403 });
return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });
}
// Verify site belongs to organization
@@ -133,7 +133,7 @@ export async function DELETE(
});
if (!existingSite) {
return NextResponse.json({ error: 'Sede no encontrada' }, { status: 404 });
return NextResponse.json({ error: 'Site not found' }, { status: 404 });
}
// Soft delete
@@ -146,7 +146,7 @@ export async function DELETE(
} catch (error) {
console.error('Error deleting site:', error);
return NextResponse.json(
{ error: 'Error al eliminar sede' },
{ error: 'Error deleting site' },
{ status: 500 }
);
}

View File

@@ -80,7 +80,7 @@ export async function POST(request: NextRequest) {
}
if (!['super_admin', 'site_admin'].includes(session.user.role)) {
return NextResponse.json({ error: 'Sin permisos' }, { status: 403 });
return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });
}
const body = await request.json();
@@ -88,7 +88,7 @@ export async function POST(request: NextRequest) {
if (!name || !address) {
return NextResponse.json(
{ error: 'Nombre y dirección son requeridos' },
{ error: 'Name and address are required' },
{ status: 400 }
);
}
@@ -116,7 +116,7 @@ export async function POST(request: NextRequest) {
} catch (error) {
console.error('Error creating site:', error);
return NextResponse.json(
{ error: 'Error al crear sede' },
{ error: 'Error creating site' },
{ status: 500 }
);
}

View File

@@ -8,7 +8,7 @@ export async function GET(request: NextRequest) {
const session = await getServerSession(authOptions);
if (!session?.user) {
return NextResponse.json({ error: "No autorizado" }, { status: 401 });
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const users = await db.user.findMany({
@@ -45,7 +45,7 @@ export async function GET(request: NextRequest) {
} catch (error) {
console.error("Error fetching users:", error);
return NextResponse.json(
{ error: "Error al obtener usuarios" },
{ error: "Error fetching users" },
{ status: 500 }
);
}
@@ -56,12 +56,12 @@ export async function POST(request: NextRequest) {
const session = await getServerSession(authOptions);
if (!session?.user) {
return NextResponse.json({ error: "No autorizado" }, { status: 401 });
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// Only super_admin and site_admin can create users
if (!["super_admin", "site_admin"].includes(session.user.role)) {
return NextResponse.json({ error: "Sin permisos" }, { status: 403 });
return NextResponse.json({ error: "Insufficient permissions" }, { status: 403 });
}
const body = await request.json();
@@ -69,7 +69,7 @@ export async function POST(request: NextRequest) {
if (!email || !password || !firstName || !lastName || !role) {
return NextResponse.json(
{ error: "Faltan campos requeridos" },
{ error: "Missing required fields" },
{ status: 400 }
);
}
@@ -84,7 +84,7 @@ export async function POST(request: NextRequest) {
if (existingUser) {
return NextResponse.json(
{ error: "El email ya está registrado" },
{ error: "This email is already registered" },
{ status: 400 }
);
}
@@ -129,7 +129,7 @@ export async function POST(request: NextRequest) {
} catch (error) {
console.error("Error creating user:", error);
return NextResponse.json(
{ error: "Error al crear usuario" },
{ error: "Error creating user" },
{ status: 500 }
);
}