Add new frontend - fix 9

This commit is contained in:
Urtzi Alfaro
2025-07-22 17:01:12 +02:00
parent 5959eb6e15
commit 06cbe3f4e8
16 changed files with 2048 additions and 166 deletions

View File

@@ -1,5 +1,5 @@
// frontend/src/pages/onboarding.tsx - ORIGINAL DESIGN WITH AUTH FIXES ONLY
import React, { useState, useEffect, useCallback } from 'react';
import React, { useState, useRef, useEffect, useCallback } from 'react';
import { useRouter } from 'next/router';
import Head from 'next/head';
import {
@@ -14,7 +14,6 @@ import {
import { SalesUploader } from '../components/data/SalesUploader';
import { TrainingProgressCard } from '../components/training/TrainingProgressCard';
import { useAuth } from '../contexts/AuthContext';
import { RegisterData } from '../api/services/authService';
import { dataApi, TrainingRequest, TrainingTask } from '../api/services/api';
import { NotificationToast } from '../components/common/NotificationToast';
import { Product, defaultProducts } from '../components/common/ProductSelector';
@@ -76,6 +75,76 @@ const OnboardingPage: React.FC = () => {
const [errors, setErrors] = useState<Partial<OnboardingFormData>>({});
const addressInputRef = useRef<HTMLInputElement>(null); // Ref for the address input
let autocompleteTimeout: NodeJS.Timeout | null = null; // For debouncing API calls
const handleAddressInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const query = e.target.value;
setFormData(prevData => ({ ...prevData, address: query })); // Update address immediately
if (autocompleteTimeout) {
clearTimeout(autocompleteTimeout);
}
if (query.length < 3) { // Only search if at least 3 characters are typed
return;
}
autocompleteTimeout = setTimeout(async () => {
try {
// Construct the Nominatim API URL
// Make sure NOMINATIM_PORT matches your .env file, default is 8080
const gatewayNominatimApiUrl = `/api/v1/nominatim/search`; // Relative path if frontend serves from gateway's domain/port
const params = new URLSearchParams({
q: query,
format: 'json',
addressdetails: '1', // Request detailed address components
limit: '5', // Number of results to return
'accept-language': 'es', // Request results in Spanish
countrycodes: 'es' // Restrict search to Spain
});
const response = await fetch(`${gatewayNominatimApiUrl}?${params.toString()}`);
const data = await response.json();
// Process Nominatim results and update form data
if (data && data.length > 0) {
// Take the first result or let the user choose from suggestions if you implement a dropdown
const place = data[0]; // For simplicity, take the first result
let address = '';
let city = '';
let postal_code = '';
// Nominatim's 'address' object contains components
if (place.address) {
const addr = place.address;
// Reconstruct the address in a common format
const street = addr.road || '';
const houseNumber = addr.house_number || '';
address = `${street} ${houseNumber}`.trim();
city = addr.city || addr.town || addr.village || '';
postal_code = addr.postcode || '';
}
setFormData(prevData => ({
...prevData,
address: address || query, // Use parsed address or fall back to user input
city: city || prevData.city,
postal_code: postal_code || prevData.postal_code,
}));
}
} catch (error) {
console.error('Error fetching Nominatim suggestions:', error);
// Optionally show an error notification
// showNotification('error', 'Error de Autocompletado', 'No se pudieron cargar las sugerencias de dirección.');
}
}, 500); // Debounce time: 500ms
}, []); // Re-create if dependencies change, none for now
useEffect(() => {
// If user is already authenticated and on onboarding, redirect to dashboard
if (user && currentStep === 1) {
@@ -106,7 +175,7 @@ const OnboardingPage: React.FC = () => {
setLoading(true);
try {
const registerData: RegisterData = {
const registerData: dataApi.auth.RegisterData = {
full_name: formData.full_name,
email: formData.email,
password: formData.password,
@@ -287,9 +356,11 @@ const OnboardingPage: React.FC = () => {
<input
type="text"
id="address"
ref={addressInputRef}
className="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:ring-pania-blue focus:border-pania-blue sm:text-sm"
value={formData.address}
onChange={(e) => setFormData({ ...formData, address: e.target.value })}
// Use the new handler for changes to trigger autocomplete
onChange={handleAddressInputChange}
required
/>
{errors.address && <p className="mt-1 text-sm text-red-600">{errors.address}</p>}