Add traslations

This commit is contained in:
Urtzi Alfaro
2025-12-18 20:12:32 +01:00
parent f10a2b92ea
commit acb3a40844
15 changed files with 726 additions and 228 deletions

View File

@@ -1,10 +1,12 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Plus, Store, MapPin, Trash2, Edit2, Building2, X } from 'lucide-react';
import { Plus, Store, MapPin, Trash2, Edit2, Building2, X, Phone, Mail, Clock, Tag, Globe } from 'lucide-react';
import Button from '../../../ui/Button/Button';
import Card from '../../../ui/Card/Card';
import { Modal, ModalHeader, ModalBody, ModalFooter } from '../../../ui/Modal';
import { Input } from '../../../ui/Input';
import { Select } from '../../../ui/Select';
import { AddressAutocomplete } from '../../../ui/AddressAutocomplete';
export interface ChildTenantSetupStepProps {
onUpdate?: (data: { childTenants: ChildTenant[]; canContinue: boolean }) => void;
@@ -22,6 +24,14 @@ export interface ChildTenant {
address: string;
postal_code: string;
location_code: string;
latitude?: number;
longitude?: number;
phone?: string;
email?: string;
business_type?: string;
business_model?: string;
timezone?: string;
metadata?: Record<string, any>;
}
export const ChildTenantsSetupStep: React.FC<ChildTenantSetupStepProps> = ({
@@ -42,6 +52,14 @@ export const ChildTenantsSetupStep: React.FC<ChildTenantSetupStepProps> = ({
address: '',
postal_code: '',
location_code: '',
latitude: undefined,
longitude: undefined,
phone: '',
email: '',
business_type: 'bakery',
business_model: 'retail_bakery',
timezone: 'Europe/Madrid',
metadata: {},
});
const [formErrors, setFormErrors] = useState<Record<string, string>>({});
@@ -67,11 +85,35 @@ export const ChildTenantsSetupStep: React.FC<ChildTenantSetupStepProps> = ({
}
if (!formData.postal_code?.trim()) {
errors.postal_code = 'El código postal es requerido';
} else if (!/^\d{5}$/.test(formData.postal_code)) {
errors.postal_code = 'El código postal debe tener exactamente 5 dígitos';
}
if (!formData.location_code?.trim()) {
errors.location_code = 'El código de ubicación es requerido';
} else if (formData.location_code.length > 10) {
errors.location_code = 'El código no debe exceder 10 caracteres';
} else if (!/^[A-Z0-9\-_.]+$/.test(formData.location_code)) {
errors.location_code = 'Solo se permiten letras mayúsculas, números y guiones/guiones bajos';
}
// Phone validation
if (formData.phone && formData.phone.trim()) {
const phone = formData.phone.replace(/[\s\-\(\)]/g, '');
const patterns = [
/^(\+34|0034|34)?[6789]\d{8}$/, // Mobile
/^(\+34|0034|34)?9\d{8}$/ // Landline
];
if (!patterns.some(pattern => pattern.test(phone))) {
errors.phone = 'Introduce un número de teléfono español válido';
}
}
// Email validation
if (formData.email && formData.email.trim()) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(formData.email)) {
errors.email = 'Introduce un correo electrónico válido';
}
}
setFormErrors(errors);
@@ -122,6 +164,14 @@ export const ChildTenantsSetupStep: React.FC<ChildTenantSetupStepProps> = ({
address: formData.address!,
postal_code: formData.postal_code!,
location_code: formData.location_code!.toUpperCase(),
latitude: formData.latitude,
longitude: formData.longitude,
phone: formData.phone || undefined,
email: formData.email || undefined,
business_type: formData.business_type || 'bakery',
business_model: formData.business_model || 'retail_bakery',
timezone: formData.timezone || 'Europe/Madrid',
metadata: formData.metadata || {},
};
if (editingTenant) {
@@ -236,9 +286,16 @@ export const ChildTenantsSetupStep: React.FC<ChildTenantSetupStepProps> = ({
<h3 className="font-semibold text-[var(--text-primary)]">
{tenant.name}
</h3>
<span className="text-xs text-[var(--text-tertiary)] font-mono">
{tenant.location_code}
</span>
<div className="flex gap-2">
<span className="text-xs text-[var(--text-tertiary)] font-mono">
{tenant.location_code}
</span>
{tenant.zone && (
<span className="text-xs text-[var(--text-tertiary)]">
{tenant.zone}
</span>
)}
</div>
</div>
</div>
<div className="flex gap-1">
@@ -336,7 +393,142 @@ export const ChildTenantsSetupStep: React.FC<ChildTenantSetupStepProps> = ({
</p>
</div>
{/* City and Zone */}
{/* Business Type */}
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
Tipo de Negocio
</label>
<Select
value={formData.business_type || 'bakery'}
onChange={(e) => setFormData({ ...formData, business_type: e.target.value })}
>
<option value="bakery">Panadería</option>
<option value="coffee_shop">Cafetería</option>
<option value="pastry_shop">Pastelería</option>
<option value="restaurant">Restaurante</option>
</Select>
</div>
{/* Business Model */}
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
Modelo de Negocio
</label>
<Select
value={formData.business_model || 'retail_bakery'}
onChange={(e) => setFormData({ ...formData, business_model: e.target.value })}
>
<option value="retail_bakery">Panadería Minorista</option>
<option value="central_baker_satellite">Obrador Central + Sucursales</option>
<option value="hybrid_bakery">Modelo Híbrido</option>
</Select>
</div>
{/* Contact Info */}
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
Teléfono
</label>
<div className="relative">
<Phone className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-[var(--text-secondary)]" />
<Input
value={formData.phone || ''}
onChange={(e) => setFormData({ ...formData, phone: e.target.value })}
placeholder="ej. +34 123 456 789"
error={formErrors.phone}
className="pl-10"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
Email
</label>
<div className="relative">
<Mail className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-[var(--text-secondary)]" />
<Input
value={formData.email || ''}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
placeholder="ej. contacto@panaderia.com"
error={formErrors.email}
className="pl-10"
/>
</div>
</div>
</div>
{/* Timezone */}
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
Zona Horaria
</label>
<div className="relative">
<Clock className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-[var(--text-secondary)]" />
<Select
value={formData.timezone || 'Europe/Madrid'}
onChange={(e) => setFormData({ ...formData, timezone: e.target.value })}
className="pl-10"
>
<option value="Europe/Madrid">Europe/Madrid (UTC+1/UTC+2)</option>
<option value="Europe/Paris">Europe/Paris (UTC+1/UTC+2)</option>
<option value="Europe/London">Europe/London (UTC+0/UTC+1)</option>
<option value="America/New_York">America/New_York (UTC-5/UTC-4)</option>
</Select>
</div>
</div>
{/* Zone */}
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
Zona / Barrio (opcional)
</label>
<Input
value={formData.zone || ''}
onChange={(e) => setFormData({ ...formData, zone: e.target.value })}
placeholder="ej. Salamanca, Chamberí, Centro"
/>
<p className="text-xs text-[var(--text-tertiary)] mt-1">
Zona o barrio específico dentro de la ciudad
</p>
</div>
{/* Address with Autocomplete */}
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
Dirección *
</label>
<AddressAutocomplete
value={formData.address || ''}
placeholder="ej. Calle de Serrano, 48"
onAddressSelect={(address) => {
setFormData(prev => ({
...prev,
address: address.display_name,
city: address.address.city || address.address.municipality || address.address.suburb || prev.city,
postal_code: address.address.postcode || prev.postal_code,
latitude: address.lat,
longitude: address.lon,
}));
}}
onCoordinatesChange={(lat, lon) => {
setFormData(prev => ({
...prev,
latitude: lat,
longitude: lon,
}));
}}
countryCode="es"
required
/>
{formErrors.address && (
<div className="mt-1 text-sm text-[var(--color-error)]">
{formErrors.address}
</div>
)}
</div>
{/* City and Postal Code */}
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
@@ -351,41 +543,17 @@ export const ChildTenantsSetupStep: React.FC<ChildTenantSetupStepProps> = ({
</div>
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
Zona / Barrio
Código Postal *
</label>
<Input
value={formData.zone || ''}
onChange={(e) => setFormData({ ...formData, zone: e.target.value })}
placeholder="ej. Salamanca"
value={formData.postal_code || ''}
onChange={(e) => setFormData({ ...formData, postal_code: e.target.value })}
placeholder="ej. 28001"
error={formErrors.postal_code}
maxLength={5}
/>
</div>
</div>
{/* Address */}
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
Dirección *
</label>
<Input
value={formData.address || ''}
onChange={(e) => setFormData({ ...formData, address: e.target.value })}
placeholder="ej. Calle de Serrano, 48"
error={formErrors.address}
/>
</div>
{/* Postal Code */}
<div>
<label className="block text-sm font-medium text-[var(--text-primary)] mb-1">
Código Postal *
</label>
<Input
value={formData.postal_code || ''}
onChange={(e) => setFormData({ ...formData, postal_code: e.target.value })}
placeholder="ej. 28001"
error={formErrors.postal_code}
/>
</div>
</div>
</ModalBody>
<ModalFooter justify="end">