diff --git a/frontend/src/api/services/dataService.ts b/frontend/src/api/services/dataService.ts index 6578f38b..9ee68f27 100644 --- a/frontend/src/api/services/dataService.ts +++ b/frontend/src/api/services/dataService.ts @@ -82,7 +82,7 @@ export class DataService { */ async validateSalesData(file: File): Promise { const response = await apiClient.upload>( - '/api/v1/data/validate-sales', + '/api/v1/sales/import/validate-sales', file ); return response.data!; diff --git a/frontend/src/api/services/tenantService.ts b/frontend/src/api/services/tenantService.ts index 00723520..5a93ff68 100644 --- a/frontend/src/api/services/tenantService.ts +++ b/frontend/src/api/services/tenantService.ts @@ -6,14 +6,11 @@ import { export interface TenantCreate { name: string; - email: string; - phone: string; address: string; - latitude?: number; - longitude?: number; - business_type: 'individual_bakery' | 'central_workshop'; - subscription_plan?: string; - settings?: Record; + city?: string; // Optional with default "Madrid" + postal_code: string; // Required, must match pattern ^\d{5}$ + phone: string; // Required, validated for Spanish format + business_type?: string; // Optional with default "bakery", must be one of: ['bakery', 'coffee_shop', 'pastry_shop', 'restaurant'] } export interface TenantUpdate extends Partial { @@ -66,13 +63,20 @@ export interface TenantStats { subscription_expires: string; } -export interface TenantUser { +export interface TenantInfo { id: string; - email: string; - full_name: string; - role: string; + name: string; + subdomain?: string; + business_type: string; + address: string; + city: string; + postal_code: string; + phone?: string; is_active: boolean; - last_login: string | null; + subscription_tier: string; + model_trained: boolean; + last_training_date?: string; + owner_id: string; created_at: string; } diff --git a/frontend/src/pages/onboarding.tsx b/frontend/src/pages/onboarding.tsx index 9b3748e1..02d7a804 100644 --- a/frontend/src/pages/onboarding.tsx +++ b/frontend/src/pages/onboarding.tsx @@ -37,21 +37,15 @@ const OnboardingPage = () => { password: '', confirm_password: '', - // Bakery/Tenant fields - matching TenantCreate interface + // Bakery/Tenant fields - matching ACTUAL BakeryRegistration schema bakery_name: '', address: '', - city: 'Madrid', - postal_code: '', - phone: '', // Will use default if empty - business_type: 'individual_bakery' as 'individual_bakery' | 'central_workshop', + city: 'Madrid', // Default as per backend + postal_code: '', // Required - must match regex ^\d{5}$ + phone: '', // Will use default if empty, validated for Spanish format + business_type: 'bakery', // Must be one of: ['bakery', 'coffee_shop', 'pastry_shop', 'restaurant'] - // Optional fields - latitude: undefined as number | undefined, - longitude: undefined as number | undefined, - subscription_plan: undefined as string | undefined, - settings: undefined as Record | undefined, - - // Additional form fields + // Additional form fields (not part of BakeryRegistration) has_nearby_schools: false, has_nearby_offices: false, selected_products: ['Pan de molde', 'Croissants', 'Magdalenas'], @@ -150,17 +144,24 @@ const OnboardingPage = () => { case 2: if (!formData.bakery_name.trim()) newErrors.bakery_name = 'Nombre de panadería requerido'; if (!formData.address.trim()) newErrors.address = 'Dirección requerida'; - if (!formData.postal_code.trim()) newErrors.postal_code = 'Código postal requerido'; - if (!formData.email.trim()) newErrors.email = 'Email requerido'; // Email is required for TenantCreate + if (!formData.postal_code.trim()) { + newErrors.postal_code = 'Código postal requerido'; + } else if (!/^\d{5}$/.test(formData.postal_code)) { + newErrors.postal_code = 'Código postal debe tener 5 dígitos'; + } - // Validate business_type is one of the allowed values - if (!['individual_bakery', 'central_workshop'].includes(formData.business_type)) { + // Validate business_type matches backend expectations + const validBusinessTypes = ['bakery', 'coffee_shop', 'pastry_shop', 'restaurant']; + if (!validBusinessTypes.includes(formData.business_type)) { newErrors.business_type = 'Tipo de negocio inválido'; } - // Optional: Validate phone format if provided (will use default if empty) - if (formData.phone && !formData.phone.match(/^(\+34|34)?[67][0-9]{8}$/)) { - newErrors.phone = 'Formato de teléfono inválido'; + // Optional: Validate phone format if provided (Spanish format as per backend validator) + if (formData.phone && formData.phone.trim()) { + const phoneRegex = /^(\+34|0034|34)?[6789]\d{8}$/; + if (!phoneRegex.test(formData.phone.replace(/[\s\-\(\)]/g, ''))) { + newErrors.phone = 'Formato de teléfono español inválido'; + } } break; case 3: @@ -192,16 +193,12 @@ const OnboardingPage = () => { } else if (currentStep === 2) { // Register bakery using real tenant service with proper TenantCreate interface const bakeryData: TenantCreate = { - name: formData.bakery_name, - email: formData.email, // Required field from TenantCreate interface - phone: formData.phone || '+34600000000', // Required field with default - address: formData.address, - business_type: formData.business_type as 'individual_bakery' | 'central_workshop', - // Optional fields that could be added based on form data - latitude: formData.latitude, // if you have coordinates - longitude: formData.longitude, // if you have coordinates - subscription_plan: formData.subscription_plan, // if selected - settings: formData.settings // if any initial settings + name: formData.bakery_name, + address: formData.address, + city: formData.city || 'Madrid', // Default value as per backend schema + postal_code: formData.postal_code, // Required field + phone: formData.phone || '+34600000000', // Required field with default + business_type: formData.business_type || 'bakery' // Must be one of: ['bakery', 'coffee_shop', 'pastry_shop', 'restaurant'] }; // The response will be typed as TenantInfo