import { Member as CwMember } from "../../generated/prisma/client"; import { User as ApiUser } from "../../../api/generated/prisma/client"; import { Translation, skipRow } from "./types"; const isValidEmail = (value: string | null): boolean => { const normalized = value?.trim().toLowerCase(); return !!normalized && normalized.includes("@"); }; const isFullMember = (row: CwMember): boolean => row.memberClass === "F" && isValidEmail(row.emailAddress); /** * For full members, use their real email. * For hidden members (non-F or missing valid email), generate a stable * placeholder that satisfies the unique non-null login/email constraints. */ const resolveEmail = (row: CwMember): string => { if (isFullMember(row)) { return row.emailAddress!.trim().toLowerCase(); } return `${row.memberId}@cw.local`; }; export const userTranslation: Translation = { values: [ { from: "memberId", to: "login", // Use memberId@cw.local as a stable, unique login for all synced members. // The real email goes into `email`; Microsoft OAuth overwrites `login` with // the UPN on first login so this value is only a placeholder. process: (value) => `${value}@cw.local`, }, { from: "firstName", to: "firstName", process: (value) => (value && value.trim() ? value.trim() : "Unknown"), }, { from: "lastName", to: "lastName", process: (value) => (value && value.trim() ? value.trim() : "Unknown"), }, { from: "emailAddress", to: "email", process: (_value, _context, row) => resolveEmail(row), }, { from: "memberRecId", to: "cwMemberId" }, { from: "memberId", to: "cwIdentifier", process: (value) => { const normalized = value?.trim(); return normalized ? normalized : null; }, }, { from: "inactiveFlag", to: "active", process: (value) => !value, }, { from: "memberClass", to: "hidden", process: (_value, _context, row) => !isFullMember(row), }, { from: "dateHire", to: "createdAt", process: (value, _context, row) => value ?? row.lastUpdatedUtc, }, { from: "lastUpdatedUtc", to: "updatedAt" }, ], };