diff --git a/backend/main.py b/backend/main.py index a1f3020..cccd233 100644 --- a/backend/main.py +++ b/backend/main.py @@ -451,8 +451,19 @@ async def delete_guest( # ============================================ -# Bulk Guest Import +# Bulk Guest Delete # ============================================ +@app.post("/events/{event_id}/guests/bulk-delete") +async def bulk_delete_guests( + event_id: UUID, + delete_data: schemas.GuestBulkDelete, + db: Session = Depends(get_db), + current_user_id: UUID = Depends(get_current_user_id) +): + """Bulk delete guests (admin only)""" + await authz.verify_event_admin(event_id, db, current_user_id) + deleted_count = crud.delete_guests_bulk(db, event_id, delete_data.guest_ids) + return {"message": f"{deleted_count} guests deleted successfully", "deleted_count": deleted_count} @app.post("/events/{event_id}/guests/import", response_model=dict) async def bulk_import_guests( event_id: UUID, diff --git a/backend/schemas.py b/backend/schemas.py index be72145..ef56f4c 100644 --- a/backend/schemas.py +++ b/backend/schemas.py @@ -154,6 +154,10 @@ class GuestBulkImport(BaseModel): guests: List[GuestImportItem] +class GuestBulkDelete(BaseModel): + guest_ids: List[UUID] + + # ============================================ # Filter/Search Schemas # ============================================ diff --git a/frontend/src/api/api.js b/frontend/src/api/api.js index e7a6e8a..8ebafb2 100644 --- a/frontend/src/api/api.js +++ b/frontend/src/api/api.js @@ -119,6 +119,11 @@ export const deleteGuest = async (eventId, guestId) => { return response.data } +export const bulkDeleteGuests = async (eventId, guestIds) => { + const response = await api.post(`/events/${eventId}/guests/bulk-delete`, { guest_ids: guestIds }) + return response.data +} + export const bulkImportGuests = async (eventId, guests) => { const response = await api.post(`/events/${eventId}/guests/import`, { guests }) return response.data diff --git a/frontend/src/components/GuestList.css b/frontend/src/components/GuestList.css index 26e68f4..bba79a3 100644 --- a/frontend/src/components/GuestList.css +++ b/frontend/src/components/GuestList.css @@ -95,6 +95,7 @@ .btn-tool, .btn-add-guest, .btn-whatsapp, +.btn-delete-selected, .btn-export, .btn-duplicate { display: inline-flex; @@ -160,6 +161,16 @@ cursor: not-allowed; } +/* delete selected */ +.btn-delete-selected { + background: var(--color-danger, #e53e3e); + color: #fff; +} +.btn-delete-selected:hover { + background: #c53030; + box-shadow: 0 2px 8px rgba(229, 62, 62, 0.35); +} + /* ── legacy class aliases kept for any remaining refs ── */ .header-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; } .btn-members { display: none; } diff --git a/frontend/src/components/GuestList.jsx b/frontend/src/components/GuestList.jsx index 9bf25ee..b57b88f 100644 --- a/frontend/src/components/GuestList.jsx +++ b/frontend/src/components/GuestList.jsx @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react' -import { getGuests, getGuestOwners, createGuest, updateGuest, deleteGuest, sendWhatsAppInvitationToGuests, getEvent } from '../api/api' +import { getGuests, getGuestOwners, createGuest, updateGuest, deleteGuest, bulkDeleteGuests, sendWhatsAppInvitationToGuests, getEvent } from '../api/api' import GuestForm from './GuestForm' import GoogleImport from './GoogleImport' import ImportContacts from './ImportContacts' @@ -46,7 +46,10 @@ const he = { failedToDelete: 'נכשל במחיקת אורח', sendWhatsApp: '💬 שלח בוואטסאפ', noGuestsSelected: 'בחר לפחות אורח אחד', - selectGuestsFirst: 'בחר אורחים לשליחת הזמנה' + selectGuestsFirst: 'בחר אורחים לשליחת הזמנה', + deleteSelected: '🗑️ מחק נבחרים', + confirmDeleteSelected: 'האם אתה בטוח שברצונך למחוק {count} אורחים?', + failedToDeleteSelected: 'נכשל במחיקת האורחים הנבחרים' } function GuestList({ eventId, onBack, onShowMembers }) { @@ -168,6 +171,20 @@ function GuestList({ eventId, onBack, onShowMembers }) { } } + const handleDeleteSelected = async () => { + if (selectedGuestIds.size === 0) return + if (!window.confirm(he.confirmDeleteSelected.replace('{count}', selectedGuestIds.size))) return + + try { + await bulkDeleteGuests(eventId, Array.from(selectedGuestIds)) + setGuests(guests.filter(g => !selectedGuestIds.has(g.id))) + setSelectedGuestIds(new Set()) + } catch (err) { + setError(he.failedToDeleteSelected) + console.error(err) + } + } + const handleEdit = (guest) => { setEditingGuest(guest) setShowGuestForm(true) @@ -356,13 +373,21 @@ function GuestList({ eventId, onBack, onShowMembers }) {
{selectedGuestIds.size > 0 && ( - + <> + + + )}