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 = () => ( +
La tua lista è vuota. Inizia aggiungendo una nuova celebrità.
+ + Aggiungi la prima celebrità +Caricamento in corso...
} - {error &&Errore: {error}
} + {loading &&Errore: {error}
} - {!loading && ( -| Nome | -Seno (cm) | -Vita (cm) | -Fianchi (cm) | -Taglia Reggiseno | -Naturali? | -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
-
-
- |
-
| + | Nome | +Misure (S-V-F) | +Taglia Reggiseno | +Naturale? | +Azioni | +
|---|---|---|---|---|---|
|
+ |
+ + + {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'} + | ++ + | +