Skip to content

Schedule an Event Story - Implementation Audit

Schedule an Event Story - Implementation Audit

Section titled “Schedule an Event Story - Implementation Audit”

Story: Schedule an Event
Date: 2025-01-27
Status: ⚠️ PARTIALLY IMPLEMENTED - UI Complete, Backend Integration Missing

The Schedule an Event story has a complete UI implementation with all required form fields and validation. However, events are not persisted to the data layer after creation. The form submission shows success but doesn’t actually save the event, similar to the add_venue issue that was recently fixed.

✅ 1. I must provide a Title (Name) for the event

Section titled “✅ 1. I must provide a Title (Name) for the event”

Status:COMPLETE

  • Implementation: shaker/components/EventForm.tsx
  • Location: Lines 158-164
  • Details:
    • TextInput with label “Event Name *”
    • Required field validation
    • Placeholder: “e.g., Halloween Party 2025”
    • Error handling implemented

✅ 2. I must provide a Date for the event

Section titled “✅ 2. I must provide a Date for the event”

Status:COMPLETE

  • Implementation: shaker/components/EventForm.tsx
  • Location: Lines 187-195
  • Details:
    • DateTimePicker with label “Date *”
    • Required field validation
    • Minimum date validation (prevents past dates)
    • Date format validation

✅ 3. I can optionally provide a Start Time and End Time

Section titled “✅ 3. I can optionally provide a Start Time and End Time”

Status:COMPLETE

  • Implementation: shaker/components/EventForm.tsx
  • Location: Lines 197-219
  • Details:
    • Two DateTimePicker components (Start Time and End Time)
    • Optional fields (no required validation)
    • Time format validation (HH:MM)
    • End time validation (must be after start time)
    • Side-by-side layout for better UX

✅ 4. I can optionally provide a Description

Section titled “✅ 4. I can optionally provide a Description”

Status:COMPLETE

  • Implementation: shaker/components/EventForm.tsx
  • Location: Lines 166-174
  • Details:
    • TextInput with multiline support
    • Optional field
    • Placeholder: “Tell us about your event…”

Status:COMPLETE

  • Implementation: shaker/components/EventForm.tsx
  • Location: Lines 246-252
  • Details:
    • Picker component with theme options
    • Options loaded from getThemePickerOptions()
    • Optional field

Status:COMPLETE

  • Implementation: shaker/components/EventForm.tsx
  • Location: Lines 238-244
  • Details:
    • Picker component with venue options
    • Options loaded from getVenuePickerOptions()
    • Now includes newly created venues (after recent fix)
    • Optional field

✅ 7. I can optionally provide an initial Expected Guest Count

Section titled “✅ 7. I can optionally provide an initial Expected Guest Count”

Status:COMPLETE

  • Implementation: shaker/components/EventForm.tsx
  • Location: Lines 229-236
  • Details:
    • TextInput with numeric keyboard
    • Optional field
    • Validation: must be a number, must be at least 1
    • Placeholder: “Number of guests”

⚠️ 8. After creation, the event should be saved in the system

Section titled “⚠️ 8. After creation, the event should be saved in the system”

