diff --git a/server/prisma/migrations/20251118193723_add_equipment_fields/migration.sql b/server/prisma/migrations/20251118193723_add_equipment_fields/migration.sql new file mode 100644 index 0000000..220aab1 --- /dev/null +++ b/server/prisma/migrations/20251118193723_add_equipment_fields/migration.sql @@ -0,0 +1,3 @@ +-- Add equipment fields to events table +ALTER TABLE `events` ADD COLUMN `equipment_provided` BOOLEAN DEFAULT false AFTER `photos`; +ALTER TABLE `events` ADD COLUMN `required_items` JSON AFTER `equipment_provided`; diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index 3fb21f6..821fd79 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -83,6 +83,8 @@ model Event { participantCount Int? @default(0) @map("participant_count") litterCollected Decimal? @map("litter_collected") @db.Decimal(10, 2) photos Json? + equipmentProvided Boolean? @default(false) @map("equipment_provided") + requiredItems Json? @map("required_items") createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) updatedAt DateTime? @default(now()) @updatedAt @map("updated_at") @db.Timestamp(0) registrations EventRegistration[] diff --git a/server/src/controllers/eventController.ts b/server/src/controllers/eventController.ts index 7a9a911..aaa20a0 100644 --- a/server/src/controllers/eventController.ts +++ b/server/src/controllers/eventController.ts @@ -109,7 +109,7 @@ export const eventController = { // Find or create user in database const userId = await findOrCreateUser(clerkId); - const { title, description, latitude, longitude, locationName, scheduledDate, duration } = req.body; + const { title, description, latitude, longitude, locationName, scheduledDate, duration, equipmentProvided, requiredItems } = req.body; // Validation if (!title || !description || !latitude || !longitude || !locationName || !scheduledDate || !duration) { @@ -129,6 +129,8 @@ export const eventController = { locationName, scheduledDate: new Date(scheduledDate), duration: parseInt(duration), + equipmentProvided: equipmentProvided !== undefined ? Boolean(equipmentProvided) : false, + requiredItems: Array.isArray(requiredItems) ? requiredItems : [], }; const event = await eventService.createEvent(eventData); diff --git a/server/src/services/eventService.ts b/server/src/services/eventService.ts index 994d5a1..2fc07a2 100644 --- a/server/src/services/eventService.ts +++ b/server/src/services/eventService.ts @@ -21,6 +21,8 @@ interface CreateEventData { locationName: string; scheduledDate: Date; duration: number; + equipmentProvided?: boolean; + requiredItems?: string[]; } interface UpdateEventData { @@ -31,6 +33,8 @@ interface UpdateEventData { status?: 'upcoming' | 'completed' | 'cancelled'; litterCollected?: number; photos?: string[]; + equipmentProvided?: boolean; + requiredItems?: string[]; } export const eventService = { @@ -93,6 +97,8 @@ export const eventService = { participantCount: event._count.registrations, litterCollected: event.litterCollected ? parseFloat(event.litterCollected.toString()) : undefined, photos: event.photos ? (Array.isArray(event.photos) ? event.photos : []) : undefined, + equipmentProvided: (event as any).equipmentProvided || false, + requiredItems: (event as any).requiredItems ? (Array.isArray((event as any).requiredItems) ? (event as any).requiredItems : []) : [], createdAt: event.createdAt, updatedAt: event.updatedAt, })); @@ -137,6 +143,8 @@ export const eventService = { participantCount: event._count.registrations, litterCollected: event.litterCollected ? parseFloat(event.litterCollected.toString()) : undefined, photos: event.photos ? (Array.isArray(event.photos) ? event.photos : []) : undefined, + equipmentProvided: (event as any).equipmentProvided || false, + requiredItems: (event as any).requiredItems ? (Array.isArray((event as any).requiredItems) ? (event as any).requiredItems : []) : [], createdAt: event.createdAt, updatedAt: event.updatedAt, }; @@ -145,16 +153,18 @@ export const eventService = { async createEvent(data: CreateEventData) { // Create point geometry for spatial queries const locationPoint = `POINT(${data.longitude} ${data.latitude})`; + const equipmentProvided = data.equipmentProvided !== undefined ? data.equipmentProvided : false; + const requiredItems = data.requiredItems && data.requiredItems.length > 0 ? JSON.stringify(data.requiredItems) : null; const event = await prisma.$executeRaw` INSERT INTO events ( id, organizer_id, title, description, location, latitude, longitude, - location_name, scheduled_date, duration, status, participant_count + location_name, scheduled_date, duration, status, participant_count, equipment_provided, required_items ) VALUES ( UUID(), ${data.organizerId}, ${data.title}, ${data.description}, ST_GeomFromText(${locationPoint}, 4326), ${data.latitude}, ${data.longitude}, ${data.locationName}, - ${data.scheduledDate}, ${data.duration}, 'upcoming', 0 + ${data.scheduledDate}, ${data.duration}, 'upcoming', 0, ${equipmentProvided}, ${requiredItems} ) `; @@ -195,6 +205,8 @@ export const eventService = { participantCount: createdEvent._count.registrations, litterCollected: createdEvent.litterCollected ? parseFloat(createdEvent.litterCollected.toString()) : undefined, photos: createdEvent.photos ? (Array.isArray(createdEvent.photos) ? createdEvent.photos : []) : undefined, + equipmentProvided: (createdEvent as any).equipmentProvided || false, + requiredItems: (createdEvent as any).requiredItems ? (Array.isArray((createdEvent as any).requiredItems) ? (createdEvent as any).requiredItems : []) : [], createdAt: createdEvent.createdAt, updatedAt: createdEvent.updatedAt, }; diff --git a/src/components/event/EventDetailModal.tsx b/src/components/event/EventDetailModal.tsx index 1e19d65..5a10067 100644 --- a/src/components/event/EventDetailModal.tsx +++ b/src/components/event/EventDetailModal.tsx @@ -186,6 +186,54 @@ export function EventDetailModal({ + {/* Equipment Information */} +
Equipment
+ {event.equipmentProvided ? ( ++ All necessary cleanup equipment will be provided by the organizer. +
+Please bring the following items:
++ Participants should bring their own cleanup equipment. +
+ )} ++ Check this if you'll supply all necessary cleanup equipment +
++ Add items that participants should bring (e.g., gloves, litter picker, bags, coat) +
+ + {/* Add Item Input */} +Required Items:
++ 💡 Tip: Add common items like gloves, litter pickers, bags, or appropriate clothing +
++ ✓ Participants will be informed that all equipment will be provided +
+