Initial fullstack scaffold: Events, Guests, Budget, Bookings
- Express backend with PostgreSQL (JWT auth, full CRUD) - React + Vite + TailwindCSS frontend in Hebrew (RTL) - Features: Digital Booking System, Guest Management, Smart Budget Management - Docker Compose with postgres healthcheck - Auto-runs migrations on startup Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
118
routes/guests.js
Normal file
118
routes/guests.js
Normal file
@@ -0,0 +1,118 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const pool = require('../db');
|
||||
const { authMiddleware } = require('./auth');
|
||||
|
||||
// Get all guests for an event
|
||||
router.get('/event/:eventId', authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT g.* FROM guests g
|
||||
JOIN events e ON g.event_id = e.id
|
||||
WHERE g.event_id = $1 AND e.user_id = $2
|
||||
ORDER BY g.name ASC`,
|
||||
[req.params.eventId, req.userId]
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Get single guest
|
||||
router.get('/:id', authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT g.* FROM guests g
|
||||
JOIN events e ON g.event_id = e.id
|
||||
WHERE g.id = $1 AND e.user_id = $2`,
|
||||
[req.params.id, req.userId]
|
||||
);
|
||||
if (result.rows.length === 0) return res.status(404).json({ error: 'Guest not found' });
|
||||
res.json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Create guest
|
||||
router.post('/', authMiddleware, async (req, res) => {
|
||||
const { event_id, name, phone, email, rsvp_status, table_number, seat_number, dietary_restriction, notes } = req.body;
|
||||
if (!event_id || !name) return res.status(400).json({ error: 'event_id and name are required' });
|
||||
try {
|
||||
// Verify event belongs to user
|
||||
const eventCheck = await pool.query('SELECT id FROM events WHERE id=$1 AND user_id=$2', [event_id, req.userId]);
|
||||
if (eventCheck.rows.length === 0) return res.status(403).json({ error: 'Forbidden' });
|
||||
|
||||
const result = await pool.query(
|
||||
`INSERT INTO guests (event_id, name, phone, email, rsvp_status, table_number, seat_number, dietary_restriction, notes)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *`,
|
||||
[event_id, name, phone, email, rsvp_status || 'pending', table_number, seat_number, dietary_restriction, notes]
|
||||
);
|
||||
res.status(201).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Update guest
|
||||
router.put('/:id', authMiddleware, async (req, res) => {
|
||||
const { name, phone, email, rsvp_status, table_number, seat_number, dietary_restriction, notes } = req.body;
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`UPDATE guests SET name=$1, phone=$2, email=$3, rsvp_status=$4, table_number=$5, seat_number=$6,
|
||||
dietary_restriction=$7, notes=$8
|
||||
WHERE id=$9 AND event_id IN (SELECT id FROM events WHERE user_id=$10) RETURNING *`,
|
||||
[name, phone, email, rsvp_status, table_number, seat_number, dietary_restriction, notes, req.params.id, req.userId]
|
||||
);
|
||||
if (result.rows.length === 0) return res.status(404).json({ error: 'Guest not found' });
|
||||
res.json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Delete guest
|
||||
router.delete('/:id', authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`DELETE FROM guests WHERE id=$1 AND event_id IN (SELECT id FROM events WHERE user_id=$2) RETURNING id`,
|
||||
[req.params.id, req.userId]
|
||||
);
|
||||
if (result.rows.length === 0) return res.status(404).json({ error: 'Guest not found' });
|
||||
res.json({ message: 'Guest deleted' });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Bulk import guests
|
||||
router.post('/bulk', authMiddleware, async (req, res) => {
|
||||
const { event_id, guests } = req.body;
|
||||
if (!event_id || !Array.isArray(guests)) return res.status(400).json({ error: 'event_id and guests array required' });
|
||||
try {
|
||||
const eventCheck = await pool.query('SELECT id FROM events WHERE id=$1 AND user_id=$2', [event_id, req.userId]);
|
||||
if (eventCheck.rows.length === 0) return res.status(403).json({ error: 'Forbidden' });
|
||||
|
||||
const inserted = [];
|
||||
for (const g of guests) {
|
||||
const r = await pool.query(
|
||||
`INSERT INTO guests (event_id, name, phone, email, rsvp_status, dietary_restriction)
|
||||
VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`,
|
||||
[event_id, g.name, g.phone, g.email, g.rsvp_status || 'pending', g.dietary_restriction]
|
||||
);
|
||||
inserted.push(r.rows[0]);
|
||||
}
|
||||
res.status(201).json(inserted);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user