feat: Enhance condo and family data models
Adds new fields for detailed address information and notes to the Condo and Family types. Updates database schema and server API endpoints to support these new fields, improving data richness for location and specific family/condo details.
This commit is contained in:
@@ -144,22 +144,38 @@ app.get('/api/condos', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.query('SELECT * FROM condos');
|
||||
res.json(rows.map(r => ({
|
||||
id: r.id, name: r.name, address: r.address, iban: r.iban, defaultMonthlyQuota: parseFloat(r.default_monthly_quota), image: r.image
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
address: r.address,
|
||||
streetNumber: r.street_number,
|
||||
city: r.city,
|
||||
province: r.province,
|
||||
zipCode: r.zip_code,
|
||||
notes: r.notes,
|
||||
iban: r.iban,
|
||||
defaultMonthlyQuota: parseFloat(r.default_monthly_quota),
|
||||
image: r.image
|
||||
})));
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
app.post('/api/condos', authenticateToken, requireAdmin, async (req, res) => {
|
||||
const { name, address, defaultMonthlyQuota } = req.body;
|
||||
const { name, address, streetNumber, city, province, zipCode, notes, defaultMonthlyQuota } = req.body;
|
||||
const id = uuidv4();
|
||||
try {
|
||||
await pool.query('INSERT INTO condos (id, name, address, default_monthly_quota) VALUES (?, ?, ?, ?)', [id, name, address, defaultMonthlyQuota]);
|
||||
res.json({ id, name, address, defaultMonthlyQuota });
|
||||
await pool.query(
|
||||
'INSERT INTO condos (id, name, address, street_number, city, province, zip_code, notes, default_monthly_quota) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[id, name, address, streetNumber, city, province, zipCode, notes, defaultMonthlyQuota]
|
||||
);
|
||||
res.json({ id, name, address, streetNumber, city, province, zipCode, notes, defaultMonthlyQuota });
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
app.put('/api/condos/:id', authenticateToken, requireAdmin, async (req, res) => {
|
||||
const { name, address, defaultMonthlyQuota } = req.body;
|
||||
const { name, address, streetNumber, city, province, zipCode, notes, defaultMonthlyQuota } = req.body;
|
||||
try {
|
||||
await pool.query('UPDATE condos SET name = ?, address = ?, default_monthly_quota = ? WHERE id = ?', [name, address, defaultMonthlyQuota, req.params.id]);
|
||||
await pool.query(
|
||||
'UPDATE condos SET name = ?, address = ?, street_number = ?, city = ?, province = ?, zip_code = ?, notes = ?, default_monthly_quota = ? WHERE id = ?',
|
||||
[name, address, streetNumber, city, province, zipCode, notes, defaultMonthlyQuota, req.params.id]
|
||||
);
|
||||
res.json({ success: true });
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
@@ -172,32 +188,58 @@ app.delete('/api/condos/:id', authenticateToken, requireAdmin, async (req, res)
|
||||
|
||||
// --- FAMILIES ---
|
||||
app.get('/api/families', authenticateToken, async (req, res) => {
|
||||
const { condoId } = req.query;
|
||||
try {
|
||||
let query = `SELECT f.* FROM families f`;
|
||||
let params = [];
|
||||
|
||||
// Authorization/Filtering logic
|
||||
if (req.user.role !== 'admin' && req.user.role !== 'poweruser') {
|
||||
// Regular user: can only see their own family
|
||||
if (!req.user.familyId) return res.json([]);
|
||||
query += ' WHERE f.id = ?';
|
||||
params.push(req.user.familyId);
|
||||
} else {
|
||||
// Admin: If condoId provided, filter by it.
|
||||
if (condoId) {
|
||||
query += ' WHERE f.condo_id = ?';
|
||||
params.push(condoId);
|
||||
}
|
||||
}
|
||||
|
||||
const [rows] = await pool.query(query, params);
|
||||
res.json(rows.map(r => ({
|
||||
id: r.id, condoId: r.condo_id, name: r.name, unitNumber: r.unit_number, contactEmail: r.contact_email, customMonthlyQuota: r.custom_monthly_quota ? parseFloat(r.custom_monthly_quota) : undefined, balance: 0
|
||||
id: r.id,
|
||||
condoId: r.condo_id,
|
||||
name: r.name,
|
||||
unitNumber: r.unit_number,
|
||||
stair: r.stair,
|
||||
floor: r.floor,
|
||||
notes: r.notes,
|
||||
contactEmail: r.contact_email,
|
||||
customMonthlyQuota: r.custom_monthly_quota ? parseFloat(r.custom_monthly_quota) : undefined,
|
||||
balance: 0
|
||||
})));
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
app.post('/api/families', authenticateToken, requireAdmin, async (req, res) => {
|
||||
const { name, unitNumber, contactEmail, condoId, customMonthlyQuota } = req.body;
|
||||
const { name, unitNumber, stair, floor, notes, contactEmail, condoId, customMonthlyQuota } = req.body;
|
||||
const id = uuidv4();
|
||||
try {
|
||||
await pool.query('INSERT INTO families (id, condo_id, name, unit_number, contact_email, custom_monthly_quota) VALUES (?, ?, ?, ?, ?, ?)', [id, condoId, name, unitNumber, contactEmail, customMonthlyQuota || null]);
|
||||
res.json({ id, condoId, name, unitNumber, contactEmail, customMonthlyQuota });
|
||||
await pool.query(
|
||||
'INSERT INTO families (id, condo_id, name, unit_number, stair, floor, notes, contact_email, custom_monthly_quota) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[id, condoId, name, unitNumber, stair, floor, notes, contactEmail, customMonthlyQuota || null]
|
||||
);
|
||||
res.json({ id, condoId, name, unitNumber, stair, floor, notes, contactEmail, customMonthlyQuota });
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
app.put('/api/families/:id', authenticateToken, requireAdmin, async (req, res) => {
|
||||
const { name, unitNumber, contactEmail, customMonthlyQuota } = req.body;
|
||||
const { name, unitNumber, stair, floor, notes, contactEmail, customMonthlyQuota } = req.body;
|
||||
try {
|
||||
await pool.query('UPDATE families SET name = ?, unit_number = ?, contact_email = ?, custom_monthly_quota = ? WHERE id = ?', [name, unitNumber, contactEmail, customMonthlyQuota || null, req.params.id]);
|
||||
await pool.query(
|
||||
'UPDATE families SET name = ?, unit_number = ?, stair = ?, floor = ?, notes = ?, contact_email = ?, custom_monthly_quota = ? WHERE id = ?',
|
||||
[name, unitNumber, stair, floor, notes, contactEmail, customMonthlyQuota || null, req.params.id]
|
||||
);
|
||||
res.json({ success: true });
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
@@ -305,8 +347,19 @@ app.post('/api/payments', authenticateToken, async (req, res) => {
|
||||
|
||||
// --- USERS ---
|
||||
app.get('/api/users', authenticateToken, requireAdmin, async (req, res) => {
|
||||
const { condoId } = req.query;
|
||||
try {
|
||||
const [rows] = await pool.query('SELECT id, email, name, role, phone, family_id, receive_alerts FROM users');
|
||||
let query = 'SELECT u.id, u.email, u.name, u.role, u.phone, u.family_id, u.receive_alerts FROM users u';
|
||||
let params = [];
|
||||
|
||||
// Filter users by condo.
|
||||
// Logic: Users belong to families, families belong to condos.
|
||||
if (condoId) {
|
||||
query += ' LEFT JOIN families f ON u.family_id = f.id WHERE f.condo_id = ?';
|
||||
params.push(condoId);
|
||||
}
|
||||
|
||||
const [rows] = await pool.query(query, params);
|
||||
res.json(rows.map(r => ({ id: r.id, email: r.email, name: r.name, role: r.role, phone: r.phone, familyId: r.family_id, receiveAlerts: !!r.receive_alerts })));
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
@@ -344,17 +397,24 @@ app.delete('/api/users/:id', authenticateToken, requireAdmin, async (req, res) =
|
||||
|
||||
// --- ALERTS ---
|
||||
app.get('/api/alerts', authenticateToken, requireAdmin, async (req, res) => {
|
||||
const { condoId } = req.query;
|
||||
try {
|
||||
const [rows] = await pool.query('SELECT * FROM alerts');
|
||||
res.json(rows.map(r => ({ id: r.id, subject: r.subject, body: r.body, daysOffset: r.days_offset, offsetType: r.offset_type, sendHour: r.send_hour, active: !!r.active, lastSent: r.last_sent })));
|
||||
let query = 'SELECT * FROM alerts';
|
||||
let params = [];
|
||||
if (condoId) {
|
||||
query += ' WHERE condo_id = ?';
|
||||
params.push(condoId);
|
||||
}
|
||||
const [rows] = await pool.query(query, params);
|
||||
res.json(rows.map(r => ({ id: r.id, condoId: r.condo_id, subject: r.subject, body: r.body, daysOffset: r.days_offset, offsetType: r.offset_type, sendHour: r.send_hour, active: !!r.active, lastSent: r.last_sent })));
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
app.post('/api/alerts', authenticateToken, requireAdmin, async (req, res) => {
|
||||
const { subject, body, daysOffset, offsetType, sendHour, active } = req.body;
|
||||
const { condoId, subject, body, daysOffset, offsetType, sendHour, active } = req.body;
|
||||
const id = uuidv4();
|
||||
try {
|
||||
await pool.query('INSERT INTO alerts (id, subject, body, days_offset, offset_type, send_hour, active) VALUES (?, ?, ?, ?, ?, ?, ?)', [id, subject, body, daysOffset, offsetType, sendHour, active]);
|
||||
res.json({ id, subject, body, daysOffset, offsetType, sendHour, active });
|
||||
await pool.query('INSERT INTO alerts (id, condo_id, subject, body, days_offset, offset_type, send_hour, active) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [id, condoId, subject, body, daysOffset, offsetType, sendHour, active]);
|
||||
res.json({ id, condoId, subject, body, daysOffset, offsetType, sendHour, active });
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
app.put('/api/alerts/:id', authenticateToken, requireAdmin, async (req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user