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
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));
|
|
}
|