import type { FormSchemaResponse, FormSection, FormQuestion, FormOverviewResponse, } from "@/hooks/marriage/use-form-schema"; import { defaultLocale, type Locale } from "@/translations/config"; export type QuestionCardIcon = | "profile" | "contact" | "health" | "education" | "family" | "marriage" | "lifestyle" | "criteria" | "verification" | "personality" | "glasser" | "details" | "checklist" | "family_marital"; export const sectionSlugIconMap: Record = { personal_info: "profile", personal_identity: "profile", contact_residence_family_communication: "contact", contact_residence: "contact", appearance_health_activity: "health", appearance_health: "health", education_career_economic_status: "education", education_career: "education", family_background: "family", marital_history_children: "marriage", marital_history: "marriage", beliefs_lifestyle_boundaries: "lifestyle", beliefs_lifestyle: "lifestyle", future_spouse_criteria: "criteria", spouse_criteria: "criteria", identity_verification: "verification", documents_verification: "verification", personality_test: "personality", cattell_test: "personality", glasser_5_needs_test: "glasser", glasser_test: "glasser", }; export function resolveSectionIcon( slug: string, backendIcon?: string, ): QuestionCardIcon { if (slug && sectionSlugIconMap[slug]) { return sectionSlugIconMap[slug]; } if (backendIcon && iconMap[backendIcon]) { return iconMap[backendIcon]; } return "details"; } export type QuestionExtras = { placeHolder: string; range: [number, number]; options: string[]; noSearch?: boolean; }; export type QuestionAudienceRule = { genders?: string[]; maxAge?: number; minAge?: number; }; export type QuestionField = { id: string; title: string; type: string; order: number; required: boolean; baseRequired: boolean; isVisible: boolean; private?: boolean; description: string; tooltip: string; validation?: any; ui_config?: any; extras: QuestionExtras; audience?: QuestionAudienceRule | any; requiredWhen?: any; conditionalRule?: any; visibility?: any; logic?: any; showGuardianNotice?: boolean; options: { id: string; value: string | number; label: string; order: number; }[]; }; export type QuestionListItem = { slug: string; title: string; estimate: string; progress: number; icon: QuestionCardIcon; required: boolean; showInfoBadge?: boolean; summary: string; checkpoints: string[]; tooltip?: string; note?: string; questions: QuestionField[]; }; const iconMap: Record = { "user-circle": "profile", user: "profile", person: "profile", school: "education", education: "education", "heart-handshake": "marriage", "heart-pulse": "health", activity: "health", "file-text": "contact", contact: "contact", users: "family", family: "family", compass: "lifestyle", "target-heart": "criteria", "shield-check": "verification", "shield": "verification", brain: "personality", "layout-grid": "checklist", "star-half": "glasser", star: "glasser", }; export function mapBackendQuestionToFrontend( bq: FormQuestion, index: number, ): QuestionField { const minVal = bq.validation?.min; const maxVal = bq.validation?.max; const rangeVal = bq.validation?.range; const uiRange = bq.ui_config?.range; const uiMin = bq.ui_config?.min; const uiMax = bq.ui_config?.max; let range: [number, number] = [0, 0]; if ( Array.isArray(uiRange) && uiRange.length === 2 && (uiRange[0] !== 0 || uiRange[1] !== 0) ) { range = [Number(uiRange[0]), Number(uiRange[1])]; } else if ( Array.isArray(rangeVal) && rangeVal.length === 2 && (rangeVal[0] !== 0 || rangeVal[1] !== 0) ) { range = [Number(rangeVal[0]), Number(rangeVal[1])]; } else if (minVal !== undefined && maxVal !== undefined) { range = [Number(minVal), Number(maxVal)]; } else if (uiMin !== undefined && uiMax !== undefined) { range = [Number(uiMin), Number(uiMax)]; } else if (Array.isArray(uiRange) && uiRange.length === 2) { range = [Number(uiRange[0]), Number(uiRange[1])]; } return { id: bq.id, title: bq.title || "Untitled", type: bq.type, order: bq.order !== undefined ? bq.order : index, required: bq.is_required !== undefined ? bq.is_required : bq.required, baseRequired: bq.required, isVisible: bq.is_visible, private: bq.ui_config?.private, validation: bq.validation, ui_config: bq.ui_config, description: bq.description || "", tooltip: bq.tooltip || "", extras: { placeHolder: bq.placeholder || "", options: bq.options?.map((o) => o.label) || [], range, noSearch: bq.ui_config?.noSearch, }, showGuardianNotice: bq.show_guardian_notice, audience: bq.audience || undefined, requiredWhen: bq.required_when || undefined, conditionalRule: bq.conditional_rule || bq.visibility || bq.logic || undefined, visibility: bq.visibility || bq.conditional_rule || undefined, logic: bq.logic || undefined, options: [...(bq.options || [])].sort( (a, b) => (a.order ?? 0) - (b.order ?? 0), ), }; } export function mapBackendSectionToFrontend( section: FormSection, progress: number, ): QuestionListItem { const allQuestions: QuestionField[] = []; let index = 0; const cards = [...(section.cards || [])].sort( (a, b) => (a.order ?? 0) - (b.order ?? 0), ); cards.forEach((card) => { const questions = [...(card.questions || [])].sort( (a, b) => (a.order ?? 0) - (b.order ?? 0), ); questions.forEach((q) => { const fq = mapBackendQuestionToFrontend(q, index); allQuestions.push(fq); index++; }); }); return { slug: section.id, title: section.title, estimate: section.estimated_minutes ? `${section.estimated_minutes} min` : "5 min", progress: progress, icon: resolveSectionIcon(section.id, section.icon), required: section.is_required, showInfoBadge: false, summary: "", checkpoints: allQuestions.map((q) => q.title), tooltip: "", questions: allQuestions, }; } export function convertSchemaToFrontendItems( schema: FormSchemaResponse | undefined, locale: Locale = defaultLocale, ): QuestionListItem[] { if (!schema) return []; const rawItems = schema.sections.map((sec) => { const progInfo = schema.progress?.sections_progress?.[sec.id]; const progress = progInfo ? progInfo.completion_percent : 0; return mapBackendSectionToFrontend(sec, progress); }); return rawItems.sort( (a, b) => (schema.sections.find((s) => s.id === a.slug)?.order ?? 0) - (schema.sections.find((s) => s.id === b.slug)?.order ?? 0), ); } export function convertOverviewToFrontendItems( overview: FormOverviewResponse | undefined, ): QuestionListItem[] { if (!overview) return []; return [...overview.sections] .sort((a, b) => a.order - b.order) .map((section) => ({ slug: section.id, title: section.title, estimate: section.estimated_minutes ? `${section.estimated_minutes} min` : "5 min", progress: section.progress?.completion_percent ?? 0, icon: resolveSectionIcon(section.id, section.icon), required: section.is_required, showInfoBadge: false, summary: "", checkpoints: [], tooltip: "", questions: [], })); }