diff --git a/components/EventDetailsDialog.vue b/components/EventDetailsDialog.vue index 9905600..41ad31a 100644 --- a/components/EventDetailsDialog.vue +++ b/components/EventDetailsDialog.vue @@ -536,7 +536,30 @@ const guestOptions = computed(() => { // Admin/Board permissions const canDeleteEvent = computed(() => { - return isAdmin.value || isBoard.value; + console.log('[EventDetailsDialog] canDeleteEvent computed triggered'); + console.log('[EventDetailsDialog] Auth composable values:', { + isAdmin: isAdmin.value, + isBoard: isBoard.value, + typeof_isAdmin: typeof isAdmin.value, + typeof_isBoard: typeof isBoard.value + }); + + const canDelete = isAdmin.value || isBoard.value; + console.log('[EventDetailsDialog] Final canDelete result:', canDelete); + return canDelete; +}); + +// Add watcher to see when dialog opens +watch(() => show.value, (newValue) => { + if (newValue) { + console.log('[EventDetailsDialog] Dialog opened'); + console.log('[EventDetailsDialog] Event prop:', props.event); + console.log('[EventDetailsDialog] Auth status check on open:', { + isAdmin: isAdmin.value, + isBoard: isBoard.value, + canDelete: canDeleteEvent.value + }); + } }); // Methods diff --git a/pages/dashboard/events.vue b/pages/dashboard/events.vue index 43f08a9..b819825 100644 --- a/pages/dashboard/events.vue +++ b/pages/dashboard/events.vue @@ -335,14 +335,22 @@ const clearFilters = async () => { }; const handleEventClick = (eventInfo: any) => { + console.log('[Events] EVENT CLICK HANDLER CALLED'); + console.log('[Events] Raw eventInfo received:', eventInfo); + // Extract the original event data from FullCalendar's extendedProps const calendarEvent = eventInfo.event || eventInfo; const originalEvent = calendarEvent.extendedProps?.originalEvent; + console.log('[Events] Calendar event:', calendarEvent); + console.log('[Events] Original event from extendedProps:', originalEvent); + // Use original event if available, otherwise reconstruct from calendar event if (originalEvent) { selectedEvent.value = originalEvent as Event; + console.log('[Events] Using original event from extendedProps'); } else { + console.log('[Events] Reconstructing event from calendar data'); // Fallback: reconstruct event from FullCalendar event data selectedEvent.value = { id: calendarEvent.id, @@ -364,13 +372,25 @@ const handleEventClick = (eventInfo: any) => { } as Event; } - console.log('[Events] Selected event for dialog:', { + console.log('[Events] Final selected event for dialog:', { id: selectedEvent.value.id, title: selectedEvent.value.title, - event_type: selectedEvent.value.event_type + event_type: selectedEvent.value.event_type, + full_event: selectedEvent.value }); + console.log('[Events] About to show dialog...'); + console.log('[Events] showDetailsDialog current value:', showDetailsDialog.value); + showDetailsDialog.value = true; + + console.log('[Events] showDetailsDialog after setting to true:', showDetailsDialog.value); + + // Force Vue to update + nextTick(() => { + console.log('[Events] After nextTick - showDetailsDialog:', showDetailsDialog.value); + console.log('[Events] After nextTick - selectedEvent:', selectedEvent.value?.title); + }); }; const handleDateClick = (dateInfo: any) => { diff --git a/server/utils/keycloak-admin.ts b/server/utils/keycloak-admin.ts index e5f527d..b6b41e6 100644 --- a/server/utils/keycloak-admin.ts +++ b/server/utils/keycloak-admin.ts @@ -495,11 +495,10 @@ export class KeycloakAdminClient { // Assign appropriate group instead of role const groupName = userData.membershipTier || 'user'; - const groupPath = `/${groupName}`; // Keycloak groups use paths with leading slash - console.log(`[keycloak-admin] Assigning user to group: ${groupName} (path: ${groupPath})`); + console.log(`[keycloak-admin] Assigning user to group: ${groupName}`); try { - const groupId = await this.getGroupByPath(groupPath); + const groupId = await this.getGroupByName(groupName); await this.assignUserToGroup(userId, groupId); console.log(`[keycloak-admin] ✅ Successfully assigned user ${userId} to group: ${groupName}`); } catch (error: any) { @@ -675,6 +674,52 @@ export class KeycloakAdminClient { return group.id; } + /** + * Get group by name (for groups without leading slash) + */ + async getGroupByName(name: string): Promise { + const adminToken = await this.getAdminToken(); + const adminBaseUrl = this.config.issuer.replace('/realms/', '/admin/realms/'); + + console.log(`[keycloak-admin] Searching for group by name: ${name}`); + + const response = await fetch(`${adminBaseUrl}/groups?search=${encodeURIComponent(name)}`, { + headers: { + 'Authorization': `Bearer ${adminToken}`, + 'User-Agent': 'MonacoUSA-Portal/1.0' + } + }); + + if (!response.ok) { + const errorText = await response.text().catch(() => 'Unknown error'); + throw new Error(`Failed to find group: ${response.status} - ${errorText}`); + } + + const groups: KeycloakGroupRepresentation[] = await response.json(); + console.log(`[keycloak-admin] Found ${groups.length} groups matching search "${name}":`, groups.map(g => ({ id: g.id, name: g.name, path: g.path }))); + + // Try exact name match first + let group = groups.find(g => g.name === name); + + // If no exact name match, try path match with leading slash + if (!group) { + group = groups.find(g => g.path === `/${name}`); + } + + // If still no match, try path match without leading slash + if (!group) { + group = groups.find(g => g.path === name); + } + + if (!group?.id) { + console.error(`[keycloak-admin] No group found matching name "${name}". Available groups:`, groups); + throw new Error(`Group not found: ${name}. Available groups: ${groups.map(g => g.name || g.path).join(', ')}`); + } + + console.log(`[keycloak-admin] Found group: ${group.name} (path: ${group.path}) with ID: ${group.id}`); + return group.id; + } + /** * Assign user to group */ @@ -778,9 +823,9 @@ export class KeycloakAdminClient { const alreadyInNewGroup = primaryGroups.some(g => g.name === newGroupName); if (!alreadyInNewGroup) { console.log(`[keycloak-admin] Adding user to new group: ${newGroupName}`); - const newGroupPath = `/${newGroupName}`; // Keycloak groups use path format with leading slash - console.log(`[keycloak-admin] Looking up group with path: ${newGroupPath}`); - const newGroupId = await this.getGroupByPath(newGroupPath); + // Try without leading slash first (groups named directly like "board") + console.log(`[keycloak-admin] Looking up group with name: ${newGroupName}`); + const newGroupId = await this.getGroupByName(newGroupName); await this.assignUserToGroup(userId, newGroupId); } else { console.log(`[keycloak-admin] User already in target group: ${newGroupName}`);