diff --git a/packages/frontend/index.html b/packages/frontend/index.html index c20fbd3..4edd7ca 100644 --- a/packages/frontend/index.html +++ b/packages/frontend/index.html @@ -1,13 +1,18 @@ - + - frontend + + + Celebrity Catalog
- + \ No newline at end of file diff --git a/packages/frontend/src/App.css b/packages/frontend/src/App.css index b9d355d..e69de29 100644 --- a/packages/frontend/src/App.css +++ b/packages/frontend/src/App.css @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/packages/frontend/src/App.jsx b/packages/frontend/src/App.jsx index 77aaa87..4630612 100644 --- a/packages/frontend/src/App.jsx +++ b/packages/frontend/src/App.jsx @@ -3,19 +3,19 @@ import { Routes, Route } from 'react-router-dom'; import CelebrityList from './components/CelebrityList'; import CelebrityProfile from './components/CelebrityProfile'; -import CelebrityCreate from './components/CelebrityCreate'; // <-- 1. Importa il nuovo componente -import './App.css'; +import CelebrityCreate from './components/CelebrityCreate'; +// 3. Rimosso App.css function App() { return ( -
+ // 4. Aggiunto il container principale di Pico +
} /> - {/* 2. Riattiva questa rotta e puntala al nuovo componente */} } /> } /> -
+ ); } diff --git a/packages/frontend/src/components/CelebrityCreate.css b/packages/frontend/src/components/CelebrityCreate.css index 9384dee..e69de29 100644 --- a/packages/frontend/src/components/CelebrityCreate.css +++ b/packages/frontend/src/components/CelebrityCreate.css @@ -1,110 +0,0 @@ -/* packages/frontend/src/components/CelebrityCreate.css */ - -.create-form-container { - width: 100%; - max-width: 900px; - margin: 2rem auto; - padding: 2rem; - background-color: #2c2c2c; - border-radius: 8px; - border: 1px solid #444; -} - -.create-form-container h2 { - margin-top: 0; - color: #d4b996; -} - -.form-section { - margin-bottom: 2rem; - border-top: 1px solid #444; - padding-top: 1.5rem; -} - -.form-section h3 { - margin-top: 0; - margin-bottom: 1rem; -} - -.form-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 1.5rem; -} - -.form-group { - display: flex; - flex-direction: column; -} - -.form-group label { - margin-bottom: 0.5rem; - font-size: 0.9rem; - color: #ccc; -} - -.form-group input, -.form-group select, -.form-group textarea { - padding: 0.75rem; - border-radius: 4px; - border: 1px solid #555; - background-color: #1e1e1e; - color: #f0f0f0; - font-size: 1rem; -} - -.form-group input:focus, -.form-group select:focus { - outline: none; - border-color: #646cff; - box-shadow: 0 0 0 2px rgba(100, 108, 255, 0.5); -} - -.form-group-checkbox { - margin-top: 1rem; - display: flex; - align-items: center; - gap: 0.75rem; -} - -.form-group-checkbox input { - width: 18px; - height: 18px; -} - -.form-actions { - display: flex; - justify-content: flex-end; - gap: 1rem; - margin-top: 2rem; - border-top: 1px solid #444; - padding-top: 1.5rem; -} - -.button-save { - background-color: #28a745; -} -.button-save:hover { - background-color: #218838; - border-color: #1e7e34; -} -.button-save:disabled { - background-color: #555; - cursor: not-allowed; -} - -.button-cancel { - background-color: #6c757d; - padding: 0.6em 1.2em; /* Emula lo stile del bottone */ - border-radius: 8px; - font-weight: 500; - text-decoration: none; - color: white; - display: inline-block; - border: 1px solid transparent; -} -.button-cancel:hover { - background-color: #5a6268; - border-color: #545b62; -} \ No newline at end of file diff --git a/packages/frontend/src/components/CelebrityCreate.jsx b/packages/frontend/src/components/CelebrityCreate.jsx index 7690e02..59febbe 100644 --- a/packages/frontend/src/components/CelebrityCreate.jsx +++ b/packages/frontend/src/components/CelebrityCreate.jsx @@ -1,11 +1,7 @@ -// packages/frontend/src/components/CelebrityCreate.jsx - -import React, { useState } from 'react'; // <-- ECCO LA CORREZIONE +import React, { useState } from 'react'; import { useNavigate, Link } from 'react-router-dom'; import { createCelebrity } from '../services/api'; -import './CelebrityCreate.css'; // Stile dedicato per questo form -// Stato iniziale pulito per il form const initialFormState = { name: '', gender: 'female', @@ -47,130 +43,92 @@ function CelebrityCreate() { setError(null); setIsSubmitting(true); - // "Pulisce" i dati: converte le stringhe vuote dei campi numerici in `null` - // per evitare errori di validazione nel backend. const payload = { ...formData }; Object.keys(payload).forEach(key => { - if (payload[key] === '') { - payload[key] = null; - } + if (payload[key] === '') payload[key] = null; }); try { await createCelebrity(payload); - alert('Celebrità creata con successo!'); - navigate('/'); // Torna alla lista dopo la creazione + navigate('/'); } catch (err) { setError(err.message); } finally { - setIsSubmitting(false); + setIsSubmitting(false); } }; return ( -
+

Aggiungi Nuova Celebrità

Compila i campi sottostanti per aggiungere un nuovo profilo al catalogo.

-
-

Anagrafica

-
-
- - +
+ Anagrafica +
+ +
-
- - +
+ + +
-
- - -
-
- - -
-
- - -
-
-
+ -
-

Misure e Aspetto

-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
+
+ Misure e Aspetto +
+ + +
-
+
+ + + + +
+ -
-

Reggiseno

-
-
- - -
-
- - -
-
- +
+ Reggiseno +
+ + +
+
-
- +
-
+ Seno Naturale? + + - {error &&

Errore: {error}

} + {error &&

Errore: {error}

} -
- Annulla - +
+ Annulla +
-
+
); } diff --git a/packages/frontend/src/components/CelebrityList.jsx b/packages/frontend/src/components/CelebrityList.jsx index ab89056..de360ae 100644 --- a/packages/frontend/src/components/CelebrityList.jsx +++ b/packages/frontend/src/components/CelebrityList.jsx @@ -24,11 +24,10 @@ function CelebrityList() { } }; - const handleDelete = async (id) => { - if (window.confirm('Sei sicuro di voler eliminare questa celebrità?')) { + const handleDelete = async (id, name) => { + if (window.confirm(`Sei sicuro di voler eliminare ${name}?`)) { try { await deleteCelebrity(id); - // Rimuovi la celebrità dalla lista senza ricaricare i dati setCelebrities(celebrities.filter((c) => c.id !== id)); } catch (err) { alert(`Errore: ${err.message}`); @@ -36,48 +35,57 @@ function CelebrityList() { } }; - if (loading) return

Caricamento in corso...

; - if (error) return

Errore: {error}

; - return (
-

Catalogo Celebrità

- - + Aggiungi Nuova Celebrità - - - - - - - - - - - - - - - {celebrities.map((celeb) => ( - - - - - - - - - - ))} - -
NomeSeno (cm)Vita (cm)Fianchi (cm)Taglia ReggisenoNaturali?Azioni
{celeb.name}{celeb.bust_cm || 'N/A'}{celeb.waist_cm || 'N/A'}{celeb.hips_cm || 'N/A'} - {celeb.bra_band_size && celeb.bra_cup_size - ? `${celeb.bra_band_size}${celeb.bra_cup_size} (${celeb.bra_size_system})` - : 'N/A'} - {celeb.boobs_are_natural === null ? 'N/A' : celeb.boobs_are_natural ? 'Sì' : 'No'} - Modifica - -
+
+

Catalogo Celebrità

+ + + Aggiungi + +
+ + {loading &&

Caricamento in corso...

} + {error &&

Errore: {error}

} + + {!loading && ( +
+ + + + + + + + + + + + + + {celebrities.map((celeb) => ( + + + + + + + + + + ))} + +
NomeSeno (cm)Vita (cm)Fianchi (cm)Taglia ReggisenoNaturali?Azioni
{celeb.name}{celeb.bust_cm || 'N/A'}{celeb.waist_cm || 'N/A'}{celeb.hips_cm || 'N/A'} + {celeb.bra_band_size && celeb.bra_cup_size + ? `${celeb.bra_band_size}${celeb.bra_cup_size} (${celeb.bra_size_system})` + : 'N/A'} + {celeb.boobs_are_natural === null ? 'N/A' : celeb.boobs_are_natural ? 'Sì' : 'No'} +
+ Modifica + +
+
+
+ )}
); } diff --git a/packages/frontend/src/components/CelebrityProfile.css b/packages/frontend/src/components/CelebrityProfile.css index d80c056..e69de29 100644 --- a/packages/frontend/src/components/CelebrityProfile.css +++ b/packages/frontend/src/components/CelebrityProfile.css @@ -1,138 +0,0 @@ -/* packages/frontend/src/components/CelebrityProfile.css */ - -.profile-container { - display: flex; - gap: 2rem; - width: 100%; - max-width: 1200px; - margin: 0 auto; -} - -.profile-sidebar { - flex: 0 0 300px; /* Larghezza fissa per la colonna sinistra */ -} - -.profile-main-image { - width: 100%; - height: auto; - border-radius: 8px; - margin-bottom: 1rem; - border: 1px solid #444; -} - -.thumbnails { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 0.5rem; -} - -.thumbnail img { - width: 100%; - border-radius: 4px; - border: 1px solid #444; -} - -.profile-content { - flex-grow: 1; -} - -.profile-header { - border-bottom: 1px solid #555; - padding-bottom: 1rem; - margin-bottom: 1rem; -} - -.profile-header h1 { - margin: 0; - font-size: 2.5rem; - color: #f0e6d2; -} - -.profile-header .editable-field { - margin-top: 0.5rem; -} - -.profile-section { - background-color: #2c2c2c; - border-radius: 8px; - padding: 1.5rem; - margin-bottom: 1.5rem; - border: 1px solid #444; -} - -.profile-section h2 { - margin-top: 0; - border-bottom: 1px solid #555; - padding-bottom: 0.5rem; - margin-bottom: 1rem; - color: #d4b996; -} - -.profile-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 1rem; -} - -/* Stile per i campi editabili */ -.editable-field { - padding: 8px; - border-radius: 4px; - transition: background-color 0.2s ease-in-out; - cursor: pointer; -} - -.editable-field:hover { - background-color: #3a3a3a; -} - -.field-label { - display: block; - font-size: 0.8rem; - color: #aaa; - margin-bottom: 4px; - text-transform: uppercase; -} - -.field-value { - font-size: 1rem; - font-weight: 500; - color: #fff; -} - -.editable-field input, -.editable-field select, -.editable-field textarea { - width: 100%; - padding: 6px; - font-size: 1rem; - border: 1px solid #646cff; - border-radius: 4px; - background-color: #1a1a1a; - color: #fff; - box-sizing: border-box; /* Assicura che padding non alteri la larghezza */ -} - -.profile-actions { - margin-top: 2rem; - display: flex; - gap: 1rem; - justify-content: flex-end; -} - -.button-delete { - background-color: #b22222; - color: white; -} -.button-delete:hover { - background-color: #dc143c; - border-color: #dc143c; -} - -.button-back { - background-color: #444; -} -.button-back:hover { - background-color: #555; - border-color: #666; -} \ No newline at end of file diff --git a/packages/frontend/src/components/CelebrityProfile.jsx b/packages/frontend/src/components/CelebrityProfile.jsx index a6a96e6..30b7b1d 100644 --- a/packages/frontend/src/components/CelebrityProfile.jsx +++ b/packages/frontend/src/components/CelebrityProfile.jsx @@ -4,7 +4,6 @@ import React, { useState, useEffect } from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { getCelebrityById, updateCelebrity, deleteCelebrity } from '../services/api'; import EditableField from './EditableField'; -import './CelebrityProfile.css'; // Importa il nuovo CSS function CelebrityProfile() { const { id } = useParams(); @@ -14,12 +13,10 @@ function CelebrityProfile() { const [error, setError] = useState(null); useEffect(() => { - // Ignoriamo la modalità "new", questa pagina è solo per visualizzare/modificare if (id) { setLoading(true); getCelebrityById(id) .then((data) => { - // Formatta la data per l'input type="date" if (data.birth_date) { data.birth_date = data.birth_date.split('T')[0]; } @@ -28,23 +25,19 @@ function CelebrityProfile() { .catch((err) => setError(err.message)) .finally(() => setLoading(false)); } else { - navigate('/'); // Se non c'è id, torna alla home + navigate('/'); } }, [id, navigate]); const handleFieldSave = async (fieldName, newValue) => { - // Converte stringa vuota a null per il backend const valueToSend = newValue === '' ? null : newValue; const payload = { [fieldName]: valueToSend }; try { - const updatedCelebrity = await updateCelebrity(id, payload); - // Aggiorna lo stato locale per un feedback immediato + await updateCelebrity(id, payload); setCelebrity((prev) => ({ ...prev, [fieldName]: newValue })); - console.log('Salvataggio riuscito:', updatedCelebrity); } catch (err) { - setError(`Errore durante il salvataggio del campo ${fieldName}: ${err.message}`); - // Potresti voler ripristinare il valore precedente in caso di errore + setError(`Errore durante il salvataggio: ${err.message}`); } }; @@ -52,95 +45,80 @@ function CelebrityProfile() { if (window.confirm(`Sei sicuro di voler eliminare ${celebrity.name}? L'azione è irreversibile.`)) { try { await deleteCelebrity(id); - alert(`${celebrity.name} è stato eliminato con successo.`); navigate('/'); } catch (err) { setError(`Errore durante l'eliminazione: ${err.message}`); } } }; - - if (loading) return

Caricamento profilo...

; - if (error) return

Errore: {error}

; + + if (loading) return
Caricamento profilo...
; + if (error) return

Errore: {error}

; if (!celebrity) return

Nessuna celebrità trovata.

; - // Opzioni per i campi