From 948965e664200aa862b960d9c314d221acf42867 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Tue, 14 Apr 2026 22:31:32 +0200 Subject: [PATCH] fix: time slot dropdown group headers and dimming via boundary detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VAutocomplete ignores interleaved fake header items — they were filtered out before reaching the template. Replace with Approach A: keep only real selectable items sorted by group, detect group boundaries in the #item template by comparing adjacent groupName values, and render VListSubheader before each new group. - Remove _isGroupHeader from TimeSlotDropdownItem interface - Rename groupTimeSlots → sortedItems (returns only selectable items) - Add hasGroups computed for conditional header rendering - Add isNewGroup(index) boundary detection in CreateShiftDialog - Add scoped .time-slot-dimmed CSS class (opacity: 0.65) Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/app/auto-imports.d.ts | 2 + .../components/sections/CreateShiftDialog.vue | 40 +++++++++---- .../src/composables/useTimeSlotDropdown.ts | 58 ++++++++----------- 3 files changed, 56 insertions(+), 44 deletions(-) diff --git a/apps/app/auto-imports.d.ts b/apps/app/auto-imports.d.ts index 46afb6f5..8adf5b53 100644 --- a/apps/app/auto-imports.d.ts +++ b/apps/app/auto-imports.d.ts @@ -323,6 +323,7 @@ declare global { const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn'] const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory'] const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo'] + const useTimeSlotDropdown: typeof import('./src/composables/useTimeSlotDropdown')['useTimeSlotDropdown'] const useTimeout: typeof import('@vueuse/core')['useTimeout'] const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn'] const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll'] @@ -681,6 +682,7 @@ declare module 'vue' { readonly useThrottleFn: UnwrapRef readonly useThrottledRefHistory: UnwrapRef readonly useTimeAgo: UnwrapRef + readonly useTimeSlotDropdown: UnwrapRef readonly useTimeout: UnwrapRef readonly useTimeoutFn: UnwrapRef readonly useTimeoutPoll: UnwrapRef diff --git a/apps/app/src/components/sections/CreateShiftDialog.vue b/apps/app/src/components/sections/CreateShiftDialog.vue index e9099e60..ccdffd54 100644 --- a/apps/app/src/components/sections/CreateShiftDialog.vue +++ b/apps/app/src/components/sections/CreateShiftDialog.vue @@ -36,7 +36,7 @@ const { data: eventDetail } = useEventDetail(orgIdRef, eventIdRef) const sectionRef = computed(() => props.section ?? null) // Determine dropdown scenario -const { scenario, showInfoTooltip, tooltipText, fetchParams, groupTimeSlots } = useTimeSlotDropdown( +const { scenario, showInfoTooltip, hasGroups, tooltipText, fetchParams, sortedItems } = useTimeSlotDropdown( eventDetail, sectionRef, ) @@ -95,8 +95,8 @@ watch( { immediate: true }, ) -// Group time slots for the dropdown -const flattenedTimeSlots = computed(() => { +// Build sorted dropdown items (no fake header items — groups are detected by boundary) +const dropdownItems = computed(() => { // While loading, show the current shift's time slot so the dropdown doesn't flash a raw ULID if (!timeSlots.value?.length) { if (props.shift?.time_slot) { @@ -106,7 +106,6 @@ const flattenedTimeSlots = computed(() => { name: ts.name, timeRange: `${ts.start_time} – ${ts.end_time}`, displayLabel: ts.name, - _isGroupHeader: false, _isDimmed: false, groupName: '', }] @@ -114,10 +113,16 @@ const flattenedTimeSlots = computed(() => { return [] } - return groupTimeSlots(timeSlots.value) + return sortedItems(timeSlots.value) }) -const hasTimeSlots = computed(() => flattenedTimeSlots.value.some(i => !i._isGroupHeader)) +const hasTimeSlots = computed(() => dropdownItems.value.length > 0) + +// Detect group boundaries: true when the current item starts a new group +function isNewGroup(index: number): boolean { + if (index === 0) return true + return dropdownItems.value[index]?.groupName !== dropdownItems.value[index - 1]?.groupName +} const statusOptions = [ { title: 'Concept', value: 'draft' }, @@ -231,7 +236,7 @@ function onSubmit() { -