fix(portal): review display, hover overlay, and drag ghost for complex field types
- Extract formatFieldValue helper for shared use between review step
and confirmation page — one source of truth for TAG_PICKER,
AVAILABILITY_PICKER, and SECTION_PRIORITY display, so the raw-ID
and [object Object] leaks from two parallel stringifiers can't
regress on either side.
- TAG_PICKER: lookup via field.available_tags (server-inlined).
- AVAILABILITY_PICKER: lookup via usePublicFormTimeSlots, strip
seconds. "Laden…" while the cache warms.
- SECTION_PRIORITY: defensive shape-guard prevents [object Object]
leaks, sorted priority-prefixed rendering ("1. Bar, 2. Hospitality").
- Subtle primary-tinted hover (4% primary, primary border) replacing
the near-black Vuetify default overlay on unranked section cards.
- Explicit ghost-class / drag-class / chosen-class on vuedraggable
with solid drag-clone + elevation shadow and a 30%-opacity silhouette
at the origin, so mid-drag text no longer overlaps.
- 17 new formatFieldValue unit assertions + 2 new FieldSectionPriority
assertions locking in the draggable classes and the disabled-card
toggle at max.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,8 +6,11 @@ import FormErrorState from '@/components/public-form/FormErrorState.vue'
|
||||
import FormStepper from '@/components/public-form/FormStepper.vue'
|
||||
import SubmitterDetails from '@/components/public-form/SubmitterDetails.vue'
|
||||
import { extractErrorBody, useFetchPublicFormSchema } from '@/composables/api/usePublicForm'
|
||||
import { usePublicFormSections } from '@/composables/api/usePublicFormSections'
|
||||
import { usePublicFormTimeSlots } from '@/composables/api/usePublicFormTimeSlots'
|
||||
import { useFormDraft } from '@/composables/useFormDraft'
|
||||
import { isStepValid, useFormSteps } from '@/composables/useFormSteps'
|
||||
import { formatFieldValue } from '@/composables/formatFieldValue'
|
||||
import { providePublicFormToken } from '@/composables/publicFormInjection'
|
||||
import { FormFieldType } from '@/types/formBuilder'
|
||||
import type { FormErrorCode, PublicFormField } from '@/types/formBuilder'
|
||||
@@ -37,6 +40,14 @@ providePublicFormToken(token)
|
||||
|
||||
const schemaQuery = useFetchPublicFormSchema(tokenRef)
|
||||
|
||||
// Sibling endpoints — fetched at page level so the review step and
|
||||
// FormConfirmation can human-label AVAILABILITY_PICKER /
|
||||
// SECTION_PRIORITY values via formatFieldValue. Shares the same
|
||||
// 5-minute TanStack Query cache used by the field components, so
|
||||
// this is a free hit when those fields are rendered on screen.
|
||||
const timeSlotsQuery = usePublicFormTimeSlots(token)
|
||||
const sectionsQuery = usePublicFormSections(token)
|
||||
|
||||
const draft = useFormDraft(tokenRef, {
|
||||
locale: 'nl',
|
||||
})
|
||||
@@ -212,12 +223,12 @@ function answerableForReview(field: PublicFormField): boolean {
|
||||
}
|
||||
|
||||
function formatReviewValue(field: PublicFormField): string {
|
||||
const v = draft.values.value[field.slug]
|
||||
if (v === null || v === undefined || v === '') return '—'
|
||||
if (Array.isArray(v)) return v.length > 0 ? v.map(String).join(', ') : '—'
|
||||
if (typeof v === 'boolean') return v ? 'Ja' : 'Nee'
|
||||
|
||||
return String(v)
|
||||
return formatFieldValue(
|
||||
field,
|
||||
draft.values.value[field.slug],
|
||||
timeSlotsQuery.data.value,
|
||||
sectionsQuery.data.value,
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user