fix: Improve condo ID handling and add error message
Prevents client-side generation of condo IDs, delegating this to the backend/service for consistency. Introduces an alert for save condo errors and ensures the active condo is correctly updated or set. Adds logic to auto-select the first condo if none is active.
This commit is contained in:
BIN
.dockerignore
BIN
.dockerignore
Binary file not shown.
15
Dockerfile
15
Dockerfile
@@ -1,15 +0,0 @@
|
||||
# Stage 1: Build del frontend
|
||||
FROM node:20-alpine as build
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Serve con Nginx
|
||||
FROM nginx:alpine
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
|
||||
23
nginx.conf
23
nginx.conf
@@ -1,22 +1 @@
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
# Serve i file statici del frontend
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
# Fondamentale per il routing client-side di React (SPA)
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Proxy verso il backend
|
||||
location /api {
|
||||
# 'backend' è il nome del servizio definito nel docker-compose.yml
|
||||
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;
|
||||
}
|
||||
}
|
||||
<EFBFBD><EFBFBD><EFBFBD>z
|
||||
@@ -224,20 +224,30 @@ export const SettingsPage: React.FC = () => {
|
||||
const handleCondoSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
// FIX: Do not generate ID for new condo, let backend/service handle it (POST vs PUT check)
|
||||
const payload: Condo = {
|
||||
id: editingCondo ? editingCondo.id : crypto.randomUUID(),
|
||||
id: editingCondo ? editingCondo.id : '',
|
||||
name: condoForm.name,
|
||||
address: condoForm.address,
|
||||
defaultMonthlyQuota: condoForm.defaultMonthlyQuota
|
||||
};
|
||||
|
||||
await CondoService.saveCondo(payload);
|
||||
const savedCondo = await CondoService.saveCondo(payload);
|
||||
const list = await CondoService.getCondos();
|
||||
setCondos(list);
|
||||
if (activeCondo?.id === payload.id) setActiveCondo(payload);
|
||||
|
||||
if (activeCondo?.id === savedCondo.id) {
|
||||
setActiveCondo(savedCondo);
|
||||
}
|
||||
|
||||
// Auto-select if it's the first one or none selected
|
||||
if (!activeCondo && list.length === 1) {
|
||||
CondoService.setActiveCondo(savedCondo.id);
|
||||
}
|
||||
|
||||
setShowCondoModal(false);
|
||||
window.dispatchEvent(new Event('condo-updated'));
|
||||
} catch (e) { console.error(e); }
|
||||
} catch (e) { console.error(e); alert("Errore nel salvataggio del condominio"); }
|
||||
};
|
||||
|
||||
const handleDeleteCondo = async (id: string) => {
|
||||
@@ -300,7 +310,10 @@ export const SettingsPage: React.FC = () => {
|
||||
setFamilies([...families, newFamily]);
|
||||
}
|
||||
setShowFamilyModal(false);
|
||||
} catch (e) { console.error(e); }
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
alert(`Errore: ${e.message || "Impossibile salvare la famiglia"}`);
|
||||
}
|
||||
};
|
||||
|
||||
// --- User Handlers ---
|
||||
@@ -359,7 +372,7 @@ export const SettingsPage: React.FC = () => {
|
||||
...noticeForm,
|
||||
date: editingNotice ? editingNotice.date : new Date().toISOString()
|
||||
};
|
||||
const saved = await CondoService.saveNotice(payload);
|
||||
await CondoService.saveNotice(payload);
|
||||
setNotices(await CondoService.getNotices());
|
||||
setShowNoticeModal(false);
|
||||
} catch (e) { console.error(e); }
|
||||
@@ -383,7 +396,7 @@ export const SettingsPage: React.FC = () => {
|
||||
setShowReadDetailsModal(true);
|
||||
};
|
||||
|
||||
// --- Alert Handlers (Placeholder for brevity, logic same as before) ---
|
||||
// --- Alert Handlers ---
|
||||
const openAddAlertModal = () => { setEditingAlert(null); setAlertForm({ subject: '', body: '', daysOffset: 1, offsetType: 'before_next_month', sendHour: 9, active: true }); setShowAlertModal(true); };
|
||||
const openEditAlertModal = (alert: AlertDefinition) => { setEditingAlert(alert); setAlertForm(alert); setShowAlertModal(true); };
|
||||
const handleAlertSubmit = async (e: React.FormEvent) => {
|
||||
@@ -463,7 +476,7 @@ export const SettingsPage: React.FC = () => {
|
||||
{isAdmin && activeTab === 'general' && (
|
||||
<div className="space-y-6 animate-fade-in">
|
||||
{!activeCondo ? (
|
||||
<div className="bg-amber-50 border border-amber-200 text-amber-800 p-4 rounded-lg">Nessun condominio selezionato.</div>
|
||||
<div className="bg-amber-50 border border-amber-200 text-amber-800 p-4 rounded-lg">Nessun condominio selezionato. Crea un condominio nella sezione "Lista Condomini".</div>
|
||||
) : (
|
||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6 md:p-8 max-w-2xl">
|
||||
<h3 className="text-lg font-bold text-slate-800 mb-4 flex items-center gap-2"><Building className="w-5 h-5 text-blue-600" /> Dati Condominio Corrente</h3>
|
||||
@@ -514,8 +527,14 @@ export const SettingsPage: React.FC = () => {
|
||||
{/* Families Tab */}
|
||||
{isAdmin && activeTab === 'families' && (
|
||||
<div className="space-y-4 animate-fade-in">
|
||||
{!activeCondo ? (
|
||||
<div className="p-8 text-center bg-slate-50 rounded-xl border border-dashed border-slate-300">
|
||||
<p className="text-slate-500">Seleziona o crea un condominio per gestire le famiglie.</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="text-sm text-slate-500">Famiglie in: <span className="font-bold text-slate-800">{activeCondo?.name}</span></div>
|
||||
<div className="text-sm text-slate-500">Famiglie in: <span className="font-bold text-slate-800">{activeCondo.name}</span></div>
|
||||
<button onClick={openAddFamilyModal} className="bg-blue-600 text-white px-4 py-2 rounded-lg font-medium flex items-center gap-2"><Plus className="w-4 h-4" /> Aggiungi</button>
|
||||
</div>
|
||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
|
||||
@@ -531,7 +550,7 @@ export const SettingsPage: React.FC = () => {
|
||||
{family.customMonthlyQuota ? (
|
||||
<span className="font-bold text-blue-600">€ {family.customMonthlyQuota}</span>
|
||||
) : (
|
||||
<span className="text-slate-400 italic">Default (€ {activeCondo?.defaultMonthlyQuota})</span>
|
||||
<span className="text-slate-400 italic">Default (€ {activeCondo.defaultMonthlyQuota})</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-6 py-4 text-right"><div className="flex justify-end gap-2"><button onClick={() => openEditFamilyModal(family)} className="text-blue-600"><Pencil className="w-4 h-4" /></button><button onClick={() => handleDeleteFamily(family.id)} className="text-red-600"><Trash2 className="w-4 h-4" /></button></div></td>
|
||||
@@ -540,6 +559,8 @@ export const SettingsPage: React.FC = () => {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM node:20-alpine
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
EXPOSE 3001
|
||||
CMD ["npm", "start"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user