import enQuestions from "@/data/questions/en.json"; import faQuestions from "@/data/questions/fa.json"; import type { MarriageGender } from "@/hooks/marriage/types"; import { defaultLocale, type Locale } from "@/translations/config"; import { getDictionary } from "@/translations/dictionaries"; export const bookingTerms = [ "You will be contacted by your consultant.", "The call may start 10-15 minutes earlier or later than scheduled.", "Make sure you are available and in a quiet place at least 10 minutes before the session.", ] as const; export type QuestionCardIcon = | "profile" | "education" | "details" | "checklist" | "contact" | "family_marital"; type QuestionExtras = { placeHolder: string; range: [number, number]; options: string[]; noSearch?: boolean; }; type QuestionAudienceRule = { genders?: MarriageGender[]; maxAge?: number; minAge?: number; }; export type QuestionLogic = { dependsOn: { title: string; values: string[]; }; }; export type QuestionField = { title: string; type: string; required: boolean; private?: boolean; description: string; tooltip: string; extras: QuestionExtras; audience?: QuestionAudienceRule; requiredWhen?: QuestionAudienceRule; logic?: QuestionLogic; showGuardianNotice?: boolean; originalSlug?: string; originalIndex?: number; englishTitle?: string; }; export type QuestionListItem = { slug: string; title: string; estimate: string; progress: number; icon: QuestionCardIcon; required?: boolean; note?: string; showInfoBadge?: boolean; summary: string; checkpoints: readonly string[]; tooltip: string; questions: readonly QuestionField[]; audience?: QuestionAudienceRule; }; type RawQuestionListItem = { title: string; icon: string; slug: string; required?: boolean; estimateTime: string; tooltip: string; progress: number; description: string; questions: QuestionField[]; audience?: QuestionAudienceRule; }; const iconMap: Record = { "user-circle": "profile", school: "education", "heart-handshake": "details", "file-text": "contact", "layout-grid": "checklist", }; const questionsByLocale: Record = { en: enQuestions as RawQuestionListItem[], fa: faQuestions as RawQuestionListItem[], }; function mapQuestionListItem(item: RawQuestionListItem): QuestionListItem { return { slug: item.slug, title: item.title, estimate: item.estimateTime, progress: item.progress, icon: iconMap[item.icon] ?? "details", required: item.required, showInfoBadge: Boolean(item.tooltip), summary: item.description, checkpoints: item.questions.map((question) => question.title), tooltip: item.tooltip, questions: item.questions, }; } export function getQuestionListItems(locale: Locale = defaultLocale) { const rawItems = questionsByLocale[locale] ?? questionsByLocale[defaultLocale] ?? questionsByLocale.en ?? []; const enItems = questionsByLocale.en || []; const mappedRawItems = rawItems.map((item) => { const enItem = enItems.find((e) => e.slug === item.slug); if (!enItem) return item; return { ...item, questions: item.questions.map((q, idx) => { const enQ = enItem.questions[idx]; return { ...q, englishTitle: enQ ? enQ.title : q.title, }; }), }; }); const items = mappedRawItems.map(mapQuestionListItem); const fbIndex = items.findIndex((item) => item.slug === "family_background"); const mhIndex = items.findIndex( (item) => item.slug === "marital_history_children", ); if (fbIndex !== -1 && mhIndex !== -1) { const fbItem = items[fbIndex]; const mhItem = items[mhIndex]; const dict = getDictionary(locale); const mergedTitle = (dict as any)["Family Background, Marital Status, and Children"] || "Family Background, Marital Status, and Children"; const mergedEstimate = (dict as any)["20 minutes"] || "20 minutes"; const fbQuestions = fbItem.questions.map((q, idx) => ({ ...q, originalSlug: "family_background", originalIndex: idx, })); const mhQuestions = mhItem.questions.map((q, idx) => ({ ...q, originalSlug: "marital_history_children", originalIndex: idx, })); const finalQuestions = [...fbQuestions, ...mhQuestions]; const mergedItem: QuestionListItem = { slug: "family_marital_history", title: mergedTitle, estimate: mergedEstimate, progress: 0, icon: "family_marital", required: fbItem.required || mhItem.required, showInfoBadge: fbItem.showInfoBadge || mhItem.showInfoBadge, summary: `${fbItem.summary}\n\n${mhItem.summary}`, checkpoints: [...fbItem.checkpoints, ...mhItem.checkpoints], tooltip: fbItem.tooltip || mhItem.tooltip, questions: finalQuestions, }; const newItems = [...items]; newItems[fbIndex] = mergedItem; newItems.splice(mhIndex, 1); // Reorder items: bring future_spouse_criteria and identity_verification above the tests const personalityIndex = newItems.findIndex( (item) => item.slug === "personality_test", ); const spouseItem = newItems.find( (item) => item.slug === "future_spouse_criteria", ); const identityItem = newItems.find( (item) => item.slug === "identity_verification", ); if (personalityIndex !== -1 && (spouseItem || identityItem)) { const filtered = newItems.filter( (item) => item.slug !== "future_spouse_criteria" && item.slug !== "identity_verification", ); const insertAt = filtered.findIndex( (item) => item.slug === "personality_test", ); if (insertAt !== -1) { const result = [...filtered]; const itemsToInsert = []; if (spouseItem) itemsToInsert.push(spouseItem); if (identityItem) itemsToInsert.push(identityItem); result.splice(insertAt, 0, ...itemsToInsert); return result; } } return newItems; } // Also handle reordering if fbIndex/mhIndex are not found (fallback) const personalityIndex = items.findIndex( (item) => item.slug === "personality_test", ); const spouseItem = items.find( (item) => item.slug === "future_spouse_criteria", ); const identityItem = items.find( (item) => item.slug === "identity_verification", ); if (personalityIndex !== -1 && (spouseItem || identityItem)) { const filtered = items.filter( (item) => item.slug !== "future_spouse_criteria" && item.slug !== "identity_verification", ); const insertAt = filtered.findIndex( (item) => item.slug === "personality_test", ); if (insertAt !== -1) { const result = [...filtered]; const itemsToInsert = []; if (spouseItem) itemsToInsert.push(spouseItem); if (identityItem) itemsToInsert.push(identityItem); result.splice(insertAt, 0, ...itemsToInsert); return result; } } return items; } export function getQuestionListItemBySlug( slug: string, locale: Locale = defaultLocale, ) { return getQuestionListItems(locale).find((item) => item.slug === slug); } function matchesAudienceRule( rule: QuestionAudienceRule | undefined, profile: { age?: number | null; gender?: MarriageGender | null; }, ) { if (!rule) { return true; } if ( rule.genders?.length && profile.gender && !rule.genders.includes(profile.gender) ) { return false; } if ( typeof rule.minAge === "number" && profile.age != null && profile.age < rule.minAge ) { return false; } if ( typeof rule.maxAge === "number" && profile.age != null && profile.age > rule.maxAge ) { return false; } return true; } export function isQuestionListItemVisibleForProfile( item: QuestionListItem, profile: { age?: number | null; gender?: MarriageGender | null; }, ) { return matchesAudienceRule(item.audience, profile); } export function isQuestionVisibleForProfile( question: QuestionField, profile: { age?: number | null; gender?: MarriageGender | null; }, ) { return matchesAudienceRule(question.audience, profile); } export function isQuestionRequiredForProfile( question: QuestionField, profile: { age?: number | null; gender?: MarriageGender | null; }, ) { return ( question.required || (Boolean(question.requiredWhen) && matchesAudienceRule(question.requiredWhen, profile)) ); } export function getRequiredQuestionsCount( slug: string, profile: { age?: number | null; gender?: MarriageGender | null; }, locale: Locale = defaultLocale, ) { const item = getQuestionListItemBySlug(slug, locale); if (!item) return 0; return item.questions.filter((q) => isQuestionRequiredForProfile(q, profile)) .length; }