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.
 
 
 
 
 

176 lines
5.1 KiB

import type {
MarriageField,
MarriageFieldValue,
MarriagePhoneFieldValue,
MarriageBirthplaceFieldValue,
} from "@/hooks/marriage/types";
import { dictionaries } from "@/translations/dictionaries";
const persianToEnglishMap: Record<string, string> = {};
for (const [enKey, faVal] of Object.entries(dictionaries.fa)) {
if (typeof faVal === "string") {
persianToEnglishMap[faVal.trim()] = enKey;
}
}
const normalizedEnglishKeys: Record<string, string> = {};
for (const enKey of Object.keys(dictionaries.en)) {
const norm = enKey.toLowerCase().replace(/[^a-z0-9]/g, "");
if (norm) {
normalizedEnglishKeys[norm] = enKey;
}
}
export function isMarriagePhoneFieldValue(
value: unknown,
): value is MarriagePhoneFieldValue {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return false;
}
const phoneValue = value as Partial<MarriagePhoneFieldValue>;
return (
typeof phoneValue.countryCode === "string" &&
typeof phoneValue.phoneNumber === "string"
);
}
export function isMarriageBirthplaceFieldValue(
value: unknown,
): value is MarriageBirthplaceFieldValue {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return false;
}
const bpValue = value as Partial<MarriageBirthplaceFieldValue>;
return (
typeof bpValue.country === "string" && typeof bpValue.city === "string"
);
}
export function formatFieldValue(value: MarriageFieldValue): string | null {
if (value === null || value === undefined || value === "") {
return null;
}
if (isMarriagePhoneFieldValue(value)) {
return `+${value.countryCode}${value.phoneNumber}`;
}
if (typeof value === "boolean") {
return value ? "Yes" : "No";
}
if (typeof value === "object") {
if ("country" in value || "city" in value || "state" in value) {
const v = value as { country?: string; state?: string; city?: string };
const parts = [v.city, v.state, v.country]
.map((p) => (typeof p === "string" ? p.trim() : ""))
.filter(Boolean);
return parts.join(", ");
}
}
return String(value);
}
export function titleFromKey(key: string): string {
const leafKey = key.includes(".") ? key.split(".").pop()! : key;
return leafKey
.replace(/^q\d+[_-]?/i, "")
.replace(/[_-]+/g, " ")
.replace(/\s+/g, " ")
.trim()
.replace(/\b\w/g, (letter) => letter.toUpperCase());
}
export function formatFieldLabel(
field: MarriageField,
dictionary?: Record<string, string>,
): string {
const englishTitle = titleFromKey(field.key);
const rawLabel = (field.label || "").trim();
// 1. Direct dictionary match for field.label
if (rawLabel && dictionary?.[rawLabel]) {
return dictionary[rawLabel];
}
// 2. If rawLabel is in Persian, convert it to its canonical English key via reverse map
const enKeyFromFa = rawLabel ? persianToEnglishMap[rawLabel] : null;
if (enKeyFromFa) {
if (dictionary?.[enKeyFromFa]) {
return dictionary[enKeyFromFa];
}
return enKeyFromFa;
}
// 3. Direct match for English title derived from key
if (dictionary?.[englishTitle]) {
return dictionary[englishTitle];
}
// 4. Normalized match for key or label (e.g. ignoring punctuation/spaces like apostrophes and parentheses)
const normKey = (field.key || "").split(".").pop()?.toLowerCase().replace(/[^a-z0-9]/g, "") || "";
const matchedCanonicalKey = normalizedEnglishKeys[normKey];
if (matchedCanonicalKey) {
if (dictionary?.[matchedCanonicalKey]) {
return dictionary[matchedCanonicalKey];
}
return matchedCanonicalKey;
}
// 5. Fallback
return rawLabel || englishTitle;
}
export function formatOptionValue(
value: MarriageFieldValue,
dictionary?: Record<string, string>,
): string | null {
if (Array.isArray(value)) {
const formattedItems = value
.map((item) => formatOptionValue(item as MarriageFieldValue, dictionary))
.filter(Boolean);
return formattedItems.length ? formattedItems.join(", ") : null;
}
const base = formatFieldValue(value);
if (!base) return null;
const trimmed = base.trim();
// 1. Direct dictionary match
if (dictionary?.[trimmed]) return dictionary[trimmed];
// 2. Reverse map if base is in Persian
const enKeyFromFa = persianToEnglishMap[trimmed];
if (enKeyFromFa) {
if (dictionary?.[enKeyFromFa]) {
return dictionary[enKeyFromFa];
}
return enKeyFromFa;
}
// 3. Try replacing underscores with spaces: "single;_never_married" -> "single; never married"
const withSpaces = trimmed.replace(/_/g, " ").trim();
if (dictionary?.[withSpaces]) return dictionary[withSpaces];
// 4. Try capitalized first letter
const capitalized = withSpaces.charAt(0).toUpperCase() + withSpaces.slice(1);
if (dictionary?.[capitalized]) return dictionary[capitalized];
// 5. Normalized match for option value
const normVal = withSpaces.toLowerCase().replace(/[^a-z0-9]/g, "");
const matchedCanonicalKey = normalizedEnglishKeys[normVal];
if (matchedCanonicalKey) {
if (dictionary?.[matchedCanonicalKey]) {
return dictionary[matchedCanonicalKey];
}
return matchedCanonicalKey;
}
return withSpaces;
}