diff --git a/.dockerignore b/.dockerignore index 21edd64..276bbec 100644 Binary files a/.dockerignore and b/.dockerignore differ diff --git a/Dockerfile b/Dockerfile index bb87fa8..e69de29 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +0,0 @@ -# Stage 1: Build Frontend -FROM node:18-alpine as build -WORKDIR /app -COPY package*.json ./ -RUN npm install -COPY . . -RUN npm run build - -# Stage 2: Serve with Nginx -FROM nginx:alpine -COPY --from=build /app/dist /usr/share/nginx/html -# Copy the nginx configuration file (using the .txt extension as provided in source) -COPY nginx.txt /etc/nginx/nginx.conf -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] diff --git a/nginx.conf b/nginx.conf index f8625d9..e69de29 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,38 +0,0 @@ -worker_processes 1; - -events { worker_connections 1024; } - -http { - include mime.types; - default_type application/octet-stream; - sendfile on; - keepalive_timeout 65; - - server { - listen 80; - root /usr/share/nginx/html; - index index.html; - - # Limite upload per allegati (es. foto/video ticket) - Allineato con il backend - client_max_body_size 50M; - - # Compressione Gzip - gzip on; - gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; - - # Gestione SPA (React Router) - location / { - try_files $uri $uri/ /index.html; - } - - # Proxy API verso il backend - location /api/ { - proxy_pass http://backend:3001; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_cache_bypass $http_upgrade; - } - } -} diff --git a/pages/ExtraordinaryAdmin.tsx b/pages/ExtraordinaryAdmin.tsx index fa306ff..13aff04 100644 --- a/pages/ExtraordinaryAdmin.tsx +++ b/pages/ExtraordinaryAdmin.tsx @@ -47,7 +47,7 @@ export const ExtraordinaryAdmin: React.FC = () => { const totalAmount = formItems.reduce((acc, item) => acc + (item.amount || 0), 0); const recalculateShares = (selectedIds: string[], manualMode = false) => { - if (manualMode || isEditing) return; // Don't auto-calc shares in Edit mode to prevent messing up existing complex logic visually, backend handles logic + if (manualMode) return; const count = selectedIds.length; if (count === 0) { @@ -56,13 +56,27 @@ export const ExtraordinaryAdmin: React.FC = () => { } const percentage = 100 / count; - const newShares: ExpenseShare[] = selectedIds.map(fid => ({ - familyId: fid, - percentage: parseFloat(percentage.toFixed(2)), - amountDue: parseFloat(((totalAmount * percentage) / 100).toFixed(2)), - amountPaid: 0, - status: 'UNPAID' - })); + const newShares: ExpenseShare[] = selectedIds.map(fid => { + // Preserve existing data if available + const existing = formShares.find(s => s.familyId === fid); + if (existing) { + // If editing and we just toggled someone else, re-calc percentages evenly? + // Or keep manual adjustments? + // For simplicity: auto-recalc resets percentages evenly. + return { + ...existing, + percentage: parseFloat(percentage.toFixed(2)), + amountDue: parseFloat(((totalAmount * percentage) / 100).toFixed(2)) + }; + } + return { + familyId: fid, + percentage: parseFloat(percentage.toFixed(2)), + amountDue: parseFloat(((totalAmount * percentage) / 100).toFixed(2)), + amountPaid: 0, + status: 'UNPAID' + }; + }); // Adjust rounding error on last item if (newShares.length > 0) { @@ -99,9 +113,11 @@ export const ExtraordinaryAdmin: React.FC = () => { setFormItems(newItems); }; - // Trigger share recalc when total changes (if not manual/editing) + // Trigger share recalc when total changes (if not manual) + // We only trigger auto-recalc if not editing existing complex shares, + // OR if editing but user hasn't manually messed with them yet (simplification: always recalc on total change for now) useEffect(() => { - if (!isEditing) { + if (selectedFamilyIds.length > 0) { recalculateShares(selectedFamilyIds); } }, [totalAmount]); // eslint-disable-line react-hooks/exhaustive-deps @@ -131,7 +147,7 @@ export const ExtraordinaryAdmin: React.FC = () => { }; const openEditModal = async (exp: ExtraordinaryExpense) => { - // Fetch full details first to get items + // Fetch full details first to get items and shares try { const detail = await CondoService.getExpenseDetails(exp.id); setIsEditing(true); @@ -142,15 +158,27 @@ export const ExtraordinaryAdmin: React.FC = () => { setFormEnd(detail.endDate ? new Date(detail.endDate).toISOString().split('T')[0] : ''); setFormContractor(detail.contractorName); setFormItems(detail.items || []); - // Shares and attachments are not fully editable in this simple view to avoid conflicts - // We only allow editing Header Info + Items. Shares will be auto-recalculated by backend based on new total. - setFormShares([]); + + // Populate shares for editing + const currentShares = detail.shares || []; + setFormShares(currentShares); + setSelectedFamilyIds(currentShares.map(s => s.familyId)); + + // Attachments (Cannot edit attachments in this simple view for now, cleared) setFormAttachments([]); - setSelectedFamilyIds([]); + setShowModal(true); } catch(e) { alert("Errore caricamento dettagli"); } }; + const handleDeleteExpense = async (id: string) => { + if (!confirm("Sei sicuro di voler eliminare questo progetto? Questa azione è irreversibile e cancellerà anche lo storico dei pagamenti associati.")) return; + try { + await CondoService.deleteExpense(id); + loadData(); + } catch (e) { alert("Errore eliminazione progetto"); } + }; + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { @@ -161,8 +189,8 @@ export const ExtraordinaryAdmin: React.FC = () => { startDate: formStart, endDate: formEnd, contractorName: formContractor, - items: formItems - // Attachments and shares handled by backend logic to keep safe + items: formItems, + shares: formShares // Now we send shares to sync }); } else { await CondoService.createExpense({ @@ -217,17 +245,26 @@ export const ExtraordinaryAdmin: React.FC = () => {
{exp.description}
@@ -292,43 +329,41 @@ export const ExtraordinaryAdmin: React.FC = () => {In modifica le quote delle famiglie vengono ricalcolate automaticamente in proporzione al nuovo totale. I pagamenti già effettuati restano salvati.
+Nota: Modificando le quote, lo stato dei pagamenti verrà aggiornato in base agli importi già versati dalle famiglie.