Status: ⚠️ NOT FULLY IMPLEMENTED

  • Issue: Events are not persisted to the data layer, only stored in component state

  • Current State:

    Path 1: Add Event Screen (add-event.tsx)

    • Form submission creates event object in memory
    • Shows success toast and navigates away
    • Event is NOT saved anywhere (completely lost)
    • Event disappears and cannot be viewed later

    Path 2: Inline Form in Events List (events/index.tsx)

    • Form submission updates local component state (setEvents)
    • Event appears in the list temporarily
    • Event is NOT saved to allEvents array in data layer
    • Event is lost on page refresh/navigation
    • Event cannot be viewed from event detail screen (doesn’t exist in data layer)
  • Evidence - Add Event Screen:

    const handleFormSubmit = useCallback(async (formData: EventFormData) => {
    setIsLoading(true);
    try {
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 1000));
    const newEvent: Event = {
    id: Date.now().toString(),
    name: formData.name,
    description: formData.description,
    date: formData.date,
    startTime: formData.startTime,
    endTime: formData.endTime,
    expectedGuestCount: formData.expectedGuestCount ? parseInt(formData.expectedGuestCount, 10) : undefined,
    status: 'planned',
    venue: formData.venueId ? {
    id: formData.venueId,
    name: formData.venueId === 'home' ? 'Home Bar' :
    formData.venueId === 'patio' ? 'Backyard Patio' :
    formData.venueId === 'living-room' ? 'Living Room' :
    formData.venueId === 'lime-factory' ? 'LIME Factory' : 'Rooftop Terrace',
    venueType: formData.venueId === 'lime-factory' ? 'other' : 'residential',
    capacity: formData.venueId === 'lime-factory' ? 50 : 30,
    } : undefined,
    theme: formData.themeId ? {
    id: formData.themeId,
    name: formData.themeId === 'tiki' ? 'Tiki Night' :
    formData.themeId === 'speakeasy' ? 'Speakeasy' :
    formData.themeId === 'halloween' ? 'Halloween' :
    formData.themeId === 'dxd-halloween' ? 'DxD Halloween' :
    formData.themeId === 'thanksgiving' ? 'Thanksgiving' :
    formData.themeId === 'valentines' ? "Valentine's Day" : 'Fiesta',
    colorScheme: formData.themeId === 'dxd-halloween' ? 'purple' : 'blue',
    } : undefined,
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    };
    // TODO: Save to backend/state management
    setToast({
    visible: true,
    message: 'Event created successfully!',
    variant: 'success',
    });
    // Navigate back to origin screen after toast
    setTimeout(() => {
    if (returnTo) {
    router.push(returnTo as any);
    } else {
    router.back();
    }
    }, 1500);
    } catch (error) {
    setToast({
    visible: true,
    message: 'Failed to save event. Please try again.',
    variant: 'error',
    });
    } finally {
    setIsLoading(false);
    }
    }, [returnTo]);
  • Evidence - Events List Screen (Inline Form):

    const handleFormSubmit = useCallback(async (formData: EventFormData) => {
    setIsLoading(true);
    try {
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 1000));
    const newEvent: Event = {
    id: editingEvent?.id || Date.now().toString(),
    name: formData.name,
    // ... event data ...
    };
    if (editingEvent) {
    setEvents(prevEvents =>
    prevEvents.map(e => e.id === editingEvent.id ? newEvent : e)
    );
    } else {
    setEvents(prevEvents => [newEvent, ...prevEvents]); // Only updates component state
    }
    // ... success toast ...
    } catch (error) {
    // ... error handling ...
    } finally {
    setIsLoading(false);
    }
    }, [editingEvent]);
  • Missing:

    • No createEvent function in shaker/data/events/index.ts
    • No updateEvent function in shaker/data/events/index.ts
    • Events not added to allEvents array (data layer)
    • Events only stored in component-level state
    • Events lost on page refresh
  • Impact:

    • Events created via add-event.tsx route: Completely lost, never appear in list
    • Events created via inline form: Appear temporarily but lost on refresh
    • Events cannot be viewed from event detail screen (don’t exist in data layer)
    • Cannot edit events after creation (they don’t persist)
    • Breaks the entire event workflow

⚠️ 9. I should be able to view and edit the event details later

Section titled “⚠️ 9. I should be able to view and edit the event details later”

Status: ⚠️ PARTIALLY COMPLETE

  • Viewing: ✅ Complete (for existing mock data)

    • Event detail screen exists (shaker/app/(tabs)/events/[id].tsx)
    • Event list screen exists (shaker/app/(tabs)/events/index.tsx)
    • Navigation works correctly
    • Can view existing events from mock data
    • ⚠️ Cannot view newly created events (they’re not in data layer)
  • Editing: ⚠️ Partially Complete

    • Edit event screen exists (shaker/app/(tabs)/events/edit-event.tsx)
    • Form pre-populates with existing event data
    • Form submission shows success but doesn’t persist changes
    • No updateEvent function in data layer
    • Changes lost on refresh
  • Issues:

    • Newly created events cannot be viewed (don’t exist in data layer)
    • Edit screen tries to load event via getEventById() which won’t find newly created events
    • Even if editing existing events, changes aren’t persisted to data layer
  1. UI Components:

    • shaker/components/EventForm.tsx - Complete form implementation
    • shaker/app/(tabs)/events/add-event.tsx - Add event screen (doesn’t persist)
    • shaker/app/(tabs)/events/edit-event.tsx - Edit event screen (doesn’t persist)
    • shaker/app/(tabs)/events/[id].tsx - Event detail screen
    • shaker/app/(tabs)/events/index.tsx - Events list screen
  2. GraphQL Mutation:

    • shaker/graphql/mutations/CreateEvent.graphql - Exists but not used
  3. Data Layer:

    • shaker/data/events/index.ts - Missing createEvent function
    • ❌ Missing updateEvent function
    • ✅ Has getEventById function
    • ✅ Has allEvents mock data array

The EventForm includes:

  • Basic Information Card:

    • Event Name (required, validated)
    • Description (optional, multiline)
  • Date & Time Card:

    • Date (required, DateTimePicker with minimum date)
    • Start Time (optional, DateTimePicker)
    • End Time (optional, DateTimePicker with validation)
  • Event Details Card:

    • Expected Guest Count (optional, numeric validation)
    • Venue (optional, picker)
    • Theme (optional, picker)

Comprehensive validation implemented:

  • ✅ Required fields: Name, Date
  • ✅ Time format validation (HH:MM)
  • ✅ End time after start time validation
  • ✅ Guest count numeric validation
  • ✅ Guest count minimum value (>= 1)
  • ✅ Date minimum value (prevents past dates)

