diff --git a/apps/web/src/components/calendar/CalendarSidebar.tsx b/apps/web/src/components/calendar/CalendarSidebar.tsx index a3ab3f600c..ade872c831 100644 --- a/apps/web/src/components/calendar/CalendarSidebar.tsx +++ b/apps/web/src/components/calendar/CalendarSidebar.tsx @@ -20,6 +20,8 @@ interface CalendarSidebarProps { userEventsVisible: boolean; onToggleAgentEvents: () => void; onToggleUserEvents: () => void; + selectedKey?: string; + onSelectCalendar?: (key: string) => void; className?: string; } @@ -32,6 +34,8 @@ export function CalendarSidebar({ userEventsVisible, onToggleAgentEvents, onToggleUserEvents, + selectedKey, + onSelectCalendar, className, }: CalendarSidebarProps) { const hasCalendars = calendars.length > 0; @@ -57,18 +61,22 @@ export function CalendarSidebar({ key={cal.key} role="button" tabIndex={0} - onClick={() => onToggle(cal.key)} - onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onToggle(cal.key); } }} + onClick={() => onSelectCalendar ? onSelectCalendar(cal.key) : onToggle(cal.key)} + onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); if (onSelectCalendar) { onSelectCalendar(cal.key); } else { onToggle(cal.key); } } }} className={cn( 'flex items-center gap-2 px-1.5 py-1 rounded cursor-pointer transition-colors', 'hover:bg-muted/50', - !cal.visible && 'opacity-50' + !cal.visible && 'opacity-50', + cal.key === selectedKey && 'bg-accent/50' )} > { e.stopPropagation(); onToggle(cal.key); }} + onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); onToggle(cal.key); } }} className={cn( 'size-3.5 shrink-0 rounded-sm border transition-colors', cal.visible diff --git a/apps/web/src/components/calendar/CalendarView.tsx b/apps/web/src/components/calendar/CalendarView.tsx index 8d5d1bacd5..9d0c717c67 100644 --- a/apps/web/src/components/calendar/CalendarView.tsx +++ b/apps/web/src/components/calendar/CalendarView.tsx @@ -100,6 +100,7 @@ export function CalendarView({ context, driveId, driveName: _driveName, classNam const { hiddenCalendars, toggleCalendar, showAll, hideAll, hiddenEventTypes, toggleEventType, isEventTypeVisible } = useCalendarFilterStore(); const [sidebarOpen, setSidebarOpen] = useState(true); + const [selectedCalendarKey, setSelectedCalendarKey] = useState('personal'); // Force-refresh drives on mount so the sidebar reflects current memberships const isUserContext = context === 'user'; @@ -165,6 +166,19 @@ export function CalendarView({ context, driveId, driveName: _driveName, classNam [calendarEntries] ); + // When user context: derive the effective driveId/context for the event modal. + // Editing an existing event: use the event's own driveId. A null driveId means + // the event is personal — convert null→undefined so it isn't confused with "no + // event selected". Never inherit the selected calendar key when editing. + // Creating a new event: use the selected calendar key. + const creationDriveId = isUserContext && selectedCalendarKey !== 'personal' + ? selectedCalendarKey + : (isUserContext ? undefined : driveId); + const effectiveModalDriveId = selectedEvent + ? (selectedEvent.driveId ?? undefined) + : creationDriveId; + const effectiveModalContext: 'user' | 'drive' = effectiveModalDriveId ? 'drive' : 'user'; + const { data: googleCalendarStatus } = useSWR( '/api/integrations/google-calendar/status', googleCalendarStatusFetcher, @@ -265,10 +279,13 @@ export function CalendarView({ context, driveId, driveName: _driveName, classNam } else { // POST schema doesn't accept null (only undefined no-op or object upsert) const { agentTrigger, ...rest } = eventData; + const driveOverride = isUserContext && selectedCalendarKey !== 'personal' + ? selectedCalendarKey + : undefined; await createEvent({ ...rest, agentTrigger: agentTrigger ?? undefined, - }); + }, driveOverride); } setIsEventModalOpen(false); }; @@ -410,8 +427,8 @@ export function CalendarView({ context, driveId, driveName: _driveName, classNam onRsvp={handleRsvp} onAddAttendee={handleAddAttendee} onRemoveAttendee={handleRemoveAttendee} - driveId={driveId} - context={context} + driveId={effectiveModalDriveId} + context={effectiveModalContext} /> ); @@ -604,6 +621,8 @@ export function CalendarView({ context, driveId, driveName: _driveName, classNam userEventsVisible={isEventTypeVisible('user')} onToggleAgentEvents={() => toggleEventType('agent')} onToggleUserEvents={() => toggleEventType('user')} + selectedKey={selectedCalendarKey} + onSelectCalendar={setSelectedCalendarKey} /> )} @@ -673,8 +692,8 @@ export function CalendarView({ context, driveId, driveName: _driveName, classNam onRsvp={handleRsvp} onAddAttendee={handleAddAttendee} onRemoveAttendee={handleRemoveAttendee} - driveId={driveId} - context={context} + driveId={effectiveModalDriveId} + context={effectiveModalContext} /> ); diff --git a/apps/web/src/components/calendar/useCalendarData.ts b/apps/web/src/components/calendar/useCalendarData.ts index 8c4dcf95ae..fb3ae67d30 100644 --- a/apps/web/src/components/calendar/useCalendarData.ts +++ b/apps/web/src/components/calendar/useCalendarData.ts @@ -130,9 +130,12 @@ export function useCalendarData({ instructionPageId: string | null; contextPageIds: string[]; }; - }) => { + }, overrideDriveId?: string | null) => { + const targetDriveId = overrideDriveId !== undefined + ? overrideDriveId + : (context === 'drive' ? driveId : null); const result = await post('/api/calendar/events', { - driveId: context === 'drive' ? driveId : null, + driveId: targetDriveId, ...eventData, startAt: eventData.startAt.toISOString(), endAt: eventData.endAt.toISOString(),