diff --git a/packages/frontend/src/components/CelebrityList.css b/packages/frontend/src/components/CelebrityList.css new file mode 100644 index 0000000..b4bc027 --- /dev/null +++ b/packages/frontend/src/components/CelebrityList.css @@ -0,0 +1,119 @@ +/* packages/frontend/src/components/CelebrityList.css */ + +.celebrity-list-container { + max-width: 1100px; + margin: 0 auto; + padding: 1rem; +} + +.list-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.5rem; +} + +.list-header h1 { + margin: 0; +} + +.list-controls { + margin-bottom: 1rem; +} + +.table-responsive { + overflow-x: auto; +} + +.avatar-image { + width: 40px; + height: 40px; + border-radius: 50%; + object-fit: cover; + vertical-align: middle; +} + +.celeb-link { + font-weight: bold; + text-decoration: none; + color: var(--pico-primary); +} +.celeb-link:hover { + text-decoration: underline; +} + +/* Menu Azioni a tendina */ +.actions-cell { + text-align: center; +} +.actions-button { + padding: 0.25rem 0.5rem !important; + width: auto !important; + display: inline-flex !important; +} +.actions-cell details[role="list"] { + margin: 0; +} +.actions-cell summary::after { + display: none; /* Rimuove la freccia di default */ +} +.actions-cell ul[role="listbox"] { + text-align: left; +} +.actions-cell ul a { + display: flex; + align-items: center; + gap: 0.5rem; +} +.actions-cell ul a.danger { + color: var(--pico-color-red-500); +} + + +/* Paginazione */ +.pagination-controls { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 1.5rem; + padding: 0.5rem; + background-color: var(--pico-card-background-color); + border-radius: var(--pico-card-border-radius); + border: 1px solid var(--pico-card-border-color); +} +.pagination-controls .grid { + margin: 0; + grid-template-columns: 1fr 1fr; + gap: 0.5rem; +} +.pagination-controls button, +.pagination-controls select { + margin: 0; +} +.pagination-controls select { + max-width: 150px; +} + +/* Stato vuoto */ +.empty-state { + text-align: center; + padding: 3rem 1rem; + border: 2px dashed var(--pico-muted-border-color); + border-radius: var(--border-radius); + margin-top: 2rem; +} +.empty-state h3 { + margin-bottom: 0.5rem; +} +.empty-state p { + color: var(--pico-secondary); + margin-bottom: 1.5rem; +} +.empty-state .primary { + display: inline-block; +} + +/* Allineamento verticale nella tabella */ +tbody td { + vertical-align: middle; +} \ No newline at end of file diff --git a/packages/frontend/src/components/CelebrityList.jsx b/packages/frontend/src/components/CelebrityList.jsx index de360ae..b01acfe 100644 --- a/packages/frontend/src/components/CelebrityList.jsx +++ b/packages/frontend/src/components/CelebrityList.jsx @@ -1,11 +1,27 @@ -import React, { useState, useEffect } from 'react'; -import { Link } from 'react-router-dom'; +// packages/frontend/src/components/CelebrityList.jsx + +import React, { useState, useEffect, useMemo } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; import { getCelebrities, deleteCelebrity } from '../services/api'; +import './CelebrityList.css'; // Importa il nuovo CSS + +// Icone SVG semplici per le azioni +const EditIcon = () => ; +const DeleteIcon = () => ; +const MoreIcon = () => ; + function CelebrityList() { const [celebrities, setCelebrities] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + const [searchTerm, setSearchTerm] = useState(''); + + // Stato per la paginazione + const [currentPage, setCurrentPage] = useState(1); + const [itemsPerPage, setItemsPerPage] = useState(10); + + const navigate = useNavigate(); useEffect(() => { fetchCelebrities(); @@ -28,63 +44,133 @@ function CelebrityList() { if (window.confirm(`Sei sicuro di voler eliminare ${name}?`)) { try { await deleteCelebrity(id); - setCelebrities(celebrities.filter((c) => c.id !== id)); + setCelebrities(prev => prev.filter((c) => c.id !== id)); } catch (err) { alert(`Errore: ${err.message}`); } } }; + + // Memoizzazione dei dati filtrati e paginati per performance + const filteredCelebrities = useMemo(() => { + return celebrities.filter(c => + c.name.toLowerCase().includes(searchTerm.toLowerCase()) + ); + }, [celebrities, searchTerm]); + + const paginatedCelebrities = useMemo(() => { + const startIndex = (currentPage - 1) * itemsPerPage; + return filteredCelebrities.slice(startIndex, startIndex + itemsPerPage); + }, [filteredCelebrities, currentPage, itemsPerPage]); + + const totalPages = Math.ceil(filteredCelebrities.length / itemsPerPage); + + const renderPagination = () => ( +
+ + Pagina {currentPage} di {totalPages} + +
+ + +
+ +
+ ); + + const renderEmptyState = () => ( +
+

Nessun Profilo Trovato

+

La tua lista è vuota. Inizia aggiungendo una nuova celebrità.

+ + Aggiungi la prima celebrità +
+ ); return ( -
-
+
+

Catalogo Celebrità

- - + Aggiungi + + + Aggiungi Profilo +
+ +
+ { setSearchTerm(e.target.value); setCurrentPage(1); }} + />
- {loading &&

Caricamento in corso...

} - {error &&

Errore: {error}

} + {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 - -
-
-
+ {!loading && !error && ( + <> + {celebrities.length === 0 ? renderEmptyState() : ( + <> +
+ + + + + + + + + + + + + {paginatedCelebrities.map((celeb) => ( + + + + + + + + + ))} + +
NomeMisure (S-V-F)Taglia ReggisenoNaturale?Azioni
+ {celeb.name} + + + {celeb.name} + + + {celeb.bust_cm || '?'}-{celeb.waist_cm || '?'}-{celeb.hips_cm || '?'} cm + + {celeb.bra_band_size && celeb.bra_cup_size + ? `${celeb.bra_band_size}${celeb.bra_cup_size} (${celeb.bra_size_system || 'N/A'})` + : 'N/A'} + + {celeb.boobs_are_natural === null ? '?' : celeb.boobs_are_natural ? 'Sì' : 'No'} + +
+ + +
+
+
+ {totalPages > 1 && renderPagination()} + + )} + )}
);