Venue Mapping: The current implementation uses hardcoded venue name mapping:

venue: formData.venueId ? {
id: formData.venueId,
name: formData.venueId === 'home' ? 'Home Bar' :
formData.venueId === 'patio' ? 'Backyard Patio' :
formData.venueId === 'living-room' ? 'Living Room' :
formData.venueId === 'lime-factory' ? 'LIME Factory' : 'Rooftop Terrace',
venueType: formData.venueId === 'lime-factory' ? 'other' : 'residential',
capacity: formData.venueId === 'lime-factory' ? 50 : 30,
} : undefined,

Problem: New venues created via add-venue won’t be properly mapped. Should use getVenueById() to get full venue data.

Theme Mapping: Similar hardcoded theme mapping exists:

theme: formData.themeId ? {
id: formData.themeId,
name: formData.themeId === 'tiki' ? 'Tiki Night' :
formData.themeId === 'speakeasy' ? 'Speakeasy' :
formData.themeId === 'halloween' ? 'Halloween' :
formData.themeId === 'dxd-halloween' ? 'DxD Halloween' :
formData.themeId === 'thanksgiving' ? 'Thanksgiving' :
formData.themeId === 'valentines' ? "Valentine's Day" : 'Fiesta',
colorScheme: formData.themeId === 'dxd-halloween' ? 'purple' : 'blue',
} : undefined,

Problem: Should use getThemeById() to get full theme data.

File: shaker/data/events/index.ts

Required:

/**
* Create a new event
* Note: This updates mock data. Replace with GraphQL mutation when backend is ready.
*/
export function createEvent(event: Omit<Event, 'id' | 'createdAt' | 'updatedAt'>): Event {
const newId = Date.now().toString();
const now = new Date().toISOString();
const newEvent: Event = {
...event,
id: newId,
createdAt: now,
updatedAt: now,
};
allEvents.push(newEvent);
console.log('✅ Created new event:', newEvent);
return newEvent;
}

File: shaker/data/events/index.ts

Required:

/**
* Update an existing event
* Note: This updates mock data. Replace with GraphQL mutation when backend is ready.
*/
export function updateEvent(eventId: string, updates: Partial<Omit<Event, 'id' | 'createdAt'>>): Event | undefined {
const event = allEvents.find((e) => e.id === eventId);
if (!event) {
return undefined;
}
Object.assign(event, updates, {
updatedAt: new Date().toISOString(),
});
return event;
}

File: shaker/app/(tabs)/events/add-event.tsx

Required Changes:

  1. Import useMutation from @apollo/client
  2. Import CreateEventMutation from GraphQL file
  3. Import createEvent from data layer
  4. Set up mutation hook
  5. Call mutation in handleFormSubmit
  6. Add event to mock data as fallback
  7. Handle success/error states

Files: shaker/app/(tabs)/events/add-event.tsx, shaker/app/(tabs)/events/index.tsx

Current Issue: Hardcoded venue/theme name mapping doesn’t work with newly created venues/themes.

Fix: Use data layer functions to get full venue/theme objects:

  • getVenueById(formData.venueId) instead of hardcoded mapping (function exists)
  • getThemeById(formData.themeId) instead of hardcoded mapping (function exists ✅)

Note: Both getVenueById() and getThemeById() functions exist in the data layer. The hardcoded mapping should be replaced to support dynamically created venues and themes.

File: shaker/app/(tabs)/events/edit-event.tsx

Required:

  • Import and use updateEvent function
  • Persist changes to data layer
  • Update local state if needed
  1. Add createEvent function to data layer
  2. Add updateEvent function to data layer
  3. Integrate GraphQL mutation call (optional, fallback to mock data)
  4. Update form to persist event data
  5. Fix venue/theme mapping to use data layer functions
  • Add proper error handling for GraphQL mutation failures
  • Show user-friendly error messages
  • Handle network errors gracefully
  • Ensure venue data comes from getVenueById()
  • Ensure theme data comes from getThemeById()
  • Validate venue and theme exist before saving
  • ⚠️ ScheduleEvent (C1) - GraphQL mutation exists but not integrated
  • DefineEventTheme (C2) - Themes can be selected, theme creation separate story

The Schedule an Event story has excellent UI implementation with comprehensive validation and all required fields. The main gap is backend integration - events are not actually saved when created. This prevents the story from being functional, as created events cannot be viewed, edited, or used in the application.

Estimated Effort to Complete: 3-4 hours

  • Add data layer functions: 30 minutes
  • Fix venue/theme mapping: 30 minutes
  • Integrate GraphQL mutation: 1 hour
  • Update edit functionality: 1 hour
  • Testing and edge cases: 1 hour

Similar to: This issue is identical to the add_venue story that was recently fixed. The same pattern should be applied here.