You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

144 lines
3.8 KiB

import type {
FormSchemaResponse,
FormSection,
FormQuestion,
} from "@/hooks/marriage/use-form-schema";
import { defaultLocale, type Locale } from "@/translations/config";
export type QuestionCardIcon =
| "profile"
| "education"
| "details"
| "checklist"
| "contact"
| "family_marital";
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;
requiredWhen?: QuestionAudienceRule;
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<string, QuestionCardIcon> = {
"user-circle": "profile",
school: "education",
"heart-handshake": "details",
"file-text": "contact",
"layout-grid": "checklist",
};
export function mapBackendQuestionToFrontend(bq: FormQuestion, index: number): QuestionField {
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: bq.ui_config?.range || [0, 0],
noSearch: bq.ui_config?.noSearch,
},
showGuardianNotice: bq.show_guardian_notice,
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: iconMap[section.icon] ?? "details",
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));
}