@realtek/core-theme 0.0.366 → 0.0.367

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"AddFormV1-CRP2dpGK.js","names":[],"sources":["../src/utils/autoValueRules.js","../src/components/form/duplicateRecord.js","../src/components/form/useDuplicateCheck.js","../src/components/form/storedFileName.js","../src/services/pendingHandoff.js","../src/services/skillMatchApi.js","../src/services/candidatesApi.js","../src/services/sourceProviderActions.js","../src/components/AddFormV1.jsx"],"sourcesContent":["// Field-level \"force a value based on who is submitting\" rules.\n//\n// This is the FRONTEND half of an admin-configured feature (formGroupConfig →\n// field.autoValueRules), e.g. a submission's \"Submit Source\" that must read\n// External when an employer-type user submits and Internal for everyone else.\n//\n// It mirrors the backend exactly (models.AutoValueRule.Matches +\n// applyAutoValueRules in moduleWriteOrchestrator.go). The backend is the\n// authority — it re-evaluates these rules from the auth token on every\n// create/update, so a request that bypasses the UI is still corrected. This copy\n// exists purely so the user SEES the forced value while filling the form.\n//\n// Nothing here special-cases a module, field, role or value: which roleId/userId\n// maps to which value is entirely admin data.\n\n// autoValueFor evaluates a field's rules against the acting user's identity\n// ({roleId, userId}). whenRoleId and whenUserId are OR-ed; a rule with neither\n// set never fires. First matching rule wins — same as the backend.\nexport function autoValueFor(field, identity = {}) {\n const rules = Array.isArray(field?.autoValueRules) ? field.autoValueRules : [];\n for (const rule of rules) {\n const roles = Array.isArray(rule?.whenRoleId) ? rule.whenRoleId.map(Number) : [];\n const users = Array.isArray(rule?.whenUserId) ? rule.whenUserId.map(Number) : [];\n const roleHit = identity.roleId !== undefined && roles.includes(identity.roleId);\n const userHit = identity.userId !== undefined && users.includes(identity.userId);\n if (roleHit || userHit) return { matched: true, value: rule.value };\n }\n return { matched: false, value: undefined };\n}\n\nexport default autoValueFor;\n","// ─────────────────────────────────────────────────────────────────────────\n// duplicateRecord — the client half of the staged duplicate check.\n//\n// The backend (POST /v1/module/duplicate-check) decides WHETHER a record is a\n// duplicate, entirely from the module's configured stages. This module decides\n// only how to SAY it, and it takes every word from config too:\n//\n// automations.duplicateCheck.message → the sentence, with {tokens}\n// automations.duplicateCheck.policy → \"prompt\" (offer to update) | \"block\"\n// automations.duplicateCheck.displayFields → which keys name the record\n//\n// Nothing here knows a module, a field, or how long \"recently\" is.\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * describeAge — \"how stale is the existing record?\", in words.\n *\n * The requirement asks for exactly this: \"in the error message we need to show\n * last updated date — for example 60 days back the same candidate is updated,\n * like that — so we can get a proper idea that the candidate already was there\n * with the date.\"\n *\n * A bare date (\"07 Aug 2026\") makes the reader do the arithmetic; the elapsed\n * time is the part that carries the decision, so both are offered and the\n * caller's template chooses.\n */\nexport function describeAge(daysAgo) {\n // null/undefined/'' must NOT fall through to Number()'s 0, which would render\n // a record with no timestamp at all as \"updated today\" — a confident false\n // statement about exactly the fact the user is being asked to judge.\n if (daysAgo === null || daysAgo === undefined || daysAgo === '') return '';\n const days = Number(daysAgo);\n if (!Number.isFinite(days) || days < 0) return '';\n if (days === 0) return 'today';\n if (days === 1) return 'yesterday';\n if (days < 30) return `${days} days ago`;\n if (days < 60) return 'about a month ago';\n if (days < 365) return `about ${Math.round(days / 30)} months ago`;\n const years = Math.floor(days / 365);\n return years === 1 ? 'over a year ago' : `over ${years} years ago`;\n}\n\n/**\n * describeRecord — a human label for the matched record, built from whichever\n * of the configured display fields actually carry a value.\n */\nexport function describeRecord(record, displayFields) {\n const keys = Array.isArray(displayFields) && displayFields.length\n ? displayFields\n : Object.keys(record ?? {});\n const parts = keys\n .map((key) => record?.[key])\n .map((v) => (v === null || v === undefined ? '' : String(v).trim()))\n .filter(Boolean);\n return parts.join(' · ');\n}\n\n/**\n * fillTemplate — {token} substitution. An unknown token is left INTACT so a\n * typo in admin config is visible rather than silently blanking the sentence.\n */\nexport function fillTemplate(template, tokens = {}) {\n if (!template) return '';\n return String(template).replace(\n /\\{(\\w+)\\}/g,\n (match, key) => (tokens[key] === undefined ? match : String(tokens[key])),\n );\n}\n\n/**\n * duplicateTokens — everything a configured message may reference.\n */\nexport function duplicateTokens(result, displayFields) {\n const name = describeRecord(result?.record, displayFields);\n const age = describeAge(result?.updatedDaysAgo);\n return {\n name: name || 'an existing record',\n age: age || 'previously',\n days: Number.isFinite(Number(result?.updatedDaysAgo)) ? String(result.updatedDaysAgo) : '',\n updatedOn: result?.updatedAt ? String(result.updatedAt).slice(0, 10) : '',\n stage: result?.stage ?? '',\n weight: result?.weight ?? '',\n };\n}\n\n// Default wording, used until an admin writes their own. Deliberately states\n// BOTH the identity and the age, because those are the two things that let\n// someone decide whether this really is the same person.\nexport const DEFAULT_DUPLICATE_MESSAGE =\n 'We already have {name} on file \\u2014 last updated {age}. '\n + 'You can carry on and update that record with what you\\u2019ve just entered, '\n + 'or go back and check first.';\n\nexport const DEFAULT_BLOCK_MESSAGE =\n 'We already have {name} on file \\u2014 last updated {age}. '\n + 'Please open that record and update it, rather than adding a second copy.';\n\n/**\n * duplicateMessage — the finished sentence for a result.\n */\nexport function duplicateMessage(result, cfg = {}) {\n const tokens = duplicateTokens(result, cfg.displayFields);\n const isBlock = (result?.policy ?? cfg.policy) === 'block';\n const template = result?.message\n || cfg.message\n || (isBlock ? DEFAULT_BLOCK_MESSAGE : DEFAULT_DUPLICATE_MESSAGE);\n return fillTemplate(template, tokens);\n}\n\n/**\n * duplicateBlocks — should the create be refused outright?\n *\n * The response's own policy wins (it comes from the module config the backend\n * actually applied); the caller's config is only a fallback for a backend that\n * predates the field. Default is \"prompt\", so a misconfiguration inconveniences\n * rather than blocks.\n */\nexport function duplicateBlocks(result, cfg = {}) {\n if (!result?.duplicate) return false;\n return (result.policy ?? cfg.policy ?? 'prompt') === 'block';\n}\n\n/**\n * duplicateFacts — the matched record as scannable label/value pairs.\n *\n * The prose sentence carries the same information, but a reader deciding \"is\n * this the same person?\" should not have to parse it out of a paragraph. The\n * facts that settle it are WHO and HOW STALE, so those are surfaced; whatever\n * else the module chose to display comes with them.\n *\n * Labels are derived from the key itself (\"firstName\" → \"First name\"), so a\n * module that adds a display field gets a sensible label with no extra config.\n */\nexport function duplicateFacts(result, displayFields) {\n const record = result?.record ?? {};\n const keys = Array.isArray(displayFields) && displayFields.length\n ? displayFields\n : Object.keys(record);\n\n const facts = keys\n .map((key) => ({ label: humanizeKey(key), value: record[key] }))\n .filter((f) => f.label && f.value !== undefined && f.value !== null && String(f.value).trim() !== '');\n\n const age = describeAge(result?.updatedDaysAgo);\n if (age) facts.push({ label: 'Last updated', value: age });\n return facts;\n}\n\n// humanizeKey — \"firstName\" / \"contact_number\" → \"First name\".\n// Only the first word is capitalised: these are labels in a list, not titles.\nfunction humanizeKey(key) {\n const words = String(key ?? '')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/[_\\-.]+/g, ' ')\n .trim()\n .toLowerCase();\n return words ? words.charAt(0).toUpperCase() + words.slice(1) : '';\n}\n","// ─────────────────────────────────────────────────────────────────────────\n// useDuplicateCheck — \"have we got this person already?\", asked at the moment\n// it is useful.\n//\n// WHEN IT RUNS\n// • right after a résumé has been read and the form filled in, because that\n// is the first time an email and phone number exist to check;\n// • again on submit, as the authoritative gate.\n//\n// WHAT IT SHOWS\n// A dialog naming the existing record and how long ago it was touched, with the\n// two things a user can actually do: open that record and update it (the new\n// file is kept as another version), or go back and look again. Every word comes\n// from the module's own config — see components/form/duplicateRecord.js.\n//\n// It FAILS OPEN. A check that cannot run (offline, a backend that predates the\n// endpoint, a module with no stages configured) must never stop someone\n// creating a legitimate record.\n// ─────────────────────────────────────────────────────────────────────────\nimport { useCallback, useRef, useState } from 'react';\nimport { checkDuplicateRecord } from '../../services/uniqueValidationApi';\nimport { duplicateMessage, duplicateBlocks, duplicateFacts } from './duplicateRecord';\nimport { openFormDecision, openFormNotice } from './formDecisionDialog';\n\n/**\n * @param {object} opts\n * @param {object} opts.form the antd form instance\n * @param {string} opts.moduleName module being created\n * @param {string} [opts.recordId] set on EDIT, so a record never matches itself\n * @param {object} [opts.config] { message, policy, displayFields } fallback\n * @param {function}[opts.onUseExisting] called with the matched id when the user\n * chooses to update the existing record\n */\nexport default function useDuplicateCheck({\n form,\n moduleName,\n recordId,\n config = {},\n onUseExisting,\n} = {}) {\n const [checking, setChecking] = useState(false);\n // Remembers a match the user has already accepted, so submitting after\n // choosing \"update the existing one\" does not ask the same question twice.\n const acknowledged = useRef(null);\n\n /**\n * check — ask the backend.\n *\n * `payload` overrides the form's own values. That matters right after a\n * résumé is read: the parsed email and phone exist in the RESPONSE and are\n * not on the form yet, so checking the form would ask about a blank page.\n */\n const check = useCallback(async (payload) => {\n if (!moduleName) return { duplicate: false };\n setChecking(true);\n try {\n return await checkDuplicateRecord({\n module: moduleName,\n payload: payload ?? form.getFieldsValue(true) ?? {},\n excludeId: recordId,\n });\n } finally {\n setChecking(false);\n }\n }, [form, moduleName, recordId]);\n\n /**\n * prompt — run the check and, if something matches, ask.\n *\n * Resolves to:\n * 'clear' nothing matched — carry on\n * 'existing' the user chose to update the record we already have\n * 'blocked' the module is set to refuse, or the user backed out\n */\n const prompt = useCallback(async ({ reason, payload, carry } = {}) => {\n const result = await check(payload);\n if (!result?.duplicate) {\n acknowledged.current = null;\n return 'clear';\n }\n if (acknowledged.current && acknowledged.current === result.id) return 'existing';\n\n const body = duplicateMessage(result, config);\n // The two things that actually decide the answer — WHO matched and HOW OLD\n // that record is — are shown as facts rather than left inside the sentence.\n const facts = duplicateFacts(result, config.displayFields);\n // A stage-1 hit (email or phone) is near proof; a stage-2 hit (name only)\n // is a maybe. Saying which stops both being read with the same weight.\n const heading = result.weight === 'weak'\n ? 'This might be someone you already have'\n : 'You already have this person on file';\n\n if (duplicateBlocks(result, config)) {\n await openFormNotice({ tone: 'duplicate', title: heading, facts, body });\n return 'blocked';\n }\n\n const useExisting = await openFormDecision({\n tone: 'duplicate',\n title: heading,\n facts,\n body,\n // Naming the OUTCOMES rather than \"OK\"/\"Cancel\": the choice is between\n // two different results, and neither is obviously the default.\n okText: 'Open their record',\n cancelText: 'Let me check first',\n // Says what happens to the FILE, because that is the thing the user has\n // just spent effort on and the thing they will assume is lost.\n footnote: carry?.files\n ? 'We\\u2019ll take you to their record with the r\\u00e9sum\\u00e9 you just uploaded already '\n + 'attached \\u2014 save there to keep it. The one already on file is kept too, as an '\n + 'earlier version. Nothing on this form has been filled in.'\n : 'Everything already on their record is kept. Nothing on this form has been filled in.',\n });\n\n if (!useExisting) return 'blocked';\n acknowledged.current = result.id ?? true;\n // The whole result is handed over, because it carries `editRoute` — the\n // configured path for opening the matched record. The caller must never\n // derive that path; see DuplicateCheckStrategy.EditRoute.\n // `carry` travels through untouched — today the file the user just\n // uploaded, so it arrives with them at the existing record instead of\n // having to be found and attached again.\n onUseExisting?.(result.id, result, reason, carry);\n return 'existing';\n }, [check, config, onUseExisting]);\n\n return { prompt, check, checking, acknowledgedId: acknowledged };\n}\n","// =============================================================================\n// The display name of an ALREADY-STORED file\n// -----------------------------------------------------------------------------\n// Legacy candidate schemas are NOT uniform about where a file's original name\n// lives, and the fileFieldMaps config says so out loud:\n//\n// passport passportUploadName ← \"upload name\"\n// alternateVisa alternateVisaUploadName ← \"upload name\"\n// visa visaUniqueName ← \"UNIQUE name\" holds the\n// ORIGINAL name here\n// resume uploadedFileName\n//\n// Matching only on `*UploadName` therefore found nothing for a visa, the name\n// resolved to empty, and the form fell back to the literal string \"file\" — so a\n// submission prefilled from a candidate showed Passport and Alternate Visa\n// correctly and the Visa as an anonymous \"file\". The user could not tell what\n// had been attached, or whether it was the right document.\n//\n// Ordering matters as much as the keys. `*CopyUniqueName` holds the SANITISED\n// name (\"Resume_of_Vinoth_Satti.doc\"), so it is consulted last: it is better\n// than \"file\", but it is not what the user uploaded.\n// =============================================================================\n\n/** Suffix groups, best first. Each is matched case-insensitively. */\nconst NAME_KEY_SUFFIXES = [\n // The original filename, under the two names the schemas give it.\n ['uploadname', 'uploadedfilename', 'originalname', 'filename'],\n // visa reuses \"unique name\" for the original — but NOT the \"copy unique\n // name\", which is the sanitised form and is handled in the next group.\n ['uniquename'],\n];\n\nconst SANITISED_SUFFIX = 'copyuniquename';\n\nfunction suffixMatch(key, suffixes, { excludeSanitised = false } = {}) {\n const lower = String(key).toLowerCase();\n if (excludeSanitised && lower.endsWith(SANITISED_SUFFIX)) return false;\n return suffixes.some((suffix) => lower.endsWith(suffix));\n}\n\n/**\n * storedFileName — the name to show for a stored file container.\n *\n * Returns '' when the object carries no usable name, so the caller decides what\n * to do about that rather than being handed a placeholder that looks like data.\n */\nexport function storedFileName(value) {\n if (!value || typeof value !== 'object') return '';\n\n const direct = value.uploadedFileName ?? value.name;\n if (typeof direct === 'string' && direct.trim()) return direct.trim();\n\n const entries = Object.entries(value)\n .filter(([, v]) => typeof v === 'string' && v.trim());\n\n for (const suffixes of NAME_KEY_SUFFIXES) {\n const hit = entries.find(([k]) => suffixMatch(k, suffixes, { excludeSanitised: true }));\n if (hit) return hit[1].trim();\n }\n // Last resort: the sanitised copy name. Underscored and not what was\n // uploaded, but it names the document, which \"file\" does not.\n const sanitised = entries.find(([k]) => String(k).toLowerCase().endsWith(SANITISED_SUFFIX));\n return sanitised ? sanitised[1].trim() : '';\n}\n\n/**\n * storedFileUrl — the storage location of a stored file container, under any of\n * the names the legacy schemas use.\n */\nexport function storedFileUrl(value) {\n if (!value || typeof value !== 'object') return '';\n const direct = value.location ?? value.url;\n if (typeof direct === 'string' && direct.trim()) return direct.trim();\n const hit = Object.entries(value).find(([k, v]) => (\n typeof v === 'string' && v.trim() && String(k).toLowerCase().endsWith('copylocation')\n ));\n return hit ? hit[1].trim() : '';\n}\n","// pendingHandoff — pass an in-flight Promise from one route to the next.\n//\n// react-router's navigate(path, { state }) stores `state` via\n// history.pushState, which requires the value to be STRUCTURED-CLONEABLE.\n// A Promise is not: passing one directly throws\n// \"Failed to execute 'pushState' on 'History': #<Promise> could not be\n// cloned\" — silently killing the navigation itself, not just the feature that\n// tried to carry the promise.\n//\n// The fix is a token indirection: stash the promise in an in-memory map and\n// hand nav state a plain string key instead. Both routes live in the same SPA\n// runtime, so the map survives the navigation; a hard reload or a link opened\n// in a new tab naturally has no entry, which callers must treat as \"nothing to\n// wait for\" (never as an error).\nconst pending = new Map();\nlet counter = 0;\n\n/**\n * Stash a promise and return a token to carry through navigate(path, { state }).\n * @param {Promise<any>} promise\n * @returns {string} token\n */\nexport function stashPendingPromise(promise) {\n const token = `ph_${Date.now()}_${(counter += 1)}`;\n pending.set(token, promise);\n // Self-cleaning: if the destination never mounts to consume it (the user\n // cancels, or navigates elsewhere first), don't hold the promise forever.\n promise.finally(() => {\n setTimeout(() => pending.delete(token), 0);\n }).catch(() => {}); // already-handled elsewhere; this is only cleanup\n return token;\n}\n\n/**\n * Retrieve and remove a stashed promise by token. Returns undefined for an\n * unknown/already-consumed token — callers must treat that as \"nothing to\n * wait for\", not as an error (e.g. the page was reloaded, or opened directly).\n * @param {string | undefined} token\n * @returns {Promise<any> | undefined}\n */\nexport function takePendingPromise(token) {\n if (!token) return undefined;\n const promise = pending.get(token);\n pending.delete(token);\n return promise;\n}\n","import { ensureToken } from './authApi';\nimport { AUTH_URL } from './apiConfig';\n\n// ── Relevant-skill matching ─────────────────────────────────────────────────\n// Which of a candidate's skills does this job actually need?\n//\n// Sends IDS ONLY. The gateway reads both records from the caller's own\n// tenant-scoped database and calls the configured AI service, so this file —\n// like every other service module here — never holds a service URL or a\n// credential.\n//\n// NEVER THROWS and never rejects: the only caller is a submission flow, and a\n// failed match must degrade to \"the recruiter fills Relevant Skills by hand\",\n// exactly as today. An empty list is the honest answer for every failure.\n\n/**\n * @param {Object} args\n * @param {string} args.jobId\n * @param {string} args.applicantId\n * @param {number} [args.timeoutMs=15000] give up and return [] after this\n * @returns {Promise<string[]>} the candidate's skills this job asks for\n */\nexport async function matchRelevantSkills({ jobId, applicantId, timeoutMs = 15000 }) {\n if (!jobId || !applicantId) return [];\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const token = await ensureToken();\n const res = await fetch(`${AUTH_URL}/skill-match`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ jobId, applicantId }),\n signal: controller.signal,\n });\n if (!res.ok) return [];\n const json = await res.json();\n const skills = json?.data?.relevantSkills ?? json?.relevantSkills;\n return Array.isArray(skills) ? skills.filter((s) => typeof s === 'string' && s.trim()) : [];\n } catch {\n // Aborted, offline, 5xx, malformed body — all the same outcome.\n return [];\n } finally {\n clearTimeout(timer);\n }\n}\n","import { apiGetWithAuth, fetchJsonWithAuth, ensureToken } from './authApi';\nimport { AUTH_URL, CANDIDATES_URL, JOBS_URL } from './apiConfig';\n\nexport async function getCandidateSummary(startDate, endDate) {\n const params = new URLSearchParams();\n if (startDate) params.set('startDate', startDate);\n if (endDate) params.set('endDate', endDate);\n const query = params.toString();\n return apiGetWithAuth(CANDIDATES_URL, `/profile-summary${query ? `?${query}` : ''}`);\n}\n\nexport async function getQuickSubmitCandidates({ isFromSubmission, jobId, submissionId, search = '' } = {}) {\n const body = { search };\n if (isFromSubmission) {\n body.submissionId = submissionId;\n } else {\n body.jobId = jobId;\n }\n const json = await fetchJsonWithAuth(CANDIDATES_URL, '/quicksubmit/list', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n return json.data ?? json;\n}\n\nexport async function getCandidateFormGroups(options = {}) {\n const token = await ensureToken();\n const params = new URLSearchParams({ module: 'candidates' });\n if (options.id) params.set('id', options.id);\n const res = await fetch(`${AUTH_URL}/admin/form-groups?${params}`, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },\n });\n if (!res.ok) throw new Error(`API ${res.status}: ${res.statusText}`);\n const json = await res.json();\n return json.data ?? json;\n}\n\nexport async function getMentionUsers(search = '') {\n const params = search ? `?search=${encodeURIComponent(search)}` : '';\n return apiGetWithAuth(JOBS_URL, `/users/any${params}`);\n}\n\nexport async function migrateDiceCandidate(diceId) {\n if (!diceId) throw new Error('Dice candidate ID is required');\n\n const token = await ensureToken();\n const url = `${AUTH_URL}/dicemigrate/${encodeURIComponent(String(diceId))}`;\n // const url = `http://localhost:9009/v1/dicemigrate/${encodeURIComponent(String(diceId))}`;\n if (process.env.NODE_ENV === 'development') {\n console.log('[DiceMigration] Request URL:', url);\n }\n const response = await fetch(\n url,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n },\n );\n\n const payload = await response.json().catch(() => null);\n if (!response.ok) {\n const error = new Error(\n payload?.message\n ?? payload?.error\n ?? `Failed to migrate candidate (${response.status})`,\n );\n error.status = response.status;\n throw error;\n }\n\n return payload;\n}\n","import { migrateDiceCandidate } from './candidatesApi';\nimport { resolveDiceProfileId } from './diceCandidateMapper';\n\nexport function normalizeSourceKey(value) {\n if (value && typeof value === 'object') {\n return normalizeSourceKey(value.value ?? value.key ?? value.id ?? value.label ?? value.name);\n }\n\n return String(value ?? '').trim().toLowerCase();\n}\n\nexport function getSearchSources(value) {\n return (Array.isArray(value) ? value : [value])\n .flat()\n .map(normalizeSourceKey)\n .filter((item, index, source) => item && item !== 'all' && source.indexOf(item) === index);\n}\n\nexport function resolveSearchSource(value, fallback = 'internal') {\n const sources = getSearchSources(value);\n if (sources.includes('internal')) return 'internal';\n const normalizedFallback = normalizeSourceKey(fallback);\n if (sources[0]) return sources[0];\n if (normalizedFallback) return normalizedFallback;\n return fallback === '' ? '' : 'internal';\n}\n\n// Which module key answers for each source tab, as { [sourceKey]: moduleKey }.\n// A source with no entry uses the form's own module, which is every source on\n// every form until someone configures otherwise.\n//\n// Two places can declare it and BOTH are honoured, config last so it wins:\n// 1. a `sourceModules` prop, for a host app that wants to say so in code\n// before the option key is persisted backend-side;\n// 2. the source option itself ({ value:'dice', module:'dice' }), which is what\n// the Admin option editor writes.\n//\n// Built once and shared, because the module has to be identical on both request\n// paths — the `/module-data-list` call and the unified search endpoint. They\n// each used to work it out for themselves, and only one of the two read config,\n// so the Dice tab asked for Candidates' columns and actions.\nexport function buildSourceModuleMap(fields, sourceModules) {\n const map = { ...(sourceModules ?? {}) };\n\n (Array.isArray(fields) ? fields : [])\n .flatMap((field) => (Array.isArray(field?.options) ? field.options : []))\n .forEach((option) => {\n const key = normalizeSourceKey(option?.value);\n // Blank is not a value: it means \"use the form's module\", the same reading\n // the Admin editor gives it by refusing to store an empty module.\n const module = String(option?.module ?? '').trim();\n if (key && module) map[key] = module;\n });\n\n return map;\n}\n\nfunction toTitle(value) {\n return String(value ?? '')\n .replace(/[-_]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n}\n\n// The key a tab is MATCHED by — lowercased, so a configured source and the\n// backend's spelling of it land on the same map entry.\nfunction getTabKey(tab) {\n return normalizeSourceKey(rawTabKey(tab));\n}\n\n// The key a tab is EMITTED with, which is what goes back to the API when the tab\n// is clicked. It has to survive verbatim: a source key is lowercase either way,\n// but a field-based tab like \"myJobs\" is not, and sending \"myjobs\" would filter\n// on a value no record has.\nfunction rawTabKey(tab) {\n const key = tab?.key ?? tab?.value ?? tab?.id ?? tab?.source ?? tab?.name ?? tab?.title ?? tab?.label;\n return String(key ?? '').trim();\n}\n\nfunction getTabCount(tab) {\n const count = tab?.count ?? tab?.countValue;\n const number = Number(count);\n return Number.isFinite(number) ? number : undefined;\n}\n\nfunction getSourceCount(source, responseCounts, currentCounts, activeSource, activeCount) {\n // Both endpoints report a count for EVERY requested source, not just the one\n // being viewed — module-data-list in `count.internal`/`count.dice`, boolean\n // search in the same shape. So the live response wins for any tab; restricting\n // this to the active source left the other tab showing a stale cached figure\n // (or none) even though the number was sitting right there in the response.\n const responseCount = Number(responseCounts?.[source]);\n if (Number.isFinite(responseCount)) return responseCount;\n\n if (source === activeSource) {\n const activeTotal = Number(activeCount);\n if (Number.isFinite(activeTotal)) return activeTotal;\n }\n\n const currentCount = currentCounts.get(source);\n if (currentCount !== undefined) return currentCount;\n\n return undefined;\n}\n\nexport function buildSourceTabs({\n sources = [],\n activeSource = 'internal',\n activeCount = 0,\n responseCounts = {},\n currentTabs = [],\n backendTabs = [],\n} = {}) {\n const currentCounts = new Map(\n (Array.isArray(currentTabs) ? currentTabs : [])\n .map((tab) => [getTabKey(tab), getTabCount(tab)])\n .filter(([source, count]) => source && count !== undefined),\n );\n\n const sourceMap = new Map();\n\n // Pass 1 — the CONFIGURED sources define the order. Seeding from backendTabs\n // instead put whichever tab was active first, because the backend only ever\n // returns a tab for the active source — so the strip reordered on every\n // switch. A Map keeps insertion order, and set() on an existing key updates\n // the value without moving it, which is what makes pass 2 order-safe.\n // Falling back to [activeSource] when nothing is configured used to invent an\n // \"Internal\" tab on every form, including modules with no source picker at\n // all — it would sit beside a Jobs form's real My Jobs / All Jobs tabs. With\n // no configured sources there is nothing to seed, and pass 2 lets the\n // backend's own tabs stand on their own.\n const selectedSources = getSearchSources(sources);\n const activeKey = normalizeSourceKey(activeSource);\n const seeds = selectedSources.length\n ? selectedSources\n : (activeKey ? [activeKey] : []);\n\n seeds.forEach((source) => {\n if (!source || sourceMap.has(source)) return;\n const count = getSourceCount(source, responseCounts, currentCounts, activeSource, activeCount);\n sourceMap.set(source, {\n key: source,\n title: toTitle(source),\n ...(count !== undefined ? { count } : {}),\n });\n });\n\n // Pass 2 — the backend contributes a real label and count, never a position.\n // Falling back to the previous count keeps a known figure on screen instead\n // of blanking it out the moment you switch away from that tab.\n (Array.isArray(backendTabs) ? backendTabs : []).forEach((tab) => {\n const key = getTabKey(tab);\n if (!key) return;\n const previous = sourceMap.get(key);\n const count = getTabCount(tab) ?? previous?.count ?? currentCounts.get(key);\n sourceMap.set(key, {\n // Matched case-insensitively, emitted as the backend spelled it.\n key: previous ? previous.key : rawTabKey(tab),\n title: tab.title ?? tab.label ?? tab.name ?? previous?.title ?? toTitle(key),\n ...(count !== undefined ? { count } : {}),\n });\n });\n\n return Array.from(sourceMap.values());\n}\n\nfunction collectSourceValues(record) {\n return [\n record?.sourceType,\n record?.profileSource,\n record?.selectedSource,\n record?.source,\n record?.provider,\n record?.customFields?.sourceType,\n record?.customFields?.profileSource,\n record?.customFields?.source,\n record?.customFields?.provider,\n ].flat().map(normalizeSourceKey).filter(Boolean);\n}\n\nfunction recordMatchesSource(record, sourceKey, marker) {\n const normalizedSource = normalizeSourceKey(sourceKey);\n if (!normalizedSource) return false;\n if (collectSourceValues(record).includes(normalizedSource)) return true;\n return typeof marker === 'function' ? marker(record) : false;\n}\n\nconst SOURCE_ACTIONS = [\n {\n source: 'dice',\n field: '__sourceAction_dice_migrate',\n label: 'Action',\n buttonLabel: 'Migrate',\n completedLabel: 'Migrated',\n successMessage: 'Candidate migrated successfully.',\n errorMessage: 'Failed to migrate candidate.',\n isRecordFromSource: (record) => Boolean(record?.customFields?.diceProfileData),\n getRecordId: resolveDiceProfileId,\n execute: migrateDiceCandidate,\n },\n];\n\nexport function getAvailableSourceActions({ rows = [], selectedSource = '' } = {}) {\n return SOURCE_ACTIONS.filter((action) => {\n const selectedMatches = normalizeSourceKey(selectedSource) === action.source;\n return selectedMatches || rows.some((record) => recordMatchesSource(record, action.source, action.isRecordFromSource));\n });\n}\n\nexport function sourceActionAppliesToRecord(action, record, selectedSource = '') {\n return normalizeSourceKey(selectedSource) === action.source\n || recordMatchesSource(record, action.source, action.isRecordFromSource);\n}\n\nexport function getSourceActionInstanceKey(action, record) {\n const id = action?.getRecordId?.(record);\n return id ? `${action.source}:${action.field}:${id}` : '';\n}\n\nexport async function runSourceAction(action, record) {\n const id = action?.getRecordId?.(record);\n if (!id) throw new Error(`${action?.buttonLabel ?? 'Action'} ID is required`);\n return action.execute(id, record);\n}\n","import { Fragment, createContext, forwardRef, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState, useCallback } from 'react';\nimport dayjs from 'dayjs';\nimport {\n Alert,\n Button,\n Card,\n Checkbox,\n Col,\n DatePicker,\n Form,\n Input,\n message,\n Radio,\n Row,\n Select,\n Space,\n Spin,\n Switch,\n TimePicker,\n Tooltip,\n Typography,\n Upload,\n} from 'antd';\nimport {\n CalendarOutlined,\n CloudUploadOutlined,\n DeleteOutlined,\n DownOutlined,\n EnvironmentOutlined,\n EyeOutlined,\n FileExcelOutlined,\n FileImageOutlined,\n FileOutlined,\n FilePdfOutlined,\n FileTextOutlined,\n FileWordOutlined,\n InfoCircleOutlined,\n LockOutlined,\n MailOutlined,\n PhoneOutlined,\n PlusOutlined,\n SolutionOutlined,\n TagsOutlined,\n UpOutlined,\n UserOutlined,\n} from '@ant-design/icons';\nimport TipTapEditor from './TipTapEditor';\nimport DocumentViewer from './DocumentViewer';\nimport { useLocation, useNavigate, useParams, useSearchParams } from 'react-router-dom';\nimport { fetchJsonWithAuth, getActingIdentity } from '../services/authApi';\nimport { autoValueFor } from '../utils/autoValueRules';\nimport { AUTH_URL } from '../services/apiConfig';\nimport { getDropdownValues, searchModuleData } from '../services/moduleDataApi';\nimport { getFormGroups, createModuleRecord } from '../services/addFormApi';\nimport { verifyEmail, getModuleDefaultFields } from '../services/adminApi';\nimport { uploadModuleDocuments } from '../services/documentApi';\nimport { getAdminClients, getCustomForms, getRoleFormPermissions } from '../services/adminApi';\nimport { updateRecord } from '../services/detailedViewApi';\nimport { loadDetailDefaults, formatPhone, phoneDigits, parsePhoneFormat } from '../services/detailDefaults';\nimport { groupAllowedByRole, fieldAllowedByRole, fieldEditableByRole } from '../utils/roleFormPermissionGate';\nimport { buildPayload, buildInitialValue, buildRepeatFieldInitial, singleFieldOf, collectFileParts, effectiveDataType, getDeep, toSelectControlValue, usesLabeledSelectValue, rowDefaultsFor } from './form/payloadTransformer';\nimport { computeLinkedSets, findLinkedSet, padLinkedInitialValues } from './form/linkedAddRowGroups';\nimport useAiActions, { groupActionsByPosition } from './form/useAiActions';\nimport AiActionButtonGroup from './form/AiActionButtons';\nimport { applyInputValidator, getKeyPattern } from './form/inputValidator';\nimport { configuredEmailRule, isValidConfiguredEmail } from './form/emailValidator';\nimport { securityValidationRule } from './form/inputSecurity';\nimport {\n buildUniqueValidationRule,\n attachUniqueSyncGuards,\n collectUniqueRules,\n createUniqueChecker,\n extractDuplicateFieldErrors,\n} from './form/uniqueFieldValidation';\nimport {\n checkFieldUnique,\n createSupersedingUniqueCheck,\n normalizeUniqueCheckDebounceMs,\n uniqueCheckItemProps,\n} from '../services/uniqueValidationApi';\nimport { uploadAcceptCategory } from './form/uploadAccept';\nimport { useQuickField } from './form/QuickCreateEditField';\nimport { maxFromFieldRule, maxFromFieldDependency, resolveScopedFieldPath } from './form/crossFieldRules';\nimport { checkMaxWithFallback, parseCompareFields, readCompareValue, resolveCompareFieldName } from './form/maxCeiling';\nimport { contextRecordId } from './form/contextPrefill';\nimport ValidationOverrideCheckbox from './form/ValidationOverrideCheckbox';\nimport {\n overrideConfig,\n overrideFlagPath,\n overrideRuleMapper,\n} from './form/validationOverride';\nimport { prefillWhenWatchFields, prefillWhenWatchPaths, resolvePrefillWhen } from './form/prefillWhenRules';\nimport { narrowOptionsByConstraint, stripExclusivePrefillOptions } from './form/optionConstraints';\nimport { filterLookupOptionRows, lookupExtraFieldKeys } from './form/optionRowFilters';\nimport {\n normalizeCourseModuleLessonRows,\n withCourseModuleLessonExtraFields,\n} from './form/courseModuleLessonLookup';\nimport { fieldTooltipText } from './form/fieldTooltip';\nimport { writeFormValue } from './form/applyGroupValues';\nimport { PARENT_FILTER_UNSEEN, shouldClearDependentValue } from './form/dependentLookupReset';\nimport { roleAllowsAction } from '../utils/roleAllowsAction';\nimport { resolveAfterSubmit, safeNavTarget } from '../utils/afterSubmitNav';\nimport { goBackOrTo } from '../utils/backNav';\nimport FormWizard, {\n buildFormWizardSteps,\n isWizardConfigEnabled,\n mergeWizardSubmitValues,\n wizardStepForGroup,\n wizardStepIndexForField,\n wizardValidationNames,\n WizardBackButton,\n WizardNextButton,\n} from './form/FormWizard';\nimport WizardStepContent from './form/WizardStepContent';\nimport { useWizardRuntime, WizardStepNotice } from './form/useWizardRuntime';\nimport { wizardAddRowView } from './form/wizardRuntime';\nimport useDuplicateCheck from './form/useDuplicateCheck';\nimport {\n resolveRegionRules,\n inProgressAllowed,\n inProgressBlocks,\n inProgressError,\n buildInProgressValidator,\n levelRuleVerdict,\n promptRowMove,\n} from './form/educationRules';\nimport { getDefaults } from '../services/detailDefaults';\nimport { openFormNotice, openFormDecision } from './form/formDecisionDialog';\nimport { applyGroupClear } from './form/clearGroupOnChange';\nimport { storedFileName, storedFileUrl } from './form/storedFileName';\nimport { fetchLookupLabels, mergeResolvedOptions, missingOptionValues } from './form/resolveStoredOptions';\nimport {\n buildPairValidator,\n buildRowHierarchyValidator,\n buildDisabledDate,\n defaultPickerValue,\n getComparableDateTime,\n getComparableTimeOfDay,\n} from './form/dateRules';\nimport { submitSuccessMessage, submitErrorMessage } from '../utils/submitMessages';\nimport { scrollToFirstFormError } from '../utils/scrollToFirstFormError';\nimport { conditionFieldPath, configuredFieldLabel, conditionMatches as labelConditionMatches, colWhenRules, resolveColSpan } from './form/conditionalFieldLabel';\nimport AppBreadcrumb from '../components/Breadcrumb';\nimport ListView from './ListView';\nimport { clearAuthTokenOverride, setAuthTokenOverride } from '../services/authApi';\nimport { takePendingPromise } from '../services/pendingHandoff';\nimport { matchRelevantSkills } from '../services/skillMatchApi';\nimport {\n buildSourceTabs,\n getAvailableSourceActions,\n getSearchSources,\n getSourceActionInstanceKey,\n resolveSearchSource,\n runSourceAction,\n sourceActionAppliesToRecord,\n} from '../services/sourceProviderActions';\n\nconst { Text } = Typography;\nconst { TextArea } = Input;\nconst emptyGroups = [];\n\nconst sectionIcons = [\n <UserOutlined />,\n <EnvironmentOutlined />,\n <SolutionOutlined />,\n <InfoCircleOutlined />,\n <FileTextOutlined />,\n];\n\nconst fieldIcons = {\n email: <MailOutlined className=\"v1-input-icon\" />,\n contactNumber: <PhoneOutlined className=\"v1-input-icon\" />,\n phone: <PhoneOutlined className=\"v1-input-icon\" />,\n currentLocation: <EnvironmentOutlined className=\"v1-input-icon\" />,\n preferredLocation: <EnvironmentOutlined className=\"v1-input-icon\" />,\n skills: <TagsOutlined className=\"v1-input-icon\" />,\n firstName: <UserOutlined className=\"v1-input-icon\" />,\n lastName: <UserOutlined className=\"v1-input-icon\" />,\n};\n\nconst truthy = (value) => value === true || value === 1 || value === '1';\nconst editable = (field, moduleName) => (field?.edit === undefined || truthy(field.edit))\n && (!field?.editablePermission || roleAllowsAction(field.editablePermission, moduleName));\n\nfunction normalizeOptions(options = []) {\n return options.map((option) => {\n if (typeof option === 'string') return { label: option, value: option };\n return {\n label: option.label ?? option.name ?? option.value,\n value: option.value ?? option.id ?? option.name ?? option.label,\n };\n });\n}\n\nfunction namePathFromString(path) {\n return String(path ?? '').split('.').map((part) => part.trim()).filter(Boolean);\n}\n\nfunction siblingFieldPath(absoluteName, key) {\n return Array.isArray(absoluteName) && absoluteName.length > 1\n ? [...absoluteName.slice(0, -1), key]\n : [key];\n}\n\n// VerifyFieldButton — admin-configured \"Verify\" button beside a field\n// (field.verifyAction, e.g. \"email\"). Calls the generic /email-verify\n// endpoint and writes the boolean result + a timestamp into two sibling\n// fields (verifyResultField/verifyTimestampField), within the same addRow\n// row when nested. Not specific to \"recruiter\" or any module — any field\n// can opt in.\nfunction VerifyFieldButton({ form, field, absoluteName }) {\n const [checking, setChecking] = useState(false);\n const [verdict, setVerdict] = useState(null);\n const verifiedValueRef = useRef(null);\n const resultValue = Form.useWatch(\n field.verifyResultField ? siblingFieldPath(absoluteName, field.verifyResultField) : ['__noop_verify__'],\n { form, preserve: true },\n );\n const currentValue = Form.useWatch(absoluteName, form);\n\n // A successful result belongs to the exact value that was checked. Existing\n // Edit records hydrate once; later source-value changes invalidate the\n // configured result so the form gate cannot accept a different email.\n useEffect(() => {\n const normalized = String(currentValue ?? '').trim();\n if (resultValue === true && verifiedValueRef.current === null && normalized) {\n verifiedValueRef.current = normalized;\n return;\n }\n if (resultValue === true && verifiedValueRef.current !== null && normalized !== verifiedValueRef.current) {\n if (field.verifyResultField) form.setFieldValue(siblingFieldPath(absoluteName, field.verifyResultField), false);\n if (field.verifyTimestampField) form.setFieldValue(siblingFieldPath(absoluteName, field.verifyTimestampField), undefined);\n verifiedValueRef.current = null;\n }\n }, [absoluteName, currentValue, field.verifyResultField, field.verifyTimestampField, form, resultValue]);\n\n if (field.verifyAction !== 'email') return null;\n\n const runVerify = async () => {\n const email = String(currentValue ?? '').trim();\n if (!email) {\n message.warning('Enter an email first');\n return;\n }\n setChecking(true);\n try {\n const result = await verifyEmail(email);\n verifiedValueRef.current = result.valid ? email : null;\n setVerdict(result.valid ? result : null);\n if (field.verifyResultField) form.setFieldValue(siblingFieldPath(absoluteName, field.verifyResultField), result.valid);\n if (field.verifyTimestampField) {\n form.setFieldValue(siblingFieldPath(absoluteName, field.verifyTimestampField), result.valid ? new Date().toISOString() : undefined);\n }\n // Three outcomes, not two. \"Accepted but unconfirmed\" is the common\n // case on catch-all domains (Google Workspace's default, and most\n // corporate mail) — reporting it as a plain success would tell the\n // user the mailbox exists when nothing proved that.\n if (!result.valid) {\n message.error(result.reason ? `Invalid email: ${result.reason}` : 'Email could not be verified');\n } else if (result.mailboxConfirmed) {\n message.success('Email verified \\u2014 the mail server confirmed this mailbox');\n } else {\n message.warning(result.reason || 'The domain can receive mail, but this exact mailbox could not be confirmed');\n }\n } catch (err) {\n verifiedValueRef.current = null;\n setVerdict(null);\n if (field.verifyResultField) form.setFieldValue(siblingFieldPath(absoluteName, field.verifyResultField), false);\n if (field.verifyTimestampField) form.setFieldValue(siblingFieldPath(absoluteName, field.verifyTimestampField), undefined);\n message.error(err?.message || 'Could not verify email');\n } finally {\n setChecking(false);\n }\n };\n\n if (resultValue === true) {\n // Accepted, but the mailbox itself was never proven (catch-all domain).\n // Labelling that \"Valid\" would overstate what the check established, so\n // it gets its own state. The address still passes the submit gate — the\n // account email that follows is what ultimately proves delivery.\n // Only positive evidence of \"unconfirmed\" downgrades the label. A\n // response that simply doesn't carry the field (older backend, or a\n // check that never reached the mailbox stage) keeps the plain success\n // state rather than casting doubt the check never actually raised.\n if (verdict && !verdict.mailboxConfirmed && (verdict.catchAll || verdict.result === 'risky')) {\n return (\n <Tooltip title={verdict.reason || 'This domain accepts every address, so the mailbox could not be confirmed. Delivery is proven only once the account email is actually sent.'}>\n <Text type=\"warning\" strong className=\"v1-verify-field-wrap\">\n {field.verifyUnconfirmedLabel || 'Accepted'}\n </Text>\n </Tooltip>\n );\n }\n return <Text type=\"success\" strong className=\"v1-verify-field-wrap\">{field.verifySuccessLabel || 'Valid'}</Text>;\n }\n\n return (\n <Button size=\"small\" loading={checking} onClick={runVerify} className=\"v1-verify-field-wrap\">\n {resultValue === false ? (field.verifyRetryLabel || 'Re Verify') : (field.verifyIdleLabel || 'Verify Email')}\n </Button>\n );\n}\n\nfunction ConfiguredFieldLabel({ form, field, siblingPrefix, locked, combined = false }) {\n const watchedValue = Form.useWatch(conditionFieldPath(field?.labelWhen, siblingPrefix), form);\n const label = configuredFieldLabel(field, watchedValue, combined);\n return combined ? label : <FieldLabel field={field} label={label} locked={locked} />;\n}\n\n// An ADDITIONAL admin-configured submit button (group.formActions). Same\n// validation gate as the primary Create button, plus an optional enabledWhen\n// gate that keeps it disabled until a field satisfies the condition (e.g. only\n// once \"Assign To\" is filled). `tone` picks primary vs secondary styling.\nfunction FormActionButton({ form, groups, action, disabled, loading, onFire }) {\n const unvalidated = Form.useWatch(\n (values) => groups.some((group) => {\n if (!group.addRow || !group.requireValidatedField) return false;\n const rows = values?.[group.name] ?? [];\n return rows.length === 0 || rows.some((row) => !row?.[group.requireValidatedField]);\n }),\n { form, preserve: true },\n );\n const gateValue = Form.useWatch(action?.enabledWhen?.field, form);\n const gateOk = !action?.enabledWhen?.field || groupShowIfMatches(action.enabledWhen, gateValue);\n return (\n <Button\n type={action?.tone === 'primary' ? 'primary' : 'default'}\n onClick={onFire}\n disabled={disabled || unvalidated || !gateOk}\n loading={loading}\n >\n {action?.label || 'Submit'}\n </Button>\n );\n}\n\nfunction ValidationGatedSubmitButton({ form, groups, disabled, loading, onClick, children }) {\n const unvalidated = Form.useWatch(\n (values) => groups.some((group) => {\n if (!group.addRow || !group.requireValidatedField) return false;\n const rows = values?.[group.name] ?? [];\n return rows.length === 0 || rows.some((row) => !row?.[group.requireValidatedField]);\n }),\n { form, preserve: true },\n );\n const isDisabled = disabled || unvalidated;\n // Config-driven \"why is this disabled\" tooltip: an admin sets\n // group.submitDisabledMessage (Admin → Form Groups). When a row-validation\n // gate is what's blocking, the more specific requireValidatedFieldMessage\n // (or a sensible default) is shown instead. Only rendered while disabled.\n const groupMsg = groups.find((g) => g.submitDisabledMessage)?.submitDisabledMessage;\n const validatedMsg = groups.find((g) => g.requireValidatedField)?.requireValidatedFieldMessage;\n const reason = unvalidated\n ? (validatedMsg || groupMsg || 'Verify every required row before submitting.')\n : (groupMsg || 'Complete all mandatory fields before submitting.');\n const button = (\n <Button type=\"primary\" onClick={onClick} disabled={isDisabled} loading={loading}>\n {children}\n </Button>\n );\n // A disabled antd Button has pointer-events:none, so the Tooltip must wrap a\n // span to receive hover.\n return isDisabled && !loading\n ? <Tooltip title={reason}><span style={{ display: 'inline-flex', cursor: 'not-allowed' }}>{button}</span></Tooltip>\n : button;\n}\n\n// PrefillWhenWatcher — sets ITS OWN field's value when a referenced field's\n// value matches a configured rule (e.g. contractType=\"W2\" forces employerId to\n// a fixed record id), and clears it back out when a rule says so or when no\n// rule matches any more. Opposite direction from autofillFrom (which pushes\n// into siblings when the changed field is a lookup select) — this field PULLS\n// its value from a field changing elsewhere. A tiny standalone component (not\n// inline logic) because Form.useWatch is a hook and must run in component\n// scope, not inside the plain renderField() function.\n//\n// ALL of the decision-making lives in form/prefillWhenRules.js so this form and\n// EditFormV1 can never disagree about what a rule means, and so the rules can\n// be unit-tested without importing either form (any render test that touches\n// them dies on jsdom's missing DOMMatrix, via react-pdf).\n//\n// `watchPaths` carries EVERY field a rule references — rules may point at\n// different fields, and each path was already resolved through renderField's\n// `prefixFor` closure so a rule reaching out of an addRow row lands on the\n// top-level field (see prefillWhenWatchPaths).\nfunction PrefillWhenWatcher({ form, rules, watchPaths, targetPath, resetOnNoMatch = true }) {\n // A selector useWatch (not one path per hook — hook count must be stable)\n // reduced to a STRING so the effect dependency stays a primitive; a fresh\n // array every render would re-run the effect on every keystroke anywhere.\n const watchedKey = Form.useWatch(\n (values) => JSON.stringify(\n watchPaths.map(({ path }) => path.reduce((acc, key) => (acc == null ? acc : acc[key]), values) ?? null),\n ),\n { form, preserve: true },\n );\n // Tracks the value WE last set via a matching rule (e.g. the W2 default\n // employer), so a later \"no rule matches\" tick (contractType switched away\n // from W2) can tell \"still exactly what we set\" apart from \"the user picked\n // something else since\" — only the former gets cleared. Without this guard,\n // switching e.g. W2 → C2C left the W2 default employer stuck in the field\n // forever (admin config `prefillWhenReset`, default on).\n const lastAppliedRef = useRef(undefined);\n // First tick = the form settling into its initial values, never a user\n // decision, so a clear rule must not fire on it (it would delete stored\n // data on the edit form). See prefillWhenRules.js for the full rationale.\n const initialRef = useRef(true);\n useEffect(() => {\n const values = watchedKey ? JSON.parse(watchedKey) : [];\n const watched = {};\n watchPaths.forEach(({ field }, i) => { watched[field] = values[i]; });\n const initial = initialRef.current;\n initialRef.current = false;\n const outcome = resolvePrefillWhen({\n rules,\n watched,\n current: form.getFieldValue(targetPath),\n lastApplied: lastAppliedRef.current,\n clearOnMismatch: resetOnNoMatch,\n initial,\n });\n if (outcome.action === 'set') {\n form.setFieldValue(targetPath, outcome.value);\n lastAppliedRef.current = outcome.value;\n } else if (outcome.action === 'clear') {\n form.setFieldValue(targetPath, undefined);\n lastAppliedRef.current = undefined;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [watchedKey]);\n return null;\n}\n\n// AutoFillFromApiWatcher — watches THIS field's own live value and, when it\n// changes to a non-empty value, calls a REST endpoint and populates one or\n// more sibling fields from the JSON response. Unlike prefillWhen (a static\n// value → value map), this does a real API round-trip — e.g. auto-loading a\n// campaign's Subject/Message from an admin-configured email template the\n// moment Type is set. A failed/404 lookup (no template configured yet) is\n// treated as a silent no-op, matching how callers of this endpoint already\n// tolerate a missing template elsewhere.\nfunction AutoFillFromApiWatcher({ form, config, watchPath }) {\n const watched = Form.useWatch(watchPath, form);\n const lastFetchedRef = useRef(undefined);\n useEffect(() => {\n if (empty(watched) || watched === lastFetchedRef.current) return;\n lastFetchedRef.current = watched;\n\n const url = config.endpointTemplate\n ? `${config.endpointTemplate.replace('{value}', encodeURIComponent(String(watched)))}`\n : `${config.endpoint}?${new URLSearchParams({ [config.queryParam]: String(watched) }).toString()}`;\n\n fetchJsonWithAuth(AUTH_URL, url)\n .then((json) => {\n const data = json?.data ?? json;\n if (config.substituteTokens) {\n (config.substituteInFields || []).forEach((targetField) => {\n const targetPath = namePathFromString(targetField);\n let current = form.getFieldValue(targetPath) || '';\n Object.entries(config.substituteTokens).forEach(([token, responseKey]) => {\n const inner = token.replace(/^\\{\\{|\\}\\}$/g, '').trim();\n const pattern = new RegExp(`\\\\{\\\\{\\\\s*${inner.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*\\\\}\\\\}`, 'gi');\n current = current.replace(pattern, data?.[responseKey] ?? '');\n });\n form.setFieldValue(targetPath, current);\n });\n return;\n }\n Object.entries(config.mapResponseToFields).forEach(([targetField, responseKey]) => {\n const targetPath = namePathFromString(targetField);\n if (config.onlyIfEmpty && !empty(form.getFieldValue(targetPath))) return;\n form.setFieldValue(targetPath, data?.[responseKey]);\n });\n })\n .catch(() => {\n // No template configured for this value yet, or the call\n // failed — leave existing field values untouched.\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [watched]);\n return null;\n}\n// Group-level showIf: the whole group renders only when the referenced field's\n// live value satisfies the condition (same operators as field-level showIf).\n// Kept as a module-level helper so both AddFormV1 and EditFormV1 evaluate it\n// identically.\nfunction groupShowIfMatches(showIf, value) {\n if (!showIf?.field) return true;\n const actual = String(value ?? '');\n const expected = String(showIf.value ?? '');\n const list = () => expected.split(',').map((v) => v.trim());\n switch (showIf.operator) {\n case 'eq': return actual === expected;\n case 'neq': return actual !== expected;\n case 'in': return list().includes(actual);\n case 'notIn': return !list().includes(actual);\n case 'truthy': return truthy(value);\n case 'falsy': return !truthy(value);\n case 'empty':\n case 'isEmpty':\n return value === undefined || value === null || actual.trim() === '' || (Array.isArray(value) && value.length === 0);\n case 'notEmpty':\n return !(value === undefined || value === null || actual.trim() === '' || (Array.isArray(value) && value.length === 0));\n default: return true;\n }\n}\n\n// A group with a `showIf` renders through this gate so its visibility reacts to\n// the referenced field changing. `render` is only invoked when visible, so a\n// hidden group's fields never register (nothing to validate or submit) — exactly\n// like a hidden field-level showIf. Groups without showIf bypass this entirely.\nfunction GroupShowIfGate({ form, showIf, render }) {\n const watched = Form.useWatch(showIf.field, form);\n if (!groupShowIfMatches(showIf, watched)) return null;\n return render();\n}\n\n// Group-level disable: the whole card (every field in it) goes read-only when\n// the group's `disabled` flag is set OR its `disabledIf` condition matches — the\n// group counterpart of FieldControl's field-level disabled/disabledIf. Provided\n// through context so each FieldControl in the group ORs it into its own disabled\n// state without threading a prop through renderGroup→renderFields→renderField.\n// Nested/merged groups inherit the parent's disabled state (never re-enable).\nconst GroupDisabledContext = createContext(false);\n\nfunction GroupDisabledProvider({ form, group, children, inheritParent = true }) {\n const parentDisabled = useContext(GroupDisabledContext);\n const path = group?.disabledIf?.field ? namePathFromString(group.disabledIf.field) : ['__noop_group_disabled__'];\n const watched = Form.useWatch(path, form);\n const conditionDisabled = group?.disabledIf?.field\n ? groupShowIfMatches(group.disabledIf, watched)\n : false;\n // `inheritParent: false` is used for a MERGED child (group.mergeInto).\n // mergeInto is presentation only — the child borrows the host's card and\n // nothing else — so inheriting the host's disabled state would give a\n // display relationship real behaviour.\n //\n // It is also the difference between working and deadlocked: the Employer\n // section is disabled until a Contract Type is chosen, and Contract Type is\n // rendered INSIDE that section. Inheriting would disable the very control\n // that enables the card, with no way out.\n const disabled = (inheritParent && parentDisabled)\n || Boolean(group?.disabled)\n || conditionDisabled;\n return <GroupDisabledContext.Provider value={disabled}>{children}</GroupDisabledContext.Provider>;\n}\n\nfunction getNestedProp(obj, dotPath) {\n return String(dotPath ?? '').split('.').reduce((cur, k) => cur?.[k], obj);\n}\n\nfunction hasMeaningfulValue(value) {\n if (value === undefined || value === null || value === '') return false;\n if (Array.isArray(value)) return value.length > 0 && value.some(hasMeaningfulValue);\n if (typeof value === 'object') return Object.values(value).some(hasMeaningfulValue);\n return true;\n}\n\nfunction extractGroups(formGroups) {\n if (Array.isArray(formGroups)) return formGroups;\n if (Array.isArray(formGroups?.groups)) return formGroups.groups;\n if (Array.isArray(formGroups?.data)) return formGroups.data;\n if (Array.isArray(formGroups?.data?.groups)) return formGroups.data.groups;\n return emptyGroups;\n}\n\nfunction normalizeGroups(formGroups = [], moduleName, rolePerms, defaultFieldSet) {\n const dset = defaultFieldSet ?? new Set();\n return [...extractGroups(formGroups)]\n // hideGroup hides everywhere; hideGroupInForm is the form-only mirror of\n // DetailViewV1's hideGroupInDetail — for server-owned groups that must be\n // read on the detail view but never typed here.\n .filter((group) => !truthy(group.hideGroup) && !truthy(group.hideGroupInForm)\n && groupAllowedByRole(rolePerms, group.name))\n .sort((a, b) => Number(a.order ?? 0) - Number(b.order ?? 0))\n .map((group) => ({\n ...group,\n fields: [...(group.fields ?? [])]\n // A \"default field\" (Form Groups → Default Fields, OTP-gated) is\n // ALWAYS shown + required regardless of its own show flag, so it\n // survives the hidden-field filter below and is forced show/req in\n // the map that follows.\n .map((field) => (\n dset.has(field.field) ? { ...field, show: 1, req: 1 } : field\n ))\n // Drop blank-keyed fields (a stray admin-config row can't render or\n // submit), any client-scope \"gate\" field (rendered as the top\n // \"Select Client\" picker, never as a body field), any field whose\n // visiblePermission the current role doesn't hold, and any field\n // this role's Form Configuration (Role Configure → Form, derived\n // from this same Form Groups config) has turned off.\n //\n // A field with show:0 (\"hidden\") is intentionally KEPT here even\n // though it must never render — this same fields array also feeds\n // buildPayload/buildRowObject (the payload engine has no other way\n // to know a hidden carrier field like isValid/isAccountCreate\n // exists). Dropping it here silently threw away every hidden\n // field's value at submit time, even one just set moments earlier\n // in this session (e.g. a Verify Email click stamping isValid on a\n // brand-new recruiter row) — see renderFields, which is what\n // actually keeps hidden fields off the screen.\n .filter((field) =>\n String(field.field ?? '').trim() !== ''\n && field.showOnAdd !== false\n && !truthy(field.clientScope)\n && (!field.visiblePermission || roleAllowsAction(field.visiblePermission, moduleName))\n && fieldAllowedByRole(rolePerms, group.name, field.field))\n // Role \"disable\": a group/field the role has marked non-editable\n // still renders but read-only. FieldControl honours field.disabled.\n .map((field) => (\n fieldEditableByRole(rolePerms, group.name, field.field)\n ? field\n : { ...field, disabled: true }\n ))\n .sort((a, b) => Number(a.order ?? 0) - Number(b.order ?? 0)),\n }))\n .filter((group) => group.fields.length);\n}\n\n// Wizard-only groups are intentionally hidden from the ordinary form body but\n// still participate in step planning (ListView, review, declaration, success,\n// etc.). Keep the field-normalised visible groups for form steps and add only\n// the hidden configuration shells back for the wizard planner.\nfunction wizardPlanningGroups(formGroups, normalizedGroups, rolePerms) {\n const normalizedByName = new Map(normalizedGroups.map((group) => [group.name, group]));\n return extractGroups(formGroups)\n .filter((group) => !truthy(group.hideGroup) && groupAllowedByRole(rolePerms, group.name))\n .sort((a, b) => Number(a.order ?? 0) - Number(b.order ?? 0))\n .map((group) => normalizedByName.get(group.name) ?? { ...group, fields: [] });\n}\n\n// pickPrefillValue reads a field's initial value from a prefill SOURCE record,\n// honouring the admin-config `prefillFrom` mapping FIRST (so a target field can\n// inherit from a differently-named source key — e.g. submission.totalExperience\n// ← candidate.yearOfExperience), then falling back to field.field and payloadKey.\n// Tolerates both flat dotted keys (the getFormGroups flat record) and nested\n// objects (addRow rows). Entirely config-driven — no field-name logic here.\n// Flattens a form-groups response (scalar fields with embedded values) into a\n// plain { fieldKey: value } record. Shared by the default prefill source and\n// the cross-module context prefill (field.prefillFromModule).\nfunction flatRecordFromGroups(groups) {\n if (!Array.isArray(groups)) return null;\n const rec = {};\n groups.forEach(group => {\n if (group.addRow) return;\n (group.fields ?? []).forEach(field => {\n if (!field.field || field.value === undefined || field.value === null) return;\n rec[field.field] = field.value;\n if (field.payloadKey && field.payloadKey !== field.field) {\n rec[field.payloadKey] = field.value;\n }\n });\n });\n return Object.keys(rec).length > 0 ? rec : null;\n}\n\nfunction pickPrefillValue(record, field) {\n if (!record || !field) return undefined;\n for (const path of [field.prefillFrom, field.field, field.payloadKey]) {\n if (!path) continue;\n let v = record[path];\n if (v === undefined || v === null) v = getDeep(record, path);\n if (v !== undefined && v !== null) return v;\n }\n return undefined;\n}\n\n// Convert a stored file-reference object to an Ant Design fileList entry so\n// file fields pre-show previously uploaded files when prefilling. Handles:\n// resume: { location, uploadedFileName, uniqueName }\n// passport: { passportCopyLocation, passportUploadName, … }\n// visa/alternateVisa: same *CopyLocation / *UploadName pattern\nfunction toFileListValue(value) {\n // A multi-file field prefills from a stored ARRAY: map each element through\n // the same single-file logic so every entry keeps its `stored` original too\n // (it used to be handed to the control raw, which showed the files but lost\n // them on save).\n if (Array.isArray(value)) return value.flatMap((item) => toFileListValue(item));\n if (!value || typeof value !== 'object') return [];\n // Legacy schemas disagree about which key holds the original filename —\n // passport uses passportUploadName, visa uses visaUniqueName. Matching only\n // \"*UploadName\" found nothing for a visa, so it rendered as \"file\".\n // See form/storedFileName.js.\n const name = storedFileName(value);\n const url = storedFileUrl(value);\n if (!name && !url) return [];\n // `stored` keeps the ORIGINAL container exactly as the record holds it\n // (passportCopyLocation / passportUploadName / …). The payload engine writes\n // it straight back when the user leaves the prefilled file untouched, so a\n // Quick Submit from a previous submission carries its documents into the new\n // record without re-uploading and without guessing at the stored shape.\n return [{ uid: url || name || '-1', name: name || 'file', status: 'done', url, existing: true, stored: value }];\n}\n\nconst empty = (value) => value === undefined || value === null || value === '';\n\nconst REGION_OPTIONS = [\n { label: 'US', value: 'US' },\n { label: 'UK', value: 'UK' },\n { label: 'India', value: 'INDIA' },\n];\n\n// Strip HTML tags and decode common entities — used so min/max validation\n// checks visible character count, not raw markup length.\nconst stripHtml = (html) =>\n String(html)\n .replace(/<[^>]*>/g, '')\n .replace(/&nbsp;/g, ' ')\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .trim();\n\nconst numberRangeRule = ({ label, message, value, compare, text }) => ({\n validator: (_, input) => {\n if (empty(input)) return Promise.resolve();\n return compare(Number(input), Number(value))\n ? Promise.resolve()\n : Promise.reject(new Error(message ?? `${label} ${text} ${value}`));\n },\n});\n\n// Date comparison + picker-constraint helpers now live in ONE place\n// (components/form/dateRules.js) and are imported at the top of this file.\n// They used to be duplicated verbatim between AddFormV1 and EditFormV1, which\n// is how a fix lands on Add and silently misses Edit.\n\n// Same resolution both forms have always used, now shared (form/maxCeiling.js)\n// so it can be unit tested: a DOTTED reference is absolute (reaches out of the\n// validated field's container), a bare one is a sibling.\nfunction getSiblingFieldName(currentName, compareField) {\n return resolveCompareFieldName(currentName, compareField);\n}\n\nconst crossFieldNumberRule = ({ label, message, value, rule, form, name, compare, text }) => ({\n validator: async (_, input) => {\n const compareField = value ?? rule.compareField ?? rule.field;\n if (!compareField || empty(input)) return Promise.resolve();\n const compareValue = form.getFieldValue(getSiblingFieldName(name, compareField));\n if (empty(compareValue)) return Promise.resolve();\n const inputNumber = Number(input);\n const compareNumber = Number(compareValue);\n if (Number.isNaN(inputNumber) || Number.isNaN(compareNumber)) return Promise.resolve();\n return compare(inputNumber, compareNumber)\n ? Promise.resolve()\n : Promise.reject(new Error(message ?? `${label} ${text} ${compareField}`));\n },\n});\n\nconst validationRulesByType = {\n noPastDate: ({ label, message }) => ({\n validator: (_, value) => {\n if (empty(value)) return Promise.resolve();\n const time = getComparableDateTime(value);\n if (time === null) return Promise.resolve();\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n return time < today.getTime()\n ? Promise.reject(new Error(message ?? `${label} cannot be a past date`))\n : Promise.resolve();\n },\n }),\n noFutureDate: ({ label, message }) => ({\n validator: (_, value) => {\n if (empty(value)) return Promise.resolve();\n const time = getComparableDateTime(value);\n if (time === null) return Promise.resolve();\n const endOfDay = new Date();\n endOfDay.setHours(23, 59, 59, 999);\n return time > endOfDay.getTime()\n ? Promise.reject(new Error(message ?? `${label} cannot be a future date`))\n : Promise.resolve();\n },\n }),\n minAge: ({ label, message, value }) => ({\n validator: (_, input) => {\n if (empty(input)) return Promise.resolve();\n const time = getComparableDateTime(input);\n if (time === null) return Promise.resolve();\n const years = Number(value ?? 18);\n const cutoff = new Date();\n cutoff.setFullYear(cutoff.getFullYear() - years);\n cutoff.setHours(23, 59, 59, 999);\n return time > cutoff.getTime()\n ? Promise.reject(new Error(message ?? `Must be at least ${years} years old`))\n : Promise.resolve();\n },\n }),\n // Both date-pair rules delegate to the shared engine, so `strict` (reject an\n // equal date — the 7-July bug) and `minGap`/`minGapFrom` (the duration\n // dropdown) behave identically on Add and Edit, and the SAME rule object\n // also drives the picker's disabledDate below.\n dateAfterField: ({ label, message, value, rule, form, name }) => buildPairValidator({\n type: 'dateAfterField',\n label,\n rule: { ...rule, value: value ?? rule?.compareField ?? rule?.field, message },\n readSibling: (key) => form.getFieldValue(getSiblingFieldName(name, key)),\n }),\n dateBeforeField: ({ label, message, value, rule, form, name }) => buildPairValidator({\n type: 'dateBeforeField',\n label,\n rule: { ...rule, value: value ?? rule?.compareField ?? rule?.field, message },\n readSibling: (key) => form.getFieldValue(getSiblingFieldName(name, key)),\n }),\n timeAfterField: ({ label, message, value, rule, form, name }) => ({\n validator: async (_, input) => {\n const compareField = value ?? rule.compareField ?? rule.field;\n if (!compareField || empty(input)) return Promise.resolve();\n const compareValue = form.getFieldValue(getSiblingFieldName(name, compareField));\n if (empty(compareValue)) return Promise.resolve();\n const inputTime = getComparableTimeOfDay(input);\n const compareTime = getComparableTimeOfDay(compareValue);\n if (inputTime === null || compareTime === null || inputTime > compareTime) return Promise.resolve();\n return Promise.reject(new Error(message ?? `${label} must be after ${compareField}`));\n },\n }),\n timeBeforeField: ({ label, message, value, rule, form, name }) => ({\n validator: async (_, input) => {\n const compareField = value ?? rule.compareField ?? rule.field;\n if (!compareField || empty(input)) return Promise.resolve();\n const compareValue = form.getFieldValue(getSiblingFieldName(name, compareField));\n if (empty(compareValue)) return Promise.resolve();\n const inputTime = getComparableTimeOfDay(input);\n const compareTime = getComparableTimeOfDay(compareValue);\n if (inputTime === null || compareTime === null || inputTime < compareTime) return Promise.resolve();\n return Promise.reject(new Error(message ?? `${label} must be before ${compareField}`));\n },\n }),\n greaterThanField: (args) => crossFieldNumberRule({ ...args, compare: (input, other) => input >= other, text: 'must be greater than or equal to' }),\n strictGreaterThanField: (args) => crossFieldNumberRule({ ...args, compare: (input, other) => input > other, text: 'must be greater than' }),\n strictLessThanField: (args) => crossFieldNumberRule({ ...args, compare: (input, other) => input < other, text: 'must be less than' }),\n lessThanOrEqualField: (args) => crossFieldNumberRule({ ...args, compare: (input, other) => input <= other, text: 'must be less than or equal to' }),\n // maxFromField — { type:'maxFromField', field:'<otherKey>', message }. The\n // ONLY cross-field rule here that can reach OUT of its addRow row: it\n // resolves the referenced key through renderField's `prefixFor` closure,\n // i.e. exactly the scoping a Show Condition uses (row when the key is one of\n // the row's own fields, top level otherwise). That is what lets a per-row\n // \"experience\" be capped by a top-level overall-experience field, with which\n // field caps which left entirely to Form Groups config.\n maxFromField: (args) => maxFromFieldRule(args),\n // maxFieldWithFallback — cap against the FIRST compare field carrying a\n // usable maximum (\"cap at the To value, else the From value\"). Decision\n // logic (incl. why a 0 ceiling means \"no ceiling\") lives in form/maxCeiling.js.\n maxFieldWithFallback: ({ label, message, value, rule, form, name }) => ({\n validator: async (_, input) => {\n const compareFields = parseCompareFields(value ?? rule.compareFields);\n const result = checkMaxWithFallback({\n input,\n compareFields,\n readValue: (fieldName) => readCompareValue(form, name, fieldName),\n });\n if (result.ok) return Promise.resolve();\n return Promise.reject(new Error(message ?? `${label} must not exceed ${result.field}`));\n },\n }),\n required: ({ field, message }) => ({\n validator: (_, value) => {\n let isEmpty = value === undefined || value === null || value === ''\n || (Array.isArray(value) && value.length === 0);\n if (!isEmpty && field?.type === 'text-editor') {\n isEmpty = stripHtml(value) === '';\n }\n return isEmpty\n ? Promise.reject(new Error(message ?? 'Mandatory Field'))\n : Promise.resolve();\n },\n }),\n email: ({ label, message }) => configuredEmailRule(label, message),\n // Admin-configured \"already present\" check. Everything about it — the\n // trigger, the blank handling, the normalizer, the message — comes from the\n // validations entry; the server resolves the collection and the scope.\n unique: ({ field, rule, uniqueContext }) => buildUniqueValidationRule({\n field, validation: rule, context: uniqueContext,\n }),\n\n emailTags: ({ label, message }) => ({\n validator: (_, value) => {\n const tags = Array.isArray(value) ? value : [];\n const invalid = tags.find((tag) => !isValidConfiguredEmail(tag));\n return invalid\n ? Promise.reject(new Error(message ?? `${label} contains an invalid email: ${invalid}`))\n : Promise.resolve();\n },\n }),\n\n noHtml: ({ label, message }) => ({\n validator: (_, value) => {\n if (value === undefined || value === null || value === '') return Promise.resolve();\n const hasHtmlTag = /<\\/?[a-z][\\s\\S]*>/i.test(String(value));\n return hasHtmlTag\n ? Promise.reject(new Error(message ?? `${label} cannot contain HTML tags`))\n : Promise.resolve();\n },\n }),\n url: ({ label, message }) => ({ type: 'url', message: message ?? `Enter valid ${label}` }),\n number: ({ label, message }) => ({ pattern: /^[0-9]+$/, message: message ?? `${label} must be a number` }),\n phone: ({ message }) => ({\n // Accepts the configured mask (e.g. 999-878-3413) — validates on the\n // stripped digits so the separators the formatter inserts don't fail it.\n validator: (_, value) => {\n if (value === undefined || value === null || value === '') return Promise.resolve();\n const { total } = parsePhoneFormat();\n return phoneDigits(value).length === total\n ? Promise.resolve()\n : Promise.reject(new Error(message ?? `Phone number must contain exactly ${total} digits`));\n },\n }),\n\n // The pre-existing minLength3 / minLength5 pair baked the threshold into the\n // TYPE NAME, and existed only in AddFormV1 — configuring one on a field did\n // nothing at all on the Edit form. Both now delegate to the generic `min`\n // rule (admin: \"Min length/value\"), which already implements exactly this\n // for non-number fields and is present in BOTH forms.\n minLength3: (args) => validationRulesByType.min({ ...args, value: 3 }),\n minLength5: (args) => validationRulesByType.min({ ...args, value: 5 }),\n\n len: ({ label, message, value }) => ({ len: Number(value), message: message ?? `${label} must be ${value} characters` }),\n pattern: ({ label, message, rule }) => ({\n pattern: new RegExp(rule.pattern ?? rule.value, rule.flags),\n message: message ?? `Enter valid ${label}`,\n }),\n min: ({ field, label, message, value }) => (\n field.type === 'number'\n ? numberRangeRule({ label, message, value, compare: (input, min) => input >= min, text: 'must be at least' })\n : {\n validator: (_, input) => {\n if (input == null || input === '') return Promise.resolve();\n const content = field.type === 'text-editor' ? stripHtml(input) : String(input);\n if (content === '') return Promise.resolve();\n return content.length >= Number(value)\n ? Promise.resolve()\n : Promise.reject(new Error(message ?? `${label} must be at least ${value} characters`));\n },\n }\n ),\n max: ({ field, label, message, value }) => (\n field.type === 'number'\n ? numberRangeRule({ label, message, value, compare: (input, max) => input <= max, text: 'must not exceed' })\n : {\n validator: (_, input) => {\n if (input == null || input === '') return Promise.resolve();\n const content = field.type === 'text-editor' ? stripHtml(input) : String(input);\n if (content === '') return Promise.resolve();\n return content.length <= Number(value)\n ? Promise.resolve()\n : Promise.reject(new Error(message ?? `${label} must not exceed ${value} characters`));\n },\n }\n ),\n};\n\n// `prefixFor` is renderField's showIf prefix resolver; it is forwarded so a rule\n// that references another field resolves it with the same row-vs-top-level\n// scoping the Show Conditions use. Undefined for call sites that have no row\n// context (a repeat-scalar item), where the rules keep their sibling behaviour.\nfunction validationToRule(validation, field, form, name, prefixFor, uniqueContext) {\n const rule = typeof validation === 'string' ? { type: validation } : validation;\n const type = rule.type ?? rule.rule ?? rule.name;\n const value = rule.value ?? rule.length ?? rule.min ?? rule.max;\n const label = field.label ?? field.field ?? 'Field';\n const factory = validationRulesByType[type];\n\n return factory\n ? factory({ field, label, message: rule.message, rule, value, form, name, prefixFor, uniqueContext })\n : rule;\n}\n\nfunction getSiblingFieldPath(name, siblingField) {\n return Array.isArray(name) && name.length > 1\n ? [...name.slice(0, -1), siblingField]\n : [siblingField];\n}\n\n// A field is required either via the simple \"req\" toggle or via a \"required\"\n// entry in the admin-configured validations list — the Form.Item asterisk and\n// the addRow \"at least one row\" check must honour both, not just field.req.\nfunction isFieldRequired(field, form, name) {\n if (truthy(field?.req)) return true;\n const apiRules = field?.validations ?? field?.validation ?? field?.rules ?? [];\n if (apiRules.some((rule) => (typeof rule === 'string' ? rule : rule?.type) === 'required')) return true;\n if (field?.requiredIfField && form && name) {\n return truthy(form.getFieldValue(getSiblingFieldPath(name, field.requiredIfField)));\n }\n return false;\n}\n\n// `uniqueContext` ({ checker, module, clientId, region }) is what turns a\n// configured `unique` validation into a live preflight check. Call sites with\n// no context (search forms, repeat-scalar items) still render the field; the\n// unique rule degrades to a no-op there and the server stays authoritative.\nfunction getRules(field, form, name, skipRequired = false, prefixFor = undefined, uniqueContext = undefined,\n extraRules = undefined) {\n const label = field.label ?? field.field ?? 'Field';\n const apiRules = field.validations ?? field.validation ?? field.rules ?? [];\n const hasApiRequired = apiRules.some((rule) => (typeof rule === 'string' ? rule : rule?.type) === 'required');\n const hasApiEmail = apiRules.some((rule) => (typeof rule === 'string' ? rule : rule?.type) === 'email');\n const rules = [];\n\n // Rules the CALLER resolved because they need the group, which this\n // function never sees — today, a region that refuses an in-progress entry.\n // They go first so a blocked row reports that before anything else.\n if (extraRules?.length) rules.push(...extraRules);\n\n // Cross-row hierarchy: a newest-first list constrains each row against its\n // NEIGHBOURS. The picker already greys the impossible dates out; this\n // catches one that arrived another way — typed, pasted, prefilled from a\n // résumé, or entered before the neighbouring row was filled in.\n if (field.rowHierarchy) {\n const ctx = rowContext(form, name);\n if (ctx.rows) rules.push(buildRowHierarchyValidator({ field, ...ctx }));\n }\n\n\n // `requiredIfField` (e.g. \"make this mandatory once its sibling has a\n // value\") stands on its own — it must not need field.req ALSO set, or a\n // field configured with only requiredIfField silently never validates.\n if (!skipRequired && !hasApiRequired && truthy(field.req) && field.disabledByField) {\n // A field disabled via disabledByField (e.g. endDate while\n // currentlyPursuing is checked) must not block submit with a\n // \"required\" error the user has no way to satisfy.\n rules.push({\n validator: (_, input) => {\n const disabledNow = truthy(form.getFieldValue(getSiblingFieldPath(name, field.disabledByField)));\n if (disabledNow) return Promise.resolve();\n return (input === undefined || input === null || input === '')\n ? Promise.reject(new Error('Mandatory Field'))\n : Promise.resolve();\n },\n });\n } else if (!skipRequired && !hasApiRequired && field.requiredIfField) {\n rules.push({\n validator: (_, input) => {\n const triggerValue = form.getFieldValue(getSiblingFieldPath(name, field.requiredIfField));\n if (!truthy(triggerValue)) return Promise.resolve();\n return (input === undefined || input === null || input === '')\n ? Promise.reject(new Error('Mandatory Field'))\n : Promise.resolve();\n },\n });\n } else if (!skipRequired && truthy(field.req) && !hasApiRequired) {\n rules.push({ required: true, message: 'Mandatory Field' });\n }\n if ((field.type === 'email' || field.formatter === 'email') && !hasApiEmail) {\n rules.push(configuredEmailRule(label));\n }\n // Number fields are whole-number-only unless the admin marks them decimal\n // (e.g. a commission of 5.5). Both patterns still reject any non-numeric\n // character, so \"float only\" stays enforced either way.\n if (field.type === 'number') {\n rules.push(truthy(field.decimal)\n ? { pattern: /^\\d+(\\.\\d+)?$/, message: `${label} must be a number` }\n : { pattern: /^[0-9]+$/, message: `${label} must be a number` });\n }\n\n // attachUniqueSyncGuards re-wraps any `unique` rule so it only calls the\n // server once every synchronous rule in this same list has passed.\n // An admin-configured override checkbox (field.overrideCheckbox) suspends\n // the validation TYPES it names while it is ticked. Applied here, over the\n // built rules, so a gated rule is withheld at validation time rather than\n // at render time — see form/validationOverride.js.\n const buildRule = (rule) => validationToRule(rule, field, form, name, prefixFor, uniqueContext);\n const mapRule = overrideRuleMapper(field, name, prefixFor, buildRule);\n\n return attachUniqueSyncGuards([\n ...rules,\n ...apiRules.map(mapRule),\n securityValidationRule(field),\n ]);\n}\n\nfunction getValidationValue(field, type) {\n const rules = field.validations ?? field.validation ?? field.rules ?? [];\n const rule = rules.find((item) => (typeof item === 'string' ? item : item?.type) === type);\n if (!rule || typeof rule === 'string') return undefined;\n return rule.value ?? rule.length ?? rule[type];\n}\n\nfunction getInputLimits(field) {\n const len = field.len ?? getValidationValue(field, 'len');\n const min = field.min ?? getValidationValue(field, 'min');\n const max = field.max ?? getValidationValue(field, 'max');\n\n if (field.type === 'number') {\n return {\n min: min ?? undefined,\n max: max ?? undefined,\n };\n }\n\n return {\n minLength: min ?? undefined,\n maxLength: field.maxLength ?? len ?? max ?? undefined,\n };\n}\n\n// Thin adapters over the shared engine (components/form/dateRules.js). The\n// bodies used to live here AND in EditFormV1; the picker's greyed-out range and\n// the submit-time error are now generated from the same rule object, so a\n// calendar that disagrees with its own error message is structurally impossible.\n// rowContext — the sibling ROWS of the repeatable group this field sits in,\n// plus this field's row index.\n//\n// A per-row `readSibling` can only see the row it is in, but a newest-first\n// list constrains a row against its NEIGHBOURS. Inside a Form.List the field\n// path is [listName, rowIndex, fieldKey], which is exactly what is needed to\n// read the whole list and locate this row within it.\n//\n// Returns {} outside a repeatable group, so the hierarchy simply never applies.\nfunction rowContext(form, name) {\n if (!Array.isArray(name) || name.length < 3 || typeof name[1] !== 'number') return {};\n const rows = form.getFieldValue(name[0]);\n if (!Array.isArray(rows)) return {};\n return { rows, rowIndex: name[1] };\n}\n\nfunction getDisabledDate(field, form, name) {\n return buildDisabledDate({\n field,\n readSibling: (key) => form.getFieldValue(getSiblingFieldName(name, key)),\n ...rowContext(form, name),\n });\n}\n\nfunction getDefaultPickerValue(field) {\n return defaultPickerValue(field);\n}\n\nfunction cleanValue(value, formatter) {\n if (!formatter) return value;\n // Phone gets the common, config-driven mask (default 3-3-4 → 999-878-3413).\n // \"digits\" stays a bare digit string (no separators).\n if (formatter === 'phone') return formatPhone(value);\n if (formatter === 'digits') return value.replace(/\\D/g, '').slice(0, 10);\n if (formatter === 'email' || formatter === 'noSpaces') return value.replace(/\\s/g, '');\n if (formatter === 'name') return value.replace(/\\s+/g, ' ').trimStart().replace(/\\b\\w/g, (char) => char.toUpperCase());\n return value;\n}\n\nfunction normalizeModule(moduleName = '') {\n const normalized = String(moduleName).toLowerCase();\n if (normalized === 'job') return 'jobs';\n if (normalized === 'candidate') return 'candidates';\n if (normalized === 'submissions') return 'submission';\n return normalized;\n}\n\nconst SEARCH_SOURCE_ONLY_FIELDS = new Set([\n 'selectedSource',\n 'source',\n 'sourceType',\n 'scope',\n]);\n\nfunction hasSearchCriterionValue(value) {\n if (value === null || value === undefined) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value === 'boolean') return value;\n if (dayjs.isDayjs(value)) return value.isValid();\n if (Array.isArray(value)) return value.some(hasSearchCriterionValue);\n if (typeof value === 'object') {\n if ('value' in value || 'label' in value || 'name' in value) {\n return hasSearchCriterionValue(value.value ?? value.label ?? value.name);\n }\n return Object.entries(value).some(([key, nestedValue]) => (\n !SEARCH_SOURCE_ONLY_FIELDS.has(key) && hasSearchCriterionValue(nestedValue)\n ));\n }\n\n return false;\n}\n\nfunction hasSearchCriteria(values = {}) {\n return Object.entries(values ?? {}).some(([key, value]) => (\n !SEARCH_SOURCE_ONLY_FIELDS.has(key) && hasSearchCriterionValue(value)\n ));\n}\n\n// buildDynamicFormData — builds the multipart FormData payload to send to the\n// Auth gateway.\n//\n// • File fields are appended as separate FormData parts. The part name is the\n// field's `fileKey` if configured, else the first segment of its path\n// (e.g. \"passport.passportUploadName\" → \"passport\"). Files nested inside an\n// addRow group array are collected from every row.\n// • All other fields are turned into the JSON \"json\" part by the shared,\n// config-driven payload engine (buildPayload). There is ZERO field-name or\n// module-specific logic here — payloadKey / dataType / payloadMode / template\n// are all read from the admin form-group config.\n//\n// Dynamic by design: any new field added in the admin panel is automatically\n// included — no code change required. New modules work the same way.\nfunction buildDynamicFormData(values, groups, extraPayload = {}, module = '') {\n const formData = new FormData();\n\n // New files → multipart parts, via the SHARED engine helper. On CREATE we\n // attach only the flat (non-repeatable) file fields — resume, photo, jobs\n // \"file\", passport, visa. Repeatable (addRow) document files are uploaded in\n // a follow-up update (see submit) because the create handler mishandles them;\n // the indexed update path is the reliable one. The document METADATA still\n // rides along in the JSON payload here, so the rows are created on insert and\n // the follow-up update just attaches each file to its row by index.\n collectFileParts(values, groups, { scope: 'flat', module }).forEach(({ formKey, file }) => {\n formData.append(formKey, file);\n });\n\n // Config-driven JSON payload (file fields are skipped by the engine).\n // extraPayload carries linkage/context keys that are NOT form fields but the\n // downstream create requires (e.g. submission needs jobId + applicantId). These\n // are merged first so a real form field of the same name still wins.\n const payload = { ...extraPayload, ...buildPayload(values, groups, { module }) };\n payload.schemaVersion = 1;\n\n formData.append('json', JSON.stringify(payload));\n return formData;\n}\n\nfunction FieldControl({ field, form, name, moduleName, value, checked, onChange, scopeValues = {}, onAiUpload, onDuplicateBlur, onRegionBlocked, onRowOrderChange, formDisabled, rowFieldKeys }) {\n const type = field.type ?? 'text';\n const baseDisabled = !editable(field, moduleName);\n const [dynamicOptions, setDynamicOptions] = useState(null);\n const [optionsLoading, setOptionsLoading] = useState(false);\n const [locationSearch, setLocationSearch] = useState('');\n const [lookupSearch, setLookupSearch] = useState('');\n const [masterSearch, setMasterSearch] = useState('');\n // Bumped after a quick create/edit (\"Add More\") so the dropdown refetches its\n // options and the freshly created/edited record appears immediately.\n const [refetchNonce, setRefetchNonce] = useState(0);\n const [viewer, setViewer] = useState({ open: false, docs: [], index: 0 });\n const [inputError, setInputError] = useState(null);\n const rawLookupRef = useRef([]);\n // lookupFilterValueFrom resolves against the SAME addRow row first (so a\n // per-row cascade like employerId → that row's recruiter list works), then\n // falls back to the top-level path — which is what every pre-existing\n // top-level config used. Both are always watched (hooks can't be\n // conditional); the row value wins whenever it is non-empty.\n const insideListRow = Array.isArray(name) && name.length >= 3 && typeof name[1] === 'number';\n const topFilterPath = field.lookupFilterValueFrom ? namePathFromString(field.lookupFilterValueFrom) : [`__lookup_filter_${field.field}`];\n const rowFilterPath = (field.lookupFilterValueFrom && insideListRow)\n ? [...name.slice(0, 2), ...namePathFromString(field.lookupFilterValueFrom)]\n : ['__noop_row_filter__'];\n const topFilterValue = Form.useWatch(topFilterPath, form);\n const rowFilterValue = Form.useWatch(rowFilterPath, form);\n const formFilterValue = !empty(rowFilterValue) ? rowFilterValue : topFilterValue;\n // Watch sibling field for disabledByField — e.g. endDate disabled when currentlyPursuing is checked\n const disabledBySiblingPath = field.disabledByField\n ? (Array.isArray(name) && name.length > 1 ? [...name.slice(0, -1), field.disabledByField] : [field.disabledByField])\n : ['__noop_disabled_watch__'];\n const disabledByValue = Form.useWatch(disabledBySiblingPath, form);\n // disabledIf — conditional read-only, same operator set as showIf (eq/neq/\n // truthy/falsy/in/notIn), e.g. lock the Employer to the configured default\n // when Contract Type is W2. The row value wins when the condition field\n // lives in this row; otherwise the top-level field drives it.\n const disabledIfTopPath = field.disabledIf?.field ? namePathFromString(field.disabledIf.field) : ['__noop_disabled_if__'];\n const disabledIfRowPath = (field.disabledIf?.field && insideListRow)\n ? [...name.slice(0, 2), ...namePathFromString(field.disabledIf.field)]\n : ['__noop_disabled_if_row__'];\n const disabledIfTop = Form.useWatch(disabledIfTopPath, form);\n const disabledIfRow = Form.useWatch(disabledIfRowPath, form);\n const conditionallyDisabled = field.disabledIf?.field\n ? labelConditionMatches(field.disabledIf, !empty(disabledIfRow) ? disabledIfRow : disabledIfTop)\n : false;\n // optionsFromField (admin config) — narrow this select's options to the live\n // value of ANOTHER field (e.g. the candidate rate unit may only be the unit\n // the linked job was raised in, which prefillFromModule already puts on the\n // form). Resolved with the same scoping a Show Condition uses: the row's own\n // field when the key belongs to this row (rowFieldKeys), the top-level field\n // otherwise — with a row-first fallback when membership is unknown, matching\n // lookupFilterValueFrom above. Both paths are always watched (hooks cannot be\n // conditional) so the dropdown re-narrows the moment the source changes.\n const constraintKey = field.optionsFromField || '';\n const constraintTopPath = constraintKey ? namePathFromString(constraintKey) : ['__noop_options_from__'];\n const constraintRowPath = (constraintKey && insideListRow && (!rowFieldKeys || rowFieldKeys.has(constraintKey)))\n ? [...name.slice(0, 2), ...namePathFromString(constraintKey)]\n : ['__noop_options_from_row__'];\n const constraintTopValue = Form.useWatch(constraintTopPath, form);\n const constraintRowValue = Form.useWatch(constraintRowPath, form);\n const constraintValue = !empty(constraintRowValue) ? constraintRowValue : constraintTopValue;\n // prefillWhenExclusive (admin config) — \"a value a Conditional Default rule\n // would SET is EXCLUSIVE to that rule's condition\". While the rule matches,\n // its value is offered (and PrefillWhenWatcher auto-selects it, as today);\n // while it does not, the value is REMOVED from the list instead of merely\n // being a stale default. Reuses field.prefillWhen so the hidden value and\n // the auto-filled value can never drift apart. Default off — a field\n // without the flag offers exactly what it offers today.\n //\n // HOOK SAFETY: the rule list is admin data, so it must never decide how\n // many hooks run. ONE selector-form useWatch reads every referenced field\n // out of the whole store and reduces them to a STRING (a fresh array each\n // render would churn the memo); the rule count changes what the selector\n // reads, never the hook count. Same row-vs-top-level scoping as\n // optionsFromField above: a rule key belonging to this addRow row resolves\n // to the row's own field, anything else (the top-level contract type read\n // from inside repeatable employer rows) to the top-level path.\n const exclusivePrefillRules = (truthy(field.prefillWhenExclusive) && field.prefillWhen?.length)\n ? field.prefillWhen\n : null;\n const exclusivePrefillKey = Form.useWatch(\n (values) => (exclusivePrefillRules\n ? JSON.stringify(prefillWhenWatchFields(exclusivePrefillRules).map((key) => {\n const read = (path) => path.reduce((acc, k) => (acc == null ? acc : acc[k]), values);\n const rowValue = (insideListRow && (!rowFieldKeys || rowFieldKeys.has(key)))\n ? read([...name.slice(0, 2), ...namePathFromString(key)])\n : undefined;\n return (!empty(rowValue) ? rowValue : read(namePathFromString(key))) ?? null;\n }))\n : ''),\n { form, preserve: true },\n );\n const exclusivePrefillWatched = useMemo(() => {\n if (!exclusivePrefillRules || !exclusivePrefillKey) return null;\n const values = JSON.parse(exclusivePrefillKey);\n const watched = {};\n prefillWhenWatchFields(exclusivePrefillRules).forEach((key, i) => { watched[key] = values[i]; });\n return watched;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [exclusivePrefillKey]);\n const groupDisabled = useContext(GroupDisabledContext);\n // exclusiveInGroup — only ONE row of a repeatable group may hold this flag\n // (e.g. \"Currently Working Here\" / \"Currently Pursuing\": a person has one\n // current employer and one course in progress). Once any row claims it, the\n // control is disabled on every OTHER row, so the state cannot become\n // ambiguous. The claiming row keeps its control enabled — that is how the\n // user releases the claim and moves it elsewhere.\n //\n // Watching the whole Form.List (not one sibling) is what makes this react\n // to a change in a DIFFERENT row.\n const exclusiveListPath = (field.exclusiveInGroup && insideListRow)\n ? [name[0]]\n : ['__noop_exclusive_watch__'];\n const exclusiveRows = Form.useWatch(exclusiveListPath, form);\n const claimedByAnotherRow = useMemo(() => {\n if (!field.exclusiveInGroup || !insideListRow || !Array.isArray(exclusiveRows)) return false;\n const myIndex = name[1];\n const leaf = name[name.length - 1];\n return exclusiveRows.some((row, index) => index !== myIndex && truthy(row?.[leaf]));\n }, [field.exclusiveInGroup, insideListRow, exclusiveRows, name]);\n // scopeValues only wins when it actually carries a value — a key present\n // but undefined/empty must fall back to the field's own live form value,\n // or the lookup filter is permanently starved and never resolves options.\n const scopeFilterValue = field.lookupFilterValueFrom\n ? scopeValues[field.lookupFilterValueFrom]\n : undefined;\n const lookupFilterValue = !empty(scopeFilterValue) ? scopeFilterValue : formFilterValue;\n // ---- Dependent-lookup staleness guard (generic; see also EditFormV1) ----\n // A lookup scoped by `lookupFilterValueFrom` must not keep a value that was\n // chosen under a DIFFERENT parent. Changing the parent refetches the OPTIONS\n // (lookupFilterValue is a dependency of that effect) but used to leave this\n // field's own value untouched — so picking client A's contact \"Naveen\" and\n // then switching to client B left A's contact id sitting on the form.\n //\n // That went unnoticed because a nested reference id is only unique WITHIN\n // its parent: clientContact.clientContactId is a per-client sequence\n // (1, 2, 3 ...), so the orphaned id still resolved against the new client —\n // to a DIFFERENT person — and saved looking perfectly valid. A wrong name\n // that looks right is worse than a blank one.\n //\n // Only a genuine CHANGE clears. The first observed value is recorded without\n // clearing, so edit prefill (which sets parent and child together) and the\n // initial mount are untouched; and a parent going from empty -> known never\n // clears, because nothing can have been chosen under an unknown parent yet.\n const parentFilterRef = useRef(PARENT_FILTER_UNSEEN);\n useEffect(() => {\n if (!field.lookupFilterField || !field.lookupFilterValueFrom) return;\n const previous = parentFilterRef.current;\n parentFilterRef.current = lookupFilterValue;\n if (!shouldClearDependentValue({\n previous,\n next: lookupFilterValue,\n currentValue: form.getFieldValue(name),\n })) return;\n form.setFields([{ name, value: undefined, errors: [] }]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [lookupFilterValue]);\n\n\n // locationMaster cascade (Country → State → City, sourced from the\n // locationMasters collection). Same top/row watch pattern as\n // lookupFilterValueFrom above: the sibling holding the PARENT level's\n // selected value, watched so options refetch — and the control disables —\n // the moment it changes. `locationCountryFrom` feeds a \"state\" level\n // field; \"city\" needs both `locationCountryFrom` and `locationStateFrom`.\n const locCountryTopPath = field.locationCountryFrom ? namePathFromString(field.locationCountryFrom) : ['__noop_loc_country__'];\n const locCountryRowPath = (field.locationCountryFrom && insideListRow)\n ? [...name.slice(0, 2), ...namePathFromString(field.locationCountryFrom)]\n : ['__noop_loc_country_row__'];\n const locCountryTop = Form.useWatch(locCountryTopPath, form);\n const locCountryRow = Form.useWatch(locCountryRowPath, form);\n const locCountryValue = !empty(locCountryRow) ? locCountryRow : locCountryTop;\n const locStateTopPath = field.locationStateFrom ? namePathFromString(field.locationStateFrom) : ['__noop_loc_state__'];\n const locStateRowPath = (field.locationStateFrom && insideListRow)\n ? [...name.slice(0, 2), ...namePathFromString(field.locationStateFrom)]\n : ['__noop_loc_state_row__'];\n const locStateTop = Form.useWatch(locStateTopPath, form);\n const locStateRow = Form.useWatch(locStateRowPath, form);\n const locStateValue = !empty(locStateRow) ? locStateRow : locStateTop;\n const locationLocked = field.dataSource === 'locationMaster' && (\n (field.locationLevel === 'state' && empty(locCountryValue))\n || (field.locationLevel === 'city' && (empty(locCountryValue) || empty(locStateValue)))\n );\n const disabled = baseDisabled || Boolean(field.disabled) || conditionallyDisabled || (field.disabledByField ? truthy(disabledByValue) : false) || Boolean(formDisabled) || groupDisabled || claimedByAnotherRow || locationLocked;\n\n // Fetch options dynamically when dataSource is master / module / lookup.\n // Static and undefined sources skip the API call and use field.options directly.\n useEffect(() => {\n if (type === 'location') {\n let cancelled = false;\n setOptionsLoading(true);\n\n async function fetchLocations() {\n try {\n const params = new URLSearchParams({\n search: locationSearch,\n limit: String(field.limit ?? 50),\n offset: '0',\n });\n const json = await fetchJsonWithAuth(AUTH_URL, `/admin/location-dropdown-values?${params}`);\n const raw = json?.data ?? json ?? [];\n if (!cancelled) setDynamicOptions(normalizeOptions(Array.isArray(raw) ? raw : []));\n } catch (err) {\n console.error(`[AddFormV1] Failed to fetch locations for \"${field.field}\":`, err);\n if (!cancelled) setDynamicOptions([]);\n } finally {\n if (!cancelled) setOptionsLoading(false);\n }\n }\n\n fetchLocations();\n return () => { cancelled = true; };\n }\n const ds = field.dataSource;\n if (!['select', 'radio', 'checkbox'].includes(type)) return undefined;\n if (!ds || ds === 'static') return undefined;\n if (ds === 'lookup' && field.lookupFilterField && empty(lookupFilterValue)) {\n setDynamicOptions([]);\n setOptionsLoading(false);\n return undefined;\n }\n\n // lookupMinSearchLength (opt-in): don't preload the full list on\n // mount — wait until the user has actually typed enough characters.\n // Existing lookup fields without this flag keep today's behavior\n // (full list shown immediately) untouched.\n if (ds === 'lookup' && field.lookupMinSearchLength && lookupSearch.trim().length < field.lookupMinSearchLength) {\n setDynamicOptions([]);\n setOptionsLoading(false);\n return undefined;\n }\n\n let cancelled = false;\n setOptionsLoading(true);\n\n async function fetchOptions() {\n try {\n let raw = [];\n if (ds === 'master' || ds === 'module') {\n raw = await getDropdownValues(\n moduleName,\n field.field,\n ds === 'master' ? masterSearch : '',\n field.limit ?? 50,\n 0,\n {\n dataSource: ds,\n masterName: field.masterName,\n groupName: field.groupName,\n },\n );\n } else if (ds === 'lookup') {\n const params = new URLSearchParams({\n collection: field.lookupCollection ?? '',\n displayField: field.displayField ?? '',\n valueField: field.valueField ?? '_id',\n });\n if (field.displayField2) params.set('displayField2', field.displayField2);\n if (lookupSearch) params.set('search', lookupSearch);\n if (field.lookupFilterField && !empty(lookupFilterValue)) {\n params.set('filterField', field.lookupFilterField);\n params.set('filterValue', String(lookupFilterValue));\n }\n if (Array.isArray(field.filters) && field.filters.length > 0) {\n params.set('filters', JSON.stringify(field.filters));\n }\n // The row-filter config, rebuilt from the individual keys\n // rather than passing `field` itself: every key here is a\n // dependency of this effect, so the options refetch and\n // re-filter whenever an admin changes one of them.\n const rowFilterConfig = {\n field: field.field,\n extraFields: field.extraFields,\n optionsRequireExtraField: field.optionsRequireExtraField,\n optionsRequireExtraValue: field.optionsRequireExtraValue,\n optionsHierarchyParentField: field.optionsHierarchyParentField,\n optionsHierarchySelfFrom: field.optionsHierarchySelfFrom,\n };\n // Every extraData key the row filters need is requested\n // automatically alongside the explicit extraFields, so a\n // filter key can never be configured without its data.\n let extraKeys = lookupExtraFieldKeys(rowFilterConfig);\n // Exact Course -> Module -> Lesson compatibility path. Older BE builds\n // return one array-valued option per module. Requesting moduleTitle\n // lets us select and flatten only the currently selected module.\n extraKeys = withCourseModuleLessonExtraFields(field, extraKeys);\n if (extraKeys.length) params.set('extraFields', extraKeys.join(','));\n const json = await fetchJsonWithAuth(AUTH_URL, `/admin/lookup-dropdown-values?${params}`);\n raw = json?.data ?? json ?? [];\n raw = normalizeCourseModuleLessonRows(raw, field, lookupFilterValue, { source: 'AddFormV1' });\n // Config-driven row filters: value match on an extraData key\n // (e.g. only list a recruiter once verified, or only a given\n // role) and/or the signed-in user's reporting downline.\n raw = filterLookupOptionRows(raw, rowFilterConfig, { source: 'AddFormV1' });\n } else if (ds === 'locationMaster') {\n const level = field.locationLevel || 'country';\n if (level === 'state' && empty(locCountryValue)) {\n raw = [];\n } else if (level === 'city' && (empty(locCountryValue) || empty(locStateValue))) {\n raw = [];\n } else {\n const params = new URLSearchParams({ level, limit: String(field.limit ?? 250), offset: '0' });\n if (!empty(locCountryValue)) params.set('country', String(locCountryValue));\n if (!empty(locStateValue)) params.set('state', String(locStateValue));\n if (lookupSearch) params.set('search', lookupSearch);\n const json = await fetchJsonWithAuth(AUTH_URL, `/admin/location-dropdown-values?${params}`);\n raw = json?.data ?? json ?? [];\n }\n } else if (ds === 'group') {\n const gn = (field.groupName ?? '').toLowerCase().trim();\n if (gn === 'users' || gn === 'user') {\n const json = await fetchJsonWithAuth(AUTH_URL, '/get-all-users?limit=500&offset=0');\n const users = json?.data?.users ?? json?.users ?? json?.data ?? [];\n // groupRoleContains (admin config) — e.g. \"manager\" lists every\n // user whose role NAME contains that word (Delivery Manager,\n // Onboarding Manager, Submission Manager, …), not just a single\n // exact role. `/get-all-users` already returns each user's\n // roleName, so this narrows client-side with no extra request.\n const roleContains = String(field.groupRoleContains ?? '').trim().toLowerCase();\n const filteredUsers = roleContains\n ? (Array.isArray(users) ? users.filter((u) => String(u.roleName ?? '').toLowerCase().includes(roleContains)) : [])\n : users;\n raw = Array.isArray(filteredUsers) ? filteredUsers.map((u) => ({\n label: [u.firstName, u.lastName].filter(Boolean).join(' ').trim() || u.userName || u.email || String(u.userId),\n value: u.userId ?? u.id,\n })) : [];\n }\n }\n if (!cancelled) {\n rawLookupRef.current = Array.isArray(raw) ? raw : [];\n setDynamicOptions(normalizeOptions(rawLookupRef.current));\n }\n } catch (err) {\n console.error(`[AddFormV1] Failed to fetch options for \"${field.field}\":`, err);\n if (!cancelled) setDynamicOptions([]);\n } finally {\n if (!cancelled) setOptionsLoading(false);\n }\n }\n\n fetchOptions();\n return () => { cancelled = true; };\n }, [type, field.dataSource, field.field, field.limit, field.lookupCollection, field.displayField, field.displayField2, field.valueField, field.lookupFilterField, lookupFilterValue, field.groupName, field.groupRoleContains, field.masterName, locationSearch, lookupSearch, masterSearch, moduleName, field.extraFields, field.optionsRequireExtraField, field.optionsRequireExtraValue, field.optionsHierarchyParentField, field.optionsHierarchySelfFrom, refetchNonce, field.lookupMinSearchLength, field.locationLevel, field.locationCountryFrom, field.locationStateFrom, locCountryValue, locStateValue]);\n\n const staticOptions = normalizeOptions(field.options ?? field.values ?? []);\n const baseOptions = dynamicOptions ?? staticOptions;\n\n // ── Stored values outside the filtered option list ──────────────────────\n // `lookupFilters` decide what may be PICKED. They must not decide what an\n // already-assigned value is allowed to SHOW — a job assigned to somebody\n // outside the current user's reporting chain rendered its raw id (\"149\")\n // instead of a name. Resolved separately, unfiltered, and appended.\n const [resolvedOptions, setResolvedOptions] = useState([]);\n const missingValues = missingOptionValues(value, baseOptions);\n // Joined into a string: the array identity changes every render, and a raw\n // array dependency would refetch forever.\n const missingKey = missingValues.join(',');\n useEffect(() => {\n if (!missingKey || field.dataSource !== 'lookup' || optionsLoading) return undefined;\n let cancelled = false;\n fetchLookupLabels(field, missingKey.split(','))\n .then((rows) => { if (!cancelled) setResolvedOptions(rows); })\n // Best effort. Failing to resolve a label must never break the\n // field — the value is still there and still submits.\n .catch(() => { if (!cancelled) setResolvedOptions([]); });\n return () => { cancelled = true; };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [missingKey, field.dataSource, field.lookupCollection, field.displayField,\n field.displayField2, field.valueField, optionsLoading]);\n // optionsFromField constraint applied here so EVERY option-driven control\n // (select, radio, checkbox group, location…) is narrowed the same way.\n // Fails open — see narrowOptionsByConstraint. prefillWhenExclusive then\n // COMPOSES on top of that narrowing (it removes, it never restores).\n const optionsWithStored = mergeResolvedOptions(baseOptions, resolvedOptions);\n const constrainedOptions = constraintKey ? narrowOptionsByConstraint(optionsWithStored, constraintValue) : optionsWithStored;\n const options = exclusivePrefillRules\n ? stripExclusivePrefillOptions(constrainedOptions, exclusivePrefillRules, exclusivePrefillWatched ?? {})\n : constrainedOptions;\n\n // Select multiplicity is config-driven: multiSelect flag → explicit mode →\n // field.multiple → array dataType. No field-name list. \"tags\" is opt-in via\n // an explicit field.mode === \"tags\".\n const selectMode = field.multiSelect\n ? 'multiple'\n : (field.mode ?? (truthy(field.multiple) ? 'multiple' : undefined));\n const inferredSelectMode = selectMode ?? (effectiveDataType(field) === 'array' ? 'multiple' : undefined);\n // allowCustomValues (admin config) — the field keeps a value the user TYPED\n // even when it is not in the list (Candidate → Skills is the first user, but\n // nothing here is module- or field-specific: any select/lookup field can opt\n // in from Form Groups). Until now free entry existed only for the hardcoded\n // `type: 'tagify'` control, which is not per-field selectable and loses every\n // other select behaviour (lookup, autofill, quick-create).\n const allowCustomValues = truthy(field.allowCustomValues);\n // antd's \"tags\" mode is what keeps a typed value; it always emits an ARRAY,\n // so a single-valued field has to be unwrapped again on the way out (see\n // handleSelectChange) and wrapped on the way in.\n const effectiveSelectMode = allowCustomValues ? 'tags' : inferredSelectMode;\n const isArrayValued = Boolean(field.multiSelect) || truthy(field.multiple)\n || effectiveDataType(field) === 'array' || inferredSelectMode === 'multiple';\n // Config-driven separators that commit a typed entry (default comma).\n const tokenSeparators = allowCustomValues\n ? (typeof field.tokenSeparators === 'string' && field.tokenSeparators\n ? field.tokenSeparators.split('')\n : [','])\n : undefined;\n\n const isSelectLike = ['select', 'location'].includes(type);\n const placeholder = field.hidePlaceholder\n ? undefined\n : (field.placeholder ?? `${isSelectLike ? 'Select' : 'Enter'} ${String(field.label ?? '').toLowerCase()}`);\n const inputLimits = getInputLimits(field);\n // Sets the value in the form store first, then re-validates.\n // Required because FieldControl is a custom wrapper — Form.Item's injected\n // onChange never reaches the inner Ant Design components, so the store\n // would otherwise hold stale/undefined values when validation runs.\n const updateAndValidate = (nextValue) => {\n onChange?.(nextValue);\n\n setTimeout(() => {\n form.validateFields([name]).catch(() => { });\n }, 0);\n };\n\n // Config-driven \"Add More\"/\"Edit\" quick actions inside a select dropdown.\n // Called unconditionally (rules of hooks) — returns nulls unless the field\n // opts in via quickCreate/quickEdit. On success, refetch options and (for a\n // fresh create on a single select) select the new record.\n const quick = useQuickField({ \n field, form, name, moduleName, scopeValues, ownValue: value,\n onDone: (kind, newId) => {\n setRefetchNonce((n) => n + 1);\n const single = effectiveDataType(field) !== 'array' && !field.multiSelect && !field.multiple;\n if (kind === 'create' && newId != null && single) {\n // Same clearing the ordinary onChange does. Creating an employer\n // from inside the dropdown IS changing the employer, so the rest\n // of the group — recruiter, email, contact, VMS — still describes\n // the PREVIOUS one and must go. This path set the new value and\n // skipped the clear, so a brand-new employer kept the old\n // employer's recruiter beside it, which reads as a real pairing.\n //\n // Cleared BEFORE the value is written, so anything the new\n // selection autofills is preserved rather than wiped after.\n if (field.clearGroupOnChange || field.linkedClearField) {\n applyGroupClear(form, field, name, rowFieldKeys);\n }\n updateAndValidate(usesLabeledSelectValue(field) ? { value: newId } : newId);\n }\n },\n });\n\n // Build validator config once (null when not set)\n const validatorCfg = field.validator?.type\n ? { ...field.validator, title: field.validator.title || field.label || 'Field' }\n : null;\n\n const inputProps = {\n ...inputLimits,\n disabled,\n placeholder,\n prefix: field.icon ? null : fieldIcons[field.field],\n value: value ?? '',\n onChange: (event) => {\n let nextValue = field.formatter\n ? cleanValue(event.target.value, field.formatter)\n : event.target.value;\n\n if (validatorCfg) {\n const { cleaned, error } = applyInputValidator(nextValue, validatorCfg, 'change');\n setInputError(error);\n nextValue = cleaned;\n }\n\n updateAndValidate(nextValue);\n },\n // Composed, not conditional. The character-validator blur only exists\n // when a validator is configured, so hanging the duplicate check off it\n // would silently skip every field without one — including a plain email\n // box, which is exactly the field this is for.\n onBlur: (e) => {\n if (validatorCfg) {\n const { cleaned, error } = applyInputValidator(e.target.value, validatorCfg, 'blur');\n setInputError(error);\n if (cleaned !== e.target.value) updateAndValidate(cleaned);\n }\n // Typing an email that already exists should be caught here, not on\n // submit after the whole form has been filled in.\n if (field.checkDuplicateOnBlur && String(e.target.value ?? '').trim()) {\n onDuplicateBlur?.(field);\n }\n },\n ...(validatorCfg && {\n onKeyPress: (e) => {\n const pattern = getKeyPattern(validatorCfg.type);\n if (!pattern) return;\n if (e.which === 0 || e.keyCode === 8 || e.keyCode === 13) return;\n const char = String.fromCharCode(e.which ?? e.keyCode);\n if (!pattern.test(char)) {\n e.preventDefault();\n const hint = `${validatorCfg.title} — invalid character.`;\n setInputError(hint);\n setTimeout(() => setInputError((prev) => (prev === hint ? null : prev)), 1800);\n }\n },\n maxLength: validatorCfg.maxLength ?? inputLimits.maxLength,\n }),\n };\n\n if (type === 'tagify') {\n return (\n <Select\n value={value}\n allowClear\n disabled={disabled}\n mode=\"tags\"\n placeholder={placeholder}\n onChange={updateAndValidate}\n />\n );\n }\n if (type === 'location') {\n return (\n <Select\n value={value}\n allowClear\n showSearch\n filterOption={false}\n disabled={disabled}\n loading={optionsLoading}\n // Single or multi is admin config (Form Groups → the field's\n // \"Location selection\"). inferredSelectMode is the SAME resolver\n // an ordinary select uses, so multiSelect / multiple / an array\n // dataType all mean the same thing on a location field as they\n // do everywhere else — and effectiveDataType already types a\n // multiSelect field's payload as an array, so nothing extra is\n // needed to store several locations.\n mode={inferredSelectMode}\n options={options}\n placeholder={placeholder}\n notFoundContent={optionsLoading ? <Spin size=\"small\" /> : undefined}\n onSearch={setLocationSearch}\n onFocus={() => setLocationSearch((current) => current)}\n onChange={updateAndValidate}\n />\n );\n }\n if (type === 'select') {\n const remoteLookup = field.dataSource === 'lookup';\n const remoteMaster = field.dataSource === 'master';\n const remoteSearch = remoteLookup || remoteMaster;\n const keepLabel = usesLabeledSelectValue(field);\n const rawControlValue = toSelectControlValue(field, value, options);\n // \"tags\" mode renders from an array. A single-valued field that opted\n // into allowCustomValues still stores a scalar, so wrap it for display\n // only — the stored shape never changes.\n const controlValue = (allowCustomValues && !isArrayValued)\n ? (rawControlValue === undefined || rawControlValue === null || rawControlValue === ''\n ? undefined\n : (Array.isArray(rawControlValue) ? rawControlValue : [rawControlValue]))\n : rawControlValue;\n const handleSelectChange = (raw) => {\n // …and unwrap on the way out: keep the LAST entry the user typed or\n // picked, so a single-valued field never starts storing an array\n // just because free entry was switched on.\n const val = (allowCustomValues && !isArrayValued && Array.isArray(raw))\n ? (raw.length ? raw[raw.length - 1] : undefined)\n : raw;\n updateAndValidate(val);\n // Changing this field can invalidate the rest of its group: an\n // employer's recruiter, email, contact and VMS all describe the\n // PREVIOUS employer, and leaving them behind silently attaches one\n // company's details to another. Cleared BEFORE autofill below, so a\n // new selection's own values are written straight back in.\n if (field.clearGroupOnChange || field.linkedClearField) {\n applyGroupClear(form, field, name, rowFieldKeys);\n }\n if (field.autofillFrom?.length) {\n const selectedValue = val && !Array.isArray(val) && typeof val === 'object' ? val.value : val;\n const isInsideList = Array.isArray(name) && name.length >= 3 && typeof name[1] === 'number';\n if (val == null) {\n // Cleared — wipe all autofill targets\n field.autofillFrom.forEach(({ targetField: tf }) => {\n const tp = isInsideList\n ? [...name.slice(0, 2), ...namePathFromString(tf)]\n : namePathFromString(tf);\n form.setFieldValue(tp, null);\n });\n } else if (rawLookupRef.current.length > 0) {\n const vField = field.valueField ?? '_id';\n const rawItem = rawLookupRef.current.find(item =>\n getNestedProp(item, vField) === selectedValue || item._id === selectedValue || item.id === selectedValue || item.value === selectedValue\n );\n if (rawItem) {\n field.autofillFrom.forEach(({ optionKey, targetField: tf }) => {\n const v = getNestedProp(rawItem, optionKey) ?? rawItem.extraData?.[optionKey] ?? null;\n const tp = isInsideList\n ? [...name.slice(0, 2), ...namePathFromString(tf)]\n : namePathFromString(tf);\n form.setFieldValue(tp, v);\n });\n }\n }\n }\n };\n return (\n <>\n <Select\n value={controlValue}\n labelInValue={keepLabel || undefined}\n allowClear\n // Every select is type-to-search. It used to be enabled only\n // for remote/lookup/group sources, so a static-option field\n // (Currency, Unit, Work Mode, Status…) could only be picked\n // by scrolling — painful once a list runs to 30 entries, as\n // Relevant Experience does. Local lists filter on the LABEL\n // (optionFilterProp); remote ones keep filterOption=false\n // because the server already filtered.\n // `field.showSearch: false` turns it off for a specific field.\n showSearch={field.showSearch !== false}\n optionFilterProp=\"label\"\n filterOption={remoteSearch ? false : undefined}\n disabled={disabled}\n loading={optionsLoading}\n mode={effectiveSelectMode}\n tokenSeparators={tokenSeparators}\n options={options}\n placeholder={placeholder}\n notFoundContent={optionsLoading ? <Spin size=\"small\" /> : undefined}\n onSearch={remoteLookup ? setLookupSearch : remoteMaster ? setMasterSearch : undefined}\n onChange={handleSelectChange}\n dropdownRender={quick.footer ? (menu) => (<>{menu}{quick.footer}</>) : undefined}\n />\n {quick.modal}\n </>\n );\n }\n if (type === 'radio') {\n return (\n <Radio.Group\n value={value}\n disabled={disabled}\n options={options}\n onChange={(e) => updateAndValidate(e.target.value)}\n />\n );\n }\n if (type === 'checkbox') {\n if (options.length > 0) {\n return (\n <Checkbox.Group\n value={value}\n disabled={disabled}\n options={options}\n onChange={updateAndValidate}\n />\n );\n }\n return (\n <Checkbox\n checked={Boolean(checked ?? value)}\n disabled={disabled}\n onChange={(e) => {\n const next = e.target.checked;\n // Region gate: some markets do not accept an entry that is\n // still in progress. The tick is REVERSED rather than left\n // standing with an error underneath — leaving it ticked\n // invites the user to try to submit and be refused twice.\n if (next && onRegionBlocked?.(field)) return;\n updateAndValidate(next);\n // Ticking \"still ongoing\" makes this the most recent entry,\n // so it may now belong at the top of a newest-first list.\n if (next) onRowOrderChange?.(field, name);\n if (field.linkedClearField && next) {\n const clearPath = Array.isArray(name) && name.length > 1\n ? [...name.slice(0, -1), field.linkedClearField]\n : [field.linkedClearField];\n form.setFieldValue(clearPath, null);\n }\n }}\n >\n {field.checkboxLabel ?? field.label}\n </Checkbox>\n );\n }\n if (type === 'text-editor') {\n return (\n <>\n <TipTapEditor\n value={value ?? form.getFieldValue(name) ?? ''}\n disabled={disabled}\n placeholder={placeholder}\n onChange={(html) => {\n if (validatorCfg) {\n const { error } = applyInputValidator(html, validatorCfg, 'change');\n setInputError(error);\n }\n updateAndValidate(html);\n }}\n />\n {inputError && <div className=\"v1-input-validator-hint\">{inputError}</div>}\n </>\n );\n }\n if (type === 'textarea') {\n return (\n <>\n <TextArea {...inputProps} rows={field.rows ?? 3} className=\"v1-scroll-textarea\" />\n {inputError && <div className=\"v1-input-validator-hint\">{inputError}</div>}\n </>\n );\n }\n if (type === 'date') {\n return (\n <DatePicker\n disabled={disabled}\n placeholder={placeholder}\n style={{ width: '100%' }}\n suffixIcon={<CalendarOutlined />}\n value={value ?? null}\n disabledDate={getDisabledDate(field, form, name)}\n defaultPickerValue={getDefaultPickerValue(field)}\n onChange={(date) => {\n updateAndValidate(date);\n // Dates are the other way a row becomes the most recent\n // one — the tick-box is not the only trigger.\n onRowOrderChange?.(field, name);\n }}\n />\n );\n }\n if (type === 'time') return <TimePicker disabled={disabled} placeholder={placeholder} style={{ width: '100%' }} value={value ?? null} onChange={(time) => updateAndValidate(time)} />;\n if (type === 'file') {\n const fileRules = field.validations ?? field.validation ?? field.rules ?? [];\n const fileTypeRule = fileRules.find((r) => (typeof r === 'string' ? r : r?.type) === 'fileType');\n const fileSizeRule = fileRules.find((r) => (typeof r === 'string' ? r : r?.type) === 'fileSize');\n const maxFilesRule = fileRules.find((r) => (typeof r === 'string' ? r : r?.type) === 'maxFiles');\n\n // Admin \"Allowed Content\" category (field.accept) takes priority over the\n // fine-grained fileType rule; 'any'/unset falls through to the rule.\n const acceptCategory = uploadAcceptCategory(field);\n const acceptTypes = acceptCategory\n ? acceptCategory.exts.map((e) => `.${e}`).join(',')\n : (fileTypeRule?.value\n ? fileTypeRule.value.split(',').map((e) => `.${e.trim().replace(/^\\./, '')}`).join(',')\n : undefined);\n const maxSizeMB = fileSizeRule ? Number(fileSizeRule?.value ?? 5) : undefined;\n // maxFiles validation rule takes top priority; otherwise use field.multiple/maxCount\n // (set via admin panel toggle), falling back to single-file mode.\n const maxFiles = maxFilesRule\n ? Number(maxFilesRule?.value ?? 1)\n : (truthy(field.multiple) ? (field.maxCount ?? 5) : 1);\n\n const fileList = Array.isArray(value) ? value : [];\n const canAddMore = fileList.length < maxFiles;\n\n const formatFileSize = (bytes) => {\n if (!bytes) return '';\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`;\n return `${(bytes / 1024 / 1024).toFixed(2)} MB`;\n };\n\n const getFileIcon = (fileName) => {\n const ext = String(fileName ?? '').split('.').pop()?.toLowerCase();\n if (ext === 'pdf') return <FilePdfOutlined className=\"v1-file-type-icon v1-file-icon-pdf\" />;\n if (['doc', 'docx'].includes(ext)) return <FileWordOutlined className=\"v1-file-type-icon v1-file-icon-word\" />;\n if (['xls', 'xlsx', 'csv'].includes(ext)) return <FileExcelOutlined className=\"v1-file-type-icon v1-file-icon-excel\" />;\n if (['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'].includes(ext)) return <FileImageOutlined className=\"v1-file-type-icon v1-file-icon-image\" />;\n return <FileOutlined className=\"v1-file-type-icon v1-file-icon-default\" />;\n };\n\n const handleFileDelete = (index) => {\n updateAndValidate(fileList.filter((_, i) => i !== index));\n };\n\n const handleFileView = (file, fileIdx) => {\n const docs = fileList.map((f) => {\n let url = f.url ?? f.thumbUrl ?? '';\n if (!url && f.originFileObj instanceof File) url = URL.createObjectURL(f.originFileObj);\n return { url, name: f.name ?? 'file' };\n }).filter(d => d.url);\n setViewer({ open: true, docs, index: fileIdx ?? 0 });\n };\n\n const isMulti = maxFiles > 1;\n const remaining = maxFiles - fileList.length;\n\n const typeHint = acceptCategory\n ? acceptCategory.hint\n : (acceptTypes\n ? acceptTypes.split(',').map((t) => t.replace('.', '').toUpperCase()).join(', ')\n : null);\n const sizeHint = maxSizeMB ? `up to ${maxSizeMB} MB` : null;\n const baseHint = [typeHint, sizeHint].filter(Boolean).join(' ');\n const dropHint = isMulti && fileList.length > 0\n ? [baseHint, `${remaining} of ${maxFiles} remaining`].filter(Boolean).join(' • ')\n : baseHint;\n const dropTitle = fileList.length > 0\n ? `Add ${isMulti ? 'more files' : 'file'}`\n : (field.buttonLabel ?? `Upload ${field.label ?? 'File'}`);\n\n const beforeUploadHandler = (file) => {\n if (fileList.length >= maxFiles) return Upload.LIST_IGNORE;\n if (acceptTypes) {\n const ext = (file.name.split('.').pop() ?? '').toLowerCase();\n const allowed = acceptTypes.split(',').map((t) => t.replace(/^\\./, '').toLowerCase());\n if (!allowed.includes(ext)) {\n message.error(acceptCategory\n ? acceptCategory.error\n : (fileTypeRule?.message ?? `Only ${fileTypeRule.value} files are allowed`));\n return Upload.LIST_IGNORE;\n }\n }\n if (maxSizeMB !== undefined && file.size / 1024 / 1024 > maxSizeMB) {\n message.error(fileSizeRule?.message ?? `File must be smaller than ${maxSizeMB} MB`);\n return Upload.LIST_IGNORE;\n }\n return false;\n };\n\n // antd calls onChange once per file even in multi-select, each time with the\n // full accumulated newList. Slicing to maxFiles guards against racing additions.\n const handleUploadChange = ({ fileList: newList }) => {\n const sliced = newList.slice(0, maxFiles);\n updateAndValidate(sliced);\n // An \"upload\"-trigger AI action (e.g. auto-parse a resume) fires once\n // per newly-added file, using the raw browser File object.\n if (onAiUpload && sliced.length > fileList.length) {\n const added = sliced[sliced.length - 1];\n if (added?.originFileObj) onAiUpload(added.originFileObj);\n }\n };\n\n const multiUploadProps = {\n accept: acceptTypes,\n fileList,\n showUploadList: false,\n multiple: true,\n maxCount: maxFiles,\n beforeUpload: beforeUploadHandler,\n onChange: handleUploadChange,\n disabled,\n };\n\n const fileRows = fileList.map((file, index) => (\n <div key={file.uid ?? index} className=\"v1-file-item\">\n <div className=\"v1-file-item-icon\">{getFileIcon(file.name)}</div>\n <div className=\"v1-file-item-info\">\n <span className=\"v1-file-item-name\" title={file.name}>{file.name}</span>\n <span className=\"v1-file-item-meta\">\n {file.existing\n ? 'Previously uploaded'\n : `${formatFileSize(file.size)}${file.size ? ' • ' : ''}Uploaded just now`}\n </span>\n </div>\n <Space size={6} className=\"v1-file-item-actions\">\n <Button\n size=\"small\"\n icon={<EyeOutlined />}\n onClick={() => handleFileView(file, index)}\n className=\"v1-file-view-btn\"\n >\n View\n </Button>\n <Button\n size=\"small\"\n danger\n icon={<DeleteOutlined />}\n onClick={() => handleFileDelete(index)}\n className=\"v1-file-delete-btn\"\n />\n </Space>\n </div>\n ));\n\n const viewerEl = (\n <DocumentViewer\n documents={viewer.docs}\n open={viewer.open}\n onClose={() => setViewer(v => ({ ...v, open: false }))}\n initialIndex={viewer.index}\n />\n );\n\n if (isMulti) {\n const multiTitle = fileList.length > 0\n ? `Upload more ${field.label ?? 'files'}`\n : (field.buttonLabel ?? `Upload ${field.label ?? 'File'}`);\n\n return (\n <>\n <div className=\"v1-file-upload-wrapper\">\n {/* Centered dropzone — always at top in multiple mode */}\n {canAddMore && (\n <Upload {...multiUploadProps} style={{ width: '100%', display: 'block' }}>\n <div className={`v1-upload-dropzone v1-upload-dropzone-center${disabled ? ' v1-upload-dropzone-disabled' : ''}`}>\n <div className=\"v1-upload-dropzone-title-row\">\n <CloudUploadOutlined className=\"v1-upload-cloud-icon v1-upload-cloud-icon-sm\" />\n <span className=\"v1-upload-dropzone-title v1-upload-dropzone-title-blue\">{multiTitle}</span>\n </div>\n <span className=\"v1-upload-dropzone-sub\">Drag & drop or click to upload</span>\n {baseHint && <span className=\"v1-upload-dropzone-sub\">{baseHint}</span>}\n </div>\n </Upload>\n )}\n\n {/* Uploaded file rows — 2-column grid */}\n {fileList.length > 0 && (\n <div className=\"v1-file-grid\">\n {fileRows}\n </div>\n )}\n\n {/* \"+ Add more files\" text link at the bottom */}\n {canAddMore && fileList.length > 0 && (\n <Upload {...multiUploadProps} style={{ display: 'inline-block' }}>\n <Button type=\"link\" size=\"small\" icon={<PlusOutlined />} className=\"v1-add-more-files-btn\">\n Add more files\n </Button>\n </Upload>\n )}\n </div>\n {viewerEl}\n </>\n );\n }\n\n return (\n <>\n <div className=\"v1-file-upload-wrapper\">\n {/* Single mode: compact file row at field height */}\n {fileList.length > 0 && <div className=\"v1-file-rows-single\">{fileRows}</div>}\n\n {canAddMore && (\n <Upload\n accept={acceptTypes}\n fileList={fileList}\n showUploadList={false}\n multiple={false}\n maxCount={1}\n beforeUpload={beforeUploadHandler}\n onChange={handleUploadChange}\n disabled={disabled}\n style={{ width: '100%', display: 'block' }}\n >\n <div className={`v1-upload-dropzone v1-upload-dropzone-single${disabled ? ' v1-upload-dropzone-disabled' : ''}`}>\n <CloudUploadOutlined className=\"v1-upload-cloud-icon\" />\n <span className=\"v1-upload-dropzone-title\">{dropTitle}</span>\n {dropHint && <span className=\"v1-upload-dropzone-sub\">— {dropHint}</span>}\n </div>\n </Upload>\n )}\n </div>\n {viewerEl}\n </>\n );\n }\n\n return (\n <>\n <Input\n {...inputProps}\n type={type === 'number' ? 'number' : type}\n // step=\"any\" so the browser's own number input accepts a\n // fractional value on a field the admin marked decimal.\n {...(type === 'number' && truthy(field.decimal) ? { step: 'any' } : {})}\n // Admin-configured unit shown inside the input (e.g. \"%\").\n {...(field.suffix ? { suffix: field.suffix } : {})}\n />\n {inputError && <div className=\"v1-input-validator-hint\">{inputError}</div>}\n </>\n );\n}\n\nfunction SectionTitle({ icon, title }) {\n return (\n <Space size={10} align=\"center\">\n <div className=\"v1-section-icon-box\">{icon}</div>\n <Text strong className=\"v1-section-label\">{title}</Text>\n </Space>\n );\n}\n\nfunction FieldLabel({ field, label, locked }) {\n if (!label) return label;\n // field.tooltip (admin config) OR the older infoEnabled/infoText pair — one\n // resolver (fieldTooltipText) so both forms and every control type agree on\n // where a field's help text comes from. The TEXT is always admin config.\n const infoText = fieldTooltipText(field);\n const showInfo = Boolean(infoText);\n if (!showInfo && !locked) return label;\n return (\n <span className=\"v1-field-label-with-info\">\n <span>{label}</span>\n {showInfo && (\n <Tooltip title={infoText}>\n <InfoCircleOutlined className=\"v1-field-info-icon\" />\n </Tooltip>\n )}\n {locked && (\n <Tooltip title=\"You don't have permission to edit this field\">\n <LockOutlined className=\"v1-field-info-icon\" />\n </Tooltip>\n )}\n </span>\n );\n}\n\nfunction GroupInfoMessage({ group }) {\n if (!truthy(group?.infoEnabled) || empty(group?.infoText)) return null;\n return <Text type=\"secondary\" className=\"v1-group-info-message\">{group.infoText}</Text>;\n}\n\nfunction GroupToggleControl({ group }) {\n if (!truthy(group?.toggleEnabled) || empty(group?.toggleField)) return null;\n return (\n <Space size={6} align=\"center\" onClick={(event) => event.stopPropagation()}>\n <Text type=\"secondary\" className=\"v1-combine-toggle-label\">{group.toggleLabel || 'Toggle'}</Text>\n <Form.Item name={group.toggleField} valuePropName=\"checked\" initialValue={Boolean(group.toggleValue)} noStyle>\n <Switch size=\"small\" />\n </Form.Item>\n </Space>\n );\n}\n\n\n// renderFieldHelp — the guidance under a field.\n//\n// `helpText` accepts a STRING or an ARRAY of strings. An array renders as\n// stacked lines, which is what lets one field carry two different KINDS of\n// help without them running together: the mechanical constraint (\"Supports\n// .pdf, .doc, .docx up to 2MB\") and the reason to bother (\"Upload the résumé\n// first — we can read the details straight out of it\"). Jammed into one\n// paragraph they read as a wall and the second half is skipped.\n//\n// A plain string keeps rendering exactly as before, so nothing existing moves.\n// formatPrefillHint renders a previous value as one readable line.\n//\n// The label is admin config (`prefillHintLabel`, \"{value}\" substituted) so the\n// wording belongs to whoever configured the field, not to this file.\n//\n// A history container is the interesting case: an append-only field such as\n// candidateBudget stores an ARRAY of stamped entries, and the one worth showing\n// is the LAST. Rendering the raw array would print \"[object Object]\", which is\n// worse than showing nothing.\nfunction formatPrefillHint(field, stored) {\n let value = stored;\n if (Array.isArray(value)) value = value[value.length - 1];\n if (value && typeof value === 'object') {\n // Join the entry's meaningful leaves, skipping the audit stamps every\n // history entry carries — they describe the WRITE, not the value.\n const skip = new Set(['timestamp', 'updatedBy', 'updatedAt', 'createdAt', 'createdBy', '_id']);\n const parts = Object.entries(value)\n .filter(([k, v]) => !skip.has(k) && v !== null && v !== undefined && v !== ''\n && typeof v !== 'object')\n .map(([, v]) => String(v).trim())\n .filter(Boolean);\n if (!parts.length) return '';\n value = parts.join(' ');\n }\n const text = String(value ?? '').trim();\n if (!text) return '';\n const label = String(field?.prefillHintLabel ?? 'Last recorded: {value}');\n return label.includes('{value}') ? label.replace('{value}', text) : `${label} ${text}`;\n}\n\n// hint is an extra line appended under the field — used by `prefillAsHint`\n// (see the prefill effect) to SHOW a previous value instead of filling it in.\nfunction renderFieldHelp(field, hint) {\n const raw = field?.helpText;\n const lines = (Array.isArray(raw) ? raw : [raw])\n .map((line) => (line == null ? '' : String(line).trim()))\n .filter(Boolean);\n if (hint) lines.push(hint);\n if (!lines.length) return undefined;\n return (\n <span className=\"v1-field-help-text\">\n {lines.map((line, i) => (\n <Text key={i} type=\"secondary\" className=\"v1-field-help-line\">{line}</Text>\n ))}\n </span>\n );\n}\n\n// forwardRef, not a plain `ref` prop: this package declares `react >=18` as its\n// peer, and on React 18 a function component does not receive `ref` as a prop.\n// React 19 no longer needs the wrapper but still honours it, so this is the one\n// form that works across the whole supported range.\n//\n// Exported inline rather than via a `const AddFormV1 = forwardRef(...)` binding:\n// a const of the same name shadows the render function, and the transform then\n// renames the inner one (\"AddFormV12\"), which is what DevTools and every error\n// stack would go on to display.\nexport default forwardRef(function AddFormV1({\n moduleName,\n action,\n authToken,\n clientId,\n region,\n formGroups: providedFormGroups,\n loading: providedLoading = false,\n error: providedError = '',\n breadcrumbItems = [],\n // formType — controls the mode of operation:\n // 'add' → Add Form (default, existing behavior)\n // 'search' → Search Form (lighter validation, Reset button, no auto-create)\n formType = 'add',\n submitText: propSubmitText,\n cancelPath = '/candidates',\n onSubmit,\n // Optional host workflow used only after Admin has a complete, enabled\n // wizard configuration. It lets a domain preserve established side effects\n // (for example Batch draft/session operations) while AddFormV1 remains the\n // route entry point and the normal form remains the automatic fallback.\n wizardAdapter: WizardAdapter = null,\n wizardAdapterProps = null,\n // initialRecord — prefill flat form fields from a plain record object.\n // Matched by field.field / payloadKey / dot-path; best-effort, never required.\n initialRecord: initialRecordProp = null,\n // initialValues (opt-in alias, PLAN-20261105-01) — same as initialRecord,\n // the name EditFormV1 uses. initialRecord wins when both are given.\n initialValues = null,\n // prefillFromUrl — when set (quickSubmit flow), AddFormV1 reads the route to\n // decide the prefill source and the job/candidate linkage entirely on its own:\n // • isFromSubmission=true + submissionId → read the submissions collection\n // • otherwise candidateId → read the candidates collection\n // Both resolve through getFormGroups(id) (field.value + group.rows embedded) —\n // no separate detail-view API. The linkage the submission create requires\n // (applicantId + jobId) is derived from the same URL params.\n prefillFromUrl = false,\n // extraPayload — context/linkage keys merged into the create payload that are\n // NOT form fields (e.g. submission needs { jobId, applicantId }). Kept out of\n // the form so the config stays generic. Ignored when prefillFromUrl derives\n // its own linkage from the route.\n extraPayload = null,\n // presetClientId — caller already knows the client (e.g. Quick Submit knows\n // it from the selected job) so the client-scope gate should resolve silently\n // instead of showing the manual \"Select Client\" picker.\n presetClientId = null,\n // ListView props for search mode — passed through from parent when search results\n // should be displayed below the search form.\n listViewProps = {},\n // selectedScope — optional scope parameter for filtering search results\n selectedScope = '',\n // searchActionContext — page-level context (e.g. { jobId }) merged into every\n // search-result row action's popupState, so a popup opened from here (like\n // Source Candidates' \"Shortlisted\"/\"Tag to Jobs\") already knows what the\n // caller knows instead of asking the user to re-select it. Mirrors the\n // action.popupState convention ListView already spreads into the popup's\n // navigation state — see ListView.jsx's handleActionClick.\n searchActionContext = null,\n // embedded — render the form for use inside a modal (quick \"Add More\" from a\n // select dropdown). Suppresses page chrome/navigation; on a successful create\n // onSuccess(newRecordId, values) is called instead of navigating away, and the\n // Cancel button calls onCancel. Entirely opt-in; the standalone page path is\n // unchanged when embedded is false.\n embedded = false,\n onSuccess = null,\n onCancel = null,\n // Opt-in only. Uses Admin Form Groups as steps while retaining this form's\n // validation, payload, upload and submit engines.\n wizard,\n hideFooter = false,\n // uniqueCheckDebounceMs (opt-in, REQ-20261103-01) — wait this many ms after\n // the last change before a `unique` field is checked; an older request for\n // the same field is cancelled. 0 (default) = every check at once, as before.\n // The submit-time check is never delayed (see uniqueValidationApi.js).\n uniqueCheckDebounceMs = 0,\n}, ref) {\n const initialRecord = initialRecordProp ?? initialValues;\n useEffect(() => {\n if (authToken) setAuthTokenOverride(authToken);\n return () => {\n if (authToken) clearAuthTokenOverride();\n };\n }, [authToken]);\n\n const isSearch = formType === 'search';\n const submitText = propSubmitText ?? (isSearch ? 'Search' : 'Create');\n const navigate = useNavigate();\n // Router location — nav state carries the in-flight relevant-skill match\n // handed over by Quick Submit (see the prefill effect below).\n const routerLocation = useLocation();\n // Cache for the relevant-skill match promise, keyed by its token — see the\n // prefill effect below and services/pendingHandoff.js.\n const skillMatchTokenRef = useRef(null);\n const skillMatchPromiseRef = useRef(null);\n const routeParams = useParams();\n const [searchParams] = useSearchParams();\n const [form] = Form.useForm();\n const [wizardStep, setWizardStep] = useState(0);\n\n // ── Imperative handle ───────────────────────────────────────────────────\n // Lets a host drive the form from outside it — submit it from its own\n // button, validate before advancing a wizard step, read the current values\n // for a preview, or reset it after a modal closes.\n //\n // Deliberately only these four. Exposing `form` itself would hand callers\n // the entire antd API, including setFieldsValue — and a host writing\n // directly into the store bypasses every conditional default, payload gate\n // and linked-clear rule this component maintains, in ways nothing here\n // could see or correct.\n //\n // submit() goes through form.submit() rather than calling the submit\n // handler, so an imperative submit runs validation, the duplicate gate and\n // the after-submit navigation exactly as pressing the button does.\n useImperativeHandle(ref, () => ({\n submit: () => form.submit(),\n validate: () => form.validateFields(),\n getValues: () => form.getFieldsValue(true),\n reset: () => form.resetFields(),\n }), [form]);\n\n // formGroups (opt-in, PLAN-20261105-01) — an ARRAY here wins over moduleName:\n // the form renders these groups and skips every config fetch it makes on\n // mount (form groups, role perms, default fields, linked-job scope), so it\n // can run on a public page with no login. moduleName still names the\n // payload/upload module. Absent → unchanged (moduleName fetches config).\n const hostGroups = Array.isArray(providedFormGroups) ? providedFormGroups : null;\n const configModule = hostGroups ? null : moduleName;\n const searchFormValues = Form.useWatch([], form);\n const [searchLoading, setSearchLoading] = useState(false);\n const [collapsed, setCollapsed] = useState({});\n const [apiFormGroups, setApiFormGroups] = useState([]);\n const [apiLoading, setApiLoading] = useState(Boolean(configModule));\n const [apiError, setApiError] = useState('');\n const [searchFormLabel, setSearchFormLabel] = useState('');\n const [submitLoading, setSubmitLoading] = useState(false);\n // Search results state — used when formType === 'search' to store and display results\n const [searchResults, setSearchResults] = useState({\n searched: false,\n rows: [],\n total: 0,\n fields: [],\n actions: [],\n actionRules: [],\n loading: false,\n });\n const [searchPagination, setSearchPagination] = useState({ current: 1, pageSize: 10 });\n const [lastSearchValues, setLastSearchValues] = useState({});\n const [selectedSource, setSelectedSource] = useState('internal');\n const [tabs, setTabs] = useState([]);\n const [sourceActionState, setSourceActionState] = useState({});\n const [clientOptions, setClientOptions] = useState([]);\n const [scopeClientId, setScopeClientId] = useState(clientId ?? '');\n const [scopeRegion, setScopeRegion] = useState(region ?? '');\n // URL-driven prefill state — populated when prefillFromUrl is set. Holds the\n // source record's form groups (candidate OR submission) with values embedded.\n const [prefillGroups, setPrefillGroups] = useState(null);\n const [prefillLoading, setPrefillLoading] = useState(false);\n // Role Configure → Form permissions for the CURRENT user's role, derived\n // server-side from this module's Form Groups config (see\n // GetRoleFormPermissions). null until loaded / when unavailable, in which\n // case normalizeGroups' rolePerms checks fail open — no behavior change\n // for a role/module that hasn't been configured.\n const [rolePerms, setRolePerms] = useState(null);\n // Default Fields (Form Groups → Default Fields) — always-shown + required\n // field keys for this module. Empty set until loaded / when unconfigured.\n const [defaultFieldSet, setDefaultFieldSet] = useState(() => new Set());\n const formGroups = configModule ? apiFormGroups : (providedFormGroups ?? emptyGroups);\n const loading = configModule ? apiLoading : providedLoading;\n const error = configModule ? apiError : providedError;\n // ── Client-scoped form render, resolved from the linked JOB ──────────────\n // A submission is always created against a job, and the job owns the client.\n // So when the form is opened with a jobId (/submission-create/:jobId, Quick\n // Submit, Source Candidates…) we look the job up, read its clientId, and use\n // it as THIS form's client scope. getFormGroups then returns the client's\n // Form Groups variant when the admin has configured one for that client, and\n // transparently falls back to the module default when they haven't (the\n // backend tries clientId+region → clientId → region → default), so this is\n // safe for every client that has no override.\n const [linkedClientId, setLinkedClientId] = useState('');\n const linkedJobId = (routeParams?.jobId && routeParams.jobId !== '_')\n ? routeParams.jobId\n : (searchParams.get('jobId') || '');\n\n useEffect(() => {\n // An explicit client from the caller always wins — nothing to resolve.\n if (hostGroups || clientId || presetClientId || !linkedJobId) return undefined;\n let cancelled = false;\n (async () => {\n try {\n const data = await getFormGroups({ module: 'jobs', id: linkedJobId });\n const record = flatRecordFromGroups(extractGroups(data)) ?? {};\n // A reference field comes back either as a raw id or {id,value}.\n const raw = record.clientId ?? record.client ?? '';\n const resolved = (raw && typeof raw === 'object') ? (raw.id ?? raw.value ?? '') : raw;\n if (!cancelled && resolved) setLinkedClientId(String(resolved));\n } catch (err) {\n console.error('Client-scope resolve from job failed:', err);\n }\n })();\n return () => { cancelled = true; };\n }, [hostGroups, clientId, presetClientId, linkedJobId]);\n\n const effectiveClientId = clientId || presetClientId || linkedClientId || scopeClientId;\n const effectiveRegion = region || scopeRegion;\n\n // Load the common display defaults (phone format, date format, …) once so a\n // phone field re-formats to the admin-configured mask. Cached; safe to call.\n useEffect(() => { loadDetailDefaults(); }, []);\n\n useEffect(() => {\n let cancelled = false;\n queueMicrotask(() => {\n if (cancelled) return;\n if (!configModule) { setRolePerms(null); return; }\n // Same client/region scope the form's own structure is fetched\n // with (getFormGroups below) — a client-scoped Form Groups\n // override must gate the SAME scoped structure, not the\n // tenant-wide default.\n getRoleFormPermissions({ roleId: localStorage.getItem('roleId') }, configModule, { clientId: effectiveClientId, region: effectiveRegion })\n .then((data) => { if (!cancelled) setRolePerms(Array.isArray(data) && data.length ? data : null); })\n .catch(() => { if (!cancelled) setRolePerms(null); });\n });\n return () => { cancelled = true; };\n }, [configModule, effectiveClientId, effectiveRegion]);\n\n useEffect(() => {\n let cancelled = false;\n queueMicrotask(() => {\n if (cancelled) return;\n if (!configModule) { setDefaultFieldSet(new Set()); return; }\n getModuleDefaultFields(configModule)\n .then((keys) => { if (!cancelled) setDefaultFieldSet(new Set(Array.isArray(keys) ? keys : [])); })\n .catch(() => { if (!cancelled) setDefaultFieldSet(new Set()); });\n });\n return () => { cancelled = true; };\n }, [configModule]);\n\n const groups = useMemo(() => normalizeGroups(formGroups, moduleName, rolePerms, defaultFieldSet), [formGroups, moduleName, rolePerms, defaultFieldSet]);\n const wizardConfigGroups = useMemo(\n () => wizardPlanningGroups(formGroups, groups, rolePerms),\n [formGroups, groups, rolePerms],\n );\n const visibleWizardGroups = useMemo(() => wizardConfigGroups.filter((group) => (\n !group.showIf?.field\n || groupShowIfMatches(group.showIf, getNestedProp(searchFormValues ?? {}, group.showIf.field))\n )), [wizardConfigGroups, searchFormValues]);\n const wizardSteps = useMemo(() => buildFormWizardSteps(visibleWizardGroups), [visibleWizardGroups]);\n const configuredWizardEnabled = isWizardConfigEnabled(wizardConfigGroups);\n const wizardEnabled = !isSearch && (typeof wizard === 'boolean' ? wizard : configuredWizardEnabled);\n const activeWizardStep = Math.min(wizardStep, Math.max(0, wizardSteps.length - 1));\n const wizardSuccessStepIndex = wizardEnabled && wizardSteps.at(-1)?.content?.type === 'success'\n ? wizardSteps.length - 1 : -1;\n const wizardShowingSuccess = activeWizardStep === wizardSuccessStepIndex;\n const wizardNextIsSuccess = activeWizardStep + 1 === wizardSuccessStepIndex;\n\n const goToWizardStep = (next) => {\n setWizardStep(next);\n setCollapsed({});\n };\n\n const advanceWizard = () => wizardRuntime.next();\n\n const submitWizard = (values) => submit(wizardRuntime.prepareSubmitValues(\n mergeWizardSubmitValues(form.getFieldsValue(true), values),\n ));\n\n const handleWizardSubmitFailed = (info) => {\n setCollapsed({});\n const errorStep = wizardEnabled\n ? wizardStepIndexForField(wizardSteps, info?.errorFields?.[0]?.name)\n : -1;\n if (wizardEnabled) wizardRuntime.onSubmitFailed(info, errorStep);\n if (errorStep >= 0 && errorStep !== activeWizardStep) {\n setWizardStep(errorStep);\n requestAnimationFrame(() => scrollToFirstFormError(info, form));\n return;\n }\n scrollToFirstFormError(info, form);\n };\n\n // ── Config-driven field uniqueness ──────────────────────────────────────\n // One checker per form session owns the request sequence, the\n // normalized-value cache and the pending count (see\n // form/uniqueFieldValidation.js). While a check is in flight the submit\n // button is disabled so a record can never be created on a value whose\n // answer has not come back yet. A search form never checks uniqueness.\n const [uniquePending, setUniquePending] = useState(0);\n const uniqueDebounceMs = normalizeUniqueCheckDebounceMs(uniqueCheckDebounceMs);\n const uniqueDebounceOn = uniqueDebounceMs > 0;\n // Debounce off: the API function itself, exactly as before.\n const uniqueCheckApi = useMemo(\n () => (uniqueDebounceOn ? createSupersedingUniqueCheck(checkFieldUnique) : checkFieldUnique),\n [uniqueDebounceOn],\n );\n const uniqueChecker = useMemo(\n () => createUniqueChecker({ checkFieldUnique: uniqueCheckApi, onPendingChange: setUniquePending }),\n [uniqueCheckApi],\n );\n const uniqueContext = useMemo(() => (isSearch ? undefined : {\n checker: uniqueChecker,\n module: moduleName,\n clientId: effectiveClientId || undefined,\n region: effectiveRegion || undefined,\n // NO recordId on the Add form — there is no record to exclude yet.\n }), [isSearch, uniqueChecker, moduleName, effectiveClientId, effectiveRegion]);\n // Every unique-configured field in this form, used to map a submit-time\n // duplicate back onto its field when the response body was flattened.\n const uniqueRuleIndex = useMemo(() => collectUniqueRules(groups), [groups]);\n\n // group.linkGroup — addRow groups sharing the same value stay row-synced\n // (see form/linkedAddRowGroups.js). Empty for every group with no\n // linkGroup, i.e. every group that predates this feature.\n const linkedGroupSets = useMemo(() => computeLinkedSets(groups), [groups]);\n // Registry of each addRow group's live Form.List {add, remove}, written on\n // every render from inside the Form.List's own render-prop (synchronous\n // within the same commit, so it's fully populated before a user can click\n // anything). A linked group's \"Add Row\" / row-delete calls every member's\n // add()/remove() through this registry; unlinked groups just call their own.\n const listControlsRef = useRef({});\n // When an ADDITIONAL submit button (group.formActions, e.g. \"Create and\n // Source Candidate\") is clicked, it stashes its own afterSubmit here so the\n // shared submit() navigates per that button instead of the group default.\n // Reset after every submit and by the plain Create button.\n const pendingAfterSubmitRef = useRef(null);\n const formActions = useMemo(() => groups.flatMap((g) => g.formActions ?? []), [groups]);\n // \"Have we got this person already?\" — asked right after a résumé fills the\n // form in (the first moment an email/phone exist to check), and again on\n // submit as the authoritative gate. Config-driven; a module with no\n // duplicate stages configured never sees any of it.\n const duplicateConfig = useMemo(() => {\n const groupWithConfig = extractGroups(formGroups).find((g) => g?.duplicateCheck);\n return groupWithConfig?.duplicateCheck ?? {};\n }, [formGroups]);\n\n const duplicates = useDuplicateCheck({\n form,\n moduleName,\n config: duplicateConfig,\n // Choosing \"update the existing record\" hands off to that record's Edit\n // form, carrying the file just uploaded so it is stored as another\n // version rather than being lost with the abandoned Add form.\n // The edit route is CONFIG, never guessed. There is no derivable rule:\n // this app routes candidates at \"/candidate/edit/:id\" (singular) and\n // clients at \"/clients/edit/:id\" (plural). Deriving it sent every\n // candidate to \"/candidates/edit/:id\", which matches no route, so the\n // catch-all redirected to the dashboard — the record the user asked to\n // open simply vanished.\n //\n // With no route configured we do NOT navigate. Closing the dialog and\n // leaving the user where they are is recoverable; throwing them at a\n // wrong URL is not.\n onUseExisting: useCallback((id, result, reason, carry) => {\n if (!id) return;\n // The backend delivers the configured route WITH the answer, so\n // there is one source of truth; the group-level value is only an\n // override for a project that wants a different destination.\n const template = result?.editRoute || duplicateConfig?.editRoute;\n if (!template) {\n console.warn(\n `[duplicate-check] ${moduleName}: no editRoute configured, so the existing `\n + 'record was not opened. Set it in Admin → Automations → \"Check for someone '\n + 'already on file\" → \"Where to open the existing record\".',\n );\n return;\n }\n const target = safeNavTarget(template, id, {});\n if (!target) return;\n // The uploaded file travels WITH the user. They picked that résumé\n // for that person; sending them to the existing record and quietly\n // dropping it would make them find and attach it again — and the\n // whole point of opening the existing record is to add this newer\n // file to it (file versioning keeps the previous one).\n navigate(target, {\n state: {\n fromDuplicate: true,\n carryFiles: carry?.files ?? null,\n },\n });\n }, [duplicateConfig, navigate]),\n });\n\n const aiActions = useAiActions({\n form,\n groups,\n module: moduleName,\n // BEFORE any parsed value reaches the form. This is the first moment an\n // email and phone exist, so it is the first moment the question can be\n // asked — and if we already have this person there is no point filling\n // in a form the user is about to abandon.\n onParsed: useCallback(async ({ field, payload }) => {\n const key = field?.field;\n // The file the user just picked, handed to the prompt so it can\n // travel with them to the existing record.\n const carry = key ? { files: { [key]: form.getFieldValue(key) } } : null;\n\n const verdict = await duplicates.prompt({ reason: 'upload', payload, carry });\n if (verdict === 'clear') return true;\n\n // 'existing' — they were sent to the record we already have and the\n // file went WITH them, so it must not also be left behind here.\n // 'blocked' — they backed out to check; leaving the file attached to\n // a form that was never filled in just means the next thing they do\n // starts from a half-state they did not choose.\n // Either way the upload is undone: nothing on this form was filled\n // in, so nothing on it should look as though it was.\n if (key) {\n form.setFieldValue(key, []);\n message.info(verdict === 'existing'\n ? 'Résumé moved to their record.'\n : 'Résumé removed — nothing on this form was filled in.');\n }\n return 'abort';\n }, [duplicates, form]),\n // AFTER the form is filled — a second, cheaper pass that also covers\n // anything the user had typed before uploading.\n onApplied: useCallback(async () => {\n await duplicates.prompt({ reason: 'upload' });\n }, [duplicates]),\n });\n\n // Blur on a field marked `checkDuplicateOnBlur` (the email box). Debounced\n // through a ref rather than fired directly: tabbing quickly through a form\n // can blur the same field twice, and two overlapping checks would open two\n // dialogs on top of each other.\n // ── Region gate ─────────────────────────────────────────────────────────\n // The active region (Admin → Detail Groups → Display Defaults → Region)\n // selects which `regionRules` block each group applies. A region is a KEY\n // into config, never a branch in code — which is what lets a new market be\n // added without touching this file.\n //\n // Today's use: a candidate may be put forward mid-course in the US and UK,\n // but not in India, where a company only accepts a completed qualification.\n const handleRegionBlocked = useCallback((field) => {\n const region = getDefaults().region;\n // Find the group this \"still ongoing\" tick-box belongs to, so its own\n // region rules decide — not some global setting.\n const group = groups.find((g) => (g.fields ?? []).some((f) => f.field === field.field));\n if (!group) return false;\n\n const effective = resolveRegionRules(group, region);\n // Only gates the field the group nominates as its ongoing flag, so an\n // unrelated checkbox in the same group is never caught by this.\n const ongoingField = effective.orderBy?.inProgressField ?? 'currentStudyingHere';\n if (field.field !== ongoingField) return false;\n if (inProgressAllowed(effective)) return false;\n\n // Warn vs block. A warning explains the consequence and lets the tick\n // stand — recording a real person mid-degree is worth doing even where\n // they could not be put forward today. A block reverses the tick, and\n // the submit-time validator below refuses the row however it arrived.\n const blocking = inProgressBlocks(effective);\n openFormNotice({\n tone: blocking ? 'duplicate' : 'overwrite',\n title: blocking\n ? 'This has to be completed first'\n // States the CONSEQUENCE, not a vague heading. The user's next\n // action depends on knowing that saving this is fine but\n // submitting them later will not be.\n : 'You can add this, but they cannot be submitted',\n facts: [\n { label: 'Region', value: region || 'Common' },\n { label: 'Entry', value: group.label ?? group.name },\n ],\n body: inProgressError(effective),\n okText: blocking ? 'Got it' : 'Keep it anyway',\n });\n return blocking;\n }, [groups]);\n\n // ── The submit-time half of the same rule ───────────────────────────────\n // Reversing the tick-box only catches a row somebody ticked BY HAND. A\n // submission prefills its rows from the candidate, and the candidate is\n // allowed to hold an in-progress entry — so on a blocking region the row\n // arrives already ticked and nobody ever touched the box. Without a rule on\n // the field the form would happily submit it, and the restriction would\n // apply to exactly the users who did not need stopping.\n //\n // Resolved here rather than inside getRules because it depends on the\n // GROUP, which getRules never sees.\n const inProgressRulesFor = useCallback((field, groupName) => {\n const group = groups.find((g) => g.name === groupName);\n if (!group) return undefined;\n const effective = resolveRegionRules(group, getDefaults().region);\n const ongoingField = effective.orderBy?.inProgressField ?? 'currentStudyingHere';\n if (field.field !== ongoingField) return undefined;\n const rule = buildInProgressValidator(effective);\n return rule ? [rule] : undefined;\n }, [groups]);\n\n\n // ── Newest-first row ordering ───────────────────────────────────────────\n // After the user changes a row's dates or ticks \"still ongoing\", check\n // whether that row now belongs somewhere else and ASK. Nothing is ever\n // reordered silently — a list that rearranges itself while you are typing\n // in it is disorienting, and the user may have a reason for the order.\n const handleRowOrder = useCallback(async (field, name) => {\n // Only meaningful inside a repeatable group: [listName, rowIndex, key].\n if (!Array.isArray(name) || name.length < 3 || typeof name[1] !== 'number') return;\n const groupName = name[0];\n const rowIndex = name[1];\n\n const group = groups.find((g) => g.name === groupName);\n if (!group) return;\n // Region-resolved, so a market that reorders differently is honoured.\n const effective = resolveRegionRules(group, getDefaults().region);\n if (!effective.orderBy) return;\n\n // Read AFTER the change has landed in the store, so the row being\n // judged carries the value the user just set rather than the previous\n // one — the whole decision turns on that value.\n await Promise.resolve();\n const rows = form.getFieldValue(groupName);\n if (!Array.isArray(rows)) return;\n\n await promptRowMove({\n group: effective,\n rows,\n rowIndex,\n move: listControlsRef.current[groupName]?.move,\n confirm: ({ title, body, okText, cancelText, from, to }) => openFormDecision({\n tone: 'suggestion',\n title,\n facts: [\n { label: 'This entry is at', value: `Row ${from + 1}` },\n { label: 'It belongs at', value: `Row ${to + 1}` },\n ],\n body,\n okText,\n cancelText,\n }),\n });\n }, [groups, form]);\n\n const duplicateBlurRef = useRef(false);\n const handleDuplicateBlur = useCallback(async () => {\n if (duplicateBlurRef.current) return;\n duplicateBlurRef.current = true;\n try {\n await duplicates.prompt({ reason: 'blur' });\n } finally {\n duplicateBlurRef.current = false;\n }\n }, [duplicates]);\n const [viewMode, setViewMode] = useState(\"list\");\n const searchDisabled = isSearch && !hasSearchCriteria(searchFormValues);\n\n // Scan raw formGroups (before normalizeGroups strips the clientScope field) to\n // auto-detect whether this module needs a client gate and read its optional message.\n // The Admin field config is the only source that enables this gate.\n const { hasClientScope, clientGateMessage, clientGateResetOnChange } = useMemo(() => {\n const gateField = extractGroups(formGroups).flatMap(g => g.fields ?? []).find(f => truthy(f.clientScope));\n return gateField\n ? {\n hasClientScope: true,\n clientGateMessage: gateField.clientGateMessage || '',\n clientGateResetOnChange: truthy(gateField.clientGateResetOnChange),\n }\n : { hasClientScope: false, clientGateMessage: '', clientGateResetOnChange: false };\n }, [formGroups]);\n\n const handleClientGateChange = (nextClientId) => {\n if (clientGateResetOnChange) {\n form.resetFields();\n // resetFields restores configured initial/default values. Explicitly\n // clear every root key as well so changing the Client Gate truly\n // removes nested values, files and repeatable-group rows.\n const storedValues = form.getFieldsValue(true);\n form.setFieldsValue(Object.fromEntries(\n Object.keys(storedValues).map((fieldName) => [fieldName, undefined]),\n ));\n setSearchResults({ searched: false, rows: [], total: 0, fields: [], loading: false });\n setSearchPagination({ current: 1, pageSize: 10 });\n }\n setScopeClientId(nextClientId ?? '');\n };\n\n const waitingForClientScope = hasClientScope && !effectiveClientId;\n\n const loadClientOptions = useCallback(() => (\n getAdminClients({ limit: 200 }).then(setClientOptions).catch(() => setClientOptions([]))\n ), []);\n\n useEffect(() => {\n // No picker needed when the client is already known (caller-supplied or\n // resolved from the linked job).\n if (!hasClientScope || presetClientId || linkedClientId) return;\n loadClientOptions();\n }, [hasClientScope, presetClientId, linkedClientId, loadClientOptions]);\n\n // Quick-create hook for the \"Select Client\" gate — the same \"Add More\"\n // in-dropdown create used by ordinary lookup fields (useQuickField), so the\n // gate can open the Clients Add form in a modal and, on save, refetch the\n // options and select the new client. Reuses the generic clients Add flow.\n //\n // NOTE — this synthetic field object is HARDCODED (a pre-existing wart: the\n // client gate is rendered by this component rather than as an ordinary\n // configured field, so it has no admin field-config document to read).\n // Every OTHER field gets the same behaviour purely from admin config via the\n // generic `quickCreateNotice` key; only this one gate has to restate it in\n // code. The gate is the actual submission/job path the requirement is about,\n // so it must carry the notice too — leaving it out would mean the one flow\n // the product owner described was the one flow without the warning.\n const clientGateQuick = useQuickField({\n field: {\n field: 'clientId',\n quickCreate: true,\n quickCreateModule: 'clients',\n quickCreateLabel: 'Add Client',\n lookupCollection: 'clients',\n displayField: 'clientName',\n quickCreateNotice: {\n enabled: true,\n title: 'New Client Created',\n // message omitted on purpose — the built-in default IS the\n // product-owner-approved wording (see quickCreateNotice.js).\n showCreator: true,\n showRecordName: true,\n recordLabel: 'Client name',\n creatorLabel: 'Created by',\n },\n },\n form,\n name: 'clientId',\n moduleName,\n scopeValues: {},\n ownValue: effectiveClientId,\n onDone: (kind, newId) => {\n loadClientOptions();\n if (kind === 'create' && newId != null) handleClientGateChange(String(newId));\n },\n });\n\n useEffect(() => {\n if (!configModule) return undefined;\n\n let cancelled = false;\n\n async function fetchFormGroups() {\n try {\n setApiLoading(true);\n setApiError('');\n const data = isSearch\n ? await getCustomForms(moduleName, 'search', action)\n : await getFormGroups({ module: moduleName, action, clientId: effectiveClientId, region: effectiveRegion });\n if (!cancelled) {\n setApiFormGroups(extractGroups(isSearch ? data?.[0] : data));\n if (isSearch) setSearchFormLabel(data?.[0]?.label || '');\n }\n } catch (err) {\n console.error(`Failed to fetch ${moduleName} form groups:`, err);\n if (!cancelled) setApiError(err?.message || 'Failed to fetch form groups');\n } finally {\n if (!cancelled) setApiLoading(false);\n }\n }\n\n fetchFormGroups();\n\n return () => {\n cancelled = true;\n };\n }, [configModule, moduleName, action, isSearch, effectiveClientId, effectiveRegion]);\n\n // ── URL-driven prefill source + linkage ──\n // Decode the route once. The submission flow arrives at\n // /submission-create/:jobId?candidateId=…&isFromSubmission=…[&submissionId=…]\n // • isFromSubmission=true + submissionId → prefill from the submissions record\n // • otherwise candidateId → prefill from the candidates record\n const urlPrefill = useMemo(() => {\n if (!prefillFromUrl) return null;\n\n const candidateId = searchParams.get('candidateId') || '';\n const submissionId = searchParams.get('submissionId') || '';\n const fromSubmission = String(searchParams.get('isFromSubmission')) === 'true';\n const jobId = (routeParams.jobId && routeParams.jobId !== '_')\n ? routeParams.jobId\n : (searchParams.get('jobId') || '');\n\n const source = (fromSubmission && submissionId)\n ? { module: 'submissions', id: submissionId }\n : (candidateId ? { module: 'candidates', id: candidateId } : null);\n\n // Linkage the submission create requires (NOT form fields).\n const linkage = {};\n if (candidateId) linkage.applicantId = candidateId;\n if (jobId) linkage.jobId = jobId;\n\n return { source, linkage: Object.keys(linkage).length ? linkage : null };\n }, [prefillFromUrl, searchParams, routeParams]);\n\n // ── Prefill fetch: load the source record's form groups with embedded values ──\n // The backend embeds field.value for scalar fields and group.rows for addRow\n // groups (workExperience, educationDetails, documents). Single source of truth\n // for BOTH the candidate and submission flows — no detail-view API call.\n useEffect(() => {\n const source = urlPrefill?.source;\n if (!source) return undefined;\n\n let cancelled = false;\n\n async function fetchPrefill() {\n try {\n setPrefillLoading(true);\n const data = await getFormGroups({ module: source.module, id: source.id });\n if (!cancelled) setPrefillGroups(extractGroups(data));\n } catch (err) {\n console.error('Failed to fetch prefill data:', err);\n if (!cancelled) setPrefillGroups([]);\n } finally {\n if (!cancelled) setPrefillLoading(false);\n }\n }\n\n fetchPrefill();\n\n return () => { cancelled = true; };\n }, [urlPrefill]);\n\n // addRow rows from the prefill source, keyed by group.payloadKey (e.g.\n // \"workExperience\"). Submission addRow groups that share the same payloadKey\n // receive these rows as their Form.List initialValue at mount. Works for both\n // sources because the DB array element keys are identical (companyName,\n // jobTitle, qualification, …).\n const addRowPrefillsByKey = useMemo(() => {\n if (!prefillGroups) return {};\n return Object.fromEntries(\n prefillGroups\n .filter(g => g.addRow && Array.isArray(g.rows) && g.rows.length > 0)\n .map(g => [g.payloadKey || g.name, g.rows]),\n );\n }, [prefillGroups]);\n\n // Flat record extracted from the prefill source's scalar fields — prefills\n // form fields whose field.field (or payloadKey) matches a source field.\n const prefillFlatRecord = useMemo(\n () => flatRecordFromGroups(prefillGroups),\n [prefillGroups],\n );\n\n // ── Cross-module context prefill (field.prefillFromModule) ──────────────\n // A field may prefill from a DIFFERENT module's record than the default\n // prefill source — e.g. submission.mspReqId ← the current JOB's mspreqId on\n // Quick Submit. The admin sets prefillFromModule (which module) +\n // prefillFrom (which key); the record id comes from the same URL linkage the\n // create payload already uses (jobId → jobs, applicantId → candidates).\n const contextPrefillModules = useMemo(() => {\n const wanted = new Set();\n groups.forEach((group) => (group.fields ?? []).forEach((field) => {\n if (field.prefillFromModule) wanted.add(normalizeModule(field.prefillFromModule));\n }));\n return [...wanted];\n }, [groups]);\n\n const [contextRecords, setContextRecords] = useState({});\n useEffect(() => {\n const linkage = urlPrefill?.linkage;\n if (!linkage || contextPrefillModules.length === 0) return undefined;\n let cancelled = false;\n // Shared with EditFormV1 (form/contextPrefill.js) — resolves <module>Id /\n // <singular>Id (+ known aliases like applicantId) out of the id map,\n // which is the URL linkage here and the record's own recordMeta there.\n contextPrefillModules.forEach(async (mod) => {\n const id = contextRecordId(mod, linkage);\n if (!id) return;\n try {\n const data = await getFormGroups({ module: mod, id });\n const record = flatRecordFromGroups(extractGroups(data));\n if (!cancelled && record) {\n setContextRecords((prev) => ({ ...prev, [mod]: record }));\n }\n } catch (err) {\n console.error(`Context prefill fetch failed for ${mod}:`, err);\n }\n });\n return () => { cancelled = true; };\n }, [contextPrefillModules, urlPrefill]);\n\n // ── prefillAsHint ───────────────────────────────────────────────────────\n // Fields the admin marked `prefillAsHint` are NOT filled in; the previous\n // record's value is shown underneath instead. See the effect below, which\n // skips them, and formatPrefillHint for the wording.\n //\n // DERIVED, not state written from an effect: it is a pure function of the\n // source record and the config, so a memo needs no synchronisation and\n // cannot render once with the old hints and once with the new.\n const prefillHints = useMemo(() => {\n const sourceRecord = initialRecord ?? prefillFlatRecord;\n if (!sourceRecord && Object.keys(contextRecords).length === 0) return {};\n const hints = {};\n groups.forEach((group) => {\n if (group.addRow) return;\n (group.fields ?? []).forEach((field) => {\n if (!field.field || !truthy(field.prefillAsHint) || truthy(field.addRow)) return;\n const fieldSource = field.prefillFromModule\n ? contextRecords[normalizeModule(field.prefillFromModule)]\n : sourceRecord;\n if (!fieldSource) return;\n const stored = pickPrefillValue(fieldSource, field);\n if (stored === undefined || stored === null) return;\n const shown = formatPrefillHint(field, stored);\n if (shown) hints[field.field] = shown;\n });\n });\n return hints;\n }, [initialRecord, prefillFlatRecord, contextRecords, groups]);\n\n // ── Prefill from initialRecord / prefillFlatRecord (best-effort) ──\n // Matches each non-file scalar field by field.field → payloadKey on the\n // source record and sets it via setFieldsValue. addRow groups are seeded via\n // Form.List initialValue (see getAddRowInitialValue below) — setFieldsValue\n // on a Form.List that mounted empty only keeps the last row.\n useEffect(() => {\n const sourceRecord = initialRecord ?? prefillFlatRecord;\n // Runs when EITHER the default source or a cross-module context record is\n // ready — a form with only prefillFromModule fields (no candidate source,\n // e.g. Quick Submit straight from a job) must still prefill those.\n if ((!sourceRecord && Object.keys(contextRecords).length === 0)\n || loading || groups.length === 0) return;\n const values = {};\n groups.forEach((group) => {\n if (group.toggleEnabled && group.toggleField && sourceRecord) {\n const stored = pickPrefillValue(sourceRecord, { field: group.toggleField });\n if (stored !== undefined && stored !== null) values[group.toggleField] = Boolean(stored);\n }\n if (group.addRow) return;\n (group.fields ?? []).forEach((field) => {\n if (!field.field) return;\n // A repeatable (addRow) field prefills via its Form.List\n // initialValue at mount — setFieldsValue on a Form.List that\n // mounted empty only keeps the last item, so skip it here.\n if (truthy(field.addRow)) return;\n // prefillFromModule redirects this field's source to another\n // module's URL-linked record (e.g. the current job).\n const fieldSource = field.prefillFromModule\n ? contextRecords[normalizeModule(field.prefillFromModule)]\n : sourceRecord;\n if (!fieldSource) return;\n // prefillFrom (admin config) → field → payloadKey, dotted or nested.\n const stored = pickPrefillValue(fieldSource, field);\n if (stored === undefined || stored === null) return;\n // `prefillAsHint` (admin config): do NOT fill this field —\n // show what it was last time and leave the box empty.\n //\n // A rate is the case this exists for. Carrying the previous\n // submission's rate forward LOOKS helpful and is the opposite:\n // it is a number the recruiter must renegotiate every time, and\n // a prefilled one gets submitted unread. Shown as a hint they\n // have to read and retype, it informs the decision instead of\n // making it for them.\n if (truthy(field.prefillAsHint)) return;\n if (field.type === 'file') {\n const fl = toFileListValue(stored);\n if (fl.length > 0) writeFormValue(values, field.field, fl);\n } else {\n // writeFormValue, NOT values[field.field]: a DOTTED field key\n // (\"candidateBudget.candidateBudgetCurrency\") is registered as an\n // ARRAY name path (see `field.field.split('.')` where `name` is\n // built), but a flat object key containing dots is treated by\n // rc-field-form as one literal field name. So the old assignment\n // wrote a key nothing was listening on, and prefillFromModule /\n // prefillFrom silently did NOTHING for every nested field — the\n // value was fetched, mapped, and then dropped on the floor.\n writeFormValue(values, field.field, buildInitialValue(field, stored));\n }\n });\n });\n if (Object.keys(values).length > 0) form.setFieldsValue(values);\n }, [initialRecord, prefillFlatRecord, contextRecords, loading, groups, form]);\n\n // ── Relevant-skill prefill (async, never blocking) ──────────────────────\n // Quick Submit starts the match at SUBMIT time and hands a TOKEN for the\n // still-in-flight promise over in nav state (the promise itself cannot\n // travel through router state — history.pushState requires\n // structured-cloneable data, and a Promise is not, see pendingHandoff.js).\n // The request overlaps this form's mount instead of delaying it. When it\n // settles we fill the rows of every addRow group the admin marked with\n // `skillMatchField` — that config key names the field inside the row that\n // receives the skill, so no group, field or module name is hardcoded here.\n //\n // Form.List rows must be written with setFieldsValue, never a remount: a\n // key change would throw away anything the recruiter has already typed.\n // Rows the user has already filled are left alone for the same reason.\n //\n // REFRESH SAFETY: history.state (and therefore the token) SURVIVES a browser\n // reload, but the in-memory map the token points into does not — the SPA\n // runtime that held it is gone. takePendingPromise then returns nothing and\n // the rows silently never fill, which is exactly what QA saw: \"relevant\n // skills are not parsed after a refresh\". So the INPUTS travel too, and when\n // the token resolves to nothing we simply re-issue the match. Inputs come\n // from nav state when the caller supplied them, else from the URL linkage\n // this form already derives (jobId in the path, candidateId in the query) —\n // which is itself refresh-proof. Still non-blocking, still driven only by\n // group.skillMatchField.\n useEffect(() => {\n const token = routerLocation?.state?.relevantSkillsToken;\n const stateInputs = routerLocation?.state?.relevantSkillsInputs;\n const jobId = stateInputs?.jobId ?? urlPrefill?.linkage?.jobId ?? '';\n const applicantId = stateInputs?.applicantId ?? stateInputs?.candidateId\n ?? urlPrefill?.linkage?.applicantId ?? '';\n // Guard on token/loading/groups BEFORE taking the promise — takePendingPromise\n // deletes on read, so calling it before we're actually ready to use the\n // result would consume it on a run that's just going to bail out, and\n // every later run (once loading clears / groups arrive) would find nothing.\n //\n // A handoff is still REQUIRED to start a match: without a token (or\n // explicit inputs in nav state) this is an ordinary visit to the form,\n // not a Quick Submit, and must not fire an AI call on its own.\n const handedOff = Boolean(token) || Boolean(stateInputs);\n if (!handedOff || loading || groups.length === 0) return undefined;\n\n const targets = groups.filter((g) => truthy(g.addRow) && g.skillMatchField);\n if (targets.length === 0) return undefined;\n\n // StrictMode double-invokes effects (mount → cleanup → mount again with\n // identical deps). Re-taking on the second mount would find the token\n // already consumed and silently skip the fill, so a same-token remount\n // reuses the promise already taken instead of consuming again. The same\n // ref also stops the refresh path from firing a SECOND match request on\n // the double-invoke.\n const runKey = token || `inputs:${jobId}:${applicantId}`;\n let promise;\n if (skillMatchTokenRef.current === runKey && skillMatchPromiseRef.current) {\n promise = skillMatchPromiseRef.current;\n } else {\n promise = token ? takePendingPromise(token) : undefined;\n // Handoff lost (page reloaded, or the link was opened directly) —\n // re-issue from the inputs. matchRelevantSkills never rejects and\n // degrades to [], which the fill below treats as \"change nothing\".\n if ((!promise || typeof promise.then !== 'function') && jobId && applicantId) {\n promise = matchRelevantSkills({ jobId, applicantId }).catch(() => []);\n }\n skillMatchTokenRef.current = runKey;\n skillMatchPromiseRef.current = promise;\n }\n if (!promise || typeof promise.then !== 'function') return undefined;\n\n let cancelled = false;\n promise.then((skills) => {\n // An empty result must NOT wipe the rows. \"Nothing matched\" and\n // \"the service was unreachable\" arrive here identically, and\n // clearing a candidate's carried-over skills because an AI call\n // failed would destroy real data.\n if (cancelled || !Array.isArray(skills) || skills.length === 0) return;\n const values = {};\n targets.forEach((group) => {\n const existing = form.getFieldValue(group.name);\n const rows = Array.isArray(existing) ? existing : [];\n // REPLACE, not append: the rows carried over from the candidate\n // are that candidate's skills in general, not the ones this job\n // asks for. The match is the answer to \"which apply here\", so\n // anything it did not return is dropped.\n //\n // A row whose skill IS in the match is REUSED rather than\n // rebuilt, so its Experience/Remarks survive — replacing it\n // with a bare { skill } would silently discard values the\n // recruiter (or the candidate record) already supplied.\n const bySkill = new Map();\n rows.forEach((row) => {\n const key = String(row?.[group.skillMatchField] ?? '').trim().toLowerCase();\n if (key && !bySkill.has(key)) bySkill.set(key, row);\n });\n values[group.name] = skills.map((skill) => (\n bySkill.get(String(skill).trim().toLowerCase())\n ?? { [group.skillMatchField]: skill }\n ));\n });\n if (Object.keys(values).length > 0) form.setFieldsValue(values);\n }).catch(() => { /* matchRelevantSkills already degrades to [] */ });\n\n return () => { cancelled = true; };\n // The linkage ids are listed as SCALARS: urlPrefill is a fresh memo\n // object on every searchParams change, so depending on it would re-run\n // (and, on the refresh path, re-request) for no reason.\n }, [\n routerLocation?.state?.relevantSkillsToken,\n routerLocation?.state?.relevantSkillsInputs,\n urlPrefill?.linkage?.jobId,\n urlPrefill?.linkage?.applicantId,\n loading, groups, form,\n ]);\n\n // Linkage merged into the create payload: URL-derived when prefillFromUrl,\n // else the explicit extraPayload prop.\n const scopePayload = hasClientScope && effectiveClientId ? { clientId: effectiveClientId } : {};\n const effectiveExtraPayload = { ...scopePayload, ...(urlPrefill?.linkage ?? extraPayload ?? {}) };\n\n // True once both the form groups and (when needed) the prefill source data are\n // ready. The Form.List components must NOT mount until this is true so that\n // getAddRowInitialValue below provides the correct initialValue at mount —\n // antd ignores initialValue changes after a Form.List has already mounted.\n const isFormReady = !waitingForClientScope && !loading && (!urlPrefill?.source || (prefillGroups !== null && !prefillLoading));\n\n // schemaVersion 1 runtime (server actions, inline \"why not\" notices,\n // payloadMap, draft record id). Inert unless the wizard renders here: a\n // host WizardAdapter keeps its own flow, and v0 steps have no actions.\n const wizardRuntime = useWizardRuntime({\n enabled: wizardEnabled && !WizardAdapter && isFormReady,\n steps: wizardSteps,\n current: activeWizardStep,\n setCurrent: goToWizardStep,\n form,\n moduleName,\n groups,\n validationNames: wizardValidationNames,\n onValidationFailed: (info) => scrollToFirstFormError(info, form),\n });\n\n\n // Build the Form.List initialValue for an addRow group. When candidate prefill\n // data is available the group's payloadKey (e.g. \"workExperience\") is looked up\n // in addRowPrefillsByKey and the stored rows are mapped through buildInitialValue\n // so antd controls receive the right shape. Falls back to a single empty row.\n const getAddRowInitialValue = (group) => {\n // prefillFrom lets an addRow group seed its rows from a DIFFERENT source\n // group key than its own (write) key — e.g. the submission employer group\n // (submission_current_employer) prefilling from the candidate's\n // current_employer_details rows on Quick Submit. Falls back to the write\n // key, so groups that already share a payloadKey are unaffected.\n const gKey = group.prefillFrom || group.payloadKey || group.name;\n const rows = addRowPrefillsByKey[gKey];\n const minRows = Math.max(0, Number(group.minRows ?? 0) || 0);\n // Admin-configured defaultValues seed every fresh row (top-level fields\n // get theirs via Form.Item initialValue, which does not reach Form.List\n // rows — e.g. VMS Commission 5.5 inside the Employer group).\n const seed = rowDefaultsFor(group);\n if (!rows || rows.length === 0) {\n // initialRows in config controls how many empty rows to start with (default 0).\n // minRows still controls the minimum kept after removal.\n const startCount = group.initialRows !== undefined\n ? Math.max(minRows, Math.max(0, Number(group.initialRows) || 0))\n : minRows;\n return Array.from({ length: startCount }, () => ({ ...seed }));\n }\n const initial = rows.map(row => {\n const rowVals = { ...seed };\n (group.fields ?? []).forEach(field => {\n if (!field.field || field.type === 'file') return;\n const val = pickPrefillValue(row, field);\n if (val !== undefined && val !== null) {\n // A repeat field inside the row (nested Form.List) hydrates as\n // an array, each element normalised for its control; a plain\n // field hydrates as a single value.\n rowVals[field.field] = truthy(field.addRow)\n ? buildRepeatFieldInitial(field, val)\n : buildInitialValue(field, val);\n }\n });\n return rowVals;\n });\n while (initial.length < minRows) initial.push({ ...seed });\n return initial;\n };\n\n // Precomputed per-group so a linked set (group.linkGroup) can be padded to\n // equal length BEFORE any Form.List mounts — antd ignores initialValue\n // changes after first mount, so this has to be ready up front, not derived\n // ad hoc per group. A no-op passthrough for every group not in a linked set.\n\n // ── Collapsible sections (group.allowCollapse / group.defaultCollapsed) ──\n // Collapsing is OPT-IN. A group that does not ask for it renders with no\n // chevron and can never be collapsed — which is the behaviour every form\n // had before this existed, so nothing already configured changes.\n //\n // `defaultCollapsed` only means anything for a group that allows collapsing\n // at all: a section that starts closed but cannot be opened would be a\n // section the user simply cannot fill in.\n //\n // Seeded once per group set rather than on every render, so a user who\n // opens a default-closed section does not have it slam shut again on the\n // next state change. `collapsedSeeded` tracks WHICH group set has been\n // applied, so a module switch (or a config reload) re-seeds exactly once.\n const collapsedSeedKey = useMemo(\n () => groups.map((g) => `${g.name}:${truthy(g.allowCollapse) ? 1 : 0}${truthy(g.defaultCollapsed) ? 1 : 0}`).join('|'),\n [groups],\n );\n const collapsedSeeded = useRef(null);\n useEffect(() => {\n if (!groups.length || collapsedSeeded.current === collapsedSeedKey) return;\n collapsedSeeded.current = collapsedSeedKey;\n const seeded = {};\n groups.forEach((group, index) => {\n const key = group.name ?? group.id ?? String(index);\n if (truthy(group.allowCollapse) && truthy(group.defaultCollapsed)) seeded[key] = true;\n });\n setCollapsed(seeded);\n }, [collapsedSeedKey, groups]);\n\n const addRowInitials = useMemo(() => {\n const raw = {};\n groups.forEach((group) => {\n if (group.addRow) raw[group.name] = getAddRowInitialValue(group);\n });\n return padLinkedInitialValues(linkedGroupSets, raw);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [groups, addRowPrefillsByKey, linkedGroupSets]);\n\n const toggle = (key) => setCollapsed((prev) => ({ ...prev, [key]: !prev[key] }));\n\n const handleReset = () => {\n form.resetFields();\n // Also reset collapsed state to default (all expanded)\n setCollapsed({});\n setSelectedSource('internal');\n setTabs([]);\n };\n\n const handleSearch = useCallback(async (values, sourceOverride, paginationOverride = {}) => {\n if (!isSearch) return;\n const nextPageSize = Number(paginationOverride.pageSize) > 0\n ? Number(paginationOverride.pageSize)\n : searchPagination.pageSize;\n const requestedCurrent = Number(paginationOverride.current);\n const nextCurrent = Number.isFinite(requestedCurrent) && requestedCurrent > 0\n ? Math.floor(requestedCurrent)\n : 1;\n\n try {\n setLastSearchValues(values);\n setSearchPagination({ current: nextCurrent, pageSize: nextPageSize });\n setSearchResults((current) => ({ ...current, loading: true, searched: true }));\n const checkedSources = getSearchSources(values?.selectedSource);\n const activeSource = sourceOverride\n ? resolveSearchSource(sourceOverride, selectedSource)\n : (checkedSources.includes('internal')\n ? 'internal'\n : resolveSearchSource(values?.selectedSource, selectedSource));\n\n // Include selectedSource in the search parameters\n const searchParamsWithSource = {\n ...values,\n selectedSource: activeSource,\n };\n\n console.log('[AddFormV1] Calling searchModuleData with scope:', activeSource);\n\n const result = await searchModuleData(moduleName || 'candidates', searchParamsWithSource, {\n limit: nextPageSize,\n offset: (nextCurrent - 1) * nextPageSize,\n }, {\n scope: activeSource,\n });\n\n setSelectedSource(activeSource);\n setSearchResults({\n searched: true,\n rows: result.rows,\n total: result.total,\n fields: result.fields,\n // Admin-configured row actions/rules — searchModuleData pulls these\n // from the same /module-data-list response the regular ListView\n // list-endpoint returns them on, so search results get the same\n // admin-driven actions instead of none.\n actions: result.actions ?? [],\n actionRules: result.actionRules ?? [],\n loading: false,\n });\n setTabs((currentTabs) => buildSourceTabs({\n sources: checkedSources,\n activeSource,\n activeCount: result.total,\n responseCounts: result.counts,\n currentTabs,\n backendTabs: result.tabs,\n }));\n } catch (error) {\n console.error('Search failed:', error);\n message.error(error?.message || 'Failed to search records');\n setSearchResults({ searched: true, rows: [], total: 0, fields: [], actions: [], actionRules: [], loading: false });\n }\n }, [isSearch, moduleName, selectedSource, searchPagination.pageSize]);\n\n const handleSourceAction = useCallback(async (action, record) => {\n const actionKey = getSourceActionInstanceKey(action, record);\n setSourceActionState((current) => ({\n ...current,\n [actionKey]: { ...(current[actionKey] ?? {}), loading: true },\n }));\n try {\n const response = await runSourceAction(action, record);\n message.success(\n response?.message\n ?? response?.data?.message\n ?? action.successMessage\n ?? 'Action completed successfully.',\n );\n setSourceActionState((current) => ({\n ...current,\n [actionKey]: { loading: false, completed: true },\n }));\n } catch (error) {\n message.error(error?.message || action.errorMessage || 'Action failed.');\n setSourceActionState((current) => ({\n ...current,\n [actionKey]: { ...(current[actionKey] ?? {}), loading: false },\n }));\n } finally {\n setSourceActionState((current) => ({\n ...current,\n [actionKey]: { ...(current[actionKey] ?? {}), loading: false },\n }));\n }\n }, []);\n\n const handleTabChange = useCallback((newSource) => {\n const activeSource = resolveSearchSource(newSource, selectedSource);\n setSelectedSource(activeSource);\n setSearchPagination({ current: 1, pageSize: searchPagination.pageSize });\n\n // Re-trigger search with new source if we have previous search values\n if (Object.keys(lastSearchValues).length > 0) {\n handleSearch(lastSearchValues, activeSource, { current: 1, pageSize: searchPagination.pageSize });\n }\n }, [searchPagination.pageSize, lastSearchValues, handleSearch, selectedSource]);\n\n const handleSearchPageChange = useCallback((current, pageSize) => {\n const nextPageSize = Number(pageSize) > 0 ? Number(pageSize) : searchPagination.pageSize;\n const nextCurrent = Number(current) > 0 ? Number(current) : 1;\n if (Object.keys(lastSearchValues).length === 0) {\n setSearchPagination({ current: nextCurrent, pageSize: nextPageSize });\n return;\n }\n handleSearch(lastSearchValues, selectedSource, { current: nextCurrent, pageSize: nextPageSize });\n }, [handleSearch, lastSearchValues, searchPagination.pageSize, selectedSource]);\n\n const handleSearchPageSizeChange = useCallback((pageSize) => {\n const nextPageSize = Number(pageSize) > 0 ? Number(pageSize) : searchPagination.pageSize;\n if (Object.keys(lastSearchValues).length === 0) {\n setSearchPagination({ current: 1, pageSize: nextPageSize });\n return;\n }\n handleSearch(lastSearchValues, selectedSource, { current: 1, pageSize: nextPageSize });\n }, [handleSearch, lastSearchValues, searchPagination.pageSize, selectedSource]);\n\n // Submit-time duplicate (\"already present\") coming back from the\n // authoritative server-side check. The record was NOT created, so the form\n // must behave exactly like a failed client-side validation: values kept,\n // form open, collapsed sections expanded, error shown under the offending\n // field, and that field scrolled to + focused (shared\n // utils/scrollToFirstFormError, same as onFinishFailed).\n //\n // The name used is the one the SERVER returned — the frontend field key,\n // which is not necessarily the stored field it maps to.\n const applyDuplicateFieldErrors = (source) => {\n const duplicates = extractDuplicateFieldErrors(source, { uniqueRules: uniqueRuleIndex });\n if (duplicates.length === 0) return false;\n\n // item.name is the FULL antd path: a plain key for an ordinary field, and\n // [group, rowIndex, key] for a field inside a repeatable (addRow) group,\n // so the error lands on the row the user actually typed into.\n form.setFields(duplicates.map((item) => ({ name: item.name ?? item.field, errors: [item.message] })));\n setCollapsed({});\n scrollToFirstFormError({\n errorFields: duplicates.map((item) => {\n const name = item.name ?? item.field;\n return { name: Array.isArray(name) ? name : [name], errors: [item.message] };\n }),\n }, form);\n return true;\n };\n\n\n // confirmLevelRule — the submit-time half of group.levelRule.\n //\n // The rule, its levels and its wording are all admin config; nothing here\n // names a qualification. Region-resolved, so a market that requires a\n // different rung is honoured.\n //\n // Returns TRUE to continue. A failure to evaluate also returns true: a\n // hierarchy check must never be the reason a submit cannot happen at all.\n const confirmLevelRule = useCallback(async (values) => {\n try {\n const region = getDefaults().region;\n const resolved = groups.map((group) => resolveRegionRules(group, region));\n const verdict = levelRuleVerdict(resolved, values);\n if (verdict.severity === 'allow') return true;\n\n if (verdict.severity === 'block') {\n openFormNotice({\n tone: 'duplicate',\n title: 'This qualification history is incomplete',\n body: verdict.message,\n okText: 'Go back',\n });\n return false;\n }\n // openFormDecision resolves TRUE for its OK button and FALSE for\n // Cancel — but here OK (\"Add it now\") means \"stop, let me go add\n // the row myself\" (continue = false) and Cancel (\"Submit anyway\")\n // means proceed (continue = true). That is the OPPOSITE of the\n // dialog's own resolve value, so it must be inverted here; passing\n // it straight through made \"Add it now\" silently submit anyway and\n // \"Submit anyway\" silently do nothing.\n const addItNow = await openFormDecision({\n tone: 'suggestion',\n title: 'Add the earlier qualification too?',\n body: verdict.message,\n okText: 'Add it now',\n cancelText: 'Submit anyway',\n });\n return !addItNow;\n } catch (err) {\n console.warn('[levelRule] check skipped:', err);\n return true;\n }\n }, [groups]);\n\n const submit = async (values) => {\n if (isSearch) {\n await handleSearch(values);\n return;\n }\n\n // The authoritative duplicate gate. The upload-time check is a courtesy\n // — it fires before the form is complete and only when a file was read\n // — so the decision is taken again here, against the finished values,\n // where it can actually stop a second copy being created.\n // 'clear' and 'existing' both continue: 'existing' means the user has\n // already been sent to the record we have, so this submit is moot.\n if (!embedded) {\n const verdict = await duplicates.prompt({ reason: 'submit' });\n if (verdict !== 'clear') return;\n }\n\n // Qualification hierarchy (admin config: group.levelRule). A Master's\n // with no Bachelor's beneath it is usually an incomplete record — but\n // not always, and the recruiter looking at the CV knows better than a\n // config does. So ASK by default and let them proceed; only a rule\n // explicitly marked severity:\"block\" refuses.\n if (!(await confirmLevelRule(values))) return;\n\n // A host page can own the confirm step (e.g. Quick Submit's Pontoon\n // attestation / preview modal) and POST the record itself. It still gets\n // the CONFIG-DRIVEN payload here — identical to what the native submit\n // below would send — so payloadMode (\"skip\"), payloadKey remapping,\n // dataType coercion and the showIf payload gating all still apply.\n // Passing only `values` (raw antd form state, as before) meant a page\n // with a custom onSubmit silently bypassed the entire Form Groups\n // config. `values` is still the first argument for callers that need the\n // raw state for display (preview cards, file lists).\n if (onSubmit) {\n await onSubmit(values, {\n moduleName,\n groups,\n // A host that POSTs the record itself (Quick Submit, Resubmit)\n // was silently skipping the shared document registry, because\n // this branch returns before the registration below ever runs.\n // The uploaded résumé therefore existed on the submission\n // record but nowhere in `documents`, so nothing could link it\n // to the candidate. Handing the host the SAME registration the\n // native path uses closes that gap without it having to know\n // how files are collected.\n registerDocuments: async (recordId, opts = {}) => {\n const parts = collectFileParts(values, groups, { module: opts.module ?? moduleName });\n if (!parts.length || !recordId) return [];\n return uploadModuleDocuments(opts.module ?? moduleName, recordId, parts);\n },\n extraPayload: effectiveExtraPayload ?? {},\n // Host-owned saves (opt-in): new files as [{ formKey, file,\n // documentModule? }]. fileParts = indexed keys exactly as\n // /module/update takes them; allFileParts = flat keys (registry).\n fileParts: collectFileParts(values, groups, { indexed: true, module: moduleName }),\n allFileParts: collectFileParts(values, groups, { module: moduleName }),\n payload: {\n ...(effectiveExtraPayload ?? {}),\n ...buildPayload(values, groups, { module: moduleName }),\n },\n });\n return;\n }\n\n if (!moduleName) {\n console.log('Form values:', values);\n return;\n }\n\n // Everything after a successful save: toast, then the success step,\n // the embedded host callback or the afterSubmit navigation. The\n // generic save below and an action-only wizard save (saveVia\n // 'action') both end here, so both behave the same after saving.\n const completeAfterSave = (newRecordId, clickedAfterSubmit) => {\n // Admin-configurable success toast (group.submitMessages); defaults to\n // \"<Module> has added successfully\" for every module, new ones included.\n const successText = submitSuccessMessage(groups, moduleName, 'add');\n if (successText) message.success(successText);\n\n // Embedded (quick \"Add More\" modal): hand the new id back to the caller\n // so it can refetch its option list and select the new record — never\n // navigate away from the host form.\n if (embedded && onSuccess) {\n onSuccess(newRecordId, values);\n return;\n }\n\n // A configured Success step is an AFTER-save screen, never a page\n // someone can advance to before the create request succeeds. Keep\n // the user in the wizard and reveal it only now.\n if (wizardSuccessStepIndex >= 0) {\n form.resetFields();\n goToWizardStep(wizardSuccessStepIndex);\n return;\n }\n\n form.resetFields();\n\n // A clicked extra button (formActions) overrides the group's default\n // afterSubmit for this submit; the plain Create button leaves the ref\n // null and keeps the existing behavior.\n const afterSubmit = clickedAfterSubmit ?? resolveAfterSubmit(groups);\n if (!afterSubmit) {\n // No admin-configured behavior: return to wherever this form was\n // opened FROM, falling back to cancelPath on a cold deep-link.\n //\n // This replaced a hardcoded module→route map (jobs→/jobs,\n // candidates→/candidates, …) — four module names living in a\n // component that is otherwise entirely config-driven, and which\n // silently did nothing at all for every other module.\n goBackOrTo(navigate, { cancelPath });\n } else if (afterSubmit.mode === 'back') {\n goBackOrTo(navigate, { cancelPath });\n } else if (afterSubmit.mode === 'route' || afterSubmit.mode === 'detail') {\n const target = safeNavTarget(afterSubmit.target, newRecordId, values);\n if (target) navigate(target);\n }\n // afterSubmit.mode === 'stay' (or an unresolvable target): no navigation.\n };\n\n try {\n setSubmitLoading(true);\n // saveVia 'action': the wizard's onFinish server action IS the save.\n // The generic create/update, file attach and document registry do\n // not run (an action receives JSON values; files are not sent). Its\n // answer is the saved record: recordId → success step / afterSubmit.\n if (wizardEnabled && !WizardAdapter && wizardRuntime.saveViaAction) {\n const clicked = pendingAfterSubmitRef.current;\n await wizardRuntime.saveThroughAction(values, (savedId) => completeAfterSave(savedId, clicked));\n return;\n }\n // A wizard whose server action already created the record (a draft,\n // e.g. actions.onNext 'draft.save') saves INTO that record: creating\n // again would leave a second copy. No draft id: the create below,\n // exactly as before.\n const wizardDraftId = wizardEnabled && !WizardAdapter ? wizardRuntime.draftRecordId : '';\n const response = wizardDraftId\n ? await updateRecord(moduleName, wizardDraftId,\n { ...(effectiveExtraPayload ?? {}), ...buildPayload(values, groups, { module: moduleName }) },\n collectFileParts(values, groups, { indexed: true, module: moduleName }))\n : await createModuleRecord(moduleName, buildDynamicFormData(values, groups, effectiveExtraPayload ?? {}, moduleName));\n const success = response?.status !== false;\n\n if (!success) {\n // A duplicate reported in a 200 envelope ({status:false}) is the\n // same failure as a 409 — handle it the same way.\n if (applyDuplicateFieldErrors(response)) return;\n message.error(submitErrorMessage(groups, moduleName, 'add',\n response?.error || response?.message || response?.data));\n return;\n }\n\n // Repeatable (addRow) document files are attached in a follow-up update\n // through the reliable indexed path (documents[0], documents[1], …). The\n // rows themselves were created on insert (metadata is in the create JSON),\n // so this only uploads each file to its row by index. Runs only when the\n // form actually carried addRow file uploads, so plain records and jobs\n // stay single-request.\n const addRowFileParts = collectFileParts(values, groups, { scope: 'addRow', indexed: true, module: moduleName });\n const newRecordId = wizardDraftId || (response?.id ?? response?.data?.id ?? response?.data?._id ?? response?._id);\n if (!wizardDraftId && addRowFileParts.length > 0 && newRecordId) {\n try {\n await updateRecord(moduleName, newRecordId, { ...(effectiveExtraPayload ?? {}), ...buildPayload(values, groups, { module: moduleName }) }, addRowFileParts);\n } catch (uploadErr) {\n console.error('Document file attach (post-create update) failed:', uploadErr);\n message.warning('Record created, but attaching document files failed. Edit the record to re-upload.');\n }\n }\n\n // Common document registry — the module record is created FIRST (the\n // Create API above generated its reference id), then every uploaded\n // file (single or multiple, flat or addRow) is registered in the\n // shared \"documents\" collection against that id, keyed by module name\n // + the form field it was uploaded under (resume, jobDescription, …).\n // Best-effort: the record already exists, so a registry failure only\n // warns and never rolls back the create.\n const allFileParts = collectFileParts(values, groups, { module: moduleName });\n if (allFileParts.length > 0 && newRecordId) {\n try {\n await uploadModuleDocuments(moduleName, newRecordId, allFileParts);\n } catch (docErr) {\n console.error('Document registry upload failed:', docErr);\n message.warning('Record created, but saving its document records failed.');\n }\n }\n\n // A wizard runs its finish step's server action (actions.onFinish)\n // first; when that fails the record is already saved, the error\n // stays in the step with \"Try again\", and this runs once the retry\n // succeeds.\n const clickedAfterSubmit = pendingAfterSubmitRef.current;\n const completeAfterSaveNow = () => completeAfterSave(newRecordId, clickedAfterSubmit);\n if (wizardEnabled && !WizardAdapter) {\n wizardRuntime.markSaved(newRecordId, values);\n if (!(await wizardRuntime.afterSave(newRecordId, values, completeAfterSaveNow))) return;\n }\n completeAfterSaveNow();\n } catch (err) {\n console.error(`Failed to create ${moduleName}:`, err);\n // Authoritative server-side uniqueness check: keep every value the\n // user entered, keep the form open, mark the field and take them to\n // it. No success toast, no navigation.\n if (applyDuplicateFieldErrors(err)) return;\n message.error(submitErrorMessage(groups, moduleName, 'add',\n err?.data?.error || err?.data?.message || err?.message));\n } finally {\n setSubmitLoading(false);\n pendingAfterSubmitRef.current = null;\n }\n };\n\n const getFieldDependencies = (field, currentName, prefixFor) => {\n const rules = field.validations ?? field.validation ?? field.rules ?? [];\n // maxFromField is listed separately because its referenced field may live\n // OUTSIDE this row: the dependency path has to be built with the same\n // scoping the rule itself uses, not the sibling assumption below.\n const scoped = rules\n .filter((rule) => (typeof rule === 'string' ? rule : rule?.type) === 'maxFromField')\n .map((rule) => maxFromFieldDependency(rule, currentName, prefixFor))\n .filter(Boolean);\n return [...scoped, ...rules\n .filter((rule) => {\n const type = typeof rule === 'string' ? rule : rule?.type;\n return ['dateAfterField', 'greaterThanField', 'strictGreaterThanField',\n 'strictLessThanField', 'lessThanOrEqualField', 'maxFieldWithFallback',\n 'dateBeforeField', 'timeAfterField', 'timeBeforeField'].includes(type);\n })\n .map((rule) => {\n const compareFields = String(rule.value ?? rule.compareField ?? rule.field ?? '')\n .split(',').map((item) => item.trim()).filter(Boolean);\n return compareFields.map((compareField) => getSiblingFieldName(currentName, compareField));\n })\n .flat()\n .filter(Boolean)];\n };\n\n // Evaluate a Show Condition. `prefixFor` resolves the sibling path prefix for\n // a referenced field key (row-first for a group's own field, else top-level);\n // it may also be a precomputed prefix array/null for legacy single-condition\n // callers. A showIf can be a single leaf ({field,operator,value}) OR carry a\n // `conditions` array combined by `logic` (\"and\" default | \"or\") — the\n // multi-condition \"add more\" form — and a leaf + conditions combine too.\n const resolvePrefix = (prefixFor, key) => (typeof prefixFor === 'function' ? prefixFor(key) : prefixFor);\n const evalShowIfLeaf = (cond, getFieldValue, prefixFor) => {\n if (!cond?.field) return true;\n const prefix = resolvePrefix(prefixFor, cond.field);\n const path = prefix != null\n ? [...(Array.isArray(prefix) ? prefix : [prefix]), cond.field]\n : [cond.field];\n const val = getFieldValue(path);\n switch (cond.operator) {\n case 'eq': return String(val ?? '') === String(cond.value ?? '');\n case 'neq': return String(val ?? '') !== String(cond.value ?? '');\n case 'truthy': return val !== undefined && val !== null && val !== '' && val !== false;\n case 'falsy': return val === undefined || val === null || val === '' || val === false;\n // notEmpty targets an addRow GROUP's own Form.List name (cond.field is\n // that group's name, e.g. \"submission_referral_details\") — true once the\n // group has at least one row. Lets a flat field elsewhere in the form\n // (e.g. \"referral rate\") only appear/require once a referral row exists.\n case 'notEmpty': return Array.isArray(val) ? val.length > 0 : Boolean(val);\n // in/notIn: cond.value is a comma-separated list (e.g. \"W2-Fulltime,W2-Contract\").\n case 'in': return String(cond.value ?? '').split(',').map((v) => v.trim()).includes(String(val ?? ''));\n case 'notIn': return !String(cond.value ?? '').split(',').map((v) => v.trim()).includes(String(val ?? ''));\n default: return true;\n }\n };\n const evaluateShowIf = (showIf, getFieldValue, prefixFor) => {\n if (!showIf) return true;\n const conditions = Array.isArray(showIf.conditions) ? showIf.conditions.filter((c) => c?.field) : [];\n if (conditions.length) {\n const results = conditions.map((c) => evalShowIfLeaf(c, getFieldValue, prefixFor));\n const orLogic = String(showIf.logic ?? 'and').toLowerCase() === 'or';\n let combined = orLogic ? results.some(Boolean) : results.every(Boolean);\n // A top-level leaf alongside conditions is folded in with the same logic.\n if (showIf.field) {\n const leaf = evalShowIfLeaf(showIf, getFieldValue, prefixFor);\n combined = orLogic ? (combined || leaf) : (combined && leaf);\n }\n return combined;\n }\n return evalShowIfLeaf(showIf, getFieldValue, prefixFor);\n };\n // True when a field carries any Show Condition (single leaf or multi-condition).\n const hasShowIf = (showIf) => Boolean(showIf?.field || showIf?.conditions?.some?.((c) => c?.field));\n\n const [combineToggles, setCombineToggles] = useState({});\n\n const fieldKey = (field) => String(field?.field ?? '');\n\n // Who is filling this form — drives admin-configured field autoValueRules\n // (display only; the gateway enforces the same rules server-side).\n const actingIdentity = useMemo(() => getActingIdentity(), []);\n\n const renderField = (field, namePrefix, listName, opts = {}) => {\n // Split dotted keys into array form so AntD Form nests values correctly:\n // \"passport.passportNumber\" → ['passport','passportNumber']\n const fieldParts = typeof field.field === 'string' && field.field.includes('.')\n ? field.field.split('.')\n : null;\n const parsedField = fieldParts ?? field.field;\n const name = namePrefix !== undefined\n ? [namePrefix, ...(fieldParts ?? [field.field])]\n : parsedField;\n // Inside a Form.List the relative name [rowIndex, fieldName] is correct for\n // Form.Item registration, but form.getFieldValue / cross-field validators need\n // the absolute path [listName, rowIndex, fieldName] to find the value in the\n // form store. Build that here so validators and validateFields use the right path.\n // listName is normally a single Form.List name (string), but a DOUBLY-nested\n // list (a repeat field's subFields rendered inside an addRow group row) passes\n // the full absolute path array of its own list — spread it instead of wrapping.\n const absoluteName = (listName !== undefined && namePrefix !== undefined)\n ? [...(Array.isArray(listName) ? listName : [listName]), ...(Array.isArray(name) ? name : [name])]\n : name;\n // Checkbox.Group (when options are configured) uses value=[]; single boolean checkbox uses checked=bool.\n const isCheckboxGroup = field.type === 'checkbox' && (\n (field.options && field.options.length > 0) ||\n (field.dataSource && field.dataSource !== 'static')\n );\n const valuePropName = (!isCheckboxGroup && field.type === 'checkbox') ? 'checked' : 'value';\n // Inline (combined) fields show no per-box label — the combined card prints a\n // single label and the boxes sit side by side (e.g. From / To / Currency).\n // hideLabel: the group renders one shared header row above all addRow rows\n // instead of repeating each field's label on every row (e.g. Languages Known).\n const permissionLocked = Boolean(field.editablePermission)\n && !roleAllowsAction(field.editablePermission, moduleName);\n // Sibling path prefix for evaluateShowIf/labelWhen: [listName, rowIndex]\n // in a Form.List, null for ordinary top-level fields.\n const showIfPrefix = (listName !== undefined && namePrefix !== undefined)\n ? [...(Array.isArray(listName) ? listName : [listName]), namePrefix]\n : null;\n // A condition may reference a sibling IN this row, or any top-level\n // field (e.g. contractType). Row prefix only applies when the referenced\n // key is one of this group's own fields; unknown membership (no\n // rowFieldKeys passed) keeps the historical row-first behavior.\n const prefixFor = (conditionKey) => (\n showIfPrefix && (!opts.rowFieldKeys || opts.rowFieldKeys.has(conditionKey))\n ? showIfPrefix\n : null\n );\n // An admin-configured override checkbox rides the LABEL, so \"this value\n // may exceed its limit\" reads as a qualifier on the field's name rather\n // than as another input. See form/validationOverride.js.\n const overrideCfg = overrideConfig(field);\n const overrideFlag = overrideCfg ? overrideFlagPath(field, absoluteName, prefixFor) : null;\n const baseFieldLabel = (opts.inline || opts.hideLabel)\n ? ''\n : (!isCheckboxGroup && field.type === 'checkbox')\n ? ''\n : <ConfiguredFieldLabel form={form} field={field} siblingPrefix={field.labelWhen?.field ? prefixFor(field.labelWhen.field) : showIfPrefix} locked={permissionLocked} />;\n // A label-less presentation (inline/combined box, shared header row) has\n // nowhere to hang it; the combined block prints it once instead — see\n // renderCombinedPack.\n const fieldLabel = (overrideCfg && baseFieldLabel) ? (\n <span className=\"v1-label-with-override\">\n {baseFieldLabel}\n <ValidationOverrideCheckbox\n form={form}\n field={field}\n flagPath={overrideFlag}\n fieldPath={absoluteName}\n disabled={permissionLocked}\n />\n </span>\n ) : baseFieldLabel;\n const dependencies = getFieldDependencies(field, absoluteName, prefixFor);\n // Admin-set help text (field.tooltip, or the older infoEnabled/infoText\n // pair). It rides the label when there is one; a label-less field\n // (inline/combined box, or a group printing one shared header row) gets\n // it on the control instead — see fieldItem below — so EVERY control\n // type can carry a tooltip.\n const tooltipText = fieldTooltipText(field);\n const mdSpan = opts.inline ? 24 : ((field.type === 'file' && truthy(field.multiple)) || field.type === 'text-editor' ? 24 : (field.col ?? 12));\n\n // Config-driven default for the Add form: a top-level field (not inside a\n // Form.List) with a configured defaultValue mounts pre-selected. Any prefill\n // (initialRecord / quick-submit) runs through setFieldsValue, which overrides\n // initialValue — so this only affects a fresh Add with no incoming value.\n //\n // An autoValueRule for the acting user (e.g. Submit Source → \"External\"\n // for an employer-type user) outranks defaultValue: the field mounts\n // showing the value the gateway will enforce anyway. Display only — the\n // backend re-evaluates the same rules and has the final say.\n const autoValue = autoValueFor(field, actingIdentity);\n const initialValue = (namePrefix === undefined && field.type !== 'file'\n && autoValue.matched && autoValue.value !== undefined && autoValue.value !== '')\n ? autoValue.value\n : ((namePrefix === undefined && field.type !== 'file'\n && field.defaultValue !== undefined && field.defaultValue !== '')\n ? field.defaultValue : undefined);\n\n // AI Actions: admin-configured buttons (Generate/Parse-style) attached to\n // this field. \"click\" actions render as buttons beside the field; an\n // \"upload\" action (on a file field) fires automatically when a new file\n // is accepted, via the onAiUpload callback passed into FieldControl.\n const clickAiActions = (field.aiActions || []).filter((a) => a.trigger === 'click');\n const uploadAiAction = (field.aiActions || []).find((a) => a.trigger === 'upload');\n\n const fieldItem = (\n <Form.Item\n label={fieldLabel}\n name={name}\n extra={renderFieldHelp(field, prefillHints[field.field])}\n rules={getRules(field, form, absoluteName, isSearch, prefixFor, uniqueContext,\n inProgressRulesFor(field, opts.groupNameForActions))}\n required={isFieldRequired(field, form, absoluteName)}\n dependencies={dependencies}\n valuePropName={valuePropName}\n initialValue={initialValue}\n getValueFromEvent={field.type === 'file' ? (event) => (Array.isArray(event) ? event : event?.fileList) : undefined}\n validateTrigger={['onBlur', 'onChange']}\n {...(isSearch ? null : uniqueCheckItemProps(field, uniqueDebounceMs))}\n >\n <FieldControl\n key={field.refreshToken != null ? `${field.field}-refresh-${field.refreshToken}` : undefined}\n field={field}\n form={form}\n name={absoluteName}\n rowFieldKeys={opts.rowFieldKeys}\n moduleName={moduleName}\n scopeValues={{ clientId: effectiveClientId }}\n onAiUpload={uploadAiAction\n ? (file) => aiActions.runAction(opts.groupNameForActions, field, uploadAiAction, file)\n : undefined}\n onDuplicateBlur={handleDuplicateBlur}\n onRegionBlocked={handleRegionBlocked}\n onRowOrderChange={handleRowOrder}\n formDisabled={aiActions.busy}\n />\n </Form.Item>\n );\n\n // A label-less field (inline/combined box, or a group that prints one\n // shared header row) has nowhere to hang the label's info icon, so the\n // whole item becomes the tooltip target. The wrapping <span> is what\n // Tooltip attaches to — passing the Form.Item straight in would make\n // antd clone it for the ref, and Form.Item's clone is reserved for\n // injecting value/onChange into its control.\n const tooltippedItem = (tooltipText && !fieldLabel)\n ? <Tooltip title={tooltipText}><span className=\"v1-field-tooltip-wrap\">{fieldItem}</span></Tooltip>\n : fieldItem;\n\n const fieldItemWithActions = clickAiActions.length > 0 ? (() => {\n const positioned = groupActionsByPosition(clickAiActions);\n const group = (position) => (\n <AiActionButtonGroup\n key={position}\n position={position}\n actions={positioned[position]}\n aiActions={aiActions}\n groupName={opts.groupNameForActions}\n field={field}\n />\n );\n return (\n <div className=\"v1-ai-action-wrap\">\n {group('top-left')}\n {group('top-center')}\n {group('top-right')}\n {tooltippedItem}\n {group('bottom-left')}\n {group('bottom-center')}\n {group('bottom-right')}\n </div>\n );\n })() : tooltippedItem;\n\n // The verify carrier fields (verifyResultField \"isValid\" / verifyTimestampField\n // \"validatedAt\") are show:0, so they are NOT rendered as Form.Items above —\n // which means the value VerifyFieldButton sets via setFieldValue lives on an\n // UNREGISTERED path and antd's onFinish drops it, so \"verified\" was never\n // persisted (and so an edit form had nothing to prefill). Registering them as\n // hidden Form.Items — under the SAME relative name (row-indexed inside an\n // addRow Form.List) — makes the set value survive submit AND lets an edit\n // prefill populate it, so VerifyFieldButton shows \"Verified\" for an already-\n // verified email. omitEmpty on the field config keeps an unverified row from\n // writing a null/false carrier.\n const carrierName = (key) => (namePrefix !== undefined ? [namePrefix, key] : key);\n const verifyCarriers = field.verifyAction ? (\n <>\n {field.verifyResultField && (\n <Form.Item name={carrierName(field.verifyResultField)} hidden noStyle>\n <Input />\n </Form.Item>\n )}\n {field.verifyTimestampField && (\n <Form.Item name={carrierName(field.verifyTimestampField)} hidden noStyle>\n <Input />\n </Form.Item>\n )}\n </>\n ) : null;\n\n const fieldItemWithVerify = field.verifyAction ? (\n <div className=\"v1-verify-field-row\">\n {fieldItemWithActions}\n <VerifyFieldButton form={form} field={field} absoluteName={absoluteName} />\n {verifyCarriers}\n </div>\n ) : fieldItemWithActions;\n\n // The override flag lives on a path nothing else registers, so — exactly\n // like the verify carriers above — it needs a hidden Form.Item or antd's\n // onFinish drops it and an edit has nothing to prefill from.\n const fieldItemWithOverride = overrideCfg ? (\n <>\n {fieldItemWithVerify}\n <Form.Item\n name={namePrefix !== undefined\n ? [namePrefix, overrideFlag[overrideFlag.length - 1]]\n : overrideFlag[overrideFlag.length - 1]}\n valuePropName=\"checked\"\n hidden\n noStyle\n >\n <Checkbox />\n </Form.Item>\n </>\n ) : fieldItemWithVerify;\n\n // Inside a combined block, each box's width follows its combineWidth weight\n // (flex-grow), so the pack can be sized by ratio (e.g. 2:1, 1:2:3). Unset → 1.\n const inlineStyle = opts.inline\n ? { flex: `${Number(field.combineWidth) > 0 ? Number(field.combineWidth) : 1} 1 0`, maxWidth: 'none' }\n : undefined;\n\n\n const autoFillWatcher = field.autoFillFromApi ? (\n <AutoFillFromApiWatcher\n key={`${field.field}-autoFillFromApi`}\n form={form}\n config={field.autoFillFromApi}\n watchPath={absoluteName}\n />\n ) : null;\n\n const prefillWatcher = field.prefillWhen?.length ? (\n <PrefillWhenWatcher\n key={`${field.field}-prefillWhen`}\n form={form}\n rules={field.prefillWhen}\n watchPaths={prefillWhenWatchPaths(field.prefillWhen, absoluteName, resolveScopedFieldPath, prefixFor)}\n targetPath={absoluteName}\n resetOnNoMatch={field.prefillWhenReset !== false}\n />\n ) : null;\n\n // A show:0 field only reaches here because it has prefillWhen (see\n // the visibleFields filter above) — it exists purely to derive and\n // hold a value via the watcher, never to be seen or directly edited.\n if (field.show === 0) {\n return (\n <Fragment key={field.field}>\n {prefillWatcher}\n {autoFillWatcher}\n <Form.Item name={name} hidden noStyle>\n <input type=\"hidden\" />\n </Form.Item>\n </Fragment>\n );\n }\n\n // colWhen: live grid width, so a field can shrink when a condition\n // reveals a sibling next to it. Inline (combined) cells are flex-sized\n // by combineWidth, so they keep their fixed span.\n const hasColWhen = !opts.inline && colWhenRules(field).length > 0;\n const spanFor = (getFieldValue) => (hasColWhen\n ? resolveColSpan(field, mdSpan, (rule) => getFieldValue(conditionFieldPath(rule, prefixFor(rule.field))))\n : mdSpan);\n\n if (hasShowIf(field.showIf) || hasColWhen) {\n return (\n <Fragment key={field.field}>\n {prefillWatcher}\n {autoFillWatcher}\n <Form.Item shouldUpdate noStyle>\n {({ getFieldValue }) =>\n (!hasShowIf(field.showIf) || evaluateShowIf(field.showIf, getFieldValue, prefixFor))\n ? <Col xs={24} md={spanFor(getFieldValue)} style={inlineStyle} className={opts.inline ? 'v1-combine-cell' : undefined}>{fieldItemWithOverride}</Col>\n : null\n }\n </Form.Item>\n </Fragment>\n );\n }\n return (\n <Fragment key={field.field}>\n {prefillWatcher}\n {autoFillWatcher}\n <Col xs={24} md={mdSpan} style={inlineStyle} className={opts.inline ? 'v1-combine-cell' : undefined}>{fieldItemWithOverride}</Col>\n </Fragment>\n );\n };\n\n // renderAddRowField — field-level \"addRow\": repeats a SINGLE field's control\n // with the same add/remove + min/initial/max config the group-level addRow\n // uses (Form.List), but each list item IS the field's value directly (no\n // sub-key row object). Config keys mirror the group ones: field.minRows /\n // field.initialRows / field.maxRows / field.addLabel.\n // • minRows — delete is disabled once the list reaches this count.\n // • initialRows— empty inputs shown on a fresh Add (falls back to minRows).\n // • maxRows — the \"Add\" button hides once the list reaches this count.\n // Required (field.req) is enforced at the LIST level (>=1 non-empty entry) —\n // per-item rules skip \"required\" so an empty-but-present item never blocks.\n // Each item renders through singleFieldOf(field) so a repeatable select/\n // multi field shows a SINGLE control per item, not a multi-select.\n // Only used for a top-level field (namePrefix === undefined) — a field with\n // addRow=true inside an addRow GROUP renders as a normal single-value field\n // (no nested repeats).\n const renderAddRowField = (field) => {\n const fieldParts = typeof field.field === 'string' && field.field.includes('.')\n ? field.field.split('.')\n : [field.field];\n const permissionLocked = Boolean(field.editablePermission)\n && !roleAllowsAction(field.editablePermission, moduleName);\n const fieldLabel = <FieldLabel field={field} label={field.label} locked={permissionLocked} />;\n const itemField = singleFieldOf(field);\n // subFields → repeat a GROUP of fields per row (each row is an object of\n // the sub-fields, e.g. question + answer) instead of a single scalar.\n // Rows render through the same renderFields the group-level addRow uses.\n const hasSubFields = Array.isArray(field.subFields) && field.subFields.length > 0;\n // Sub-fields are always shown + editable (the admin exposes no show/edit\n // toggle for them). Force both so a sub-field never renders disabled: the\n // Go FormGroupField serializes show/edit as 0 when unset (no omitempty),\n // which editable() would otherwise read as \"not editable\".\n const subFieldsToRender = hasSubFields\n ? field.subFields.map((sf) => ({ ...sf, show: 1, edit: 1 }))\n : null;\n const minRows = Math.max(0, Number(field.minRows ?? 0) || 0);\n const maxRows = field.maxRows !== undefined && field.maxRows !== '' && Number(field.maxRows) > 0\n ? Number(field.maxRows) : 0;\n // Prefill source (quick-submit / initialRecord) — the Form.List mounts\n // only once the form is ready, so this initialValue is correct at mount.\n const prefillSource = pickPrefillValue(initialRecord ?? prefillFlatRecord ?? {}, field);\n const initialValue = buildRepeatFieldInitial(field, prefillSource);\n\n return (\n <Col key={field.field} xs={24} md={24}>\n <Form.Item label={fieldLabel} required={isFieldRequired(field)} colon={false} className=\"v1-combine-field\">\n <Form.List\n name={fieldParts}\n initialValue={initialValue}\n rules={[{\n validator: async (_, items = []) => {\n if (isFieldRequired(field)) {\n const filled = hasSubFields\n ? items.some((v) => hasMeaningfulValue(v))\n : items.some((v) => v !== undefined && v !== null && v !== '' && !(Array.isArray(v) && v.length === 0));\n if (!filled) throw new Error('Mandatory Field');\n }\n if (minRows > 0 && items.length < minRows) {\n throw new Error(`Keep at least ${minRows} ${hasSubFields ? 'row' : 'value'}${minRows > 1 ? 's' : ''}.`);\n }\n },\n }]}\n >\n {(items, { add, remove }, { errors }) => (\n <div className=\"v1-addrow-wrapper\">\n {items.map(({ key: itemKey, name: itemName }) => (\n <div key={itemKey} className=\"v1-addrow-item\">\n <Button\n type=\"text\" danger icon={<DeleteOutlined />}\n onClick={() => remove(itemName)}\n disabled={items.length <= minRows}\n className=\"v1-addrow-delete-btn\"\n />\n <div className=\"v1-addrow-fields\">\n {hasSubFields ? (\n <Row gutter={[24, 0]} align=\"top\">\n {renderFields(subFieldsToRender, itemName, fieldParts[0], false, field.field)}\n </Row>\n ) : (\n <Form.Item\n name={[itemName]}\n noStyle\n valuePropName={field.type === 'checkbox' && !(field.options?.length) ? 'checked' : 'value'}\n getValueFromEvent={field.type === 'file' ? (event) => (Array.isArray(event) ? event : event?.fileList) : undefined}\n rules={getRules(itemField, form, [...fieldParts, itemName], isSearch)}\n >\n <FieldControl\n field={itemField}\n form={form}\n name={[...fieldParts, itemName]}\n moduleName={moduleName}\n scopeValues={{ clientId: effectiveClientId }}\n formDisabled={aiActions.busy}\n />\n </Form.Item>\n )}\n </div>\n </div>\n ))}\n {(!maxRows || items.length < maxRows) && (\n <Button type=\"link\" icon={<PlusOutlined />} onClick={() => add()} className=\"v1-addrow-add-btn\">\n {field.addLabel ?? `Add ${field.label ?? 'Value'}`}\n </Button>\n )}\n <Form.ErrorList errors={errors} />\n </div>\n )}\n </Form.List>\n </Form.Item>\n </Col>\n );\n };\n\n // renderNestedRepeatField — a repeat field (field.addRow) that lives INSIDE\n // an addRow group row. It nests its own Form.List under the current row so\n // every row owns an independent set of repeat values (the payload shape\n // group[rowIndex].repeatField[repeatIndex], e.g. educationDetails[0].subjects).\n // Also handles the field.subFields case (repeat a GROUP of sub-fields\n // together per row, e.g. question + answer) nested the same way — each item\n // renders the sub-fields through the same renderFields the top-level\n // subFields branch (renderAddRowField) uses, so a select/lookup sub-field\n // gets the exact same config-driven dropdown loading as any other field.\n // namePrefix is the outer row's index (from the group Form.List), listName\n // is the group's Form.List name (string) or, for a doubly-nested case, its\n // absolute path array. The nested list's `name` is relative to that list\n // context ([rowIndex, ...fieldParts]); item controls use the absolute path\n // for validators/FieldControl.\n const renderNestedRepeatField = (field, namePrefix, listName) => {\n const fieldParts = typeof field.field === 'string' && field.field.includes('.')\n ? field.field.split('.')\n : [field.field];\n const permissionLocked = Boolean(field.editablePermission)\n && !roleAllowsAction(field.editablePermission, moduleName);\n const fieldLabel = <FieldLabel field={field} label={field.label} locked={permissionLocked} />;\n const itemField = singleFieldOf(field);\n const hasSubFields = Array.isArray(field.subFields) && field.subFields.length > 0;\n const subFieldsToRender = hasSubFields\n ? field.subFields.map((sf) => ({ ...sf, show: 1, edit: 1 }))\n : null;\n const minRows = Math.max(0, Number(field.minRows ?? 0) || 0);\n const maxRows = field.maxRows !== undefined && field.maxRows !== '' && Number(field.maxRows) > 0\n ? Number(field.maxRows) : 0;\n // Relative name (group-list context prefixes the group name); the parent\n // row's initialValue already carries any stored values for this key, so a\n // fresh row falls back to config-driven empty inputs while an edited row\n // inherits its stored values (antd ignores this initialValue when the\n // store already holds a value at this path).\n const listNameRel = [namePrefix, ...fieldParts];\n const nestedAbsoluteListName = [...(Array.isArray(listName) ? listName : [listName]), namePrefix, ...fieldParts];\n const initialValue = buildRepeatFieldInitial(field, undefined);\n return (\n <Col key={`${listName}-${namePrefix}-${field.field}`} xs={24} md={hasSubFields ? 24 : (field.col ?? 24)}>\n <Form.Item label={fieldLabel} required={isFieldRequired(field)} colon={false} className=\"v1-combine-field\">\n <Form.List\n name={listNameRel}\n initialValue={initialValue}\n rules={hasSubFields ? [{\n validator: async (_, items = []) => {\n if (isFieldRequired(field)) {\n const filled = items.some((v) => hasMeaningfulValue(v));\n if (!filled) throw new Error('Mandatory Field');\n }\n if (minRows > 0 && items.length < minRows) {\n throw new Error(`Keep at least ${minRows} row${minRows > 1 ? 's' : ''}.`);\n }\n },\n }] : []}\n >\n {(items, { add, remove }, { errors }) => (\n <div className=\"v1-addrow-wrapper\">\n {items.map(({ key: itemKey, name: itemName }) => {\n const absoluteName = [...nestedAbsoluteListName, itemName];\n return (\n <div key={itemKey} className=\"v1-addrow-item\">\n <Button\n type=\"text\" danger icon={<DeleteOutlined />}\n onClick={() => remove(itemName)}\n disabled={items.length <= minRows}\n className=\"v1-addrow-delete-btn\"\n />\n <div className=\"v1-addrow-fields\">\n {hasSubFields ? (\n <Row gutter={[24, 0]} align=\"top\">\n {renderFields(subFieldsToRender, itemName, nestedAbsoluteListName, false, field.field)}\n </Row>\n ) : (\n <Form.Item\n name={[itemName]}\n noStyle\n valuePropName={field.type === 'checkbox' && !(field.options?.length) ? 'checked' : 'value'}\n getValueFromEvent={field.type === 'file' ? (event) => (Array.isArray(event) ? event : event?.fileList) : undefined}\n rules={getRules(itemField, form, absoluteName, isSearch)}\n >\n <FieldControl\n field={itemField}\n form={form}\n name={absoluteName}\n moduleName={moduleName}\n scopeValues={{ clientId: effectiveClientId }}\n formDisabled={aiActions.busy}\n />\n </Form.Item>\n )}\n </div>\n </div>\n );\n })}\n {(!maxRows || items.length < maxRows) && (\n <Button type=\"link\" icon={<PlusOutlined />} onClick={() => add()} className=\"v1-addrow-add-btn\">\n {field.addLabel ?? `Add ${field.label ?? 'Value'}`}\n </Button>\n )}\n <Form.ErrorList errors={errors} />\n </div>\n )}\n </Form.List>\n </Form.Item>\n </Col>\n );\n };\n\n\n// registerHiddenFields — a show:0 field still needs a Form.Item.\n//\n// A hidden field is not decoration: it is a CARRIER. The engine deliberately\n// keeps show:0 fields in the group (see normalizeGroups) precisely so their\n// values participate — the job's client rate rides onto a submission that way\n// (jobClientRate.*, filled by prefillFromModule), and a verify result rides on\n// isValid/validatedAt.\n//\n// But a value set with setFieldsValue on a path NOTHING has registered is not\n// reliably part of the form: onFinish drops it, and a cross-field rule reading\n// it through getFieldValue can come back empty. That is why the verify carriers\n// were already registered by hand at their own call site. Doing it here covers\n// EVERY config-declared hidden field instead of the two someone remembered,\n// which is what makes a rule like \"rate may not exceed the job's client rate\"\n// actually fire — before this it silently found no ceiling and passed anything.\n//\n// Rendered `hidden` (never visible), unstyled, and outside the layout grid, so\n// nothing about the form's appearance changes.\nconst renderHiddenCarriers = (fields, namePrefix) => fields\n .filter((f) => f.field && f.show !== undefined && !truthy(f.show))\n .map((f) => {\n const parts = String(f.field).includes('.') ? String(f.field).split('.') : f.field;\n const name = namePrefix !== undefined\n ? [namePrefix, ...(Array.isArray(parts) ? parts : [parts])]\n : parts;\n return (\n <Form.Item key={`hidden-${f.field}`} name={name} hidden noStyle>\n <Input />\n </Form.Item>\n );\n });\n\n const renderFields = (fields, namePrefix, listName, hideLabel = false, groupNameForActions) => {\n const used = new Set();\n const out = [];\n // Keys of THIS group's own fields — conditions (showIf/labelWhen/\n // prefillWhen) referencing a field OUTSIDE the group (e.g. the top-level\n // contractType from inside the addRow employer group) must resolve\n // against the top-level form, not the row.\n const rowFieldKeys = new Set(fields.map((f) => f.field).filter(Boolean));\n // Hidden (show:0) fields stay in `fields` so buildPayload can see them\n // (see normalizeGroups) — they just never get a Form.Item here.\n const visibleFields = fields.filter((f) => (\n f.show === undefined || truthy(f.show) || (f.show === 0 && Boolean(f.prefillWhen?.length))\n ));\n out.push(...renderHiddenCarriers(fields, namePrefix));\n visibleFields.forEach((field) => {\n if (truthy(field.addRow) && namePrefix === undefined) {\n out.push(renderAddRowField(field));\n return;\n }\n // A repeat field INSIDE an addRow group row (namePrefix defined) gets\n // its own nested Form.List so each row keeps independent repeat values\n // (educationDetails[rowIndex].subjects[]) — including a subFields\n // repeat-GROUP (e.g. question+answer pairs per education row).\n if (truthy(field.addRow) && namePrefix !== undefined) {\n out.push(renderNestedRepeatField(field, namePrefix, listName));\n return;\n }\n const combineKey = field.combineKey?.trim?.();\n if (!combineKey) {\n out.push(renderField(field, namePrefix, listName, { hideLabel, groupNameForActions, rowFieldKeys }));\n return;\n }\n const packKey = `${listName ?? 'root'}:${namePrefix ?? 'root'}:${combineKey}`;\n if (used.has(packKey)) return;\n const pack = visibleFields.filter((f) => f.combineKey === combineKey);\n pack.forEach((f) => used.add(`${listName ?? 'root'}:${namePrefix ?? 'root'}:${f.combineKey}`));\n\n const labelField = pack.find((f) => f.combineLabel) ?? field;\n const siblingPrefix = (listName !== undefined && namePrefix !== undefined)\n ? [...(Array.isArray(listName) ? listName : [listName]), namePrefix]\n : null;\n // A combined pack prints ONE shared label, so an override checkbox\n // configured on ANY member belongs beside that shared label — the\n // per-field path in renderField cannot fire here (inline members are\n // label-less by design). First member that declares one wins.\n const packOverrideField = pack.find((f) => overrideConfig(f)) ?? null;\n const packPrefixForOverride = (conditionKey) => (\n siblingPrefix && (!rowFieldKeys || rowFieldKeys.has(conditionKey)) ? siblingPrefix : null\n );\n const packOverrideAbsName = packOverrideField\n ? ((listName !== undefined && namePrefix !== undefined)\n ? [...(Array.isArray(listName) ? listName : [listName]), namePrefix,\n ...(String(packOverrideField.field).includes('.')\n ? String(packOverrideField.field).split('.')\n : [packOverrideField.field])]\n : (String(packOverrideField.field).includes('.')\n ? String(packOverrideField.field).split('.')\n : packOverrideField.field))\n : null;\n const baseCombinedLabel = <ConfiguredFieldLabel form={form} field={labelField} siblingPrefix={siblingPrefix} combined />;\n const label = packOverrideField ? (\n <span className=\"v1-label-with-override\">\n {baseCombinedLabel}\n <ValidationOverrideCheckbox\n form={form}\n field={packOverrideField}\n flagPath={overrideFlagPath(packOverrideField, packOverrideAbsName, packPrefixForOverride)}\n fieldPath={packOverrideAbsName}\n />\n </span>\n ) : baseCombinedLabel;\n const toggleTarget = pack.find((f) => f.combineToggleTarget)?.combineToggleTarget;\n const toggleLabel = pack.find((f) => f.combineToggleLabel)?.combineToggleLabel ?? 'Show range';\n const toggleStateKey = packKey;\n const wrapPack = pack.some((f) => truthy(f.combineWrap));\n const configuredSpan = Number(pack.find((f) => [12, 24].includes(Number(f.combineSpan)))?.combineSpan);\n const targetField = toggleTarget ? pack.find((f) => fieldKey(f) === toggleTarget) : null;\n const targetParts = targetField?.field?.includes?.('.') ? targetField.field.split('.') : [targetField?.field].filter(Boolean);\n const targetName = targetField\n ? ((listName !== undefined && namePrefix !== undefined)\n ? [listName, namePrefix, ...targetParts]\n : (targetParts.length > 1 ? targetParts : targetField.field))\n : null;\n\n // Layout mirrors the legacy combined field: one label, the boxes inline on\n // a single row, and the range toggle BELOW. Toggle off → only the primary\n // (target hidden); toggle on → the target box appears alongside. The wider\n // packs (with currency/unit) take a full row; a simple From/To pair is half.\n const primaryReq = pack.some((f) => isFieldRequired(f));\n const comboSpan = [12, 24].includes(configuredSpan)\n ? configuredSpan\n : (pack.length >= 3 ? 24 : 12);\n // A combined pack prints ONE shared label above its boxes, and that\n // label lives outside the per-field showIf gates. When every member\n // is hidden by its condition the boxes disappear but the labelled\n // shell stayed — e.g. an empty \"Contact Number\" on a W2 employer.\n // Gate the whole pack on \"is any member still visible\".\n const packPrefixFor = (conditionKey) => (\n siblingPrefix && (!rowFieldKeys || rowFieldKeys.has(conditionKey)) ? siblingPrefix : null\n );\n const packHasShowIf = pack.some((f) => hasShowIf(f.showIf));\n const anyPackMemberVisible = (getFieldValue) => pack.some(\n (f) => !hasShowIf(f.showIf) || evaluateShowIf(f.showIf, getFieldValue, packPrefixFor),\n );\n const packCol = (\n <Col key={packKey} xs={24} md={comboSpan}>\n <Form.Item label={label} required={primaryReq} colon={false} className=\"v1-combine-field\">\n <Form.Item noStyle shouldUpdate>\n {({ getFieldValue }) => {\n const hasTargetValue = targetName ? !empty(getFieldValue(targetName)) : false;\n const checked = combineToggles[toggleStateKey] ?? hasTargetValue;\n const visiblePack = toggleTarget && !checked\n ? pack.filter((f) => fieldKey(f) !== toggleTarget)\n : pack;\n return (\n <>\n <Row\n gutter={[8, 0]}\n align=\"top\"\n wrap={wrapPack}\n className={`v1-combine-row${wrapPack ? ' v1-combine-row-wrap' : ''}`}\n >\n {/* Combined-field mandatory cascade: if ANY field in a\n combined pack is required, every VISIBLE field in the\n pack is required too (e.g. Notice Period requires its\n Unit). Applied to visiblePack so a hidden range \"To\"\n stays optional until its toggle is on. */}\n {visiblePack.map((f) => renderField(primaryReq ? { ...f, req: 1 } : f, namePrefix, listName, { inline: true }))}\n </Row>\n {toggleTarget && (\n <div className=\"v1-combine-range\">\n <Switch\n size=\"small\"\n checked={checked}\n onChange={(next) => {\n if (!next && targetName) {\n form.setFieldValue(targetName, undefined);\n form.validateFields([targetName]).catch(() => { });\n }\n setCombineToggles((prev) => ({ ...prev, [toggleStateKey]: next }));\n }}\n />\n <Text type=\"secondary\" className=\"v1-combine-toggle-label\">{toggleLabel}</Text>\n </div>\n )}\n </>\n );\n }}\n </Form.Item>\n </Form.Item>\n </Col>\n );\n out.push(packHasShowIf ? (\n <Form.Item key={packKey} shouldUpdate noStyle>\n {({ getFieldValue }) => (anyPackMemberVisible(getFieldValue) ? packCol : null)}\n </Form.Item>\n ) : packCol);\n });\n return out;\n };\n\n // Derive fields from search results for ListView (same logic as JobsListPage)\n const searchFields = useMemo(() => {\n if (searchResults.fields?.length) return searchResults.fields;\n const firstRow = searchResults.rows[0];\n if (!firstRow) return [];\n\n return Object.keys(firstRow)\n .filter((key) => !key.startsWith('_') && typeof firstRow[key] !== 'object')\n .map((key) => ({\n value: key,\n field: key,\n label: key.replace(/([A-Z])/g, ' $1').replace(/^./, (char) => char.toUpperCase()),\n isVisible: true,\n }));\n }, [searchResults.fields, searchResults.rows]);\n\n // Determine view mode based on source type: show list view for external sources,\n // card view for internal sources\n const getViewModeFromRecords = (records) => {\n if (!Array.isArray(records) || records.length === 0) return 'card';\n\n const hasExternalSource = records.some((record) => {\n const sourceFields = [\n record?.sourceType,\n record?.profileSource,\n record?.selectedSource,\n record?.customFields?.sourceType,\n record?.customFields?.profileSource,\n ];\n\n return sourceFields.some((value) => {\n if (value === null || value === undefined) return false;\n const normalized = String(value).trim().toLowerCase();\n if (!normalized) return false;\n return !['all', 'internal'].includes(normalized);\n });\n });\n\n return hasExternalSource ? 'list' : 'card';\n };\n\n const defaultViewMode = useMemo(() => {\n return getViewModeFromRecords(searchResults.rows);\n }, [searchResults.rows]);\n\n const searchFieldsWithActions = useMemo(() => {\n const sourceActions = getAvailableSourceActions({\n rows: searchResults.rows,\n selectedSource,\n });\n if (!sourceActions.length) return searchFields;\n\n const actionFields = new Set(sourceActions.map((action) => action.field));\n const fieldsWithoutActions = searchFields.filter(\n (field) => field.cardRole !== 'action' && !actionFields.has(field.value),\n );\n return [\n ...fieldsWithoutActions,\n ...sourceActions.map((action) => ({\n value: action.field,\n field: action.field,\n label: action.label ?? 'Action',\n cardRole: 'action',\n isVisible: true,\n tableHidden: true,\n sorter: false,\n render: (_value, record) => {\n if (!sourceActionAppliesToRecord(action, record, selectedSource)) return null;\n const actionKey = getSourceActionInstanceKey(action, record);\n const state = sourceActionState[actionKey] ?? {};\n const missingActionId = !actionKey;\n const disabled = missingActionId || state.completed;\n\n return (\n <Button\n type=\"primary\"\n size=\"small\"\n loading={state.loading}\n disabled={disabled}\n onClick={() => handleSourceAction(action, record)}\n >\n {state.completed ? action.completedLabel : action.buttonLabel}\n </Button>\n );\n },\n })),\n ];\n }, [handleSourceAction, searchFields, searchResults.rows, selectedSource, sourceActionState]);\n\n // Merge page-level context (e.g. { jobId }) into every search-result row\n // action's popupState, so a popup it opens (via ListView's action.route\n // handling) receives that context too — see the searchActionContext prop.\n const searchResultActions = useMemo(() => {\n if (!searchActionContext) return searchResults.actions;\n const mergeContext = (action) => ({\n ...action,\n popupState: { ...searchActionContext, ...action.popupState },\n ...(action.children ? { children: action.children.map(mergeContext) } : {}),\n });\n return (searchResults.actions ?? []).map(mergeContext);\n }, [searchResults.actions, searchActionContext]);\n\n // renderGroupBody builds a group's inner controls (the addRow Form.List or\n // the flat field Row) WITHOUT its Card chrome, so a group flagged\n // `mergeInto: \"<hostGroupName>\"` can render inside another group's card\n // (e.g. Rate Details inside Employer) while keeping its own payload,\n // appendHistory and showIf semantics completely unchanged — the merge is\n // presentation only.\n const renderGroupBody = (group) => {\n const groupName = group.name ?? group.id ?? '';\n // group.linkGroup: when this group is linked to others, the LEADER owns\n // the Add button + minRows/requireOne validator for the whole set; every\n // member (leader + followers) still gets its own Form.List/Card/rows, and\n // add/remove always go through every member via listControlsRef so row\n // counts stay equal by construction. Unlinked groups (linkedSet === null,\n // i.e. every group that predates this feature) fall through leaderGroup\n // === group, so minRows/rules/initialValue below compute exactly as before.\n const linkedSet = findLinkedSet(linkedGroupSets, groupName);\n const isFollower = Boolean(linkedSet) && linkedSet.leaderName !== groupName;\n const leaderGroup = linkedSet\n ? (groups.find((g) => g.name === linkedSet.leaderName) ?? group)\n : group;\n const minRows = Math.max(0, Number(leaderGroup.minRows ?? 0) || 0);\n const maxRows = Math.max(0, Number(leaderGroup.maxRows ?? 0) || 0);\n const linkedMemberNames = linkedSet ? linkedSet.memberNames : [groupName];\n const addLinkedRow = () => {\n // New rows start from the group's admin-configured defaults (same\n // seed the initial rows get), not empty.\n linkedMemberNames.forEach((name) => {\n const member = groups.find((g) => g.name === name) ?? group;\n listControlsRef.current[name]?.add(rowDefaultsFor(member));\n });\n };\n const removeLinkedRow = (rowName) => {\n linkedMemberNames.forEach((name) => listControlsRef.current[name]?.remove(rowName));\n };\n // Opt-in (wizardContent.addRowView 'table', wizard only): rows as a\n // table — one header of labels, one line per row. Cards stay default.\n const tableRows = wizardEnabled && Boolean(group.addRow) && wizardAddRowView(group, groups) === 'table';\n const sharedLabels = truthy(group.sharedRowLabels) || tableRows;\n const body = group.addRow ? (\n <Form.List\n name={groupName}\n initialValue={addRowInitials[groupName] ?? []}\n rules={isFollower ? [] : [\n {\n validator: async (_, rows = []) => {\n // A group switched OFF via its own toggle (e.g. \"Fresher\" hiding\n // Work Experience) is not rendered at all — don't force rows on it.\n const switchedOn = truthy(group.toggleEnabled) && group.toggleField\n && Boolean(form.getFieldValue(group.toggleField));\n if (switchedOn) return;\n if (minRows > 0 && rows.length < minRows) {\n throw new Error(`Keep at least ${minRows} row${minRows > 1 ? 's' : ''}.`);\n }\n if (truthy(group.requireOne)) {\n const invalid = rows.some((row) => !hasMeaningfulValue(row));\n if (invalid) throw new Error('Fill at least one field in each added row.');\n }\n },\n },\n ]}\n >\n {(rows, { add, remove, move }, { errors }) => {\n // `move` joins the registry so the newest-first prompt can\n // reorder a row the user just marked as ongoing. Form.List's\n // own move preserves every row's values; rebuilding the\n // array by hand would not.\n listControlsRef.current[groupName] = { add, remove, move };\n return (\n <div className={tableRows ? 'v1-addrow-wrapper v1-addrow-wrapper--table' : 'v1-addrow-wrapper'}>\n <div className=\"v1-addrow-topbar\">\n {!isFollower ? (\n (!maxRows || rows.length < maxRows) && (\n <Button\n type=\"link\"\n icon={<PlusOutlined />}\n onClick={addLinkedRow}\n className=\"v1-addrow-add-btn\"\n >\n {group.addLabel ?? `Add ${group.label ?? 'Row'}`}\n </Button>\n )\n ) : (\n <Text type=\"secondary\" className=\"v1-addrow-linked-hint\">\n Rows added via {leaderGroup.label ?? leaderGroup.name}\n </Text>\n )}\n </div>\n\n {sharedLabels && rows.length > 0 && (\n <Row gutter={[24, 0]} className=\"v1-addrow-header\">\n {group.fields.filter((f) => f.show === undefined || truthy(f.show)).map((field) => (\n <Col key={fieldKey(field)} md={field.col ?? 12} className=\"v1-addrow-header-label\">\n {field.label}\n </Col>\n ))}\n </Row>\n )}\n\n {rows.map(({ key: rowKey, name }) => (\n <div key={rowKey} className=\"v1-addrow-item\">\n <Button\n type=\"text\"\n danger\n icon={<DeleteOutlined />}\n onClick={() => removeLinkedRow(name)}\n disabled={rows.length <= minRows}\n className=\"v1-addrow-delete-btn\"\n />\n\n <div className=\"v1-addrow-fields\">\n <Row gutter={[24, 0]} align=\"top\">\n {renderFields(group.fields, name, groupName, sharedLabels, groupName)}\n </Row>\n </div>\n </div>\n ))}\n <Form.ErrorList errors={errors} />\n </div>\n );\n }}\n </Form.List>\n ) : (\n <Row gutter={[24, 0]}>{renderFields(group.fields, undefined, undefined, false, groupName)}</Row>\n );\n\n return body;\n };\n\n // Groups rendered INSIDE another group's card (group.mergeInto). A child\n // keeps its own showIf gate and gets a light section title; everything else\n // (payload, validation, Form.List names) is untouched.\n const mergedChildrenOf = (group) => groups.filter(\n (g) => g !== group && g.mergeInto && String(g.mergeInto) === String(group.name),\n );\n const isMergedChild = (group) => Boolean(\n group.mergeInto && groups.some((g) => g !== group && String(g.name) === String(group.mergeInto)),\n );\n\n // A merged child renders BEFORE the host's own fields when it declares\n // `mergePosition: \"top\"`. Needed whenever the child holds the field the\n // host's fields are conditioned on — Contract Type gates every Employer\n // field, so rendering it underneath them reads backwards and invites the\n // user to fill a disabled card first.\n const mergedAt = (group, position) => mergedChildrenOf(group).filter(\n (child) => (String(child.mergePosition ?? 'bottom') === position),\n );\n\n\n const renderGroup = (group, index) => {\n const key = group.name ?? group.id ?? String(index);\n const body = renderGroupBody(group);\n const mergedTop = mergedAt(group, 'top');\n const mergedChildren = mergedAt(group, 'bottom');\n\n // One renderer for both slots, so a merged child behaves identically\n // whichever side of the host body it sits on.\n const renderMergedChild = (child) => {\n const section = (\n <div key={child.name} className=\"v1-merged-group\">\n <div className=\"v1-merged-group-title\">{child.label ?? child.name}</div>\n {renderGroupBody(child)}\n </div>\n );\n const gated = child.showIf?.field\n ? <GroupShowIfGate key={child.name} form={form} showIf={child.showIf} render={() => section} />\n : section;\n // Its OWN disabled state, not the host's — see GroupDisabledProvider.\n return (\n <GroupDisabledProvider key={child.name} form={form} group={child} inheritParent={false}>\n {gated}\n </GroupDisabledProvider>\n );\n };\n\n return (\n <Card\n key={key}\n className=\"v1-card v1-edit-card\"\n title={<SectionTitle icon={sectionIcons[index % sectionIcons.length]} title={isSearch ? (searchFormLabel || group.label) : (group.label ?? group.name ?? 'Details')} />}\n extra={(\n <Space size={8} align=\"center\" className=\"v1-group-actions\">\n <GroupInfoMessage group={group} />\n <GroupToggleControl group={group} />\n {/* Opt-in only (group.allowCollapse). Without it there is\n no chevron and the section cannot be collapsed — the\n behaviour every form had before this was configurable. */}\n {truthy(group.allowCollapse) && (\n <Button\n type=\"text\"\n size=\"small\"\n aria-expanded={!collapsed[key]}\n aria-label={collapsed[key] ? 'Expand section' : 'Collapse section'}\n icon={collapsed[key] ? <DownOutlined /> : <UpOutlined />}\n onClick={(event) => {\n event.stopPropagation();\n toggle(key);\n }}\n />\n )}\n </Space>\n )}\n >\n <Form.Item noStyle shouldUpdate>\n {({ getFieldValue }) => {\n const switchedOn = truthy(group.toggleEnabled) && group.toggleField && Boolean(getFieldValue(group.toggleField));\n return (\n <div style={{ display: collapsed[key] || switchedOn ? 'none' : 'block' }}>\n {mergedTop.map(renderMergedChild)}\n {body}\n {mergedChildren.map(renderMergedChild)}\n </div>\n );\n }}\n </Form.Item>\n </Card>\n );\n };\n\n return (\n <main>\n {breadcrumbItems.length > 0 && <AppBreadcrumb items={breadcrumbItems} />}\n {wizardEnabled && WizardAdapter ? (\n <WizardAdapter\n {...(wizardAdapterProps ?? {})}\n mode=\"add\"\n moduleName={moduleName}\n configuredSteps={wizardSteps}\n configuredGroups={wizardConfigGroups}\n />\n ) : <div className=\"v1-edit-page\">\n {hasClientScope && !presetClientId && !linkedClientId && (\n <Card className=\"v1-card v1-edit-card v1-client-gate-card\">\n <Space direction=\"vertical\" size={12} style={{ width: '100%' }}>\n <SectionTitle icon={<UserOutlined />} title=\"Select Client\" />\n {clientGateMessage && <Text type=\"secondary\">{clientGateMessage}</Text>}\n <Row gutter={[16, 0]}>\n <Col xs={24} md={14}>\n <Select\n showSearch\n allowClear\n placeholder=\"Select client\"\n style={{ width: '100%' }}\n value={effectiveClientId || undefined}\n optionFilterProp=\"label\"\n options={clientOptions.map((c) => ({\n value: c._id ?? c.id,\n label: c.clientName ?? c.name ?? c.clientRefrenceId ?? c._id,\n })).filter((c) => c.value)}\n onChange={handleClientGateChange}\n dropdownRender={clientGateQuick.footer\n ? (menu) => (<>{menu}{clientGateQuick.footer}</>)\n : undefined}\n />\n {clientGateQuick.modal}\n </Col>\n </Row>\n </Space>\n </Card>\n )}\n <div className=\"v1-page-inner\">\n {wizardEnabled && isFormReady && (\n <FormWizard\n steps={wizardSteps}\n current={activeWizardStep}\n errorStep={wizardRuntime.errorStep}\n onSelectCompleted={wizardShowingSuccess || wizardRuntime.busy ? undefined : goToWizardStep}\n />\n )}\n {/* Async work gets its OWN viewport-centred overlay.\n The wrapping Spin below centres its indicator inside the\n element it wraps — on a form this long that lands\n somewhere in the middle of the page, which after any\n scrolling is off screen entirely. Reading a résumé takes\n seconds, so the user is left looking at a frozen form\n with no visible sign that anything is happening.\n `fullscreen` pins it to the centre of the VIEWPORT with\n a scrim, so it is where the user is looking whatever\n they have scrolled to. */}\n <Spin\n fullscreen\n spinning={aiActions.busy || duplicates.checking}\n size=\"large\"\n tip={\n aiActions.busy\n ? (aiActions.loadingText || 'Reading the file…')\n : 'Checking whether we already have this person…'\n }\n />\n <Spin\n spinning={!isFormReady && !waitingForClientScope}\n description=\"Loading form fields…\"\n >\n <Form\n form={form}\n layout=\"vertical\"\n colon={false}\n className=\"v1-form\"\n // Disabled during the duplicate check too — it can\n // end by navigating away, and letting someone keep\n // typing into a form that is about to be abandoned\n // loses whatever they add in those seconds.\n disabled={aiActions.busy || duplicates.checking}\n requiredMark={(label, { required }) => (\n <>\n {label}\n {required && <span className=\"v1-required-mark\"> *</span>}\n </>\n )}\n // A wizard can finish on a step that mounts none of the\n // earlier steps' fields, so its submit reads the whole\n // store. The ordinary form keeps the exact onFinish values.\n onFinish={wizardEnabled ? submitWizard : submit}\n onFinishFailed={handleWizardSubmitFailed}\n >\n {isFormReady && (wizardEnabled ? (\n <WizardStepContent\n step={wizardSteps[activeWizardStep]}\n steps={wizardSteps}\n current={activeWizardStep}\n form={form}\n onGoToStep={goToWizardStep}\n moduleName={moduleName}\n notice={<WizardStepNotice runtime={wizardRuntime} current={activeWizardStep} />}\n actionResult={wizardRuntime.actionResult}\n savedRecord={wizardRuntime.savedRecord}\n stepBusy={wizardRuntime.busy === 'enter'}\n recordId={wizardRuntime.recordId}\n formContent={groups.filter((g) => !isMergedChild(g)).map((group, index) => {\n const stepIndex = wizardStepForGroup(wizardSteps, group, index);\n return (\n <div key={group.name ?? `grp-${index}`}\n className=\"v1-form-wizard__panel\"\n hidden={stepIndex !== activeWizardStep}>\n <GroupDisabledProvider form={form} group={group}>\n {group.showIf?.field\n ? <GroupShowIfGate form={form} showIf={group.showIf} render={() => renderGroup(group, index)} />\n : renderGroup(group, index)}\n </GroupDisabledProvider>\n </div>\n );\n })}\n />\n ) : groups.filter((g) => !isMergedChild(g)).map((group, index) => (\n <GroupDisabledProvider key={group.name ?? `grp-${index}`} form={form} group={group}>\n {group.showIf?.field\n ? <GroupShowIfGate form={form} showIf={group.showIf} render={() => renderGroup(group, index)} />\n : renderGroup(group, index)}\n </GroupDisabledProvider>\n )))}\n {isFormReady && !error && groups.length === 0 && (\n <Alert type=\"info\" showIcon message={isSearch ? \"No search configuration found.\" : \"No form fields are configured.\"} />\n )}\n {isFormReady && isSearch && (\n <div className=\"v1-search-form-actions\">\n <Space size={12}>\n <Button onClick={handleReset} disabled={!groups.length}>\n Reset\n </Button>\n <Button onClick={() => goBackOrTo(navigate, { cancelPath })}>\n Back\n </Button>\n <Button\n type=\"primary\"\n htmlType=\"submit\"\n disabled={submitLoading || !groups.length || searchDisabled}\n loading={submitLoading}\n >\n {submitText}\n </Button>\n </Space>\n </div>\n )}\n </Form>\n </Spin>\n </div>\n\n {!isSearch && !hideFooter && (\n <div className={embedded ? 'v1-footer v1-footer--embedded' : 'v1-footer'}>\n <Text type=\"secondary\">All Unsaved Changes will be lost if you cancel and reload.</Text>\n <Space size={12}>\n <Button onClick={() => (embedded && onCancel\n ? onCancel()\n : goBackOrTo(navigate, { cancelPath }))}>{wizardShowingSuccess ? 'Close' : 'Cancel'}</Button>\n {wizardEnabled && activeWizardStep > 0 && !wizardShowingSuccess && (\n <WizardBackButton disabled={Boolean(wizardRuntime.busy)} onClick={() => goToWizardStep(activeWizardStep - 1)} />\n )}\n {!wizardShowingSuccess && (!wizardEnabled || activeWizardStep === wizardSteps.length - 1 || wizardNextIsSuccess) ? formActions.map((action, index) => (\n <FormActionButton\n key={`${action.label ?? 'action'}-${index}`}\n form={form}\n groups={groups}\n action={action}\n disabled={!isFormReady || submitLoading || uniquePending > 0 || !groups.length}\n loading={submitLoading}\n onFire={() => {\n pendingAfterSubmitRef.current = action.afterSubmit ?? { mode: 'stay' };\n // Opt-in only — an action can force specific field\n // values right before submitting (e.g. a distinct\n // \"Schedule\" button implying scheduleForLater=true\n // without requiring the checkbox to be checked).\n if (action.setValuesBeforeSubmit) {\n form.setFieldsValue(action.setValuesBeforeSubmit);\n }\n form.submit();\n }}\n />\n )) : null}\n {wizardEnabled && activeWizardStep < wizardSteps.length - 1 && !wizardNextIsSuccess ? (\n <WizardNextButton onClick={advanceWizard}\n loading={wizardRuntime.busy === 'next'}\n disabled={!isFormReady || submitLoading || uniquePending > 0 || !groups.length || Boolean(wizardRuntime.busy)} />\n ) : !wizardShowingSuccess ? (\n <ValidationGatedSubmitButton\n form={form}\n groups={groups}\n onClick={() => { pendingAfterSubmitRef.current = null; form.submit(); }}\n disabled={!isFormReady || submitLoading || uniquePending > 0 || !groups.length || Boolean(wizardRuntime.busy)}\n loading={submitLoading || wizardRuntime.busy === 'finish'}\n >\n {submitText}\n </ValidationGatedSubmitButton>\n ) : null}\n </Space>\n </div>\n )}\n\n {/* Search results ListView — rendered inside AddFormV1 when in search mode */}\n {isSearch && searchResults.searched && (\n <ListView\n moduleName={moduleName}\n breadcrumbItems={[]}\n dataSource={searchResults.rows}\n fields={searchFieldsWithActions}\n total={searchResults.total}\n loading={searchResults.loading}\n current={searchPagination.current}\n pageSize={searchPagination.pageSize}\n showViewToggle\n activeView={viewMode}\n onViewChange={setViewMode}\n onPageChange={handleSearchPageChange}\n onPageSizeChange={handleSearchPageSizeChange}\n showSearch={false}\n tabs={tabs}\n selectedSource={selectedSource}\n onTabChange={handleTabChange}\n actions={searchResultActions}\n actionRules={searchResults.actionRules}\n />\n )}\n </div>}\n </main>\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"AddFormV1-Crwu7zyB.js","names":[],"sources":["../src/utils/autoValueRules.js","../src/components/form/duplicateRecord.js","../src/components/form/useDuplicateCheck.js","../src/components/form/storedFileName.js","../src/services/pendingHandoff.js","../src/services/skillMatchApi.js","../src/services/candidatesApi.js","../src/services/sourceProviderActions.js","../src/components/AddFormV1.jsx"],"sourcesContent":["// Field-level \"force a value based on who is submitting\" rules.\n//\n// This is the FRONTEND half of an admin-configured feature (formGroupConfig →\n// field.autoValueRules), e.g. a submission's \"Submit Source\" that must read\n// External when an employer-type user submits and Internal for everyone else.\n//\n// It mirrors the backend exactly (models.AutoValueRule.Matches +\n// applyAutoValueRules in moduleWriteOrchestrator.go). The backend is the\n// authority — it re-evaluates these rules from the auth token on every\n// create/update, so a request that bypasses the UI is still corrected. This copy\n// exists purely so the user SEES the forced value while filling the form.\n//\n// Nothing here special-cases a module, field, role or value: which roleId/userId\n// maps to which value is entirely admin data.\n\n// autoValueFor evaluates a field's rules against the acting user's identity\n// ({roleId, userId}). whenRoleId and whenUserId are OR-ed; a rule with neither\n// set never fires. First matching rule wins — same as the backend.\nexport function autoValueFor(field, identity = {}) {\n const rules = Array.isArray(field?.autoValueRules) ? field.autoValueRules : [];\n for (const rule of rules) {\n const roles = Array.isArray(rule?.whenRoleId) ? rule.whenRoleId.map(Number) : [];\n const users = Array.isArray(rule?.whenUserId) ? rule.whenUserId.map(Number) : [];\n const roleHit = identity.roleId !== undefined && roles.includes(identity.roleId);\n const userHit = identity.userId !== undefined && users.includes(identity.userId);\n if (roleHit || userHit) return { matched: true, value: rule.value };\n }\n return { matched: false, value: undefined };\n}\n\nexport default autoValueFor;\n","// ─────────────────────────────────────────────────────────────────────────\n// duplicateRecord — the client half of the staged duplicate check.\n//\n// The backend (POST /v1/module/duplicate-check) decides WHETHER a record is a\n// duplicate, entirely from the module's configured stages. This module decides\n// only how to SAY it, and it takes every word from config too:\n//\n// automations.duplicateCheck.message → the sentence, with {tokens}\n// automations.duplicateCheck.policy → \"prompt\" (offer to update) | \"block\"\n// automations.duplicateCheck.displayFields → which keys name the record\n//\n// Nothing here knows a module, a field, or how long \"recently\" is.\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * describeAge — \"how stale is the existing record?\", in words.\n *\n * The requirement asks for exactly this: \"in the error message we need to show\n * last updated date — for example 60 days back the same candidate is updated,\n * like that — so we can get a proper idea that the candidate already was there\n * with the date.\"\n *\n * A bare date (\"07 Aug 2026\") makes the reader do the arithmetic; the elapsed\n * time is the part that carries the decision, so both are offered and the\n * caller's template chooses.\n */\nexport function describeAge(daysAgo) {\n // null/undefined/'' must NOT fall through to Number()'s 0, which would render\n // a record with no timestamp at all as \"updated today\" — a confident false\n // statement about exactly the fact the user is being asked to judge.\n if (daysAgo === null || daysAgo === undefined || daysAgo === '') return '';\n const days = Number(daysAgo);\n if (!Number.isFinite(days) || days < 0) return '';\n if (days === 0) return 'today';\n if (days === 1) return 'yesterday';\n if (days < 30) return `${days} days ago`;\n if (days < 60) return 'about a month ago';\n if (days < 365) return `about ${Math.round(days / 30)} months ago`;\n const years = Math.floor(days / 365);\n return years === 1 ? 'over a year ago' : `over ${years} years ago`;\n}\n\n/**\n * describeRecord — a human label for the matched record, built from whichever\n * of the configured display fields actually carry a value.\n */\nexport function describeRecord(record, displayFields) {\n const keys = Array.isArray(displayFields) && displayFields.length\n ? displayFields\n : Object.keys(record ?? {});\n const parts = keys\n .map((key) => record?.[key])\n .map((v) => (v === null || v === undefined ? '' : String(v).trim()))\n .filter(Boolean);\n return parts.join(' · ');\n}\n\n/**\n * fillTemplate — {token} substitution. An unknown token is left INTACT so a\n * typo in admin config is visible rather than silently blanking the sentence.\n */\nexport function fillTemplate(template, tokens = {}) {\n if (!template) return '';\n return String(template).replace(\n /\\{(\\w+)\\}/g,\n (match, key) => (tokens[key] === undefined ? match : String(tokens[key])),\n );\n}\n\n/**\n * duplicateTokens — everything a configured message may reference.\n */\nexport function duplicateTokens(result, displayFields) {\n const name = describeRecord(result?.record, displayFields);\n const age = describeAge(result?.updatedDaysAgo);\n return {\n name: name || 'an existing record',\n age: age || 'previously',\n days: Number.isFinite(Number(result?.updatedDaysAgo)) ? String(result.updatedDaysAgo) : '',\n updatedOn: result?.updatedAt ? String(result.updatedAt).slice(0, 10) : '',\n stage: result?.stage ?? '',\n weight: result?.weight ?? '',\n };\n}\n\n// Default wording, used until an admin writes their own. Deliberately states\n// BOTH the identity and the age, because those are the two things that let\n// someone decide whether this really is the same person.\nexport const DEFAULT_DUPLICATE_MESSAGE =\n 'We already have {name} on file \\u2014 last updated {age}. '\n + 'You can carry on and update that record with what you\\u2019ve just entered, '\n + 'or go back and check first.';\n\nexport const DEFAULT_BLOCK_MESSAGE =\n 'We already have {name} on file \\u2014 last updated {age}. '\n + 'Please open that record and update it, rather than adding a second copy.';\n\n/**\n * duplicateMessage — the finished sentence for a result.\n */\nexport function duplicateMessage(result, cfg = {}) {\n const tokens = duplicateTokens(result, cfg.displayFields);\n const isBlock = (result?.policy ?? cfg.policy) === 'block';\n const template = result?.message\n || cfg.message\n || (isBlock ? DEFAULT_BLOCK_MESSAGE : DEFAULT_DUPLICATE_MESSAGE);\n return fillTemplate(template, tokens);\n}\n\n/**\n * duplicateBlocks — should the create be refused outright?\n *\n * The response's own policy wins (it comes from the module config the backend\n * actually applied); the caller's config is only a fallback for a backend that\n * predates the field. Default is \"prompt\", so a misconfiguration inconveniences\n * rather than blocks.\n */\nexport function duplicateBlocks(result, cfg = {}) {\n if (!result?.duplicate) return false;\n return (result.policy ?? cfg.policy ?? 'prompt') === 'block';\n}\n\n/**\n * duplicateFacts — the matched record as scannable label/value pairs.\n *\n * The prose sentence carries the same information, but a reader deciding \"is\n * this the same person?\" should not have to parse it out of a paragraph. The\n * facts that settle it are WHO and HOW STALE, so those are surfaced; whatever\n * else the module chose to display comes with them.\n *\n * Labels are derived from the key itself (\"firstName\" → \"First name\"), so a\n * module that adds a display field gets a sensible label with no extra config.\n */\nexport function duplicateFacts(result, displayFields) {\n const record = result?.record ?? {};\n const keys = Array.isArray(displayFields) && displayFields.length\n ? displayFields\n : Object.keys(record);\n\n const facts = keys\n .map((key) => ({ label: humanizeKey(key), value: record[key] }))\n .filter((f) => f.label && f.value !== undefined && f.value !== null && String(f.value).trim() !== '');\n\n const age = describeAge(result?.updatedDaysAgo);\n if (age) facts.push({ label: 'Last updated', value: age });\n return facts;\n}\n\n// humanizeKey — \"firstName\" / \"contact_number\" → \"First name\".\n// Only the first word is capitalised: these are labels in a list, not titles.\nfunction humanizeKey(key) {\n const words = String(key ?? '')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/[_\\-.]+/g, ' ')\n .trim()\n .toLowerCase();\n return words ? words.charAt(0).toUpperCase() + words.slice(1) : '';\n}\n","// ─────────────────────────────────────────────────────────────────────────\n// useDuplicateCheck — \"have we got this person already?\", asked at the moment\n// it is useful.\n//\n// WHEN IT RUNS\n// • right after a résumé has been read and the form filled in, because that\n// is the first time an email and phone number exist to check;\n// • again on submit, as the authoritative gate.\n//\n// WHAT IT SHOWS\n// A dialog naming the existing record and how long ago it was touched, with the\n// two things a user can actually do: open that record and update it (the new\n// file is kept as another version), or go back and look again. Every word comes\n// from the module's own config — see components/form/duplicateRecord.js.\n//\n// It FAILS OPEN. A check that cannot run (offline, a backend that predates the\n// endpoint, a module with no stages configured) must never stop someone\n// creating a legitimate record.\n// ─────────────────────────────────────────────────────────────────────────\nimport { useCallback, useRef, useState } from 'react';\nimport { checkDuplicateRecord } from '../../services/uniqueValidationApi';\nimport { duplicateMessage, duplicateBlocks, duplicateFacts } from './duplicateRecord';\nimport { openFormDecision, openFormNotice } from './formDecisionDialog';\n\n/**\n * @param {object} opts\n * @param {object} opts.form the antd form instance\n * @param {string} opts.moduleName module being created\n * @param {string} [opts.recordId] set on EDIT, so a record never matches itself\n * @param {object} [opts.config] { message, policy, displayFields } fallback\n * @param {function}[opts.onUseExisting] called with the matched id when the user\n * chooses to update the existing record\n */\nexport default function useDuplicateCheck({\n form,\n moduleName,\n recordId,\n config = {},\n onUseExisting,\n} = {}) {\n const [checking, setChecking] = useState(false);\n // Remembers a match the user has already accepted, so submitting after\n // choosing \"update the existing one\" does not ask the same question twice.\n const acknowledged = useRef(null);\n\n /**\n * check — ask the backend.\n *\n * `payload` overrides the form's own values. That matters right after a\n * résumé is read: the parsed email and phone exist in the RESPONSE and are\n * not on the form yet, so checking the form would ask about a blank page.\n */\n const check = useCallback(async (payload) => {\n if (!moduleName) return { duplicate: false };\n setChecking(true);\n try {\n return await checkDuplicateRecord({\n module: moduleName,\n payload: payload ?? form.getFieldsValue(true) ?? {},\n excludeId: recordId,\n });\n } finally {\n setChecking(false);\n }\n }, [form, moduleName, recordId]);\n\n /**\n * prompt — run the check and, if something matches, ask.\n *\n * Resolves to:\n * 'clear' nothing matched — carry on\n * 'existing' the user chose to update the record we already have\n * 'blocked' the module is set to refuse, or the user backed out\n */\n const prompt = useCallback(async ({ reason, payload, carry } = {}) => {\n const result = await check(payload);\n if (!result?.duplicate) {\n acknowledged.current = null;\n return 'clear';\n }\n if (acknowledged.current && acknowledged.current === result.id) return 'existing';\n\n const body = duplicateMessage(result, config);\n // The two things that actually decide the answer — WHO matched and HOW OLD\n // that record is — are shown as facts rather than left inside the sentence.\n const facts = duplicateFacts(result, config.displayFields);\n // A stage-1 hit (email or phone) is near proof; a stage-2 hit (name only)\n // is a maybe. Saying which stops both being read with the same weight.\n const heading = result.weight === 'weak'\n ? 'This might be someone you already have'\n : 'You already have this person on file';\n\n if (duplicateBlocks(result, config)) {\n await openFormNotice({ tone: 'duplicate', title: heading, facts, body });\n return 'blocked';\n }\n\n const useExisting = await openFormDecision({\n tone: 'duplicate',\n title: heading,\n facts,\n body,\n // Naming the OUTCOMES rather than \"OK\"/\"Cancel\": the choice is between\n // two different results, and neither is obviously the default.\n okText: 'Open their record',\n cancelText: 'Let me check first',\n // Says what happens to the FILE, because that is the thing the user has\n // just spent effort on and the thing they will assume is lost.\n footnote: carry?.files\n ? 'We\\u2019ll take you to their record with the r\\u00e9sum\\u00e9 you just uploaded already '\n + 'attached \\u2014 save there to keep it. The one already on file is kept too, as an '\n + 'earlier version. Nothing on this form has been filled in.'\n : 'Everything already on their record is kept. Nothing on this form has been filled in.',\n });\n\n if (!useExisting) return 'blocked';\n acknowledged.current = result.id ?? true;\n // The whole result is handed over, because it carries `editRoute` — the\n // configured path for opening the matched record. The caller must never\n // derive that path; see DuplicateCheckStrategy.EditRoute.\n // `carry` travels through untouched — today the file the user just\n // uploaded, so it arrives with them at the existing record instead of\n // having to be found and attached again.\n onUseExisting?.(result.id, result, reason, carry);\n return 'existing';\n }, [check, config, onUseExisting]);\n\n return { prompt, check, checking, acknowledgedId: acknowledged };\n}\n","// =============================================================================\n// The display name of an ALREADY-STORED file\n// -----------------------------------------------------------------------------\n// Legacy candidate schemas are NOT uniform about where a file's original name\n// lives, and the fileFieldMaps config says so out loud:\n//\n// passport passportUploadName ← \"upload name\"\n// alternateVisa alternateVisaUploadName ← \"upload name\"\n// visa visaUniqueName ← \"UNIQUE name\" holds the\n// ORIGINAL name here\n// resume uploadedFileName\n//\n// Matching only on `*UploadName` therefore found nothing for a visa, the name\n// resolved to empty, and the form fell back to the literal string \"file\" — so a\n// submission prefilled from a candidate showed Passport and Alternate Visa\n// correctly and the Visa as an anonymous \"file\". The user could not tell what\n// had been attached, or whether it was the right document.\n//\n// Ordering matters as much as the keys. `*CopyUniqueName` holds the SANITISED\n// name (\"Resume_of_Vinoth_Satti.doc\"), so it is consulted last: it is better\n// than \"file\", but it is not what the user uploaded.\n// =============================================================================\n\n/** Suffix groups, best first. Each is matched case-insensitively. */\nconst NAME_KEY_SUFFIXES = [\n // The original filename, under the two names the schemas give it.\n ['uploadname', 'uploadedfilename', 'originalname', 'filename'],\n // visa reuses \"unique name\" for the original — but NOT the \"copy unique\n // name\", which is the sanitised form and is handled in the next group.\n ['uniquename'],\n];\n\nconst SANITISED_SUFFIX = 'copyuniquename';\n\nfunction suffixMatch(key, suffixes, { excludeSanitised = false } = {}) {\n const lower = String(key).toLowerCase();\n if (excludeSanitised && lower.endsWith(SANITISED_SUFFIX)) return false;\n return suffixes.some((suffix) => lower.endsWith(suffix));\n}\n\n/**\n * storedFileName — the name to show for a stored file container.\n *\n * Returns '' when the object carries no usable name, so the caller decides what\n * to do about that rather than being handed a placeholder that looks like data.\n */\nexport function storedFileName(value) {\n if (!value || typeof value !== 'object') return '';\n\n const direct = value.uploadedFileName ?? value.name;\n if (typeof direct === 'string' && direct.trim()) return direct.trim();\n\n const entries = Object.entries(value)\n .filter(([, v]) => typeof v === 'string' && v.trim());\n\n for (const suffixes of NAME_KEY_SUFFIXES) {\n const hit = entries.find(([k]) => suffixMatch(k, suffixes, { excludeSanitised: true }));\n if (hit) return hit[1].trim();\n }\n // Last resort: the sanitised copy name. Underscored and not what was\n // uploaded, but it names the document, which \"file\" does not.\n const sanitised = entries.find(([k]) => String(k).toLowerCase().endsWith(SANITISED_SUFFIX));\n return sanitised ? sanitised[1].trim() : '';\n}\n\n/**\n * storedFileUrl — the storage location of a stored file container, under any of\n * the names the legacy schemas use.\n */\nexport function storedFileUrl(value) {\n if (!value || typeof value !== 'object') return '';\n const direct = value.location ?? value.url;\n if (typeof direct === 'string' && direct.trim()) return direct.trim();\n const hit = Object.entries(value).find(([k, v]) => (\n typeof v === 'string' && v.trim() && String(k).toLowerCase().endsWith('copylocation')\n ));\n return hit ? hit[1].trim() : '';\n}\n","// pendingHandoff — pass an in-flight Promise from one route to the next.\n//\n// react-router's navigate(path, { state }) stores `state` via\n// history.pushState, which requires the value to be STRUCTURED-CLONEABLE.\n// A Promise is not: passing one directly throws\n// \"Failed to execute 'pushState' on 'History': #<Promise> could not be\n// cloned\" — silently killing the navigation itself, not just the feature that\n// tried to carry the promise.\n//\n// The fix is a token indirection: stash the promise in an in-memory map and\n// hand nav state a plain string key instead. Both routes live in the same SPA\n// runtime, so the map survives the navigation; a hard reload or a link opened\n// in a new tab naturally has no entry, which callers must treat as \"nothing to\n// wait for\" (never as an error).\nconst pending = new Map();\nlet counter = 0;\n\n/**\n * Stash a promise and return a token to carry through navigate(path, { state }).\n * @param {Promise<any>} promise\n * @returns {string} token\n */\nexport function stashPendingPromise(promise) {\n const token = `ph_${Date.now()}_${(counter += 1)}`;\n pending.set(token, promise);\n // Self-cleaning: if the destination never mounts to consume it (the user\n // cancels, or navigates elsewhere first), don't hold the promise forever.\n promise.finally(() => {\n setTimeout(() => pending.delete(token), 0);\n }).catch(() => {}); // already-handled elsewhere; this is only cleanup\n return token;\n}\n\n/**\n * Retrieve and remove a stashed promise by token. Returns undefined for an\n * unknown/already-consumed token — callers must treat that as \"nothing to\n * wait for\", not as an error (e.g. the page was reloaded, or opened directly).\n * @param {string | undefined} token\n * @returns {Promise<any> | undefined}\n */\nexport function takePendingPromise(token) {\n if (!token) return undefined;\n const promise = pending.get(token);\n pending.delete(token);\n return promise;\n}\n","import { ensureToken } from './authApi';\nimport { AUTH_URL } from './apiConfig';\n\n// ── Relevant-skill matching ─────────────────────────────────────────────────\n// Which of a candidate's skills does this job actually need?\n//\n// Sends IDS ONLY. The gateway reads both records from the caller's own\n// tenant-scoped database and calls the configured AI service, so this file —\n// like every other service module here — never holds a service URL or a\n// credential.\n//\n// NEVER THROWS and never rejects: the only caller is a submission flow, and a\n// failed match must degrade to \"the recruiter fills Relevant Skills by hand\",\n// exactly as today. An empty list is the honest answer for every failure.\n\n/**\n * @param {Object} args\n * @param {string} args.jobId\n * @param {string} args.applicantId\n * @param {number} [args.timeoutMs=15000] give up and return [] after this\n * @returns {Promise<string[]>} the candidate's skills this job asks for\n */\nexport async function matchRelevantSkills({ jobId, applicantId, timeoutMs = 15000 }) {\n if (!jobId || !applicantId) return [];\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const token = await ensureToken();\n const res = await fetch(`${AUTH_URL}/skill-match`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ jobId, applicantId }),\n signal: controller.signal,\n });\n if (!res.ok) return [];\n const json = await res.json();\n const skills = json?.data?.relevantSkills ?? json?.relevantSkills;\n return Array.isArray(skills) ? skills.filter((s) => typeof s === 'string' && s.trim()) : [];\n } catch {\n // Aborted, offline, 5xx, malformed body — all the same outcome.\n return [];\n } finally {\n clearTimeout(timer);\n }\n}\n","import { apiGetWithAuth, fetchJsonWithAuth, ensureToken } from './authApi';\nimport { AUTH_URL, CANDIDATES_URL, JOBS_URL } from './apiConfig';\n\nexport async function getCandidateSummary(startDate, endDate) {\n const params = new URLSearchParams();\n if (startDate) params.set('startDate', startDate);\n if (endDate) params.set('endDate', endDate);\n const query = params.toString();\n return apiGetWithAuth(CANDIDATES_URL, `/profile-summary${query ? `?${query}` : ''}`);\n}\n\nexport async function getQuickSubmitCandidates({ isFromSubmission, jobId, submissionId, search = '' } = {}) {\n const body = { search };\n if (isFromSubmission) {\n body.submissionId = submissionId;\n } else {\n body.jobId = jobId;\n }\n const json = await fetchJsonWithAuth(CANDIDATES_URL, '/quicksubmit/list', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n return json.data ?? json;\n}\n\nexport async function getCandidateFormGroups(options = {}) {\n const token = await ensureToken();\n const params = new URLSearchParams({ module: 'candidates' });\n if (options.id) params.set('id', options.id);\n const res = await fetch(`${AUTH_URL}/admin/form-groups?${params}`, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },\n });\n if (!res.ok) throw new Error(`API ${res.status}: ${res.statusText}`);\n const json = await res.json();\n return json.data ?? json;\n}\n\nexport async function getMentionUsers(search = '') {\n const params = search ? `?search=${encodeURIComponent(search)}` : '';\n return apiGetWithAuth(JOBS_URL, `/users/any${params}`);\n}\n\nexport async function migrateDiceCandidate(diceId) {\n if (!diceId) throw new Error('Dice candidate ID is required');\n\n const token = await ensureToken();\n const url = `${AUTH_URL}/dicemigrate/${encodeURIComponent(String(diceId))}`;\n // const url = `http://localhost:9009/v1/dicemigrate/${encodeURIComponent(String(diceId))}`;\n if (process.env.NODE_ENV === 'development') {\n console.log('[DiceMigration] Request URL:', url);\n }\n const response = await fetch(\n url,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n },\n );\n\n const payload = await response.json().catch(() => null);\n if (!response.ok) {\n const error = new Error(\n payload?.message\n ?? payload?.error\n ?? `Failed to migrate candidate (${response.status})`,\n );\n error.status = response.status;\n throw error;\n }\n\n return payload;\n}\n","import { migrateDiceCandidate } from './candidatesApi';\nimport { resolveDiceProfileId } from './diceCandidateMapper';\n\nexport function normalizeSourceKey(value) {\n if (value && typeof value === 'object') {\n return normalizeSourceKey(value.value ?? value.key ?? value.id ?? value.label ?? value.name);\n }\n\n return String(value ?? '').trim().toLowerCase();\n}\n\nexport function getSearchSources(value) {\n return (Array.isArray(value) ? value : [value])\n .flat()\n .map(normalizeSourceKey)\n .filter((item, index, source) => item && item !== 'all' && source.indexOf(item) === index);\n}\n\nexport function resolveSearchSource(value, fallback = 'internal') {\n const sources = getSearchSources(value);\n if (sources.includes('internal')) return 'internal';\n const normalizedFallback = normalizeSourceKey(fallback);\n if (sources[0]) return sources[0];\n if (normalizedFallback) return normalizedFallback;\n return fallback === '' ? '' : 'internal';\n}\n\n// Which module key answers for each source tab, as { [sourceKey]: moduleKey }.\n// A source with no entry uses the form's own module, which is every source on\n// every form until someone configures otherwise.\n//\n// Two places can declare it and BOTH are honoured, config last so it wins:\n// 1. a `sourceModules` prop, for a host app that wants to say so in code\n// before the option key is persisted backend-side;\n// 2. the source option itself ({ value:'dice', module:'dice' }), which is what\n// the Admin option editor writes.\n//\n// Built once and shared, because the module has to be identical on both request\n// paths — the `/module-data-list` call and the unified search endpoint. They\n// each used to work it out for themselves, and only one of the two read config,\n// so the Dice tab asked for Candidates' columns and actions.\nexport function buildSourceModuleMap(fields, sourceModules) {\n const map = { ...(sourceModules ?? {}) };\n\n (Array.isArray(fields) ? fields : [])\n .flatMap((field) => (Array.isArray(field?.options) ? field.options : []))\n .forEach((option) => {\n const key = normalizeSourceKey(option?.value);\n // Blank is not a value: it means \"use the form's module\", the same reading\n // the Admin editor gives it by refusing to store an empty module.\n const module = String(option?.module ?? '').trim();\n if (key && module) map[key] = module;\n });\n\n return map;\n}\n\nfunction toTitle(value) {\n return String(value ?? '')\n .replace(/[-_]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n}\n\n// The key a tab is MATCHED by — lowercased, so a configured source and the\n// backend's spelling of it land on the same map entry.\nfunction getTabKey(tab) {\n return normalizeSourceKey(rawTabKey(tab));\n}\n\n// The key a tab is EMITTED with, which is what goes back to the API when the tab\n// is clicked. It has to survive verbatim: a source key is lowercase either way,\n// but a field-based tab like \"myJobs\" is not, and sending \"myjobs\" would filter\n// on a value no record has.\nfunction rawTabKey(tab) {\n const key = tab?.key ?? tab?.value ?? tab?.id ?? tab?.source ?? tab?.name ?? tab?.title ?? tab?.label;\n return String(key ?? '').trim();\n}\n\nfunction getTabCount(tab) {\n const count = tab?.count ?? tab?.countValue;\n const number = Number(count);\n return Number.isFinite(number) ? number : undefined;\n}\n\nfunction getSourceCount(source, responseCounts, currentCounts, activeSource, activeCount) {\n // Both endpoints report a count for EVERY requested source, not just the one\n // being viewed — module-data-list in `count.internal`/`count.dice`, boolean\n // search in the same shape. So the live response wins for any tab; restricting\n // this to the active source left the other tab showing a stale cached figure\n // (or none) even though the number was sitting right there in the response.\n const responseCount = Number(responseCounts?.[source]);\n if (Number.isFinite(responseCount)) return responseCount;\n\n if (source === activeSource) {\n const activeTotal = Number(activeCount);\n if (Number.isFinite(activeTotal)) return activeTotal;\n }\n\n const currentCount = currentCounts.get(source);\n if (currentCount !== undefined) return currentCount;\n\n return undefined;\n}\n\nexport function buildSourceTabs({\n sources = [],\n activeSource = 'internal',\n activeCount = 0,\n responseCounts = {},\n currentTabs = [],\n backendTabs = [],\n} = {}) {\n const currentCounts = new Map(\n (Array.isArray(currentTabs) ? currentTabs : [])\n .map((tab) => [getTabKey(tab), getTabCount(tab)])\n .filter(([source, count]) => source && count !== undefined),\n );\n\n const sourceMap = new Map();\n\n // Pass 1 — the CONFIGURED sources define the order. Seeding from backendTabs\n // instead put whichever tab was active first, because the backend only ever\n // returns a tab for the active source — so the strip reordered on every\n // switch. A Map keeps insertion order, and set() on an existing key updates\n // the value without moving it, which is what makes pass 2 order-safe.\n // Falling back to [activeSource] when nothing is configured used to invent an\n // \"Internal\" tab on every form, including modules with no source picker at\n // all — it would sit beside a Jobs form's real My Jobs / All Jobs tabs. With\n // no configured sources there is nothing to seed, and pass 2 lets the\n // backend's own tabs stand on their own.\n const selectedSources = getSearchSources(sources);\n const activeKey = normalizeSourceKey(activeSource);\n const seeds = selectedSources.length\n ? selectedSources\n : (activeKey ? [activeKey] : []);\n\n seeds.forEach((source) => {\n if (!source || sourceMap.has(source)) return;\n const count = getSourceCount(source, responseCounts, currentCounts, activeSource, activeCount);\n sourceMap.set(source, {\n key: source,\n title: toTitle(source),\n ...(count !== undefined ? { count } : {}),\n });\n });\n\n // Pass 2 — the backend contributes a real label and count, never a position.\n // Falling back to the previous count keeps a known figure on screen instead\n // of blanking it out the moment you switch away from that tab.\n (Array.isArray(backendTabs) ? backendTabs : []).forEach((tab) => {\n const key = getTabKey(tab);\n if (!key) return;\n const previous = sourceMap.get(key);\n const count = getTabCount(tab) ?? previous?.count ?? currentCounts.get(key);\n sourceMap.set(key, {\n // Matched case-insensitively, emitted as the backend spelled it.\n key: previous ? previous.key : rawTabKey(tab),\n title: tab.title ?? tab.label ?? tab.name ?? previous?.title ?? toTitle(key),\n ...(count !== undefined ? { count } : {}),\n });\n });\n\n return Array.from(sourceMap.values());\n}\n\nfunction collectSourceValues(record) {\n return [\n record?.sourceType,\n record?.profileSource,\n record?.selectedSource,\n record?.source,\n record?.provider,\n record?.customFields?.sourceType,\n record?.customFields?.profileSource,\n record?.customFields?.source,\n record?.customFields?.provider,\n ].flat().map(normalizeSourceKey).filter(Boolean);\n}\n\nfunction recordMatchesSource(record, sourceKey, marker) {\n const normalizedSource = normalizeSourceKey(sourceKey);\n if (!normalizedSource) return false;\n if (collectSourceValues(record).includes(normalizedSource)) return true;\n return typeof marker === 'function' ? marker(record) : false;\n}\n\nconst SOURCE_ACTIONS = [\n {\n source: 'dice',\n field: '__sourceAction_dice_migrate',\n label: 'Action',\n buttonLabel: 'Migrate',\n completedLabel: 'Migrated',\n successMessage: 'Candidate migrated successfully.',\n errorMessage: 'Failed to migrate candidate.',\n isRecordFromSource: (record) => Boolean(record?.customFields?.diceProfileData),\n getRecordId: resolveDiceProfileId,\n execute: migrateDiceCandidate,\n },\n];\n\nexport function getAvailableSourceActions({ rows = [], selectedSource = '' } = {}) {\n return SOURCE_ACTIONS.filter((action) => {\n const selectedMatches = normalizeSourceKey(selectedSource) === action.source;\n return selectedMatches || rows.some((record) => recordMatchesSource(record, action.source, action.isRecordFromSource));\n });\n}\n\nexport function sourceActionAppliesToRecord(action, record, selectedSource = '') {\n return normalizeSourceKey(selectedSource) === action.source\n || recordMatchesSource(record, action.source, action.isRecordFromSource);\n}\n\nexport function getSourceActionInstanceKey(action, record) {\n const id = action?.getRecordId?.(record);\n return id ? `${action.source}:${action.field}:${id}` : '';\n}\n\nexport async function runSourceAction(action, record) {\n const id = action?.getRecordId?.(record);\n if (!id) throw new Error(`${action?.buttonLabel ?? 'Action'} ID is required`);\n return action.execute(id, record);\n}\n","import { Fragment, createContext, forwardRef, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState, useCallback } from 'react';\nimport dayjs from 'dayjs';\nimport {\n Alert,\n Button,\n Card,\n Checkbox,\n Col,\n DatePicker,\n Form,\n Input,\n message,\n Radio,\n Row,\n Select,\n Space,\n Spin,\n Switch,\n TimePicker,\n Tooltip,\n Typography,\n Upload,\n} from 'antd';\nimport {\n CalendarOutlined,\n CloudUploadOutlined,\n DeleteOutlined,\n DownOutlined,\n EnvironmentOutlined,\n EyeOutlined,\n FileExcelOutlined,\n FileImageOutlined,\n FileOutlined,\n FilePdfOutlined,\n FileTextOutlined,\n FileWordOutlined,\n InfoCircleOutlined,\n LockOutlined,\n MailOutlined,\n PhoneOutlined,\n PlusOutlined,\n SolutionOutlined,\n TagsOutlined,\n UpOutlined,\n UserOutlined,\n} from '@ant-design/icons';\nimport TipTapEditor from './TipTapEditor';\nimport DocumentViewer from './DocumentViewer';\nimport { useLocation, useNavigate, useParams, useSearchParams } from 'react-router-dom';\nimport { fetchJsonWithAuth, getActingIdentity } from '../services/authApi';\nimport { autoValueFor } from '../utils/autoValueRules';\nimport { AUTH_URL } from '../services/apiConfig';\nimport { getDropdownValues, searchModuleData } from '../services/moduleDataApi';\nimport { getFormGroups, createModuleRecord } from '../services/addFormApi';\nimport { verifyEmail, getModuleDefaultFields } from '../services/adminApi';\nimport { uploadModuleDocuments } from '../services/documentApi';\nimport { getAdminClients, getCustomForms, getRoleFormPermissions } from '../services/adminApi';\nimport { updateRecord } from '../services/detailedViewApi';\nimport { loadDetailDefaults, formatPhone, phoneDigits, parsePhoneFormat } from '../services/detailDefaults';\nimport { groupAllowedByRole, fieldAllowedByRole, fieldEditableByRole } from '../utils/roleFormPermissionGate';\nimport { buildPayload, buildInitialValue, buildRepeatFieldInitial, singleFieldOf, collectFileParts, effectiveDataType, getDeep, toSelectControlValue, usesLabeledSelectValue, rowDefaultsFor } from './form/payloadTransformer';\nimport { computeLinkedSets, findLinkedSet, padLinkedInitialValues } from './form/linkedAddRowGroups';\nimport useAiActions, { groupActionsByPosition } from './form/useAiActions';\nimport AiActionButtonGroup from './form/AiActionButtons';\nimport { applyInputValidator, getKeyPattern } from './form/inputValidator';\nimport { configuredEmailRule, isValidConfiguredEmail } from './form/emailValidator';\nimport { securityValidationRule } from './form/inputSecurity';\nimport {\n buildUniqueValidationRule,\n attachUniqueSyncGuards,\n collectUniqueRules,\n createUniqueChecker,\n extractDuplicateFieldErrors,\n} from './form/uniqueFieldValidation';\nimport {\n checkFieldUnique,\n createSupersedingUniqueCheck,\n normalizeUniqueCheckDebounceMs,\n uniqueCheckItemProps,\n} from '../services/uniqueValidationApi';\nimport { uploadAcceptCategory } from './form/uploadAccept';\nimport { useQuickField } from './form/QuickCreateEditField';\nimport { maxFromFieldRule, maxFromFieldDependency, resolveScopedFieldPath } from './form/crossFieldRules';\nimport { checkMaxWithFallback, parseCompareFields, readCompareValue, resolveCompareFieldName } from './form/maxCeiling';\nimport { contextRecordId } from './form/contextPrefill';\nimport ValidationOverrideCheckbox from './form/ValidationOverrideCheckbox';\nimport {\n overrideConfig,\n overrideFlagPath,\n overrideRuleMapper,\n} from './form/validationOverride';\nimport { prefillWhenWatchFields, prefillWhenWatchPaths, resolvePrefillWhen } from './form/prefillWhenRules';\nimport { narrowOptionsByConstraint, stripExclusivePrefillOptions } from './form/optionConstraints';\nimport { filterLookupOptionRows, lookupExtraFieldKeys } from './form/optionRowFilters';\nimport {\n normalizeCourseModuleLessonRows,\n withCourseModuleLessonExtraFields,\n} from './form/courseModuleLessonLookup';\nimport { fieldTooltipText } from './form/fieldTooltip';\nimport { writeFormValue } from './form/applyGroupValues';\nimport { PARENT_FILTER_UNSEEN, shouldClearDependentValue } from './form/dependentLookupReset';\nimport { roleAllowsAction } from '../utils/roleAllowsAction';\nimport { resolveAfterSubmit, safeNavTarget } from '../utils/afterSubmitNav';\nimport { goBackOrTo } from '../utils/backNav';\nimport FormWizard, {\n buildFormWizardSteps,\n isWizardConfigEnabled,\n mergeWizardSubmitValues,\n wizardStepForGroup,\n wizardStepIndexForField,\n wizardValidationNames,\n WizardBackButton,\n WizardNextButton,\n} from './form/FormWizard';\nimport WizardStepContent from './form/WizardStepContent';\nimport { useWizardRuntime, WizardStepNotice } from './form/useWizardRuntime';\nimport { wizardAddRowView } from './form/wizardRuntime';\nimport useDuplicateCheck from './form/useDuplicateCheck';\nimport {\n resolveRegionRules,\n inProgressAllowed,\n inProgressBlocks,\n inProgressError,\n buildInProgressValidator,\n levelRuleVerdict,\n promptRowMove,\n} from './form/educationRules';\nimport { getDefaults } from '../services/detailDefaults';\nimport { openFormNotice, openFormDecision } from './form/formDecisionDialog';\nimport { applyGroupClear } from './form/clearGroupOnChange';\nimport { storedFileName, storedFileUrl } from './form/storedFileName';\nimport { fetchLookupLabels, mergeResolvedOptions, missingOptionValues } from './form/resolveStoredOptions';\nimport {\n buildPairValidator,\n buildRowHierarchyValidator,\n buildDisabledDate,\n defaultPickerValue,\n getComparableDateTime,\n getComparableTimeOfDay,\n} from './form/dateRules';\nimport { submitSuccessMessage, submitErrorMessage } from '../utils/submitMessages';\nimport { scrollToFirstFormError } from '../utils/scrollToFirstFormError';\nimport { conditionFieldPath, configuredFieldLabel, conditionMatches as labelConditionMatches, colWhenRules, resolveColSpan } from './form/conditionalFieldLabel';\nimport AppBreadcrumb from '../components/Breadcrumb';\nimport ListView from './ListView';\nimport { clearAuthTokenOverride, setAuthTokenOverride } from '../services/authApi';\nimport { takePendingPromise } from '../services/pendingHandoff';\nimport { matchRelevantSkills } from '../services/skillMatchApi';\nimport {\n buildSourceTabs,\n getAvailableSourceActions,\n getSearchSources,\n getSourceActionInstanceKey,\n resolveSearchSource,\n runSourceAction,\n sourceActionAppliesToRecord,\n} from '../services/sourceProviderActions';\n\nconst { Text } = Typography;\nconst { TextArea } = Input;\nconst emptyGroups = [];\n\nconst sectionIcons = [\n <UserOutlined />,\n <EnvironmentOutlined />,\n <SolutionOutlined />,\n <InfoCircleOutlined />,\n <FileTextOutlined />,\n];\n\nconst fieldIcons = {\n email: <MailOutlined className=\"v1-input-icon\" />,\n contactNumber: <PhoneOutlined className=\"v1-input-icon\" />,\n phone: <PhoneOutlined className=\"v1-input-icon\" />,\n currentLocation: <EnvironmentOutlined className=\"v1-input-icon\" />,\n preferredLocation: <EnvironmentOutlined className=\"v1-input-icon\" />,\n skills: <TagsOutlined className=\"v1-input-icon\" />,\n firstName: <UserOutlined className=\"v1-input-icon\" />,\n lastName: <UserOutlined className=\"v1-input-icon\" />,\n};\n\nconst truthy = (value) => value === true || value === 1 || value === '1';\nconst editable = (field, moduleName) => (field?.edit === undefined || truthy(field.edit))\n && (!field?.editablePermission || roleAllowsAction(field.editablePermission, moduleName));\n\nfunction normalizeOptions(options = []) {\n return options.map((option) => {\n if (typeof option === 'string') return { label: option, value: option };\n return {\n label: option.label ?? option.name ?? option.value,\n value: option.value ?? option.id ?? option.name ?? option.label,\n };\n });\n}\n\nfunction namePathFromString(path) {\n return String(path ?? '').split('.').map((part) => part.trim()).filter(Boolean);\n}\n\nfunction siblingFieldPath(absoluteName, key) {\n return Array.isArray(absoluteName) && absoluteName.length > 1\n ? [...absoluteName.slice(0, -1), key]\n : [key];\n}\n\n// VerifyFieldButton — admin-configured \"Verify\" button beside a field\n// (field.verifyAction, e.g. \"email\"). Calls the generic /email-verify\n// endpoint and writes the boolean result + a timestamp into two sibling\n// fields (verifyResultField/verifyTimestampField), within the same addRow\n// row when nested. Not specific to \"recruiter\" or any module — any field\n// can opt in.\nfunction VerifyFieldButton({ form, field, absoluteName }) {\n const [checking, setChecking] = useState(false);\n const [verdict, setVerdict] = useState(null);\n const verifiedValueRef = useRef(null);\n const resultValue = Form.useWatch(\n field.verifyResultField ? siblingFieldPath(absoluteName, field.verifyResultField) : ['__noop_verify__'],\n { form, preserve: true },\n );\n const currentValue = Form.useWatch(absoluteName, form);\n\n // A successful result belongs to the exact value that was checked. Existing\n // Edit records hydrate once; later source-value changes invalidate the\n // configured result so the form gate cannot accept a different email.\n useEffect(() => {\n const normalized = String(currentValue ?? '').trim();\n if (resultValue === true && verifiedValueRef.current === null && normalized) {\n verifiedValueRef.current = normalized;\n return;\n }\n if (resultValue === true && verifiedValueRef.current !== null && normalized !== verifiedValueRef.current) {\n if (field.verifyResultField) form.setFieldValue(siblingFieldPath(absoluteName, field.verifyResultField), false);\n if (field.verifyTimestampField) form.setFieldValue(siblingFieldPath(absoluteName, field.verifyTimestampField), undefined);\n verifiedValueRef.current = null;\n }\n }, [absoluteName, currentValue, field.verifyResultField, field.verifyTimestampField, form, resultValue]);\n\n if (field.verifyAction !== 'email') return null;\n\n const runVerify = async () => {\n const email = String(currentValue ?? '').trim();\n if (!email) {\n message.warning('Enter an email first');\n return;\n }\n setChecking(true);\n try {\n const result = await verifyEmail(email);\n verifiedValueRef.current = result.valid ? email : null;\n setVerdict(result.valid ? result : null);\n if (field.verifyResultField) form.setFieldValue(siblingFieldPath(absoluteName, field.verifyResultField), result.valid);\n if (field.verifyTimestampField) {\n form.setFieldValue(siblingFieldPath(absoluteName, field.verifyTimestampField), result.valid ? new Date().toISOString() : undefined);\n }\n // Three outcomes, not two. \"Accepted but unconfirmed\" is the common\n // case on catch-all domains (Google Workspace's default, and most\n // corporate mail) — reporting it as a plain success would tell the\n // user the mailbox exists when nothing proved that.\n if (!result.valid) {\n message.error(result.reason ? `Invalid email: ${result.reason}` : 'Email could not be verified');\n } else if (result.mailboxConfirmed) {\n message.success('Email verified \\u2014 the mail server confirmed this mailbox');\n } else {\n message.warning(result.reason || 'The domain can receive mail, but this exact mailbox could not be confirmed');\n }\n } catch (err) {\n verifiedValueRef.current = null;\n setVerdict(null);\n if (field.verifyResultField) form.setFieldValue(siblingFieldPath(absoluteName, field.verifyResultField), false);\n if (field.verifyTimestampField) form.setFieldValue(siblingFieldPath(absoluteName, field.verifyTimestampField), undefined);\n message.error(err?.message || 'Could not verify email');\n } finally {\n setChecking(false);\n }\n };\n\n if (resultValue === true) {\n // Accepted, but the mailbox itself was never proven (catch-all domain).\n // Labelling that \"Valid\" would overstate what the check established, so\n // it gets its own state. The address still passes the submit gate — the\n // account email that follows is what ultimately proves delivery.\n // Only positive evidence of \"unconfirmed\" downgrades the label. A\n // response that simply doesn't carry the field (older backend, or a\n // check that never reached the mailbox stage) keeps the plain success\n // state rather than casting doubt the check never actually raised.\n if (verdict && !verdict.mailboxConfirmed && (verdict.catchAll || verdict.result === 'risky')) {\n return (\n <Tooltip title={verdict.reason || 'This domain accepts every address, so the mailbox could not be confirmed. Delivery is proven only once the account email is actually sent.'}>\n <Text type=\"warning\" strong className=\"v1-verify-field-wrap\">\n {field.verifyUnconfirmedLabel || 'Accepted'}\n </Text>\n </Tooltip>\n );\n }\n return <Text type=\"success\" strong className=\"v1-verify-field-wrap\">{field.verifySuccessLabel || 'Valid'}</Text>;\n }\n\n return (\n <Button size=\"small\" loading={checking} onClick={runVerify} className=\"v1-verify-field-wrap\">\n {resultValue === false ? (field.verifyRetryLabel || 'Re Verify') : (field.verifyIdleLabel || 'Verify Email')}\n </Button>\n );\n}\n\nfunction ConfiguredFieldLabel({ form, field, siblingPrefix, locked, combined = false }) {\n const watchedValue = Form.useWatch(conditionFieldPath(field?.labelWhen, siblingPrefix), form);\n const label = configuredFieldLabel(field, watchedValue, combined);\n return combined ? label : <FieldLabel field={field} label={label} locked={locked} />;\n}\n\n// An ADDITIONAL admin-configured submit button (group.formActions). Same\n// validation gate as the primary Create button, plus an optional enabledWhen\n// gate that keeps it disabled until a field satisfies the condition (e.g. only\n// once \"Assign To\" is filled). `tone` picks primary vs secondary styling.\nfunction FormActionButton({ form, groups, action, disabled, loading, onFire }) {\n const unvalidated = Form.useWatch(\n (values) => groups.some((group) => {\n if (!group.addRow || !group.requireValidatedField) return false;\n const rows = values?.[group.name] ?? [];\n return rows.length === 0 || rows.some((row) => !row?.[group.requireValidatedField]);\n }),\n { form, preserve: true },\n );\n const gateValue = Form.useWatch(action?.enabledWhen?.field, form);\n const gateOk = !action?.enabledWhen?.field || groupShowIfMatches(action.enabledWhen, gateValue);\n return (\n <Button\n type={action?.tone === 'primary' ? 'primary' : 'default'}\n onClick={onFire}\n disabled={disabled || unvalidated || !gateOk}\n loading={loading}\n >\n {action?.label || 'Submit'}\n </Button>\n );\n}\n\nfunction ValidationGatedSubmitButton({ form, groups, disabled, loading, onClick, children }) {\n const unvalidated = Form.useWatch(\n (values) => groups.some((group) => {\n if (!group.addRow || !group.requireValidatedField) return false;\n const rows = values?.[group.name] ?? [];\n return rows.length === 0 || rows.some((row) => !row?.[group.requireValidatedField]);\n }),\n { form, preserve: true },\n );\n const isDisabled = disabled || unvalidated;\n // Config-driven \"why is this disabled\" tooltip: an admin sets\n // group.submitDisabledMessage (Admin → Form Groups). When a row-validation\n // gate is what's blocking, the more specific requireValidatedFieldMessage\n // (or a sensible default) is shown instead. Only rendered while disabled.\n const groupMsg = groups.find((g) => g.submitDisabledMessage)?.submitDisabledMessage;\n const validatedMsg = groups.find((g) => g.requireValidatedField)?.requireValidatedFieldMessage;\n const reason = unvalidated\n ? (validatedMsg || groupMsg || 'Verify every required row before submitting.')\n : (groupMsg || 'Complete all mandatory fields before submitting.');\n const button = (\n <Button type=\"primary\" onClick={onClick} disabled={isDisabled} loading={loading}>\n {children}\n </Button>\n );\n // A disabled antd Button has pointer-events:none, so the Tooltip must wrap a\n // span to receive hover.\n return isDisabled && !loading\n ? <Tooltip title={reason}><span style={{ display: 'inline-flex', cursor: 'not-allowed' }}>{button}</span></Tooltip>\n : button;\n}\n\n// PrefillWhenWatcher — sets ITS OWN field's value when a referenced field's\n// value matches a configured rule (e.g. contractType=\"W2\" forces employerId to\n// a fixed record id), and clears it back out when a rule says so or when no\n// rule matches any more. Opposite direction from autofillFrom (which pushes\n// into siblings when the changed field is a lookup select) — this field PULLS\n// its value from a field changing elsewhere. A tiny standalone component (not\n// inline logic) because Form.useWatch is a hook and must run in component\n// scope, not inside the plain renderField() function.\n//\n// ALL of the decision-making lives in form/prefillWhenRules.js so this form and\n// EditFormV1 can never disagree about what a rule means, and so the rules can\n// be unit-tested without importing either form (any render test that touches\n// them dies on jsdom's missing DOMMatrix, via react-pdf).\n//\n// `watchPaths` carries EVERY field a rule references — rules may point at\n// different fields, and each path was already resolved through renderField's\n// `prefixFor` closure so a rule reaching out of an addRow row lands on the\n// top-level field (see prefillWhenWatchPaths).\nfunction PrefillWhenWatcher({ form, rules, watchPaths, targetPath, resetOnNoMatch = true }) {\n // A selector useWatch (not one path per hook — hook count must be stable)\n // reduced to a STRING so the effect dependency stays a primitive; a fresh\n // array every render would re-run the effect on every keystroke anywhere.\n const watchedKey = Form.useWatch(\n (values) => JSON.stringify(\n watchPaths.map(({ path }) => path.reduce((acc, key) => (acc == null ? acc : acc[key]), values) ?? null),\n ),\n { form, preserve: true },\n );\n // Tracks the value WE last set via a matching rule (e.g. the W2 default\n // employer), so a later \"no rule matches\" tick (contractType switched away\n // from W2) can tell \"still exactly what we set\" apart from \"the user picked\n // something else since\" — only the former gets cleared. Without this guard,\n // switching e.g. W2 → C2C left the W2 default employer stuck in the field\n // forever (admin config `prefillWhenReset`, default on).\n const lastAppliedRef = useRef(undefined);\n // First tick = the form settling into its initial values, never a user\n // decision, so a clear rule must not fire on it (it would delete stored\n // data on the edit form). See prefillWhenRules.js for the full rationale.\n const initialRef = useRef(true);\n useEffect(() => {\n const values = watchedKey ? JSON.parse(watchedKey) : [];\n const watched = {};\n watchPaths.forEach(({ field }, i) => { watched[field] = values[i]; });\n const initial = initialRef.current;\n initialRef.current = false;\n const outcome = resolvePrefillWhen({\n rules,\n watched,\n current: form.getFieldValue(targetPath),\n lastApplied: lastAppliedRef.current,\n clearOnMismatch: resetOnNoMatch,\n initial,\n });\n if (outcome.action === 'set') {\n form.setFieldValue(targetPath, outcome.value);\n lastAppliedRef.current = outcome.value;\n } else if (outcome.action === 'clear') {\n form.setFieldValue(targetPath, undefined);\n lastAppliedRef.current = undefined;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [watchedKey]);\n return null;\n}\n\n// AutoFillFromApiWatcher — watches THIS field's own live value and, when it\n// changes to a non-empty value, calls a REST endpoint and populates one or\n// more sibling fields from the JSON response. Unlike prefillWhen (a static\n// value → value map), this does a real API round-trip — e.g. auto-loading a\n// campaign's Subject/Message from an admin-configured email template the\n// moment Type is set. A failed/404 lookup (no template configured yet) is\n// treated as a silent no-op, matching how callers of this endpoint already\n// tolerate a missing template elsewhere.\nfunction AutoFillFromApiWatcher({ form, config, watchPath }) {\n const watched = Form.useWatch(watchPath, form);\n const lastFetchedRef = useRef(undefined);\n useEffect(() => {\n if (empty(watched) || watched === lastFetchedRef.current) return;\n lastFetchedRef.current = watched;\n\n const url = config.endpointTemplate\n ? `${config.endpointTemplate.replace('{value}', encodeURIComponent(String(watched)))}`\n : `${config.endpoint}?${new URLSearchParams({ [config.queryParam]: String(watched) }).toString()}`;\n\n fetchJsonWithAuth(AUTH_URL, url)\n .then((json) => {\n const data = json?.data ?? json;\n if (config.substituteTokens) {\n (config.substituteInFields || []).forEach((targetField) => {\n const targetPath = namePathFromString(targetField);\n let current = form.getFieldValue(targetPath) || '';\n Object.entries(config.substituteTokens).forEach(([token, responseKey]) => {\n const inner = token.replace(/^\\{\\{|\\}\\}$/g, '').trim();\n const pattern = new RegExp(`\\\\{\\\\{\\\\s*${inner.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*\\\\}\\\\}`, 'gi');\n current = current.replace(pattern, data?.[responseKey] ?? '');\n });\n form.setFieldValue(targetPath, current);\n });\n return;\n }\n Object.entries(config.mapResponseToFields).forEach(([targetField, responseKey]) => {\n const targetPath = namePathFromString(targetField);\n if (config.onlyIfEmpty && !empty(form.getFieldValue(targetPath))) return;\n form.setFieldValue(targetPath, data?.[responseKey]);\n });\n })\n .catch(() => {\n // No template configured for this value yet, or the call\n // failed — leave existing field values untouched.\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [watched]);\n return null;\n}\n// Group-level showIf: the whole group renders only when the referenced field's\n// live value satisfies the condition (same operators as field-level showIf).\n// Kept as a module-level helper so both AddFormV1 and EditFormV1 evaluate it\n// identically.\nfunction groupShowIfMatches(showIf, value) {\n if (!showIf?.field) return true;\n const actual = String(value ?? '');\n const expected = String(showIf.value ?? '');\n const list = () => expected.split(',').map((v) => v.trim());\n switch (showIf.operator) {\n case 'eq': return actual === expected;\n case 'neq': return actual !== expected;\n case 'in': return list().includes(actual);\n case 'notIn': return !list().includes(actual);\n case 'truthy': return truthy(value);\n case 'falsy': return !truthy(value);\n case 'empty':\n case 'isEmpty':\n return value === undefined || value === null || actual.trim() === '' || (Array.isArray(value) && value.length === 0);\n case 'notEmpty':\n return !(value === undefined || value === null || actual.trim() === '' || (Array.isArray(value) && value.length === 0));\n default: return true;\n }\n}\n\n// A group with a `showIf` renders through this gate so its visibility reacts to\n// the referenced field changing. `render` is only invoked when visible, so a\n// hidden group's fields never register (nothing to validate or submit) — exactly\n// like a hidden field-level showIf. Groups without showIf bypass this entirely.\nfunction GroupShowIfGate({ form, showIf, render }) {\n const watched = Form.useWatch(showIf.field, form);\n if (!groupShowIfMatches(showIf, watched)) return null;\n return render();\n}\n\n// Group-level disable: the whole card (every field in it) goes read-only when\n// the group's `disabled` flag is set OR its `disabledIf` condition matches — the\n// group counterpart of FieldControl's field-level disabled/disabledIf. Provided\n// through context so each FieldControl in the group ORs it into its own disabled\n// state without threading a prop through renderGroup→renderFields→renderField.\n// Nested/merged groups inherit the parent's disabled state (never re-enable).\nconst GroupDisabledContext = createContext(false);\n\nfunction GroupDisabledProvider({ form, group, children, inheritParent = true }) {\n const parentDisabled = useContext(GroupDisabledContext);\n const path = group?.disabledIf?.field ? namePathFromString(group.disabledIf.field) : ['__noop_group_disabled__'];\n const watched = Form.useWatch(path, form);\n const conditionDisabled = group?.disabledIf?.field\n ? groupShowIfMatches(group.disabledIf, watched)\n : false;\n // `inheritParent: false` is used for a MERGED child (group.mergeInto).\n // mergeInto is presentation only — the child borrows the host's card and\n // nothing else — so inheriting the host's disabled state would give a\n // display relationship real behaviour.\n //\n // It is also the difference between working and deadlocked: the Employer\n // section is disabled until a Contract Type is chosen, and Contract Type is\n // rendered INSIDE that section. Inheriting would disable the very control\n // that enables the card, with no way out.\n const disabled = (inheritParent && parentDisabled)\n || Boolean(group?.disabled)\n || conditionDisabled;\n return <GroupDisabledContext.Provider value={disabled}>{children}</GroupDisabledContext.Provider>;\n}\n\nfunction getNestedProp(obj, dotPath) {\n return String(dotPath ?? '').split('.').reduce((cur, k) => cur?.[k], obj);\n}\n\nfunction hasMeaningfulValue(value) {\n if (value === undefined || value === null || value === '') return false;\n if (Array.isArray(value)) return value.length > 0 && value.some(hasMeaningfulValue);\n if (typeof value === 'object') return Object.values(value).some(hasMeaningfulValue);\n return true;\n}\n\nfunction extractGroups(formGroups) {\n if (Array.isArray(formGroups)) return formGroups;\n if (Array.isArray(formGroups?.groups)) return formGroups.groups;\n if (Array.isArray(formGroups?.data)) return formGroups.data;\n if (Array.isArray(formGroups?.data?.groups)) return formGroups.data.groups;\n return emptyGroups;\n}\n\nfunction normalizeGroups(formGroups = [], moduleName, rolePerms, defaultFieldSet) {\n const dset = defaultFieldSet ?? new Set();\n return [...extractGroups(formGroups)]\n // hideGroup hides everywhere; hideGroupInForm is the form-only mirror of\n // DetailViewV1's hideGroupInDetail — for server-owned groups that must be\n // read on the detail view but never typed here.\n .filter((group) => !truthy(group.hideGroup) && !truthy(group.hideGroupInForm)\n && groupAllowedByRole(rolePerms, group.name))\n .sort((a, b) => Number(a.order ?? 0) - Number(b.order ?? 0))\n .map((group) => ({\n ...group,\n fields: [...(group.fields ?? [])]\n // A \"default field\" (Form Groups → Default Fields, OTP-gated) is\n // ALWAYS shown + required regardless of its own show flag, so it\n // survives the hidden-field filter below and is forced show/req in\n // the map that follows.\n .map((field) => (\n dset.has(field.field) ? { ...field, show: 1, req: 1 } : field\n ))\n // Drop blank-keyed fields (a stray admin-config row can't render or\n // submit), any client-scope \"gate\" field (rendered as the top\n // \"Select Client\" picker, never as a body field), any field whose\n // visiblePermission the current role doesn't hold, and any field\n // this role's Form Configuration (Role Configure → Form, derived\n // from this same Form Groups config) has turned off.\n //\n // A field with show:0 (\"hidden\") is intentionally KEPT here even\n // though it must never render — this same fields array also feeds\n // buildPayload/buildRowObject (the payload engine has no other way\n // to know a hidden carrier field like isValid/isAccountCreate\n // exists). Dropping it here silently threw away every hidden\n // field's value at submit time, even one just set moments earlier\n // in this session (e.g. a Verify Email click stamping isValid on a\n // brand-new recruiter row) — see renderFields, which is what\n // actually keeps hidden fields off the screen.\n .filter((field) =>\n String(field.field ?? '').trim() !== ''\n && field.showOnAdd !== false\n && !truthy(field.clientScope)\n && (!field.visiblePermission || roleAllowsAction(field.visiblePermission, moduleName))\n && fieldAllowedByRole(rolePerms, group.name, field.field))\n // Role \"disable\": a group/field the role has marked non-editable\n // still renders but read-only. FieldControl honours field.disabled.\n .map((field) => (\n fieldEditableByRole(rolePerms, group.name, field.field)\n ? field\n : { ...field, disabled: true }\n ))\n .sort((a, b) => Number(a.order ?? 0) - Number(b.order ?? 0)),\n }))\n .filter((group) => group.fields.length);\n}\n\n// Wizard-only groups are intentionally hidden from the ordinary form body but\n// still participate in step planning (ListView, review, declaration, success,\n// etc.). Keep the field-normalised visible groups for form steps and add only\n// the hidden configuration shells back for the wizard planner.\nfunction wizardPlanningGroups(formGroups, normalizedGroups, rolePerms) {\n const normalizedByName = new Map(normalizedGroups.map((group) => [group.name, group]));\n return extractGroups(formGroups)\n .filter((group) => !truthy(group.hideGroup) && groupAllowedByRole(rolePerms, group.name))\n .sort((a, b) => Number(a.order ?? 0) - Number(b.order ?? 0))\n .map((group) => normalizedByName.get(group.name) ?? { ...group, fields: [] });\n}\n\n// pickPrefillValue reads a field's initial value from a prefill SOURCE record,\n// honouring the admin-config `prefillFrom` mapping FIRST (so a target field can\n// inherit from a differently-named source key — e.g. submission.totalExperience\n// ← candidate.yearOfExperience), then falling back to field.field and payloadKey.\n// Tolerates both flat dotted keys (the getFormGroups flat record) and nested\n// objects (addRow rows). Entirely config-driven — no field-name logic here.\n// Flattens a form-groups response (scalar fields with embedded values) into a\n// plain { fieldKey: value } record. Shared by the default prefill source and\n// the cross-module context prefill (field.prefillFromModule).\nfunction flatRecordFromGroups(groups) {\n if (!Array.isArray(groups)) return null;\n const rec = {};\n groups.forEach(group => {\n if (group.addRow) return;\n (group.fields ?? []).forEach(field => {\n if (!field.field || field.value === undefined || field.value === null) return;\n rec[field.field] = field.value;\n if (field.payloadKey && field.payloadKey !== field.field) {\n rec[field.payloadKey] = field.value;\n }\n });\n });\n return Object.keys(rec).length > 0 ? rec : null;\n}\n\nfunction pickPrefillValue(record, field) {\n if (!record || !field) return undefined;\n for (const path of [field.prefillFrom, field.field, field.payloadKey]) {\n if (!path) continue;\n let v = record[path];\n if (v === undefined || v === null) v = getDeep(record, path);\n if (v !== undefined && v !== null) return v;\n }\n return undefined;\n}\n\n// Convert a stored file-reference object to an Ant Design fileList entry so\n// file fields pre-show previously uploaded files when prefilling. Handles:\n// resume: { location, uploadedFileName, uniqueName }\n// passport: { passportCopyLocation, passportUploadName, … }\n// visa/alternateVisa: same *CopyLocation / *UploadName pattern\nfunction toFileListValue(value) {\n // A multi-file field prefills from a stored ARRAY: map each element through\n // the same single-file logic so every entry keeps its `stored` original too\n // (it used to be handed to the control raw, which showed the files but lost\n // them on save).\n if (Array.isArray(value)) return value.flatMap((item) => toFileListValue(item));\n if (!value || typeof value !== 'object') return [];\n // Legacy schemas disagree about which key holds the original filename —\n // passport uses passportUploadName, visa uses visaUniqueName. Matching only\n // \"*UploadName\" found nothing for a visa, so it rendered as \"file\".\n // See form/storedFileName.js.\n const name = storedFileName(value);\n const url = storedFileUrl(value);\n if (!name && !url) return [];\n // `stored` keeps the ORIGINAL container exactly as the record holds it\n // (passportCopyLocation / passportUploadName / …). The payload engine writes\n // it straight back when the user leaves the prefilled file untouched, so a\n // Quick Submit from a previous submission carries its documents into the new\n // record without re-uploading and without guessing at the stored shape.\n return [{ uid: url || name || '-1', name: name || 'file', status: 'done', url, existing: true, stored: value }];\n}\n\nconst empty = (value) => value === undefined || value === null || value === '';\n\nconst REGION_OPTIONS = [\n { label: 'US', value: 'US' },\n { label: 'UK', value: 'UK' },\n { label: 'India', value: 'INDIA' },\n];\n\n// Strip HTML tags and decode common entities — used so min/max validation\n// checks visible character count, not raw markup length.\nconst stripHtml = (html) =>\n String(html)\n .replace(/<[^>]*>/g, '')\n .replace(/&nbsp;/g, ' ')\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .trim();\n\nconst numberRangeRule = ({ label, message, value, compare, text }) => ({\n validator: (_, input) => {\n if (empty(input)) return Promise.resolve();\n return compare(Number(input), Number(value))\n ? Promise.resolve()\n : Promise.reject(new Error(message ?? `${label} ${text} ${value}`));\n },\n});\n\n// Date comparison + picker-constraint helpers now live in ONE place\n// (components/form/dateRules.js) and are imported at the top of this file.\n// They used to be duplicated verbatim between AddFormV1 and EditFormV1, which\n// is how a fix lands on Add and silently misses Edit.\n\n// Same resolution both forms have always used, now shared (form/maxCeiling.js)\n// so it can be unit tested: a DOTTED reference is absolute (reaches out of the\n// validated field's container), a bare one is a sibling.\nfunction getSiblingFieldName(currentName, compareField) {\n return resolveCompareFieldName(currentName, compareField);\n}\n\nconst crossFieldNumberRule = ({ label, message, value, rule, form, name, compare, text }) => ({\n validator: async (_, input) => {\n const compareField = value ?? rule.compareField ?? rule.field;\n if (!compareField || empty(input)) return Promise.resolve();\n const compareValue = form.getFieldValue(getSiblingFieldName(name, compareField));\n if (empty(compareValue)) return Promise.resolve();\n const inputNumber = Number(input);\n const compareNumber = Number(compareValue);\n if (Number.isNaN(inputNumber) || Number.isNaN(compareNumber)) return Promise.resolve();\n return compare(inputNumber, compareNumber)\n ? Promise.resolve()\n : Promise.reject(new Error(message ?? `${label} ${text} ${compareField}`));\n },\n});\n\nconst validationRulesByType = {\n noPastDate: ({ label, message }) => ({\n validator: (_, value) => {\n if (empty(value)) return Promise.resolve();\n const time = getComparableDateTime(value);\n if (time === null) return Promise.resolve();\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n return time < today.getTime()\n ? Promise.reject(new Error(message ?? `${label} cannot be a past date`))\n : Promise.resolve();\n },\n }),\n noFutureDate: ({ label, message }) => ({\n validator: (_, value) => {\n if (empty(value)) return Promise.resolve();\n const time = getComparableDateTime(value);\n if (time === null) return Promise.resolve();\n const endOfDay = new Date();\n endOfDay.setHours(23, 59, 59, 999);\n return time > endOfDay.getTime()\n ? Promise.reject(new Error(message ?? `${label} cannot be a future date`))\n : Promise.resolve();\n },\n }),\n minAge: ({ label, message, value }) => ({\n validator: (_, input) => {\n if (empty(input)) return Promise.resolve();\n const time = getComparableDateTime(input);\n if (time === null) return Promise.resolve();\n const years = Number(value ?? 18);\n const cutoff = new Date();\n cutoff.setFullYear(cutoff.getFullYear() - years);\n cutoff.setHours(23, 59, 59, 999);\n return time > cutoff.getTime()\n ? Promise.reject(new Error(message ?? `Must be at least ${years} years old`))\n : Promise.resolve();\n },\n }),\n // Both date-pair rules delegate to the shared engine, so `strict` (reject an\n // equal date — the 7-July bug) and `minGap`/`minGapFrom` (the duration\n // dropdown) behave identically on Add and Edit, and the SAME rule object\n // also drives the picker's disabledDate below.\n dateAfterField: ({ label, message, value, rule, form, name }) => buildPairValidator({\n type: 'dateAfterField',\n label,\n rule: { ...rule, value: value ?? rule?.compareField ?? rule?.field, message },\n readSibling: (key) => form.getFieldValue(getSiblingFieldName(name, key)),\n }),\n dateBeforeField: ({ label, message, value, rule, form, name }) => buildPairValidator({\n type: 'dateBeforeField',\n label,\n rule: { ...rule, value: value ?? rule?.compareField ?? rule?.field, message },\n readSibling: (key) => form.getFieldValue(getSiblingFieldName(name, key)),\n }),\n timeAfterField: ({ label, message, value, rule, form, name }) => ({\n validator: async (_, input) => {\n const compareField = value ?? rule.compareField ?? rule.field;\n if (!compareField || empty(input)) return Promise.resolve();\n const compareValue = form.getFieldValue(getSiblingFieldName(name, compareField));\n if (empty(compareValue)) return Promise.resolve();\n const inputTime = getComparableTimeOfDay(input);\n const compareTime = getComparableTimeOfDay(compareValue);\n if (inputTime === null || compareTime === null || inputTime > compareTime) return Promise.resolve();\n return Promise.reject(new Error(message ?? `${label} must be after ${compareField}`));\n },\n }),\n timeBeforeField: ({ label, message, value, rule, form, name }) => ({\n validator: async (_, input) => {\n const compareField = value ?? rule.compareField ?? rule.field;\n if (!compareField || empty(input)) return Promise.resolve();\n const compareValue = form.getFieldValue(getSiblingFieldName(name, compareField));\n if (empty(compareValue)) return Promise.resolve();\n const inputTime = getComparableTimeOfDay(input);\n const compareTime = getComparableTimeOfDay(compareValue);\n if (inputTime === null || compareTime === null || inputTime < compareTime) return Promise.resolve();\n return Promise.reject(new Error(message ?? `${label} must be before ${compareField}`));\n },\n }),\n greaterThanField: (args) => crossFieldNumberRule({ ...args, compare: (input, other) => input >= other, text: 'must be greater than or equal to' }),\n strictGreaterThanField: (args) => crossFieldNumberRule({ ...args, compare: (input, other) => input > other, text: 'must be greater than' }),\n strictLessThanField: (args) => crossFieldNumberRule({ ...args, compare: (input, other) => input < other, text: 'must be less than' }),\n lessThanOrEqualField: (args) => crossFieldNumberRule({ ...args, compare: (input, other) => input <= other, text: 'must be less than or equal to' }),\n // maxFromField — { type:'maxFromField', field:'<otherKey>', message }. The\n // ONLY cross-field rule here that can reach OUT of its addRow row: it\n // resolves the referenced key through renderField's `prefixFor` closure,\n // i.e. exactly the scoping a Show Condition uses (row when the key is one of\n // the row's own fields, top level otherwise). That is what lets a per-row\n // \"experience\" be capped by a top-level overall-experience field, with which\n // field caps which left entirely to Form Groups config.\n maxFromField: (args) => maxFromFieldRule(args),\n // maxFieldWithFallback — cap against the FIRST compare field carrying a\n // usable maximum (\"cap at the To value, else the From value\"). Decision\n // logic (incl. why a 0 ceiling means \"no ceiling\") lives in form/maxCeiling.js.\n maxFieldWithFallback: ({ label, message, value, rule, form, name }) => ({\n validator: async (_, input) => {\n const compareFields = parseCompareFields(value ?? rule.compareFields);\n const result = checkMaxWithFallback({\n input,\n compareFields,\n readValue: (fieldName) => readCompareValue(form, name, fieldName),\n });\n if (result.ok) return Promise.resolve();\n return Promise.reject(new Error(message ?? `${label} must not exceed ${result.field}`));\n },\n }),\n required: ({ field, message }) => ({\n validator: (_, value) => {\n let isEmpty = value === undefined || value === null || value === ''\n || (Array.isArray(value) && value.length === 0);\n if (!isEmpty && field?.type === 'text-editor') {\n isEmpty = stripHtml(value) === '';\n }\n return isEmpty\n ? Promise.reject(new Error(message ?? 'Mandatory Field'))\n : Promise.resolve();\n },\n }),\n email: ({ label, message }) => configuredEmailRule(label, message),\n // Admin-configured \"already present\" check. Everything about it — the\n // trigger, the blank handling, the normalizer, the message — comes from the\n // validations entry; the server resolves the collection and the scope.\n unique: ({ field, rule, uniqueContext }) => buildUniqueValidationRule({\n field, validation: rule, context: uniqueContext,\n }),\n\n emailTags: ({ label, message }) => ({\n validator: (_, value) => {\n const tags = Array.isArray(value) ? value : [];\n const invalid = tags.find((tag) => !isValidConfiguredEmail(tag));\n return invalid\n ? Promise.reject(new Error(message ?? `${label} contains an invalid email: ${invalid}`))\n : Promise.resolve();\n },\n }),\n\n noHtml: ({ label, message }) => ({\n validator: (_, value) => {\n if (value === undefined || value === null || value === '') return Promise.resolve();\n const hasHtmlTag = /<\\/?[a-z][\\s\\S]*>/i.test(String(value));\n return hasHtmlTag\n ? Promise.reject(new Error(message ?? `${label} cannot contain HTML tags`))\n : Promise.resolve();\n },\n }),\n url: ({ label, message }) => ({ type: 'url', message: message ?? `Enter valid ${label}` }),\n number: ({ label, message }) => ({ pattern: /^[0-9]+$/, message: message ?? `${label} must be a number` }),\n phone: ({ message }) => ({\n // Accepts the configured mask (e.g. 999-878-3413) — validates on the\n // stripped digits so the separators the formatter inserts don't fail it.\n validator: (_, value) => {\n if (value === undefined || value === null || value === '') return Promise.resolve();\n const { total } = parsePhoneFormat();\n return phoneDigits(value).length === total\n ? Promise.resolve()\n : Promise.reject(new Error(message ?? `Phone number must contain exactly ${total} digits`));\n },\n }),\n\n // The pre-existing minLength3 / minLength5 pair baked the threshold into the\n // TYPE NAME, and existed only in AddFormV1 — configuring one on a field did\n // nothing at all on the Edit form. Both now delegate to the generic `min`\n // rule (admin: \"Min length/value\"), which already implements exactly this\n // for non-number fields and is present in BOTH forms.\n minLength3: (args) => validationRulesByType.min({ ...args, value: 3 }),\n minLength5: (args) => validationRulesByType.min({ ...args, value: 5 }),\n\n len: ({ label, message, value }) => ({ len: Number(value), message: message ?? `${label} must be ${value} characters` }),\n pattern: ({ label, message, rule }) => ({\n pattern: new RegExp(rule.pattern ?? rule.value, rule.flags),\n message: message ?? `Enter valid ${label}`,\n }),\n min: ({ field, label, message, value }) => (\n field.type === 'number'\n ? numberRangeRule({ label, message, value, compare: (input, min) => input >= min, text: 'must be at least' })\n : {\n validator: (_, input) => {\n if (input == null || input === '') return Promise.resolve();\n const content = field.type === 'text-editor' ? stripHtml(input) : String(input);\n if (content === '') return Promise.resolve();\n return content.length >= Number(value)\n ? Promise.resolve()\n : Promise.reject(new Error(message ?? `${label} must be at least ${value} characters`));\n },\n }\n ),\n max: ({ field, label, message, value }) => (\n field.type === 'number'\n ? numberRangeRule({ label, message, value, compare: (input, max) => input <= max, text: 'must not exceed' })\n : {\n validator: (_, input) => {\n if (input == null || input === '') return Promise.resolve();\n const content = field.type === 'text-editor' ? stripHtml(input) : String(input);\n if (content === '') return Promise.resolve();\n return content.length <= Number(value)\n ? Promise.resolve()\n : Promise.reject(new Error(message ?? `${label} must not exceed ${value} characters`));\n },\n }\n ),\n};\n\n// `prefixFor` is renderField's showIf prefix resolver; it is forwarded so a rule\n// that references another field resolves it with the same row-vs-top-level\n// scoping the Show Conditions use. Undefined for call sites that have no row\n// context (a repeat-scalar item), where the rules keep their sibling behaviour.\nfunction validationToRule(validation, field, form, name, prefixFor, uniqueContext) {\n const rule = typeof validation === 'string' ? { type: validation } : validation;\n const type = rule.type ?? rule.rule ?? rule.name;\n const value = rule.value ?? rule.length ?? rule.min ?? rule.max;\n const label = field.label ?? field.field ?? 'Field';\n const factory = validationRulesByType[type];\n\n return factory\n ? factory({ field, label, message: rule.message, rule, value, form, name, prefixFor, uniqueContext })\n : rule;\n}\n\nfunction getSiblingFieldPath(name, siblingField) {\n return Array.isArray(name) && name.length > 1\n ? [...name.slice(0, -1), siblingField]\n : [siblingField];\n}\n\n// A field is required either via the simple \"req\" toggle or via a \"required\"\n// entry in the admin-configured validations list — the Form.Item asterisk and\n// the addRow \"at least one row\" check must honour both, not just field.req.\nfunction isFieldRequired(field, form, name) {\n if (truthy(field?.req)) return true;\n const apiRules = field?.validations ?? field?.validation ?? field?.rules ?? [];\n if (apiRules.some((rule) => (typeof rule === 'string' ? rule : rule?.type) === 'required')) return true;\n if (field?.requiredIfField && form && name) {\n return truthy(form.getFieldValue(getSiblingFieldPath(name, field.requiredIfField)));\n }\n return false;\n}\n\n// `uniqueContext` ({ checker, module, clientId, region }) is what turns a\n// configured `unique` validation into a live preflight check. Call sites with\n// no context (search forms, repeat-scalar items) still render the field; the\n// unique rule degrades to a no-op there and the server stays authoritative.\nfunction getRules(field, form, name, skipRequired = false, prefixFor = undefined, uniqueContext = undefined,\n extraRules = undefined) {\n const label = field.label ?? field.field ?? 'Field';\n const apiRules = field.validations ?? field.validation ?? field.rules ?? [];\n const hasApiRequired = apiRules.some((rule) => (typeof rule === 'string' ? rule : rule?.type) === 'required');\n const hasApiEmail = apiRules.some((rule) => (typeof rule === 'string' ? rule : rule?.type) === 'email');\n const rules = [];\n\n // Rules the CALLER resolved because they need the group, which this\n // function never sees — today, a region that refuses an in-progress entry.\n // They go first so a blocked row reports that before anything else.\n if (extraRules?.length) rules.push(...extraRules);\n\n // Cross-row hierarchy: a newest-first list constrains each row against its\n // NEIGHBOURS. The picker already greys the impossible dates out; this\n // catches one that arrived another way — typed, pasted, prefilled from a\n // résumé, or entered before the neighbouring row was filled in.\n if (field.rowHierarchy) {\n const ctx = rowContext(form, name);\n if (ctx.rows) rules.push(buildRowHierarchyValidator({ field, ...ctx }));\n }\n\n\n // `requiredIfField` (e.g. \"make this mandatory once its sibling has a\n // value\") stands on its own — it must not need field.req ALSO set, or a\n // field configured with only requiredIfField silently never validates.\n if (!skipRequired && !hasApiRequired && truthy(field.req) && field.disabledByField) {\n // A field disabled via disabledByField (e.g. endDate while\n // currentlyPursuing is checked) must not block submit with a\n // \"required\" error the user has no way to satisfy.\n rules.push({\n validator: (_, input) => {\n const disabledNow = truthy(form.getFieldValue(getSiblingFieldPath(name, field.disabledByField)));\n if (disabledNow) return Promise.resolve();\n return (input === undefined || input === null || input === '')\n ? Promise.reject(new Error('Mandatory Field'))\n : Promise.resolve();\n },\n });\n } else if (!skipRequired && !hasApiRequired && field.requiredIfField) {\n rules.push({\n validator: (_, input) => {\n const triggerValue = form.getFieldValue(getSiblingFieldPath(name, field.requiredIfField));\n if (!truthy(triggerValue)) return Promise.resolve();\n return (input === undefined || input === null || input === '')\n ? Promise.reject(new Error('Mandatory Field'))\n : Promise.resolve();\n },\n });\n } else if (!skipRequired && truthy(field.req) && !hasApiRequired) {\n rules.push({ required: true, message: 'Mandatory Field' });\n }\n if ((field.type === 'email' || field.formatter === 'email') && !hasApiEmail) {\n rules.push(configuredEmailRule(label));\n }\n // Number fields are whole-number-only unless the admin marks them decimal\n // (e.g. a commission of 5.5). Both patterns still reject any non-numeric\n // character, so \"float only\" stays enforced either way.\n if (field.type === 'number') {\n rules.push(truthy(field.decimal)\n ? { pattern: /^\\d+(\\.\\d+)?$/, message: `${label} must be a number` }\n : { pattern: /^[0-9]+$/, message: `${label} must be a number` });\n }\n\n // attachUniqueSyncGuards re-wraps any `unique` rule so it only calls the\n // server once every synchronous rule in this same list has passed.\n // An admin-configured override checkbox (field.overrideCheckbox) suspends\n // the validation TYPES it names while it is ticked. Applied here, over the\n // built rules, so a gated rule is withheld at validation time rather than\n // at render time — see form/validationOverride.js.\n const buildRule = (rule) => validationToRule(rule, field, form, name, prefixFor, uniqueContext);\n const mapRule = overrideRuleMapper(field, name, prefixFor, buildRule);\n\n return attachUniqueSyncGuards([\n ...rules,\n ...apiRules.map(mapRule),\n securityValidationRule(field),\n ]);\n}\n\nfunction getValidationValue(field, type) {\n const rules = field.validations ?? field.validation ?? field.rules ?? [];\n const rule = rules.find((item) => (typeof item === 'string' ? item : item?.type) === type);\n if (!rule || typeof rule === 'string') return undefined;\n return rule.value ?? rule.length ?? rule[type];\n}\n\nfunction getInputLimits(field) {\n const len = field.len ?? getValidationValue(field, 'len');\n const min = field.min ?? getValidationValue(field, 'min');\n const max = field.max ?? getValidationValue(field, 'max');\n\n if (field.type === 'number') {\n return {\n min: min ?? undefined,\n max: max ?? undefined,\n };\n }\n\n return {\n minLength: min ?? undefined,\n maxLength: field.maxLength ?? len ?? max ?? undefined,\n };\n}\n\n// Thin adapters over the shared engine (components/form/dateRules.js). The\n// bodies used to live here AND in EditFormV1; the picker's greyed-out range and\n// the submit-time error are now generated from the same rule object, so a\n// calendar that disagrees with its own error message is structurally impossible.\n// rowContext — the sibling ROWS of the repeatable group this field sits in,\n// plus this field's row index.\n//\n// A per-row `readSibling` can only see the row it is in, but a newest-first\n// list constrains a row against its NEIGHBOURS. Inside a Form.List the field\n// path is [listName, rowIndex, fieldKey], which is exactly what is needed to\n// read the whole list and locate this row within it.\n//\n// Returns {} outside a repeatable group, so the hierarchy simply never applies.\nfunction rowContext(form, name) {\n if (!Array.isArray(name) || name.length < 3 || typeof name[1] !== 'number') return {};\n const rows = form.getFieldValue(name[0]);\n if (!Array.isArray(rows)) return {};\n return { rows, rowIndex: name[1] };\n}\n\nfunction getDisabledDate(field, form, name) {\n return buildDisabledDate({\n field,\n readSibling: (key) => form.getFieldValue(getSiblingFieldName(name, key)),\n ...rowContext(form, name),\n });\n}\n\nfunction getDefaultPickerValue(field) {\n return defaultPickerValue(field);\n}\n\nfunction cleanValue(value, formatter) {\n if (!formatter) return value;\n // Phone gets the common, config-driven mask (default 3-3-4 → 999-878-3413).\n // \"digits\" stays a bare digit string (no separators).\n if (formatter === 'phone') return formatPhone(value);\n if (formatter === 'digits') return value.replace(/\\D/g, '').slice(0, 10);\n if (formatter === 'email' || formatter === 'noSpaces') return value.replace(/\\s/g, '');\n if (formatter === 'name') return value.replace(/\\s+/g, ' ').trimStart().replace(/\\b\\w/g, (char) => char.toUpperCase());\n return value;\n}\n\nfunction normalizeModule(moduleName = '') {\n const normalized = String(moduleName).toLowerCase();\n if (normalized === 'job') return 'jobs';\n if (normalized === 'candidate') return 'candidates';\n if (normalized === 'submissions') return 'submission';\n return normalized;\n}\n\nconst SEARCH_SOURCE_ONLY_FIELDS = new Set([\n 'selectedSource',\n 'source',\n 'sourceType',\n 'scope',\n]);\n\nfunction hasSearchCriterionValue(value) {\n if (value === null || value === undefined) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value === 'boolean') return value;\n if (dayjs.isDayjs(value)) return value.isValid();\n if (Array.isArray(value)) return value.some(hasSearchCriterionValue);\n if (typeof value === 'object') {\n if ('value' in value || 'label' in value || 'name' in value) {\n return hasSearchCriterionValue(value.value ?? value.label ?? value.name);\n }\n return Object.entries(value).some(([key, nestedValue]) => (\n !SEARCH_SOURCE_ONLY_FIELDS.has(key) && hasSearchCriterionValue(nestedValue)\n ));\n }\n\n return false;\n}\n\nfunction hasSearchCriteria(values = {}) {\n return Object.entries(values ?? {}).some(([key, value]) => (\n !SEARCH_SOURCE_ONLY_FIELDS.has(key) && hasSearchCriterionValue(value)\n ));\n}\n\n// buildDynamicFormData — builds the multipart FormData payload to send to the\n// Auth gateway.\n//\n// • File fields are appended as separate FormData parts. The part name is the\n// field's `fileKey` if configured, else the first segment of its path\n// (e.g. \"passport.passportUploadName\" → \"passport\"). Files nested inside an\n// addRow group array are collected from every row.\n// • All other fields are turned into the JSON \"json\" part by the shared,\n// config-driven payload engine (buildPayload). There is ZERO field-name or\n// module-specific logic here — payloadKey / dataType / payloadMode / template\n// are all read from the admin form-group config.\n//\n// Dynamic by design: any new field added in the admin panel is automatically\n// included — no code change required. New modules work the same way.\nfunction buildDynamicFormData(values, groups, extraPayload = {}, module = '') {\n const formData = new FormData();\n\n // New files → multipart parts, via the SHARED engine helper. On CREATE we\n // attach only the flat (non-repeatable) file fields — resume, photo, jobs\n // \"file\", passport, visa. Repeatable (addRow) document files are uploaded in\n // a follow-up update (see submit) because the create handler mishandles them;\n // the indexed update path is the reliable one. The document METADATA still\n // rides along in the JSON payload here, so the rows are created on insert and\n // the follow-up update just attaches each file to its row by index.\n collectFileParts(values, groups, { scope: 'flat', module }).forEach(({ formKey, file }) => {\n formData.append(formKey, file);\n });\n\n // Config-driven JSON payload (file fields are skipped by the engine).\n // extraPayload carries linkage/context keys that are NOT form fields but the\n // downstream create requires (e.g. submission needs jobId + applicantId). These\n // are merged first so a real form field of the same name still wins.\n const payload = { ...extraPayload, ...buildPayload(values, groups, { module }) };\n payload.schemaVersion = 1;\n\n formData.append('json', JSON.stringify(payload));\n return formData;\n}\n\nfunction FieldControl({ field, form, name, moduleName, value, checked, onChange, scopeValues = {}, onAiUpload, onDuplicateBlur, onRegionBlocked, onRowOrderChange, formDisabled, rowFieldKeys }) {\n const type = field.type ?? 'text';\n const baseDisabled = !editable(field, moduleName);\n const [dynamicOptions, setDynamicOptions] = useState(null);\n const [optionsLoading, setOptionsLoading] = useState(false);\n const [locationSearch, setLocationSearch] = useState('');\n const [lookupSearch, setLookupSearch] = useState('');\n const [masterSearch, setMasterSearch] = useState('');\n // Bumped after a quick create/edit (\"Add More\") so the dropdown refetches its\n // options and the freshly created/edited record appears immediately.\n const [refetchNonce, setRefetchNonce] = useState(0);\n const [viewer, setViewer] = useState({ open: false, docs: [], index: 0 });\n const [inputError, setInputError] = useState(null);\n const rawLookupRef = useRef([]);\n // lookupFilterValueFrom resolves against the SAME addRow row first (so a\n // per-row cascade like employerId → that row's recruiter list works), then\n // falls back to the top-level path — which is what every pre-existing\n // top-level config used. Both are always watched (hooks can't be\n // conditional); the row value wins whenever it is non-empty.\n const insideListRow = Array.isArray(name) && name.length >= 3 && typeof name[1] === 'number';\n const topFilterPath = field.lookupFilterValueFrom ? namePathFromString(field.lookupFilterValueFrom) : [`__lookup_filter_${field.field}`];\n const rowFilterPath = (field.lookupFilterValueFrom && insideListRow)\n ? [...name.slice(0, 2), ...namePathFromString(field.lookupFilterValueFrom)]\n : ['__noop_row_filter__'];\n const topFilterValue = Form.useWatch(topFilterPath, form);\n const rowFilterValue = Form.useWatch(rowFilterPath, form);\n const formFilterValue = !empty(rowFilterValue) ? rowFilterValue : topFilterValue;\n // Watch sibling field for disabledByField — e.g. endDate disabled when currentlyPursuing is checked\n const disabledBySiblingPath = field.disabledByField\n ? (Array.isArray(name) && name.length > 1 ? [...name.slice(0, -1), field.disabledByField] : [field.disabledByField])\n : ['__noop_disabled_watch__'];\n const disabledByValue = Form.useWatch(disabledBySiblingPath, form);\n // disabledIf — conditional read-only, same operator set as showIf (eq/neq/\n // truthy/falsy/in/notIn), e.g. lock the Employer to the configured default\n // when Contract Type is W2. The row value wins when the condition field\n // lives in this row; otherwise the top-level field drives it.\n const disabledIfTopPath = field.disabledIf?.field ? namePathFromString(field.disabledIf.field) : ['__noop_disabled_if__'];\n const disabledIfRowPath = (field.disabledIf?.field && insideListRow)\n ? [...name.slice(0, 2), ...namePathFromString(field.disabledIf.field)]\n : ['__noop_disabled_if_row__'];\n const disabledIfTop = Form.useWatch(disabledIfTopPath, form);\n const disabledIfRow = Form.useWatch(disabledIfRowPath, form);\n const conditionallyDisabled = field.disabledIf?.field\n ? labelConditionMatches(field.disabledIf, !empty(disabledIfRow) ? disabledIfRow : disabledIfTop)\n : false;\n // optionsFromField (admin config) — narrow this select's options to the live\n // value of ANOTHER field (e.g. the candidate rate unit may only be the unit\n // the linked job was raised in, which prefillFromModule already puts on the\n // form). Resolved with the same scoping a Show Condition uses: the row's own\n // field when the key belongs to this row (rowFieldKeys), the top-level field\n // otherwise — with a row-first fallback when membership is unknown, matching\n // lookupFilterValueFrom above. Both paths are always watched (hooks cannot be\n // conditional) so the dropdown re-narrows the moment the source changes.\n const constraintKey = field.optionsFromField || '';\n const constraintTopPath = constraintKey ? namePathFromString(constraintKey) : ['__noop_options_from__'];\n const constraintRowPath = (constraintKey && insideListRow && (!rowFieldKeys || rowFieldKeys.has(constraintKey)))\n ? [...name.slice(0, 2), ...namePathFromString(constraintKey)]\n : ['__noop_options_from_row__'];\n const constraintTopValue = Form.useWatch(constraintTopPath, form);\n const constraintRowValue = Form.useWatch(constraintRowPath, form);\n const constraintValue = !empty(constraintRowValue) ? constraintRowValue : constraintTopValue;\n // prefillWhenExclusive (admin config) — \"a value a Conditional Default rule\n // would SET is EXCLUSIVE to that rule's condition\". While the rule matches,\n // its value is offered (and PrefillWhenWatcher auto-selects it, as today);\n // while it does not, the value is REMOVED from the list instead of merely\n // being a stale default. Reuses field.prefillWhen so the hidden value and\n // the auto-filled value can never drift apart. Default off — a field\n // without the flag offers exactly what it offers today.\n //\n // HOOK SAFETY: the rule list is admin data, so it must never decide how\n // many hooks run. ONE selector-form useWatch reads every referenced field\n // out of the whole store and reduces them to a STRING (a fresh array each\n // render would churn the memo); the rule count changes what the selector\n // reads, never the hook count. Same row-vs-top-level scoping as\n // optionsFromField above: a rule key belonging to this addRow row resolves\n // to the row's own field, anything else (the top-level contract type read\n // from inside repeatable employer rows) to the top-level path.\n const exclusivePrefillRules = (truthy(field.prefillWhenExclusive) && field.prefillWhen?.length)\n ? field.prefillWhen\n : null;\n const exclusivePrefillKey = Form.useWatch(\n (values) => (exclusivePrefillRules\n ? JSON.stringify(prefillWhenWatchFields(exclusivePrefillRules).map((key) => {\n const read = (path) => path.reduce((acc, k) => (acc == null ? acc : acc[k]), values);\n const rowValue = (insideListRow && (!rowFieldKeys || rowFieldKeys.has(key)))\n ? read([...name.slice(0, 2), ...namePathFromString(key)])\n : undefined;\n return (!empty(rowValue) ? rowValue : read(namePathFromString(key))) ?? null;\n }))\n : ''),\n { form, preserve: true },\n );\n const exclusivePrefillWatched = useMemo(() => {\n if (!exclusivePrefillRules || !exclusivePrefillKey) return null;\n const values = JSON.parse(exclusivePrefillKey);\n const watched = {};\n prefillWhenWatchFields(exclusivePrefillRules).forEach((key, i) => { watched[key] = values[i]; });\n return watched;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [exclusivePrefillKey]);\n const groupDisabled = useContext(GroupDisabledContext);\n // exclusiveInGroup — only ONE row of a repeatable group may hold this flag\n // (e.g. \"Currently Working Here\" / \"Currently Pursuing\": a person has one\n // current employer and one course in progress). Once any row claims it, the\n // control is disabled on every OTHER row, so the state cannot become\n // ambiguous. The claiming row keeps its control enabled — that is how the\n // user releases the claim and moves it elsewhere.\n //\n // Watching the whole Form.List (not one sibling) is what makes this react\n // to a change in a DIFFERENT row.\n const exclusiveListPath = (field.exclusiveInGroup && insideListRow)\n ? [name[0]]\n : ['__noop_exclusive_watch__'];\n const exclusiveRows = Form.useWatch(exclusiveListPath, form);\n const claimedByAnotherRow = useMemo(() => {\n if (!field.exclusiveInGroup || !insideListRow || !Array.isArray(exclusiveRows)) return false;\n const myIndex = name[1];\n const leaf = name[name.length - 1];\n return exclusiveRows.some((row, index) => index !== myIndex && truthy(row?.[leaf]));\n }, [field.exclusiveInGroup, insideListRow, exclusiveRows, name]);\n // scopeValues only wins when it actually carries a value — a key present\n // but undefined/empty must fall back to the field's own live form value,\n // or the lookup filter is permanently starved and never resolves options.\n const scopeFilterValue = field.lookupFilterValueFrom\n ? scopeValues[field.lookupFilterValueFrom]\n : undefined;\n const lookupFilterValue = !empty(scopeFilterValue) ? scopeFilterValue : formFilterValue;\n // ---- Dependent-lookup staleness guard (generic; see also EditFormV1) ----\n // A lookup scoped by `lookupFilterValueFrom` must not keep a value that was\n // chosen under a DIFFERENT parent. Changing the parent refetches the OPTIONS\n // (lookupFilterValue is a dependency of that effect) but used to leave this\n // field's own value untouched — so picking client A's contact \"Naveen\" and\n // then switching to client B left A's contact id sitting on the form.\n //\n // That went unnoticed because a nested reference id is only unique WITHIN\n // its parent: clientContact.clientContactId is a per-client sequence\n // (1, 2, 3 ...), so the orphaned id still resolved against the new client —\n // to a DIFFERENT person — and saved looking perfectly valid. A wrong name\n // that looks right is worse than a blank one.\n //\n // Only a genuine CHANGE clears. The first observed value is recorded without\n // clearing, so edit prefill (which sets parent and child together) and the\n // initial mount are untouched; and a parent going from empty -> known never\n // clears, because nothing can have been chosen under an unknown parent yet.\n const parentFilterRef = useRef(PARENT_FILTER_UNSEEN);\n useEffect(() => {\n if (!field.lookupFilterField || !field.lookupFilterValueFrom) return;\n const previous = parentFilterRef.current;\n parentFilterRef.current = lookupFilterValue;\n if (!shouldClearDependentValue({\n previous,\n next: lookupFilterValue,\n currentValue: form.getFieldValue(name),\n })) return;\n form.setFields([{ name, value: undefined, errors: [] }]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [lookupFilterValue]);\n\n\n // locationMaster cascade (Country → State → City, sourced from the\n // locationMasters collection). Same top/row watch pattern as\n // lookupFilterValueFrom above: the sibling holding the PARENT level's\n // selected value, watched so options refetch — and the control disables —\n // the moment it changes. `locationCountryFrom` feeds a \"state\" level\n // field; \"city\" needs both `locationCountryFrom` and `locationStateFrom`.\n const locCountryTopPath = field.locationCountryFrom ? namePathFromString(field.locationCountryFrom) : ['__noop_loc_country__'];\n const locCountryRowPath = (field.locationCountryFrom && insideListRow)\n ? [...name.slice(0, 2), ...namePathFromString(field.locationCountryFrom)]\n : ['__noop_loc_country_row__'];\n const locCountryTop = Form.useWatch(locCountryTopPath, form);\n const locCountryRow = Form.useWatch(locCountryRowPath, form);\n const locCountryValue = !empty(locCountryRow) ? locCountryRow : locCountryTop;\n const locStateTopPath = field.locationStateFrom ? namePathFromString(field.locationStateFrom) : ['__noop_loc_state__'];\n const locStateRowPath = (field.locationStateFrom && insideListRow)\n ? [...name.slice(0, 2), ...namePathFromString(field.locationStateFrom)]\n : ['__noop_loc_state_row__'];\n const locStateTop = Form.useWatch(locStateTopPath, form);\n const locStateRow = Form.useWatch(locStateRowPath, form);\n const locStateValue = !empty(locStateRow) ? locStateRow : locStateTop;\n const locationLocked = field.dataSource === 'locationMaster' && (\n (field.locationLevel === 'state' && empty(locCountryValue))\n || (field.locationLevel === 'city' && (empty(locCountryValue) || empty(locStateValue)))\n );\n const disabled = baseDisabled || Boolean(field.disabled) || conditionallyDisabled || (field.disabledByField ? truthy(disabledByValue) : false) || Boolean(formDisabled) || groupDisabled || claimedByAnotherRow || locationLocked;\n\n // Fetch options dynamically when dataSource is master / module / lookup.\n // Static and undefined sources skip the API call and use field.options directly.\n useEffect(() => {\n if (type === 'location') {\n let cancelled = false;\n setOptionsLoading(true);\n\n async function fetchLocations() {\n try {\n const params = new URLSearchParams({\n search: locationSearch,\n limit: String(field.limit ?? 50),\n offset: '0',\n });\n const json = await fetchJsonWithAuth(AUTH_URL, `/admin/location-dropdown-values?${params}`);\n const raw = json?.data ?? json ?? [];\n if (!cancelled) setDynamicOptions(normalizeOptions(Array.isArray(raw) ? raw : []));\n } catch (err) {\n console.error(`[AddFormV1] Failed to fetch locations for \"${field.field}\":`, err);\n if (!cancelled) setDynamicOptions([]);\n } finally {\n if (!cancelled) setOptionsLoading(false);\n }\n }\n\n fetchLocations();\n return () => { cancelled = true; };\n }\n const ds = field.dataSource;\n if (!['select', 'radio', 'checkbox'].includes(type)) return undefined;\n if (!ds || ds === 'static') return undefined;\n if (ds === 'lookup' && field.lookupFilterField && empty(lookupFilterValue)) {\n setDynamicOptions([]);\n setOptionsLoading(false);\n return undefined;\n }\n\n // lookupMinSearchLength (opt-in): don't preload the full list on\n // mount — wait until the user has actually typed enough characters.\n // Existing lookup fields without this flag keep today's behavior\n // (full list shown immediately) untouched.\n if (ds === 'lookup' && field.lookupMinSearchLength && lookupSearch.trim().length < field.lookupMinSearchLength) {\n setDynamicOptions([]);\n setOptionsLoading(false);\n return undefined;\n }\n\n let cancelled = false;\n setOptionsLoading(true);\n\n async function fetchOptions() {\n try {\n let raw = [];\n if (ds === 'master' || ds === 'module') {\n raw = await getDropdownValues(\n moduleName,\n field.field,\n ds === 'master' ? masterSearch : '',\n field.limit ?? 50,\n 0,\n {\n dataSource: ds,\n masterName: field.masterName,\n groupName: field.groupName,\n },\n );\n } else if (ds === 'lookup') {\n const params = new URLSearchParams({\n collection: field.lookupCollection ?? '',\n displayField: field.displayField ?? '',\n valueField: field.valueField ?? '_id',\n });\n if (field.displayField2) params.set('displayField2', field.displayField2);\n if (lookupSearch) params.set('search', lookupSearch);\n if (field.lookupFilterField && !empty(lookupFilterValue)) {\n params.set('filterField', field.lookupFilterField);\n params.set('filterValue', String(lookupFilterValue));\n }\n if (Array.isArray(field.filters) && field.filters.length > 0) {\n params.set('filters', JSON.stringify(field.filters));\n }\n // The row-filter config, rebuilt from the individual keys\n // rather than passing `field` itself: every key here is a\n // dependency of this effect, so the options refetch and\n // re-filter whenever an admin changes one of them.\n const rowFilterConfig = {\n field: field.field,\n extraFields: field.extraFields,\n optionsRequireExtraField: field.optionsRequireExtraField,\n optionsRequireExtraValue: field.optionsRequireExtraValue,\n optionsHierarchyParentField: field.optionsHierarchyParentField,\n optionsHierarchySelfFrom: field.optionsHierarchySelfFrom,\n };\n // Every extraData key the row filters need is requested\n // automatically alongside the explicit extraFields, so a\n // filter key can never be configured without its data.\n let extraKeys = lookupExtraFieldKeys(rowFilterConfig);\n // Exact Course -> Module -> Lesson compatibility path. Older BE builds\n // return one array-valued option per module. Requesting moduleTitle\n // lets us select and flatten only the currently selected module.\n extraKeys = withCourseModuleLessonExtraFields(field, extraKeys);\n if (extraKeys.length) params.set('extraFields', extraKeys.join(','));\n const json = await fetchJsonWithAuth(AUTH_URL, `/admin/lookup-dropdown-values?${params}`);\n raw = json?.data ?? json ?? [];\n raw = normalizeCourseModuleLessonRows(raw, field, lookupFilterValue, { source: 'AddFormV1' });\n // Config-driven row filters: value match on an extraData key\n // (e.g. only list a recruiter once verified, or only a given\n // role) and/or the signed-in user's reporting downline.\n raw = filterLookupOptionRows(raw, rowFilterConfig, { source: 'AddFormV1' });\n } else if (ds === 'locationMaster') {\n const level = field.locationLevel || 'country';\n if (level === 'state' && empty(locCountryValue)) {\n raw = [];\n } else if (level === 'city' && (empty(locCountryValue) || empty(locStateValue))) {\n raw = [];\n } else {\n const params = new URLSearchParams({ level, limit: String(field.limit ?? 250), offset: '0' });\n if (!empty(locCountryValue)) params.set('country', String(locCountryValue));\n if (!empty(locStateValue)) params.set('state', String(locStateValue));\n if (lookupSearch) params.set('search', lookupSearch);\n const json = await fetchJsonWithAuth(AUTH_URL, `/admin/location-dropdown-values?${params}`);\n raw = json?.data ?? json ?? [];\n }\n } else if (ds === 'group') {\n const gn = (field.groupName ?? '').toLowerCase().trim();\n if (gn === 'users' || gn === 'user') {\n const json = await fetchJsonWithAuth(AUTH_URL, '/get-all-users?limit=500&offset=0');\n const users = json?.data?.users ?? json?.users ?? json?.data ?? [];\n // groupRoleContains (admin config) — e.g. \"manager\" lists every\n // user whose role NAME contains that word (Delivery Manager,\n // Onboarding Manager, Submission Manager, …), not just a single\n // exact role. `/get-all-users` already returns each user's\n // roleName, so this narrows client-side with no extra request.\n const roleContains = String(field.groupRoleContains ?? '').trim().toLowerCase();\n const filteredUsers = roleContains\n ? (Array.isArray(users) ? users.filter((u) => String(u.roleName ?? '').toLowerCase().includes(roleContains)) : [])\n : users;\n raw = Array.isArray(filteredUsers) ? filteredUsers.map((u) => ({\n label: [u.firstName, u.lastName].filter(Boolean).join(' ').trim() || u.userName || u.email || String(u.userId),\n value: u.userId ?? u.id,\n })) : [];\n }\n }\n if (!cancelled) {\n rawLookupRef.current = Array.isArray(raw) ? raw : [];\n setDynamicOptions(normalizeOptions(rawLookupRef.current));\n }\n } catch (err) {\n console.error(`[AddFormV1] Failed to fetch options for \"${field.field}\":`, err);\n if (!cancelled) setDynamicOptions([]);\n } finally {\n if (!cancelled) setOptionsLoading(false);\n }\n }\n\n fetchOptions();\n return () => { cancelled = true; };\n }, [type, field.dataSource, field.field, field.limit, field.lookupCollection, field.displayField, field.displayField2, field.valueField, field.lookupFilterField, lookupFilterValue, field.groupName, field.groupRoleContains, field.masterName, locationSearch, lookupSearch, masterSearch, moduleName, field.extraFields, field.optionsRequireExtraField, field.optionsRequireExtraValue, field.optionsHierarchyParentField, field.optionsHierarchySelfFrom, refetchNonce, field.lookupMinSearchLength, field.locationLevel, field.locationCountryFrom, field.locationStateFrom, locCountryValue, locStateValue]);\n\n const staticOptions = normalizeOptions(field.options ?? field.values ?? []);\n const baseOptions = dynamicOptions ?? staticOptions;\n\n // ── Stored values outside the filtered option list ──────────────────────\n // `lookupFilters` decide what may be PICKED. They must not decide what an\n // already-assigned value is allowed to SHOW — a job assigned to somebody\n // outside the current user's reporting chain rendered its raw id (\"149\")\n // instead of a name. Resolved separately, unfiltered, and appended.\n const [resolvedOptions, setResolvedOptions] = useState([]);\n const missingValues = missingOptionValues(value, baseOptions);\n // Joined into a string: the array identity changes every render, and a raw\n // array dependency would refetch forever.\n const missingKey = missingValues.join(',');\n useEffect(() => {\n if (!missingKey || field.dataSource !== 'lookup' || optionsLoading) return undefined;\n let cancelled = false;\n fetchLookupLabels(field, missingKey.split(','))\n .then((rows) => { if (!cancelled) setResolvedOptions(rows); })\n // Best effort. Failing to resolve a label must never break the\n // field — the value is still there and still submits.\n .catch(() => { if (!cancelled) setResolvedOptions([]); });\n return () => { cancelled = true; };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [missingKey, field.dataSource, field.lookupCollection, field.displayField,\n field.displayField2, field.valueField, optionsLoading]);\n // optionsFromField constraint applied here so EVERY option-driven control\n // (select, radio, checkbox group, location…) is narrowed the same way.\n // Fails open — see narrowOptionsByConstraint. prefillWhenExclusive then\n // COMPOSES on top of that narrowing (it removes, it never restores).\n const optionsWithStored = mergeResolvedOptions(baseOptions, resolvedOptions);\n const constrainedOptions = constraintKey ? narrowOptionsByConstraint(optionsWithStored, constraintValue) : optionsWithStored;\n const options = exclusivePrefillRules\n ? stripExclusivePrefillOptions(constrainedOptions, exclusivePrefillRules, exclusivePrefillWatched ?? {})\n : constrainedOptions;\n\n // Select multiplicity is config-driven: multiSelect flag → explicit mode →\n // field.multiple → array dataType. No field-name list. \"tags\" is opt-in via\n // an explicit field.mode === \"tags\".\n const selectMode = field.multiSelect\n ? 'multiple'\n : (field.mode ?? (truthy(field.multiple) ? 'multiple' : undefined));\n const inferredSelectMode = selectMode ?? (effectiveDataType(field) === 'array' ? 'multiple' : undefined);\n // allowCustomValues (admin config) — the field keeps a value the user TYPED\n // even when it is not in the list (Candidate → Skills is the first user, but\n // nothing here is module- or field-specific: any select/lookup field can opt\n // in from Form Groups). Until now free entry existed only for the hardcoded\n // `type: 'tagify'` control, which is not per-field selectable and loses every\n // other select behaviour (lookup, autofill, quick-create).\n const allowCustomValues = truthy(field.allowCustomValues);\n // antd's \"tags\" mode is what keeps a typed value; it always emits an ARRAY,\n // so a single-valued field has to be unwrapped again on the way out (see\n // handleSelectChange) and wrapped on the way in.\n const effectiveSelectMode = allowCustomValues ? 'tags' : inferredSelectMode;\n const isArrayValued = Boolean(field.multiSelect) || truthy(field.multiple)\n || effectiveDataType(field) === 'array' || inferredSelectMode === 'multiple';\n // Config-driven separators that commit a typed entry (default comma).\n const tokenSeparators = allowCustomValues\n ? (typeof field.tokenSeparators === 'string' && field.tokenSeparators\n ? field.tokenSeparators.split('')\n : [','])\n : undefined;\n\n const isSelectLike = ['select', 'location'].includes(type);\n const placeholder = field.hidePlaceholder\n ? undefined\n : (field.placeholder ?? `${isSelectLike ? 'Select' : 'Enter'} ${String(field.label ?? '').toLowerCase()}`);\n const inputLimits = getInputLimits(field);\n // Sets the value in the form store first, then re-validates.\n // Required because FieldControl is a custom wrapper — Form.Item's injected\n // onChange never reaches the inner Ant Design components, so the store\n // would otherwise hold stale/undefined values when validation runs.\n const updateAndValidate = (nextValue) => {\n onChange?.(nextValue);\n\n setTimeout(() => {\n form.validateFields([name]).catch(() => { });\n }, 0);\n };\n\n // Config-driven \"Add More\"/\"Edit\" quick actions inside a select dropdown.\n // Called unconditionally (rules of hooks) — returns nulls unless the field\n // opts in via quickCreate/quickEdit. On success, refetch options and (for a\n // fresh create on a single select) select the new record.\n const quick = useQuickField({ \n field, form, name, moduleName, scopeValues, ownValue: value,\n onDone: (kind, newId) => {\n setRefetchNonce((n) => n + 1);\n const single = effectiveDataType(field) !== 'array' && !field.multiSelect && !field.multiple;\n if (kind === 'create' && newId != null && single) {\n // Same clearing the ordinary onChange does. Creating an employer\n // from inside the dropdown IS changing the employer, so the rest\n // of the group — recruiter, email, contact, VMS — still describes\n // the PREVIOUS one and must go. This path set the new value and\n // skipped the clear, so a brand-new employer kept the old\n // employer's recruiter beside it, which reads as a real pairing.\n //\n // Cleared BEFORE the value is written, so anything the new\n // selection autofills is preserved rather than wiped after.\n if (field.clearGroupOnChange || field.linkedClearField) {\n applyGroupClear(form, field, name, rowFieldKeys);\n }\n updateAndValidate(usesLabeledSelectValue(field) ? { value: newId } : newId);\n }\n },\n });\n\n // Build validator config once (null when not set)\n const validatorCfg = field.validator?.type\n ? { ...field.validator, title: field.validator.title || field.label || 'Field' }\n : null;\n\n const inputProps = {\n ...inputLimits,\n disabled,\n placeholder,\n prefix: field.icon ? null : fieldIcons[field.field],\n value: value ?? '',\n onChange: (event) => {\n let nextValue = field.formatter\n ? cleanValue(event.target.value, field.formatter)\n : event.target.value;\n\n if (validatorCfg) {\n const { cleaned, error } = applyInputValidator(nextValue, validatorCfg, 'change');\n setInputError(error);\n nextValue = cleaned;\n }\n\n updateAndValidate(nextValue);\n },\n // Composed, not conditional. The character-validator blur only exists\n // when a validator is configured, so hanging the duplicate check off it\n // would silently skip every field without one — including a plain email\n // box, which is exactly the field this is for.\n onBlur: (e) => {\n if (validatorCfg) {\n const { cleaned, error } = applyInputValidator(e.target.value, validatorCfg, 'blur');\n setInputError(error);\n if (cleaned !== e.target.value) updateAndValidate(cleaned);\n }\n // Typing an email that already exists should be caught here, not on\n // submit after the whole form has been filled in.\n if (field.checkDuplicateOnBlur && String(e.target.value ?? '').trim()) {\n onDuplicateBlur?.(field);\n }\n },\n ...(validatorCfg && {\n onKeyPress: (e) => {\n const pattern = getKeyPattern(validatorCfg.type);\n if (!pattern) return;\n if (e.which === 0 || e.keyCode === 8 || e.keyCode === 13) return;\n const char = String.fromCharCode(e.which ?? e.keyCode);\n if (!pattern.test(char)) {\n e.preventDefault();\n const hint = `${validatorCfg.title} — invalid character.`;\n setInputError(hint);\n setTimeout(() => setInputError((prev) => (prev === hint ? null : prev)), 1800);\n }\n },\n maxLength: validatorCfg.maxLength ?? inputLimits.maxLength,\n }),\n };\n\n if (type === 'tagify') {\n return (\n <Select\n value={value}\n allowClear\n disabled={disabled}\n mode=\"tags\"\n placeholder={placeholder}\n onChange={updateAndValidate}\n />\n );\n }\n if (type === 'location') {\n return (\n <Select\n value={value}\n allowClear\n showSearch\n filterOption={false}\n disabled={disabled}\n loading={optionsLoading}\n // Single or multi is admin config (Form Groups → the field's\n // \"Location selection\"). inferredSelectMode is the SAME resolver\n // an ordinary select uses, so multiSelect / multiple / an array\n // dataType all mean the same thing on a location field as they\n // do everywhere else — and effectiveDataType already types a\n // multiSelect field's payload as an array, so nothing extra is\n // needed to store several locations.\n mode={inferredSelectMode}\n options={options}\n placeholder={placeholder}\n notFoundContent={optionsLoading ? <Spin size=\"small\" /> : undefined}\n onSearch={setLocationSearch}\n onFocus={() => setLocationSearch((current) => current)}\n onChange={updateAndValidate}\n />\n );\n }\n if (type === 'select') {\n const remoteLookup = field.dataSource === 'lookup';\n const remoteMaster = field.dataSource === 'master';\n const remoteSearch = remoteLookup || remoteMaster;\n const keepLabel = usesLabeledSelectValue(field);\n const rawControlValue = toSelectControlValue(field, value, options);\n // \"tags\" mode renders from an array. A single-valued field that opted\n // into allowCustomValues still stores a scalar, so wrap it for display\n // only — the stored shape never changes.\n const controlValue = (allowCustomValues && !isArrayValued)\n ? (rawControlValue === undefined || rawControlValue === null || rawControlValue === ''\n ? undefined\n : (Array.isArray(rawControlValue) ? rawControlValue : [rawControlValue]))\n : rawControlValue;\n const handleSelectChange = (raw) => {\n // …and unwrap on the way out: keep the LAST entry the user typed or\n // picked, so a single-valued field never starts storing an array\n // just because free entry was switched on.\n const val = (allowCustomValues && !isArrayValued && Array.isArray(raw))\n ? (raw.length ? raw[raw.length - 1] : undefined)\n : raw;\n updateAndValidate(val);\n // Changing this field can invalidate the rest of its group: an\n // employer's recruiter, email, contact and VMS all describe the\n // PREVIOUS employer, and leaving them behind silently attaches one\n // company's details to another. Cleared BEFORE autofill below, so a\n // new selection's own values are written straight back in.\n if (field.clearGroupOnChange || field.linkedClearField) {\n applyGroupClear(form, field, name, rowFieldKeys);\n }\n if (field.autofillFrom?.length) {\n const selectedValue = val && !Array.isArray(val) && typeof val === 'object' ? val.value : val;\n const isInsideList = Array.isArray(name) && name.length >= 3 && typeof name[1] === 'number';\n if (val == null) {\n // Cleared — wipe all autofill targets\n field.autofillFrom.forEach(({ targetField: tf }) => {\n const tp = isInsideList\n ? [...name.slice(0, 2), ...namePathFromString(tf)]\n : namePathFromString(tf);\n form.setFieldValue(tp, null);\n });\n } else if (rawLookupRef.current.length > 0) {\n const vField = field.valueField ?? '_id';\n const rawItem = rawLookupRef.current.find(item =>\n getNestedProp(item, vField) === selectedValue || item._id === selectedValue || item.id === selectedValue || item.value === selectedValue\n );\n if (rawItem) {\n field.autofillFrom.forEach(({ optionKey, targetField: tf }) => {\n const v = getNestedProp(rawItem, optionKey) ?? rawItem.extraData?.[optionKey] ?? null;\n const tp = isInsideList\n ? [...name.slice(0, 2), ...namePathFromString(tf)]\n : namePathFromString(tf);\n form.setFieldValue(tp, v);\n });\n }\n }\n }\n };\n return (\n <>\n <Select\n value={controlValue}\n labelInValue={keepLabel || undefined}\n allowClear\n // Every select is type-to-search. It used to be enabled only\n // for remote/lookup/group sources, so a static-option field\n // (Currency, Unit, Work Mode, Status…) could only be picked\n // by scrolling — painful once a list runs to 30 entries, as\n // Relevant Experience does. Local lists filter on the LABEL\n // (optionFilterProp); remote ones keep filterOption=false\n // because the server already filtered.\n // `field.showSearch: false` turns it off for a specific field.\n showSearch={field.showSearch !== false}\n optionFilterProp=\"label\"\n filterOption={remoteSearch ? false : undefined}\n disabled={disabled}\n loading={optionsLoading}\n mode={effectiveSelectMode}\n tokenSeparators={tokenSeparators}\n options={options}\n placeholder={placeholder}\n notFoundContent={optionsLoading ? <Spin size=\"small\" /> : undefined}\n onSearch={remoteLookup ? setLookupSearch : remoteMaster ? setMasterSearch : undefined}\n onChange={handleSelectChange}\n dropdownRender={quick.footer ? (menu) => (<>{menu}{quick.footer}</>) : undefined}\n />\n {quick.modal}\n </>\n );\n }\n if (type === 'radio') {\n return (\n <Radio.Group\n value={value}\n disabled={disabled}\n options={options}\n onChange={(e) => updateAndValidate(e.target.value)}\n />\n );\n }\n if (type === 'checkbox') {\n if (options.length > 0) {\n return (\n <Checkbox.Group\n value={value}\n disabled={disabled}\n options={options}\n onChange={updateAndValidate}\n />\n );\n }\n return (\n <Checkbox\n checked={Boolean(checked ?? value)}\n disabled={disabled}\n onChange={(e) => {\n const next = e.target.checked;\n // Region gate: some markets do not accept an entry that is\n // still in progress. The tick is REVERSED rather than left\n // standing with an error underneath — leaving it ticked\n // invites the user to try to submit and be refused twice.\n if (next && onRegionBlocked?.(field)) return;\n updateAndValidate(next);\n // Ticking \"still ongoing\" makes this the most recent entry,\n // so it may now belong at the top of a newest-first list.\n if (next) onRowOrderChange?.(field, name);\n if (field.linkedClearField && next) {\n const clearPath = Array.isArray(name) && name.length > 1\n ? [...name.slice(0, -1), field.linkedClearField]\n : [field.linkedClearField];\n form.setFieldValue(clearPath, null);\n }\n }}\n >\n {field.checkboxLabel ?? field.label}\n </Checkbox>\n );\n }\n if (type === 'text-editor') {\n return (\n <>\n <TipTapEditor\n value={value ?? form.getFieldValue(name) ?? ''}\n disabled={disabled}\n placeholder={placeholder}\n onChange={(html) => {\n if (validatorCfg) {\n const { error } = applyInputValidator(html, validatorCfg, 'change');\n setInputError(error);\n }\n updateAndValidate(html);\n }}\n />\n {inputError && <div className=\"v1-input-validator-hint\">{inputError}</div>}\n </>\n );\n }\n if (type === 'textarea') {\n return (\n <>\n <TextArea {...inputProps} rows={field.rows ?? 3} className=\"v1-scroll-textarea\" />\n {inputError && <div className=\"v1-input-validator-hint\">{inputError}</div>}\n </>\n );\n }\n if (type === 'date') {\n return (\n <DatePicker\n disabled={disabled}\n placeholder={placeholder}\n style={{ width: '100%' }}\n suffixIcon={<CalendarOutlined />}\n value={value ?? null}\n disabledDate={getDisabledDate(field, form, name)}\n defaultPickerValue={getDefaultPickerValue(field)}\n onChange={(date) => {\n updateAndValidate(date);\n // Dates are the other way a row becomes the most recent\n // one — the tick-box is not the only trigger.\n onRowOrderChange?.(field, name);\n }}\n />\n );\n }\n if (type === 'time') return <TimePicker disabled={disabled} placeholder={placeholder} style={{ width: '100%' }} value={value ?? null} onChange={(time) => updateAndValidate(time)} />;\n if (type === 'file') {\n const fileRules = field.validations ?? field.validation ?? field.rules ?? [];\n const fileTypeRule = fileRules.find((r) => (typeof r === 'string' ? r : r?.type) === 'fileType');\n const fileSizeRule = fileRules.find((r) => (typeof r === 'string' ? r : r?.type) === 'fileSize');\n const maxFilesRule = fileRules.find((r) => (typeof r === 'string' ? r : r?.type) === 'maxFiles');\n\n // Admin \"Allowed Content\" category (field.accept) takes priority over the\n // fine-grained fileType rule; 'any'/unset falls through to the rule.\n const acceptCategory = uploadAcceptCategory(field);\n const acceptTypes = acceptCategory\n ? acceptCategory.exts.map((e) => `.${e}`).join(',')\n : (fileTypeRule?.value\n ? fileTypeRule.value.split(',').map((e) => `.${e.trim().replace(/^\\./, '')}`).join(',')\n : undefined);\n const maxSizeMB = fileSizeRule ? Number(fileSizeRule?.value ?? 5) : undefined;\n // maxFiles validation rule takes top priority; otherwise use field.multiple/maxCount\n // (set via admin panel toggle), falling back to single-file mode.\n const maxFiles = maxFilesRule\n ? Number(maxFilesRule?.value ?? 1)\n : (truthy(field.multiple) ? (field.maxCount ?? 5) : 1);\n\n const fileList = Array.isArray(value) ? value : [];\n const canAddMore = fileList.length < maxFiles;\n\n const formatFileSize = (bytes) => {\n if (!bytes) return '';\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`;\n return `${(bytes / 1024 / 1024).toFixed(2)} MB`;\n };\n\n const getFileIcon = (fileName) => {\n const ext = String(fileName ?? '').split('.').pop()?.toLowerCase();\n if (ext === 'pdf') return <FilePdfOutlined className=\"v1-file-type-icon v1-file-icon-pdf\" />;\n if (['doc', 'docx'].includes(ext)) return <FileWordOutlined className=\"v1-file-type-icon v1-file-icon-word\" />;\n if (['xls', 'xlsx', 'csv'].includes(ext)) return <FileExcelOutlined className=\"v1-file-type-icon v1-file-icon-excel\" />;\n if (['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'].includes(ext)) return <FileImageOutlined className=\"v1-file-type-icon v1-file-icon-image\" />;\n return <FileOutlined className=\"v1-file-type-icon v1-file-icon-default\" />;\n };\n\n const handleFileDelete = (index) => {\n updateAndValidate(fileList.filter((_, i) => i !== index));\n };\n\n const handleFileView = (file, fileIdx) => {\n const docs = fileList.map((f) => {\n let url = f.url ?? f.thumbUrl ?? '';\n if (!url && f.originFileObj instanceof File) url = URL.createObjectURL(f.originFileObj);\n return { url, name: f.name ?? 'file' };\n }).filter(d => d.url);\n setViewer({ open: true, docs, index: fileIdx ?? 0 });\n };\n\n const isMulti = maxFiles > 1;\n const remaining = maxFiles - fileList.length;\n\n const typeHint = acceptCategory\n ? acceptCategory.hint\n : (acceptTypes\n ? acceptTypes.split(',').map((t) => t.replace('.', '').toUpperCase()).join(', ')\n : null);\n const sizeHint = maxSizeMB ? `up to ${maxSizeMB} MB` : null;\n const baseHint = [typeHint, sizeHint].filter(Boolean).join(' ');\n const dropHint = isMulti && fileList.length > 0\n ? [baseHint, `${remaining} of ${maxFiles} remaining`].filter(Boolean).join(' • ')\n : baseHint;\n const dropTitle = fileList.length > 0\n ? `Add ${isMulti ? 'more files' : 'file'}`\n : (field.buttonLabel ?? `Upload ${field.label ?? 'File'}`);\n\n const beforeUploadHandler = (file) => {\n if (fileList.length >= maxFiles) return Upload.LIST_IGNORE;\n if (acceptTypes) {\n const ext = (file.name.split('.').pop() ?? '').toLowerCase();\n const allowed = acceptTypes.split(',').map((t) => t.replace(/^\\./, '').toLowerCase());\n if (!allowed.includes(ext)) {\n message.error(acceptCategory\n ? acceptCategory.error\n : (fileTypeRule?.message ?? `Only ${fileTypeRule.value} files are allowed`));\n return Upload.LIST_IGNORE;\n }\n }\n if (maxSizeMB !== undefined && file.size / 1024 / 1024 > maxSizeMB) {\n message.error(fileSizeRule?.message ?? `File must be smaller than ${maxSizeMB} MB`);\n return Upload.LIST_IGNORE;\n }\n return false;\n };\n\n // antd calls onChange once per file even in multi-select, each time with the\n // full accumulated newList. Slicing to maxFiles guards against racing additions.\n const handleUploadChange = ({ fileList: newList }) => {\n const sliced = newList.slice(0, maxFiles);\n updateAndValidate(sliced);\n // An \"upload\"-trigger AI action (e.g. auto-parse a resume) fires once\n // per newly-added file, using the raw browser File object.\n if (onAiUpload && sliced.length > fileList.length) {\n const added = sliced[sliced.length - 1];\n if (added?.originFileObj) onAiUpload(added.originFileObj);\n }\n };\n\n const multiUploadProps = {\n accept: acceptTypes,\n fileList,\n showUploadList: false,\n multiple: true,\n maxCount: maxFiles,\n beforeUpload: beforeUploadHandler,\n onChange: handleUploadChange,\n disabled,\n };\n\n const fileRows = fileList.map((file, index) => (\n <div key={file.uid ?? index} className=\"v1-file-item\">\n <div className=\"v1-file-item-icon\">{getFileIcon(file.name)}</div>\n <div className=\"v1-file-item-info\">\n <span className=\"v1-file-item-name\" title={file.name}>{file.name}</span>\n <span className=\"v1-file-item-meta\">\n {file.existing\n ? 'Previously uploaded'\n : `${formatFileSize(file.size)}${file.size ? ' • ' : ''}Uploaded just now`}\n </span>\n </div>\n <Space size={6} className=\"v1-file-item-actions\">\n <Button\n size=\"small\"\n icon={<EyeOutlined />}\n onClick={() => handleFileView(file, index)}\n className=\"v1-file-view-btn\"\n >\n View\n </Button>\n <Button\n size=\"small\"\n danger\n icon={<DeleteOutlined />}\n onClick={() => handleFileDelete(index)}\n className=\"v1-file-delete-btn\"\n />\n </Space>\n </div>\n ));\n\n const viewerEl = (\n <DocumentViewer\n documents={viewer.docs}\n open={viewer.open}\n onClose={() => setViewer(v => ({ ...v, open: false }))}\n initialIndex={viewer.index}\n />\n );\n\n if (isMulti) {\n const multiTitle = fileList.length > 0\n ? `Upload more ${field.label ?? 'files'}`\n : (field.buttonLabel ?? `Upload ${field.label ?? 'File'}`);\n\n return (\n <>\n <div className=\"v1-file-upload-wrapper\">\n {/* Centered dropzone — always at top in multiple mode */}\n {canAddMore && (\n <Upload {...multiUploadProps} style={{ width: '100%', display: 'block' }}>\n <div className={`v1-upload-dropzone v1-upload-dropzone-center${disabled ? ' v1-upload-dropzone-disabled' : ''}`}>\n <div className=\"v1-upload-dropzone-title-row\">\n <CloudUploadOutlined className=\"v1-upload-cloud-icon v1-upload-cloud-icon-sm\" />\n <span className=\"v1-upload-dropzone-title v1-upload-dropzone-title-blue\">{multiTitle}</span>\n </div>\n <span className=\"v1-upload-dropzone-sub\">Drag & drop or click to upload</span>\n {baseHint && <span className=\"v1-upload-dropzone-sub\">{baseHint}</span>}\n </div>\n </Upload>\n )}\n\n {/* Uploaded file rows — 2-column grid */}\n {fileList.length > 0 && (\n <div className=\"v1-file-grid\">\n {fileRows}\n </div>\n )}\n\n {/* \"+ Add more files\" text link at the bottom */}\n {canAddMore && fileList.length > 0 && (\n <Upload {...multiUploadProps} style={{ display: 'inline-block' }}>\n <Button type=\"link\" size=\"small\" icon={<PlusOutlined />} className=\"v1-add-more-files-btn\">\n Add more files\n </Button>\n </Upload>\n )}\n </div>\n {viewerEl}\n </>\n );\n }\n\n return (\n <>\n <div className=\"v1-file-upload-wrapper\">\n {/* Single mode: compact file row at field height */}\n {fileList.length > 0 && <div className=\"v1-file-rows-single\">{fileRows}</div>}\n\n {canAddMore && (\n <Upload\n accept={acceptTypes}\n fileList={fileList}\n showUploadList={false}\n multiple={false}\n maxCount={1}\n beforeUpload={beforeUploadHandler}\n onChange={handleUploadChange}\n disabled={disabled}\n style={{ width: '100%', display: 'block' }}\n >\n <div className={`v1-upload-dropzone v1-upload-dropzone-single${disabled ? ' v1-upload-dropzone-disabled' : ''}`}>\n <CloudUploadOutlined className=\"v1-upload-cloud-icon\" />\n <span className=\"v1-upload-dropzone-title\">{dropTitle}</span>\n {dropHint && <span className=\"v1-upload-dropzone-sub\">— {dropHint}</span>}\n </div>\n </Upload>\n )}\n </div>\n {viewerEl}\n </>\n );\n }\n\n return (\n <>\n <Input\n {...inputProps}\n type={type === 'number' ? 'number' : type}\n // step=\"any\" so the browser's own number input accepts a\n // fractional value on a field the admin marked decimal.\n {...(type === 'number' && truthy(field.decimal) ? { step: 'any' } : {})}\n // Admin-configured unit shown inside the input (e.g. \"%\").\n {...(field.suffix ? { suffix: field.suffix } : {})}\n />\n {inputError && <div className=\"v1-input-validator-hint\">{inputError}</div>}\n </>\n );\n}\n\nfunction SectionTitle({ icon, title }) {\n return (\n <Space size={10} align=\"center\">\n <div className=\"v1-section-icon-box\">{icon}</div>\n <Text strong className=\"v1-section-label\">{title}</Text>\n </Space>\n );\n}\n\nfunction FieldLabel({ field, label, locked }) {\n if (!label) return label;\n // field.tooltip (admin config) OR the older infoEnabled/infoText pair — one\n // resolver (fieldTooltipText) so both forms and every control type agree on\n // where a field's help text comes from. The TEXT is always admin config.\n const infoText = fieldTooltipText(field);\n const showInfo = Boolean(infoText);\n if (!showInfo && !locked) return label;\n return (\n <span className=\"v1-field-label-with-info\">\n <span>{label}</span>\n {showInfo && (\n <Tooltip title={infoText}>\n <InfoCircleOutlined className=\"v1-field-info-icon\" />\n </Tooltip>\n )}\n {locked && (\n <Tooltip title=\"You don't have permission to edit this field\">\n <LockOutlined className=\"v1-field-info-icon\" />\n </Tooltip>\n )}\n </span>\n );\n}\n\nfunction GroupInfoMessage({ group }) {\n if (!truthy(group?.infoEnabled) || empty(group?.infoText)) return null;\n return <Text type=\"secondary\" className=\"v1-group-info-message\">{group.infoText}</Text>;\n}\n\nfunction GroupToggleControl({ group }) {\n if (!truthy(group?.toggleEnabled) || empty(group?.toggleField)) return null;\n return (\n <Space size={6} align=\"center\" onClick={(event) => event.stopPropagation()}>\n <Text type=\"secondary\" className=\"v1-combine-toggle-label\">{group.toggleLabel || 'Toggle'}</Text>\n <Form.Item name={group.toggleField} valuePropName=\"checked\" initialValue={Boolean(group.toggleValue)} noStyle>\n <Switch size=\"small\" />\n </Form.Item>\n </Space>\n );\n}\n\n\n// renderFieldHelp — the guidance under a field.\n//\n// `helpText` accepts a STRING or an ARRAY of strings. An array renders as\n// stacked lines, which is what lets one field carry two different KINDS of\n// help without them running together: the mechanical constraint (\"Supports\n// .pdf, .doc, .docx up to 2MB\") and the reason to bother (\"Upload the résumé\n// first — we can read the details straight out of it\"). Jammed into one\n// paragraph they read as a wall and the second half is skipped.\n//\n// A plain string keeps rendering exactly as before, so nothing existing moves.\n// formatPrefillHint renders a previous value as one readable line.\n//\n// The label is admin config (`prefillHintLabel`, \"{value}\" substituted) so the\n// wording belongs to whoever configured the field, not to this file.\n//\n// A history container is the interesting case: an append-only field such as\n// candidateBudget stores an ARRAY of stamped entries, and the one worth showing\n// is the LAST. Rendering the raw array would print \"[object Object]\", which is\n// worse than showing nothing.\nfunction formatPrefillHint(field, stored) {\n let value = stored;\n if (Array.isArray(value)) value = value[value.length - 1];\n if (value && typeof value === 'object') {\n // Join the entry's meaningful leaves, skipping the audit stamps every\n // history entry carries — they describe the WRITE, not the value.\n const skip = new Set(['timestamp', 'updatedBy', 'updatedAt', 'createdAt', 'createdBy', '_id']);\n const parts = Object.entries(value)\n .filter(([k, v]) => !skip.has(k) && v !== null && v !== undefined && v !== ''\n && typeof v !== 'object')\n .map(([, v]) => String(v).trim())\n .filter(Boolean);\n if (!parts.length) return '';\n value = parts.join(' ');\n }\n const text = String(value ?? '').trim();\n if (!text) return '';\n const label = String(field?.prefillHintLabel ?? 'Last recorded: {value}');\n return label.includes('{value}') ? label.replace('{value}', text) : `${label} ${text}`;\n}\n\n// hint is an extra line appended under the field — used by `prefillAsHint`\n// (see the prefill effect) to SHOW a previous value instead of filling it in.\nfunction renderFieldHelp(field, hint) {\n const raw = field?.helpText;\n const lines = (Array.isArray(raw) ? raw : [raw])\n .map((line) => (line == null ? '' : String(line).trim()))\n .filter(Boolean);\n if (hint) lines.push(hint);\n if (!lines.length) return undefined;\n return (\n <span className=\"v1-field-help-text\">\n {lines.map((line, i) => (\n <Text key={i} type=\"secondary\" className=\"v1-field-help-line\">{line}</Text>\n ))}\n </span>\n );\n}\n\n// forwardRef, not a plain `ref` prop: this package declares `react >=18` as its\n// peer, and on React 18 a function component does not receive `ref` as a prop.\n// React 19 no longer needs the wrapper but still honours it, so this is the one\n// form that works across the whole supported range.\n//\n// Exported inline rather than via a `const AddFormV1 = forwardRef(...)` binding:\n// a const of the same name shadows the render function, and the transform then\n// renames the inner one (\"AddFormV12\"), which is what DevTools and every error\n// stack would go on to display.\nexport default forwardRef(function AddFormV1({\n moduleName,\n action,\n authToken,\n clientId,\n region,\n formGroups: providedFormGroups,\n loading: providedLoading = false,\n error: providedError = '',\n breadcrumbItems = [],\n // formType — controls the mode of operation:\n // 'add' → Add Form (default, existing behavior)\n // 'search' → Search Form (lighter validation, Reset button, no auto-create)\n formType = 'add',\n submitText: propSubmitText,\n cancelPath = '/candidates',\n onSubmit,\n // Optional host workflow used only after Admin has a complete, enabled\n // wizard configuration. It lets a domain preserve established side effects\n // (for example Batch draft/session operations) while AddFormV1 remains the\n // route entry point and the normal form remains the automatic fallback.\n wizardAdapter: WizardAdapter = null,\n wizardAdapterProps = null,\n // initialRecord — prefill flat form fields from a plain record object.\n // Matched by field.field / payloadKey / dot-path; best-effort, never required.\n initialRecord: initialRecordProp = null,\n // initialValues (opt-in alias, PLAN-20261105-01) — same as initialRecord,\n // the name EditFormV1 uses. initialRecord wins when both are given.\n initialValues = null,\n // prefillFromUrl — when set (quickSubmit flow), AddFormV1 reads the route to\n // decide the prefill source and the job/candidate linkage entirely on its own:\n // • isFromSubmission=true + submissionId → read the submissions collection\n // • otherwise candidateId → read the candidates collection\n // Both resolve through getFormGroups(id) (field.value + group.rows embedded) —\n // no separate detail-view API. The linkage the submission create requires\n // (applicantId + jobId) is derived from the same URL params.\n prefillFromUrl = false,\n // extraPayload — context/linkage keys merged into the create payload that are\n // NOT form fields (e.g. submission needs { jobId, applicantId }). Kept out of\n // the form so the config stays generic. Ignored when prefillFromUrl derives\n // its own linkage from the route.\n extraPayload = null,\n // presetClientId — caller already knows the client (e.g. Quick Submit knows\n // it from the selected job) so the client-scope gate should resolve silently\n // instead of showing the manual \"Select Client\" picker.\n presetClientId = null,\n // ListView props for search mode — passed through from parent when search results\n // should be displayed below the search form.\n listViewProps = {},\n // selectedScope — optional scope parameter for filtering search results\n selectedScope = '',\n // searchActionContext — page-level context (e.g. { jobId }) merged into every\n // search-result row action's popupState, so a popup opened from here (like\n // Source Candidates' \"Shortlisted\"/\"Tag to Jobs\") already knows what the\n // caller knows instead of asking the user to re-select it. Mirrors the\n // action.popupState convention ListView already spreads into the popup's\n // navigation state — see ListView.jsx's handleActionClick.\n searchActionContext = null,\n // embedded — render the form for use inside a modal (quick \"Add More\" from a\n // select dropdown). Suppresses page chrome/navigation; on a successful create\n // onSuccess(newRecordId, values) is called instead of navigating away, and the\n // Cancel button calls onCancel. Entirely opt-in; the standalone page path is\n // unchanged when embedded is false.\n embedded = false,\n onSuccess = null,\n onCancel = null,\n // Opt-in only. Uses Admin Form Groups as steps while retaining this form's\n // validation, payload, upload and submit engines.\n wizard,\n hideFooter = false,\n // uniqueCheckDebounceMs (opt-in, REQ-20261103-01) — wait this many ms after\n // the last change before a `unique` field is checked; an older request for\n // the same field is cancelled. 0 (default) = every check at once, as before.\n // The submit-time check is never delayed (see uniqueValidationApi.js).\n uniqueCheckDebounceMs = 0,\n}, ref) {\n const initialRecord = initialRecordProp ?? initialValues;\n useEffect(() => {\n if (authToken) setAuthTokenOverride(authToken);\n return () => {\n if (authToken) clearAuthTokenOverride();\n };\n }, [authToken]);\n\n const isSearch = formType === 'search';\n const submitText = propSubmitText ?? (isSearch ? 'Search' : 'Create');\n const navigate = useNavigate();\n // Router location — nav state carries the in-flight relevant-skill match\n // handed over by Quick Submit (see the prefill effect below).\n const routerLocation = useLocation();\n // Cache for the relevant-skill match promise, keyed by its token — see the\n // prefill effect below and services/pendingHandoff.js.\n const skillMatchTokenRef = useRef(null);\n const skillMatchPromiseRef = useRef(null);\n const routeParams = useParams();\n const [searchParams] = useSearchParams();\n const [form] = Form.useForm();\n const [wizardStep, setWizardStep] = useState(0);\n\n // ── Imperative handle ───────────────────────────────────────────────────\n // Lets a host drive the form from outside it — submit it from its own\n // button, validate before advancing a wizard step, read the current values\n // for a preview, or reset it after a modal closes.\n //\n // Deliberately only these four. Exposing `form` itself would hand callers\n // the entire antd API, including setFieldsValue — and a host writing\n // directly into the store bypasses every conditional default, payload gate\n // and linked-clear rule this component maintains, in ways nothing here\n // could see or correct.\n //\n // submit() goes through form.submit() rather than calling the submit\n // handler, so an imperative submit runs validation, the duplicate gate and\n // the after-submit navigation exactly as pressing the button does.\n useImperativeHandle(ref, () => ({\n submit: () => form.submit(),\n validate: () => form.validateFields(),\n getValues: () => form.getFieldsValue(true),\n reset: () => form.resetFields(),\n }), [form]);\n\n // formGroups (opt-in, PLAN-20261105-01) — an ARRAY here wins over moduleName:\n // the form renders these groups and skips every config fetch it makes on\n // mount (form groups, role perms, default fields, linked-job scope), so it\n // can run on a public page with no login. moduleName still names the\n // payload/upload module. Absent → unchanged (moduleName fetches config).\n const hostGroups = Array.isArray(providedFormGroups) ? providedFormGroups : null;\n const configModule = hostGroups ? null : moduleName;\n const searchFormValues = Form.useWatch([], form);\n const [searchLoading, setSearchLoading] = useState(false);\n const [collapsed, setCollapsed] = useState({});\n const [apiFormGroups, setApiFormGroups] = useState([]);\n const [apiLoading, setApiLoading] = useState(Boolean(configModule));\n const [apiError, setApiError] = useState('');\n const [searchFormLabel, setSearchFormLabel] = useState('');\n const [submitLoading, setSubmitLoading] = useState(false);\n // Search results state — used when formType === 'search' to store and display results\n const [searchResults, setSearchResults] = useState({\n searched: false,\n rows: [],\n total: 0,\n fields: [],\n actions: [],\n actionRules: [],\n loading: false,\n });\n const [searchPagination, setSearchPagination] = useState({ current: 1, pageSize: 10 });\n const [lastSearchValues, setLastSearchValues] = useState({});\n const [selectedSource, setSelectedSource] = useState('internal');\n const [tabs, setTabs] = useState([]);\n const [sourceActionState, setSourceActionState] = useState({});\n const [clientOptions, setClientOptions] = useState([]);\n const [scopeClientId, setScopeClientId] = useState(clientId ?? '');\n const [scopeRegion, setScopeRegion] = useState(region ?? '');\n // URL-driven prefill state — populated when prefillFromUrl is set. Holds the\n // source record's form groups (candidate OR submission) with values embedded.\n const [prefillGroups, setPrefillGroups] = useState(null);\n const [prefillLoading, setPrefillLoading] = useState(false);\n // Role Configure → Form permissions for the CURRENT user's role, derived\n // server-side from this module's Form Groups config (see\n // GetRoleFormPermissions). null until loaded / when unavailable, in which\n // case normalizeGroups' rolePerms checks fail open — no behavior change\n // for a role/module that hasn't been configured.\n const [rolePerms, setRolePerms] = useState(null);\n // Default Fields (Form Groups → Default Fields) — always-shown + required\n // field keys for this module. Empty set until loaded / when unconfigured.\n const [defaultFieldSet, setDefaultFieldSet] = useState(() => new Set());\n const formGroups = configModule ? apiFormGroups : (providedFormGroups ?? emptyGroups);\n const loading = configModule ? apiLoading : providedLoading;\n const error = configModule ? apiError : providedError;\n // ── Client-scoped form render, resolved from the linked JOB ──────────────\n // A submission is always created against a job, and the job owns the client.\n // So when the form is opened with a jobId (/submission-create/:jobId, Quick\n // Submit, Source Candidates…) we look the job up, read its clientId, and use\n // it as THIS form's client scope. getFormGroups then returns the client's\n // Form Groups variant when the admin has configured one for that client, and\n // transparently falls back to the module default when they haven't (the\n // backend tries clientId+region → clientId → region → default), so this is\n // safe for every client that has no override.\n const [linkedClientId, setLinkedClientId] = useState('');\n const linkedJobId = (routeParams?.jobId && routeParams.jobId !== '_')\n ? routeParams.jobId\n : (searchParams.get('jobId') || '');\n\n useEffect(() => {\n // An explicit client from the caller always wins — nothing to resolve.\n if (hostGroups || clientId || presetClientId || !linkedJobId) return undefined;\n let cancelled = false;\n (async () => {\n try {\n const data = await getFormGroups({ module: 'jobs', id: linkedJobId });\n const record = flatRecordFromGroups(extractGroups(data)) ?? {};\n // A reference field comes back either as a raw id or {id,value}.\n const raw = record.clientId ?? record.client ?? '';\n const resolved = (raw && typeof raw === 'object') ? (raw.id ?? raw.value ?? '') : raw;\n if (!cancelled && resolved) setLinkedClientId(String(resolved));\n } catch (err) {\n console.error('Client-scope resolve from job failed:', err);\n }\n })();\n return () => { cancelled = true; };\n }, [hostGroups, clientId, presetClientId, linkedJobId]);\n\n const effectiveClientId = clientId || presetClientId || linkedClientId || scopeClientId;\n const effectiveRegion = region || scopeRegion;\n\n // Load the common display defaults (phone format, date format, …) once so a\n // phone field re-formats to the admin-configured mask. Cached; safe to call.\n useEffect(() => { loadDetailDefaults(); }, []);\n\n useEffect(() => {\n let cancelled = false;\n queueMicrotask(() => {\n if (cancelled) return;\n if (!configModule) { setRolePerms(null); return; }\n // Same client/region scope the form's own structure is fetched\n // with (getFormGroups below) — a client-scoped Form Groups\n // override must gate the SAME scoped structure, not the\n // tenant-wide default.\n getRoleFormPermissions({ roleId: localStorage.getItem('roleId') }, configModule, { clientId: effectiveClientId, region: effectiveRegion })\n .then((data) => { if (!cancelled) setRolePerms(Array.isArray(data) && data.length ? data : null); })\n .catch(() => { if (!cancelled) setRolePerms(null); });\n });\n return () => { cancelled = true; };\n }, [configModule, effectiveClientId, effectiveRegion]);\n\n useEffect(() => {\n let cancelled = false;\n queueMicrotask(() => {\n if (cancelled) return;\n if (!configModule) { setDefaultFieldSet(new Set()); return; }\n getModuleDefaultFields(configModule)\n .then((keys) => { if (!cancelled) setDefaultFieldSet(new Set(Array.isArray(keys) ? keys : [])); })\n .catch(() => { if (!cancelled) setDefaultFieldSet(new Set()); });\n });\n return () => { cancelled = true; };\n }, [configModule]);\n\n const groups = useMemo(() => normalizeGroups(formGroups, moduleName, rolePerms, defaultFieldSet), [formGroups, moduleName, rolePerms, defaultFieldSet]);\n const wizardConfigGroups = useMemo(\n () => wizardPlanningGroups(formGroups, groups, rolePerms),\n [formGroups, groups, rolePerms],\n );\n const visibleWizardGroups = useMemo(() => wizardConfigGroups.filter((group) => (\n !group.showIf?.field\n || groupShowIfMatches(group.showIf, getNestedProp(searchFormValues ?? {}, group.showIf.field))\n )), [wizardConfigGroups, searchFormValues]);\n const wizardSteps = useMemo(() => buildFormWizardSteps(visibleWizardGroups), [visibleWizardGroups]);\n const configuredWizardEnabled = isWizardConfigEnabled(wizardConfigGroups);\n const wizardEnabled = !isSearch && (typeof wizard === 'boolean' ? wizard : configuredWizardEnabled);\n const activeWizardStep = Math.min(wizardStep, Math.max(0, wizardSteps.length - 1));\n const wizardSuccessStepIndex = wizardEnabled && wizardSteps.at(-1)?.content?.type === 'success'\n ? wizardSteps.length - 1 : -1;\n const wizardShowingSuccess = activeWizardStep === wizardSuccessStepIndex;\n const wizardNextIsSuccess = activeWizardStep + 1 === wizardSuccessStepIndex;\n\n const goToWizardStep = (next) => {\n setWizardStep(next);\n setCollapsed({});\n };\n\n const advanceWizard = () => wizardRuntime.next();\n\n const submitWizard = (values) => submit(wizardRuntime.prepareSubmitValues(\n mergeWizardSubmitValues(form.getFieldsValue(true), values),\n ));\n\n const handleWizardSubmitFailed = (info) => {\n setCollapsed({});\n const errorStep = wizardEnabled\n ? wizardStepIndexForField(wizardSteps, info?.errorFields?.[0]?.name)\n : -1;\n if (wizardEnabled) wizardRuntime.onSubmitFailed(info, errorStep);\n if (errorStep >= 0 && errorStep !== activeWizardStep) {\n setWizardStep(errorStep);\n requestAnimationFrame(() => scrollToFirstFormError(info, form));\n return;\n }\n scrollToFirstFormError(info, form);\n };\n\n // ── Config-driven field uniqueness ──────────────────────────────────────\n // One checker per form session owns the request sequence, the\n // normalized-value cache and the pending count (see\n // form/uniqueFieldValidation.js). While a check is in flight the submit\n // button is disabled so a record can never be created on a value whose\n // answer has not come back yet. A search form never checks uniqueness.\n const [uniquePending, setUniquePending] = useState(0);\n const uniqueDebounceMs = normalizeUniqueCheckDebounceMs(uniqueCheckDebounceMs);\n const uniqueDebounceOn = uniqueDebounceMs > 0;\n // Debounce off: the API function itself, exactly as before.\n const uniqueCheckApi = useMemo(\n () => (uniqueDebounceOn ? createSupersedingUniqueCheck(checkFieldUnique) : checkFieldUnique),\n [uniqueDebounceOn],\n );\n const uniqueChecker = useMemo(\n () => createUniqueChecker({ checkFieldUnique: uniqueCheckApi, onPendingChange: setUniquePending }),\n [uniqueCheckApi],\n );\n const uniqueContext = useMemo(() => (isSearch ? undefined : {\n checker: uniqueChecker,\n module: moduleName,\n clientId: effectiveClientId || undefined,\n region: effectiveRegion || undefined,\n // NO recordId on the Add form — there is no record to exclude yet.\n }), [isSearch, uniqueChecker, moduleName, effectiveClientId, effectiveRegion]);\n // Every unique-configured field in this form, used to map a submit-time\n // duplicate back onto its field when the response body was flattened.\n const uniqueRuleIndex = useMemo(() => collectUniqueRules(groups), [groups]);\n\n // group.linkGroup — addRow groups sharing the same value stay row-synced\n // (see form/linkedAddRowGroups.js). Empty for every group with no\n // linkGroup, i.e. every group that predates this feature.\n const linkedGroupSets = useMemo(() => computeLinkedSets(groups), [groups]);\n // Registry of each addRow group's live Form.List {add, remove}, written on\n // every render from inside the Form.List's own render-prop (synchronous\n // within the same commit, so it's fully populated before a user can click\n // anything). A linked group's \"Add Row\" / row-delete calls every member's\n // add()/remove() through this registry; unlinked groups just call their own.\n const listControlsRef = useRef({});\n // When an ADDITIONAL submit button (group.formActions, e.g. \"Create and\n // Source Candidate\") is clicked, it stashes its own afterSubmit here so the\n // shared submit() navigates per that button instead of the group default.\n // Reset after every submit and by the plain Create button.\n const pendingAfterSubmitRef = useRef(null);\n const formActions = useMemo(() => groups.flatMap((g) => g.formActions ?? []), [groups]);\n // \"Have we got this person already?\" — asked right after a résumé fills the\n // form in (the first moment an email/phone exist to check), and again on\n // submit as the authoritative gate. Config-driven; a module with no\n // duplicate stages configured never sees any of it.\n const duplicateConfig = useMemo(() => {\n const groupWithConfig = extractGroups(formGroups).find((g) => g?.duplicateCheck);\n return groupWithConfig?.duplicateCheck ?? {};\n }, [formGroups]);\n\n const duplicates = useDuplicateCheck({\n form,\n moduleName,\n config: duplicateConfig,\n // Choosing \"update the existing record\" hands off to that record's Edit\n // form, carrying the file just uploaded so it is stored as another\n // version rather than being lost with the abandoned Add form.\n // The edit route is CONFIG, never guessed. There is no derivable rule:\n // this app routes candidates at \"/candidate/edit/:id\" (singular) and\n // clients at \"/clients/edit/:id\" (plural). Deriving it sent every\n // candidate to \"/candidates/edit/:id\", which matches no route, so the\n // catch-all redirected to the dashboard — the record the user asked to\n // open simply vanished.\n //\n // With no route configured we do NOT navigate. Closing the dialog and\n // leaving the user where they are is recoverable; throwing them at a\n // wrong URL is not.\n onUseExisting: useCallback((id, result, reason, carry) => {\n if (!id) return;\n // The backend delivers the configured route WITH the answer, so\n // there is one source of truth; the group-level value is only an\n // override for a project that wants a different destination.\n const template = result?.editRoute || duplicateConfig?.editRoute;\n if (!template) {\n console.warn(\n `[duplicate-check] ${moduleName}: no editRoute configured, so the existing `\n + 'record was not opened. Set it in Admin → Automations → \"Check for someone '\n + 'already on file\" → \"Where to open the existing record\".',\n );\n return;\n }\n const target = safeNavTarget(template, id, {});\n if (!target) return;\n // The uploaded file travels WITH the user. They picked that résumé\n // for that person; sending them to the existing record and quietly\n // dropping it would make them find and attach it again — and the\n // whole point of opening the existing record is to add this newer\n // file to it (file versioning keeps the previous one).\n navigate(target, {\n state: {\n fromDuplicate: true,\n carryFiles: carry?.files ?? null,\n },\n });\n }, [duplicateConfig, navigate]),\n });\n\n const aiActions = useAiActions({\n form,\n groups,\n module: moduleName,\n // BEFORE any parsed value reaches the form. This is the first moment an\n // email and phone exist, so it is the first moment the question can be\n // asked — and if we already have this person there is no point filling\n // in a form the user is about to abandon.\n onParsed: useCallback(async ({ field, payload }) => {\n const key = field?.field;\n // The file the user just picked, handed to the prompt so it can\n // travel with them to the existing record.\n const carry = key ? { files: { [key]: form.getFieldValue(key) } } : null;\n\n const verdict = await duplicates.prompt({ reason: 'upload', payload, carry });\n if (verdict === 'clear') return true;\n\n // 'existing' — they were sent to the record we already have and the\n // file went WITH them, so it must not also be left behind here.\n // 'blocked' — they backed out to check; leaving the file attached to\n // a form that was never filled in just means the next thing they do\n // starts from a half-state they did not choose.\n // Either way the upload is undone: nothing on this form was filled\n // in, so nothing on it should look as though it was.\n if (key) {\n form.setFieldValue(key, []);\n message.info(verdict === 'existing'\n ? 'Résumé moved to their record.'\n : 'Résumé removed — nothing on this form was filled in.');\n }\n return 'abort';\n }, [duplicates, form]),\n // AFTER the form is filled — a second, cheaper pass that also covers\n // anything the user had typed before uploading.\n onApplied: useCallback(async () => {\n await duplicates.prompt({ reason: 'upload' });\n }, [duplicates]),\n });\n\n // Blur on a field marked `checkDuplicateOnBlur` (the email box). Debounced\n // through a ref rather than fired directly: tabbing quickly through a form\n // can blur the same field twice, and two overlapping checks would open two\n // dialogs on top of each other.\n // ── Region gate ─────────────────────────────────────────────────────────\n // The active region (Admin → Detail Groups → Display Defaults → Region)\n // selects which `regionRules` block each group applies. A region is a KEY\n // into config, never a branch in code — which is what lets a new market be\n // added without touching this file.\n //\n // Today's use: a candidate may be put forward mid-course in the US and UK,\n // but not in India, where a company only accepts a completed qualification.\n const handleRegionBlocked = useCallback((field) => {\n const region = getDefaults().region;\n // Find the group this \"still ongoing\" tick-box belongs to, so its own\n // region rules decide — not some global setting.\n const group = groups.find((g) => (g.fields ?? []).some((f) => f.field === field.field));\n if (!group) return false;\n\n const effective = resolveRegionRules(group, region);\n // Only gates the field the group nominates as its ongoing flag, so an\n // unrelated checkbox in the same group is never caught by this.\n const ongoingField = effective.orderBy?.inProgressField ?? 'currentStudyingHere';\n if (field.field !== ongoingField) return false;\n if (inProgressAllowed(effective)) return false;\n\n // Warn vs block. A warning explains the consequence and lets the tick\n // stand — recording a real person mid-degree is worth doing even where\n // they could not be put forward today. A block reverses the tick, and\n // the submit-time validator below refuses the row however it arrived.\n const blocking = inProgressBlocks(effective);\n openFormNotice({\n tone: blocking ? 'duplicate' : 'overwrite',\n title: blocking\n ? 'This has to be completed first'\n // States the CONSEQUENCE, not a vague heading. The user's next\n // action depends on knowing that saving this is fine but\n // submitting them later will not be.\n : 'You can add this, but they cannot be submitted',\n facts: [\n { label: 'Region', value: region || 'Common' },\n { label: 'Entry', value: group.label ?? group.name },\n ],\n body: inProgressError(effective),\n okText: blocking ? 'Got it' : 'Keep it anyway',\n });\n return blocking;\n }, [groups]);\n\n // ── The submit-time half of the same rule ───────────────────────────────\n // Reversing the tick-box only catches a row somebody ticked BY HAND. A\n // submission prefills its rows from the candidate, and the candidate is\n // allowed to hold an in-progress entry — so on a blocking region the row\n // arrives already ticked and nobody ever touched the box. Without a rule on\n // the field the form would happily submit it, and the restriction would\n // apply to exactly the users who did not need stopping.\n //\n // Resolved here rather than inside getRules because it depends on the\n // GROUP, which getRules never sees.\n const inProgressRulesFor = useCallback((field, groupName) => {\n const group = groups.find((g) => g.name === groupName);\n if (!group) return undefined;\n const effective = resolveRegionRules(group, getDefaults().region);\n const ongoingField = effective.orderBy?.inProgressField ?? 'currentStudyingHere';\n if (field.field !== ongoingField) return undefined;\n const rule = buildInProgressValidator(effective);\n return rule ? [rule] : undefined;\n }, [groups]);\n\n\n // ── Newest-first row ordering ───────────────────────────────────────────\n // After the user changes a row's dates or ticks \"still ongoing\", check\n // whether that row now belongs somewhere else and ASK. Nothing is ever\n // reordered silently — a list that rearranges itself while you are typing\n // in it is disorienting, and the user may have a reason for the order.\n const handleRowOrder = useCallback(async (field, name) => {\n // Only meaningful inside a repeatable group: [listName, rowIndex, key].\n if (!Array.isArray(name) || name.length < 3 || typeof name[1] !== 'number') return;\n const groupName = name[0];\n const rowIndex = name[1];\n\n const group = groups.find((g) => g.name === groupName);\n if (!group) return;\n // Region-resolved, so a market that reorders differently is honoured.\n const effective = resolveRegionRules(group, getDefaults().region);\n if (!effective.orderBy) return;\n\n // Read AFTER the change has landed in the store, so the row being\n // judged carries the value the user just set rather than the previous\n // one — the whole decision turns on that value.\n await Promise.resolve();\n const rows = form.getFieldValue(groupName);\n if (!Array.isArray(rows)) return;\n\n await promptRowMove({\n group: effective,\n rows,\n rowIndex,\n move: listControlsRef.current[groupName]?.move,\n confirm: ({ title, body, okText, cancelText, from, to }) => openFormDecision({\n tone: 'suggestion',\n title,\n facts: [\n { label: 'This entry is at', value: `Row ${from + 1}` },\n { label: 'It belongs at', value: `Row ${to + 1}` },\n ],\n body,\n okText,\n cancelText,\n }),\n });\n }, [groups, form]);\n\n const duplicateBlurRef = useRef(false);\n const handleDuplicateBlur = useCallback(async () => {\n if (duplicateBlurRef.current) return;\n duplicateBlurRef.current = true;\n try {\n await duplicates.prompt({ reason: 'blur' });\n } finally {\n duplicateBlurRef.current = false;\n }\n }, [duplicates]);\n const [viewMode, setViewMode] = useState(\"list\");\n const searchDisabled = isSearch && !hasSearchCriteria(searchFormValues);\n\n // Scan raw formGroups (before normalizeGroups strips the clientScope field) to\n // auto-detect whether this module needs a client gate and read its optional message.\n // The Admin field config is the only source that enables this gate.\n const { hasClientScope, clientGateMessage, clientGateResetOnChange } = useMemo(() => {\n const gateField = extractGroups(formGroups).flatMap(g => g.fields ?? []).find(f => truthy(f.clientScope));\n return gateField\n ? {\n hasClientScope: true,\n clientGateMessage: gateField.clientGateMessage || '',\n clientGateResetOnChange: truthy(gateField.clientGateResetOnChange),\n }\n : { hasClientScope: false, clientGateMessage: '', clientGateResetOnChange: false };\n }, [formGroups]);\n\n const handleClientGateChange = (nextClientId) => {\n if (clientGateResetOnChange) {\n form.resetFields();\n // resetFields restores configured initial/default values. Explicitly\n // clear every root key as well so changing the Client Gate truly\n // removes nested values, files and repeatable-group rows.\n const storedValues = form.getFieldsValue(true);\n form.setFieldsValue(Object.fromEntries(\n Object.keys(storedValues).map((fieldName) => [fieldName, undefined]),\n ));\n setSearchResults({ searched: false, rows: [], total: 0, fields: [], loading: false });\n setSearchPagination({ current: 1, pageSize: 10 });\n }\n setScopeClientId(nextClientId ?? '');\n };\n\n const waitingForClientScope = hasClientScope && !effectiveClientId;\n\n const loadClientOptions = useCallback(() => (\n getAdminClients({ limit: 200 }).then(setClientOptions).catch(() => setClientOptions([]))\n ), []);\n\n useEffect(() => {\n // No picker needed when the client is already known (caller-supplied or\n // resolved from the linked job).\n if (!hasClientScope || presetClientId || linkedClientId) return;\n loadClientOptions();\n }, [hasClientScope, presetClientId, linkedClientId, loadClientOptions]);\n\n // Quick-create hook for the \"Select Client\" gate — the same \"Add More\"\n // in-dropdown create used by ordinary lookup fields (useQuickField), so the\n // gate can open the Clients Add form in a modal and, on save, refetch the\n // options and select the new client. Reuses the generic clients Add flow.\n //\n // NOTE — this synthetic field object is HARDCODED (a pre-existing wart: the\n // client gate is rendered by this component rather than as an ordinary\n // configured field, so it has no admin field-config document to read).\n // Every OTHER field gets the same behaviour purely from admin config via the\n // generic `quickCreateNotice` key; only this one gate has to restate it in\n // code. The gate is the actual submission/job path the requirement is about,\n // so it must carry the notice too — leaving it out would mean the one flow\n // the product owner described was the one flow without the warning.\n const clientGateQuick = useQuickField({\n field: {\n field: 'clientId',\n quickCreate: true,\n quickCreateModule: 'clients',\n quickCreateLabel: 'Add Client',\n lookupCollection: 'clients',\n displayField: 'clientName',\n quickCreateNotice: {\n enabled: true,\n title: 'New Client Created',\n // message omitted on purpose — the built-in default IS the\n // product-owner-approved wording (see quickCreateNotice.js).\n showCreator: true,\n showRecordName: true,\n recordLabel: 'Client name',\n creatorLabel: 'Created by',\n },\n },\n form,\n name: 'clientId',\n moduleName,\n scopeValues: {},\n ownValue: effectiveClientId,\n onDone: (kind, newId) => {\n loadClientOptions();\n if (kind === 'create' && newId != null) handleClientGateChange(String(newId));\n },\n });\n\n useEffect(() => {\n if (!configModule) return undefined;\n\n let cancelled = false;\n\n async function fetchFormGroups() {\n try {\n setApiLoading(true);\n setApiError('');\n const data = isSearch\n ? await getCustomForms(moduleName, 'search', action)\n : await getFormGroups({ module: moduleName, action, clientId: effectiveClientId, region: effectiveRegion });\n if (!cancelled) {\n setApiFormGroups(extractGroups(isSearch ? data?.[0] : data));\n if (isSearch) setSearchFormLabel(data?.[0]?.label || '');\n }\n } catch (err) {\n console.error(`Failed to fetch ${moduleName} form groups:`, err);\n if (!cancelled) setApiError(err?.message || 'Failed to fetch form groups');\n } finally {\n if (!cancelled) setApiLoading(false);\n }\n }\n\n fetchFormGroups();\n\n return () => {\n cancelled = true;\n };\n }, [configModule, moduleName, action, isSearch, effectiveClientId, effectiveRegion]);\n\n // ── URL-driven prefill source + linkage ──\n // Decode the route once. The submission flow arrives at\n // /submission-create/:jobId?candidateId=…&isFromSubmission=…[&submissionId=…]\n // • isFromSubmission=true + submissionId → prefill from the submissions record\n // • otherwise candidateId → prefill from the candidates record\n const urlPrefill = useMemo(() => {\n if (!prefillFromUrl) return null;\n\n const candidateId = searchParams.get('candidateId') || '';\n const submissionId = searchParams.get('submissionId') || '';\n const fromSubmission = String(searchParams.get('isFromSubmission')) === 'true';\n const jobId = (routeParams.jobId && routeParams.jobId !== '_')\n ? routeParams.jobId\n : (searchParams.get('jobId') || '');\n\n const source = (fromSubmission && submissionId)\n ? { module: 'submissions', id: submissionId }\n : (candidateId ? { module: 'candidates', id: candidateId } : null);\n\n // Linkage the submission create requires (NOT form fields).\n const linkage = {};\n if (candidateId) linkage.applicantId = candidateId;\n if (jobId) linkage.jobId = jobId;\n\n return { source, linkage: Object.keys(linkage).length ? linkage : null };\n }, [prefillFromUrl, searchParams, routeParams]);\n\n // ── Prefill fetch: load the source record's form groups with embedded values ──\n // The backend embeds field.value for scalar fields and group.rows for addRow\n // groups (workExperience, educationDetails, documents). Single source of truth\n // for BOTH the candidate and submission flows — no detail-view API call.\n useEffect(() => {\n const source = urlPrefill?.source;\n if (!source) return undefined;\n\n let cancelled = false;\n\n async function fetchPrefill() {\n try {\n setPrefillLoading(true);\n const data = await getFormGroups({ module: source.module, id: source.id });\n if (!cancelled) setPrefillGroups(extractGroups(data));\n } catch (err) {\n console.error('Failed to fetch prefill data:', err);\n if (!cancelled) setPrefillGroups([]);\n } finally {\n if (!cancelled) setPrefillLoading(false);\n }\n }\n\n fetchPrefill();\n\n return () => { cancelled = true; };\n }, [urlPrefill]);\n\n // addRow rows from the prefill source, keyed by group.payloadKey (e.g.\n // \"workExperience\"). Submission addRow groups that share the same payloadKey\n // receive these rows as their Form.List initialValue at mount. Works for both\n // sources because the DB array element keys are identical (companyName,\n // jobTitle, qualification, …).\n const addRowPrefillsByKey = useMemo(() => {\n if (!prefillGroups) return {};\n return Object.fromEntries(\n prefillGroups\n .filter(g => g.addRow && Array.isArray(g.rows) && g.rows.length > 0)\n .map(g => [g.payloadKey || g.name, g.rows]),\n );\n }, [prefillGroups]);\n\n // Flat record extracted from the prefill source's scalar fields — prefills\n // form fields whose field.field (or payloadKey) matches a source field.\n const prefillFlatRecord = useMemo(\n () => flatRecordFromGroups(prefillGroups),\n [prefillGroups],\n );\n\n // ── Cross-module context prefill (field.prefillFromModule) ──────────────\n // A field may prefill from a DIFFERENT module's record than the default\n // prefill source — e.g. submission.mspReqId ← the current JOB's mspreqId on\n // Quick Submit. The admin sets prefillFromModule (which module) +\n // prefillFrom (which key); the record id comes from the same URL linkage the\n // create payload already uses (jobId → jobs, applicantId → candidates).\n const contextPrefillModules = useMemo(() => {\n const wanted = new Set();\n groups.forEach((group) => (group.fields ?? []).forEach((field) => {\n if (field.prefillFromModule) wanted.add(normalizeModule(field.prefillFromModule));\n }));\n return [...wanted];\n }, [groups]);\n\n const [contextRecords, setContextRecords] = useState({});\n useEffect(() => {\n const linkage = urlPrefill?.linkage;\n if (!linkage || contextPrefillModules.length === 0) return undefined;\n let cancelled = false;\n // Shared with EditFormV1 (form/contextPrefill.js) — resolves <module>Id /\n // <singular>Id (+ known aliases like applicantId) out of the id map,\n // which is the URL linkage here and the record's own recordMeta there.\n contextPrefillModules.forEach(async (mod) => {\n const id = contextRecordId(mod, linkage);\n if (!id) return;\n try {\n const data = await getFormGroups({ module: mod, id });\n const record = flatRecordFromGroups(extractGroups(data));\n if (!cancelled && record) {\n setContextRecords((prev) => ({ ...prev, [mod]: record }));\n }\n } catch (err) {\n console.error(`Context prefill fetch failed for ${mod}:`, err);\n }\n });\n return () => { cancelled = true; };\n }, [contextPrefillModules, urlPrefill]);\n\n // ── prefillAsHint ───────────────────────────────────────────────────────\n // Fields the admin marked `prefillAsHint` are NOT filled in; the previous\n // record's value is shown underneath instead. See the effect below, which\n // skips them, and formatPrefillHint for the wording.\n //\n // DERIVED, not state written from an effect: it is a pure function of the\n // source record and the config, so a memo needs no synchronisation and\n // cannot render once with the old hints and once with the new.\n const prefillHints = useMemo(() => {\n const sourceRecord = initialRecord ?? prefillFlatRecord;\n if (!sourceRecord && Object.keys(contextRecords).length === 0) return {};\n const hints = {};\n groups.forEach((group) => {\n if (group.addRow) return;\n (group.fields ?? []).forEach((field) => {\n if (!field.field || !truthy(field.prefillAsHint) || truthy(field.addRow)) return;\n const fieldSource = field.prefillFromModule\n ? contextRecords[normalizeModule(field.prefillFromModule)]\n : sourceRecord;\n if (!fieldSource) return;\n const stored = pickPrefillValue(fieldSource, field);\n if (stored === undefined || stored === null) return;\n const shown = formatPrefillHint(field, stored);\n if (shown) hints[field.field] = shown;\n });\n });\n return hints;\n }, [initialRecord, prefillFlatRecord, contextRecords, groups]);\n\n // ── Prefill from initialRecord / prefillFlatRecord (best-effort) ──\n // Matches each non-file scalar field by field.field → payloadKey on the\n // source record and sets it via setFieldsValue. addRow groups are seeded via\n // Form.List initialValue (see getAddRowInitialValue below) — setFieldsValue\n // on a Form.List that mounted empty only keeps the last row.\n useEffect(() => {\n const sourceRecord = initialRecord ?? prefillFlatRecord;\n // Runs when EITHER the default source or a cross-module context record is\n // ready — a form with only prefillFromModule fields (no candidate source,\n // e.g. Quick Submit straight from a job) must still prefill those.\n if ((!sourceRecord && Object.keys(contextRecords).length === 0)\n || loading || groups.length === 0) return;\n const values = {};\n groups.forEach((group) => {\n if (group.toggleEnabled && group.toggleField && sourceRecord) {\n const stored = pickPrefillValue(sourceRecord, { field: group.toggleField });\n if (stored !== undefined && stored !== null) values[group.toggleField] = Boolean(stored);\n }\n if (group.addRow) return;\n (group.fields ?? []).forEach((field) => {\n if (!field.field) return;\n // A repeatable (addRow) field prefills via its Form.List\n // initialValue at mount — setFieldsValue on a Form.List that\n // mounted empty only keeps the last item, so skip it here.\n if (truthy(field.addRow)) return;\n // prefillFromModule redirects this field's source to another\n // module's URL-linked record (e.g. the current job).\n const fieldSource = field.prefillFromModule\n ? contextRecords[normalizeModule(field.prefillFromModule)]\n : sourceRecord;\n if (!fieldSource) return;\n // prefillFrom (admin config) → field → payloadKey, dotted or nested.\n const stored = pickPrefillValue(fieldSource, field);\n if (stored === undefined || stored === null) return;\n // `prefillAsHint` (admin config): do NOT fill this field —\n // show what it was last time and leave the box empty.\n //\n // A rate is the case this exists for. Carrying the previous\n // submission's rate forward LOOKS helpful and is the opposite:\n // it is a number the recruiter must renegotiate every time, and\n // a prefilled one gets submitted unread. Shown as a hint they\n // have to read and retype, it informs the decision instead of\n // making it for them.\n if (truthy(field.prefillAsHint)) return;\n if (field.type === 'file') {\n const fl = toFileListValue(stored);\n if (fl.length > 0) writeFormValue(values, field.field, fl);\n } else {\n // writeFormValue, NOT values[field.field]: a DOTTED field key\n // (\"candidateBudget.candidateBudgetCurrency\") is registered as an\n // ARRAY name path (see `field.field.split('.')` where `name` is\n // built), but a flat object key containing dots is treated by\n // rc-field-form as one literal field name. So the old assignment\n // wrote a key nothing was listening on, and prefillFromModule /\n // prefillFrom silently did NOTHING for every nested field — the\n // value was fetched, mapped, and then dropped on the floor.\n writeFormValue(values, field.field, buildInitialValue(field, stored));\n }\n });\n });\n if (Object.keys(values).length > 0) form.setFieldsValue(values);\n }, [initialRecord, prefillFlatRecord, contextRecords, loading, groups, form]);\n\n // ── Relevant-skill prefill (async, never blocking) ──────────────────────\n // Quick Submit starts the match at SUBMIT time and hands a TOKEN for the\n // still-in-flight promise over in nav state (the promise itself cannot\n // travel through router state — history.pushState requires\n // structured-cloneable data, and a Promise is not, see pendingHandoff.js).\n // The request overlaps this form's mount instead of delaying it. When it\n // settles we fill the rows of every addRow group the admin marked with\n // `skillMatchField` — that config key names the field inside the row that\n // receives the skill, so no group, field or module name is hardcoded here.\n //\n // Form.List rows must be written with setFieldsValue, never a remount: a\n // key change would throw away anything the recruiter has already typed.\n // Rows the user has already filled are left alone for the same reason.\n //\n // REFRESH SAFETY: history.state (and therefore the token) SURVIVES a browser\n // reload, but the in-memory map the token points into does not — the SPA\n // runtime that held it is gone. takePendingPromise then returns nothing and\n // the rows silently never fill, which is exactly what QA saw: \"relevant\n // skills are not parsed after a refresh\". So the INPUTS travel too, and when\n // the token resolves to nothing we simply re-issue the match. Inputs come\n // from nav state when the caller supplied them, else from the URL linkage\n // this form already derives (jobId in the path, candidateId in the query) —\n // which is itself refresh-proof. Still non-blocking, still driven only by\n // group.skillMatchField.\n useEffect(() => {\n const token = routerLocation?.state?.relevantSkillsToken;\n const stateInputs = routerLocation?.state?.relevantSkillsInputs;\n const jobId = stateInputs?.jobId ?? urlPrefill?.linkage?.jobId ?? '';\n const applicantId = stateInputs?.applicantId ?? stateInputs?.candidateId\n ?? urlPrefill?.linkage?.applicantId ?? '';\n // Guard on token/loading/groups BEFORE taking the promise — takePendingPromise\n // deletes on read, so calling it before we're actually ready to use the\n // result would consume it on a run that's just going to bail out, and\n // every later run (once loading clears / groups arrive) would find nothing.\n //\n // A handoff is still REQUIRED to start a match: without a token (or\n // explicit inputs in nav state) this is an ordinary visit to the form,\n // not a Quick Submit, and must not fire an AI call on its own.\n const handedOff = Boolean(token) || Boolean(stateInputs);\n if (!handedOff || loading || groups.length === 0) return undefined;\n\n const targets = groups.filter((g) => truthy(g.addRow) && g.skillMatchField);\n if (targets.length === 0) return undefined;\n\n // StrictMode double-invokes effects (mount → cleanup → mount again with\n // identical deps). Re-taking on the second mount would find the token\n // already consumed and silently skip the fill, so a same-token remount\n // reuses the promise already taken instead of consuming again. The same\n // ref also stops the refresh path from firing a SECOND match request on\n // the double-invoke.\n const runKey = token || `inputs:${jobId}:${applicantId}`;\n let promise;\n if (skillMatchTokenRef.current === runKey && skillMatchPromiseRef.current) {\n promise = skillMatchPromiseRef.current;\n } else {\n promise = token ? takePendingPromise(token) : undefined;\n // Handoff lost (page reloaded, or the link was opened directly) —\n // re-issue from the inputs. matchRelevantSkills never rejects and\n // degrades to [], which the fill below treats as \"change nothing\".\n if ((!promise || typeof promise.then !== 'function') && jobId && applicantId) {\n promise = matchRelevantSkills({ jobId, applicantId }).catch(() => []);\n }\n skillMatchTokenRef.current = runKey;\n skillMatchPromiseRef.current = promise;\n }\n if (!promise || typeof promise.then !== 'function') return undefined;\n\n let cancelled = false;\n promise.then((skills) => {\n // An empty result must NOT wipe the rows. \"Nothing matched\" and\n // \"the service was unreachable\" arrive here identically, and\n // clearing a candidate's carried-over skills because an AI call\n // failed would destroy real data.\n if (cancelled || !Array.isArray(skills) || skills.length === 0) return;\n const values = {};\n targets.forEach((group) => {\n const existing = form.getFieldValue(group.name);\n const rows = Array.isArray(existing) ? existing : [];\n // REPLACE, not append: the rows carried over from the candidate\n // are that candidate's skills in general, not the ones this job\n // asks for. The match is the answer to \"which apply here\", so\n // anything it did not return is dropped.\n //\n // A row whose skill IS in the match is REUSED rather than\n // rebuilt, so its Experience/Remarks survive — replacing it\n // with a bare { skill } would silently discard values the\n // recruiter (or the candidate record) already supplied.\n const bySkill = new Map();\n rows.forEach((row) => {\n const key = String(row?.[group.skillMatchField] ?? '').trim().toLowerCase();\n if (key && !bySkill.has(key)) bySkill.set(key, row);\n });\n values[group.name] = skills.map((skill) => (\n bySkill.get(String(skill).trim().toLowerCase())\n ?? { [group.skillMatchField]: skill }\n ));\n });\n if (Object.keys(values).length > 0) form.setFieldsValue(values);\n }).catch(() => { /* matchRelevantSkills already degrades to [] */ });\n\n return () => { cancelled = true; };\n // The linkage ids are listed as SCALARS: urlPrefill is a fresh memo\n // object on every searchParams change, so depending on it would re-run\n // (and, on the refresh path, re-request) for no reason.\n }, [\n routerLocation?.state?.relevantSkillsToken,\n routerLocation?.state?.relevantSkillsInputs,\n urlPrefill?.linkage?.jobId,\n urlPrefill?.linkage?.applicantId,\n loading, groups, form,\n ]);\n\n // Linkage merged into the create payload: URL-derived when prefillFromUrl,\n // else the explicit extraPayload prop.\n const scopePayload = hasClientScope && effectiveClientId ? { clientId: effectiveClientId } : {};\n const effectiveExtraPayload = { ...scopePayload, ...(urlPrefill?.linkage ?? extraPayload ?? {}) };\n\n // True once both the form groups and (when needed) the prefill source data are\n // ready. The Form.List components must NOT mount until this is true so that\n // getAddRowInitialValue below provides the correct initialValue at mount —\n // antd ignores initialValue changes after a Form.List has already mounted.\n const isFormReady = !waitingForClientScope && !loading && (!urlPrefill?.source || (prefillGroups !== null && !prefillLoading));\n\n // schemaVersion 1 runtime (server actions, inline \"why not\" notices,\n // payloadMap, draft record id). Inert unless the wizard renders here: a\n // host WizardAdapter keeps its own flow, and v0 steps have no actions.\n const wizardRuntime = useWizardRuntime({\n enabled: wizardEnabled && !WizardAdapter && isFormReady,\n steps: wizardSteps,\n current: activeWizardStep,\n setCurrent: goToWizardStep,\n form,\n moduleName,\n groups,\n validationNames: wizardValidationNames,\n onValidationFailed: (info) => scrollToFirstFormError(info, form),\n });\n\n\n // Build the Form.List initialValue for an addRow group. When candidate prefill\n // data is available the group's payloadKey (e.g. \"workExperience\") is looked up\n // in addRowPrefillsByKey and the stored rows are mapped through buildInitialValue\n // so antd controls receive the right shape. Falls back to a single empty row.\n const getAddRowInitialValue = (group) => {\n // prefillFrom lets an addRow group seed its rows from a DIFFERENT source\n // group key than its own (write) key — e.g. the submission employer group\n // (submission_current_employer) prefilling from the candidate's\n // current_employer_details rows on Quick Submit. Falls back to the write\n // key, so groups that already share a payloadKey are unaffected.\n const gKey = group.prefillFrom || group.payloadKey || group.name;\n const rows = addRowPrefillsByKey[gKey];\n const minRows = Math.max(0, Number(group.minRows ?? 0) || 0);\n // Admin-configured defaultValues seed every fresh row (top-level fields\n // get theirs via Form.Item initialValue, which does not reach Form.List\n // rows — e.g. VMS Commission 5.5 inside the Employer group).\n const seed = rowDefaultsFor(group);\n if (!rows || rows.length === 0) {\n // initialRows in config controls how many empty rows to start with (default 0).\n // minRows still controls the minimum kept after removal.\n const startCount = group.initialRows !== undefined\n ? Math.max(minRows, Math.max(0, Number(group.initialRows) || 0))\n : minRows;\n return Array.from({ length: startCount }, () => ({ ...seed }));\n }\n const initial = rows.map(row => {\n const rowVals = { ...seed };\n (group.fields ?? []).forEach(field => {\n if (!field.field || field.type === 'file') return;\n const val = pickPrefillValue(row, field);\n if (val !== undefined && val !== null) {\n // A repeat field inside the row (nested Form.List) hydrates as\n // an array, each element normalised for its control; a plain\n // field hydrates as a single value.\n rowVals[field.field] = truthy(field.addRow)\n ? buildRepeatFieldInitial(field, val)\n : buildInitialValue(field, val);\n }\n });\n return rowVals;\n });\n while (initial.length < minRows) initial.push({ ...seed });\n return initial;\n };\n\n // Precomputed per-group so a linked set (group.linkGroup) can be padded to\n // equal length BEFORE any Form.List mounts — antd ignores initialValue\n // changes after first mount, so this has to be ready up front, not derived\n // ad hoc per group. A no-op passthrough for every group not in a linked set.\n\n // ── Collapsible sections (group.allowCollapse / group.defaultCollapsed) ──\n // Collapsing is OPT-IN. A group that does not ask for it renders with no\n // chevron and can never be collapsed — which is the behaviour every form\n // had before this existed, so nothing already configured changes.\n //\n // `defaultCollapsed` only means anything for a group that allows collapsing\n // at all: a section that starts closed but cannot be opened would be a\n // section the user simply cannot fill in.\n //\n // Seeded once per group set rather than on every render, so a user who\n // opens a default-closed section does not have it slam shut again on the\n // next state change. `collapsedSeeded` tracks WHICH group set has been\n // applied, so a module switch (or a config reload) re-seeds exactly once.\n const collapsedSeedKey = useMemo(\n () => groups.map((g) => `${g.name}:${truthy(g.allowCollapse) ? 1 : 0}${truthy(g.defaultCollapsed) ? 1 : 0}`).join('|'),\n [groups],\n );\n const collapsedSeeded = useRef(null);\n useEffect(() => {\n if (!groups.length || collapsedSeeded.current === collapsedSeedKey) return;\n collapsedSeeded.current = collapsedSeedKey;\n const seeded = {};\n groups.forEach((group, index) => {\n const key = group.name ?? group.id ?? String(index);\n if (truthy(group.allowCollapse) && truthy(group.defaultCollapsed)) seeded[key] = true;\n });\n setCollapsed(seeded);\n }, [collapsedSeedKey, groups]);\n\n const addRowInitials = useMemo(() => {\n const raw = {};\n groups.forEach((group) => {\n if (group.addRow) raw[group.name] = getAddRowInitialValue(group);\n });\n return padLinkedInitialValues(linkedGroupSets, raw);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [groups, addRowPrefillsByKey, linkedGroupSets]);\n\n const toggle = (key) => setCollapsed((prev) => ({ ...prev, [key]: !prev[key] }));\n\n const handleReset = () => {\n form.resetFields();\n // Also reset collapsed state to default (all expanded)\n setCollapsed({});\n setSelectedSource('internal');\n setTabs([]);\n };\n\n const handleSearch = useCallback(async (values, sourceOverride, paginationOverride = {}) => {\n if (!isSearch) return;\n const nextPageSize = Number(paginationOverride.pageSize) > 0\n ? Number(paginationOverride.pageSize)\n : searchPagination.pageSize;\n const requestedCurrent = Number(paginationOverride.current);\n const nextCurrent = Number.isFinite(requestedCurrent) && requestedCurrent > 0\n ? Math.floor(requestedCurrent)\n : 1;\n\n try {\n setLastSearchValues(values);\n setSearchPagination({ current: nextCurrent, pageSize: nextPageSize });\n setSearchResults((current) => ({ ...current, loading: true, searched: true }));\n const checkedSources = getSearchSources(values?.selectedSource);\n const activeSource = sourceOverride\n ? resolveSearchSource(sourceOverride, selectedSource)\n : (checkedSources.includes('internal')\n ? 'internal'\n : resolveSearchSource(values?.selectedSource, selectedSource));\n\n // Include selectedSource in the search parameters\n const searchParamsWithSource = {\n ...values,\n selectedSource: activeSource,\n };\n\n console.log('[AddFormV1] Calling searchModuleData with scope:', activeSource);\n\n const result = await searchModuleData(moduleName || 'candidates', searchParamsWithSource, {\n limit: nextPageSize,\n offset: (nextCurrent - 1) * nextPageSize,\n }, {\n scope: activeSource,\n });\n\n setSelectedSource(activeSource);\n setSearchResults({\n searched: true,\n rows: result.rows,\n total: result.total,\n fields: result.fields,\n // Admin-configured row actions/rules — searchModuleData pulls these\n // from the same /module-data-list response the regular ListView\n // list-endpoint returns them on, so search results get the same\n // admin-driven actions instead of none.\n actions: result.actions ?? [],\n actionRules: result.actionRules ?? [],\n loading: false,\n });\n setTabs((currentTabs) => buildSourceTabs({\n sources: checkedSources,\n activeSource,\n activeCount: result.total,\n responseCounts: result.counts,\n currentTabs,\n backendTabs: result.tabs,\n }));\n } catch (error) {\n console.error('Search failed:', error);\n message.error(error?.message || 'Failed to search records');\n setSearchResults({ searched: true, rows: [], total: 0, fields: [], actions: [], actionRules: [], loading: false });\n }\n }, [isSearch, moduleName, selectedSource, searchPagination.pageSize]);\n\n const handleSourceAction = useCallback(async (action, record) => {\n const actionKey = getSourceActionInstanceKey(action, record);\n setSourceActionState((current) => ({\n ...current,\n [actionKey]: { ...(current[actionKey] ?? {}), loading: true },\n }));\n try {\n const response = await runSourceAction(action, record);\n message.success(\n response?.message\n ?? response?.data?.message\n ?? action.successMessage\n ?? 'Action completed successfully.',\n );\n setSourceActionState((current) => ({\n ...current,\n [actionKey]: { loading: false, completed: true },\n }));\n } catch (error) {\n message.error(error?.message || action.errorMessage || 'Action failed.');\n setSourceActionState((current) => ({\n ...current,\n [actionKey]: { ...(current[actionKey] ?? {}), loading: false },\n }));\n } finally {\n setSourceActionState((current) => ({\n ...current,\n [actionKey]: { ...(current[actionKey] ?? {}), loading: false },\n }));\n }\n }, []);\n\n const handleTabChange = useCallback((newSource) => {\n const activeSource = resolveSearchSource(newSource, selectedSource);\n setSelectedSource(activeSource);\n setSearchPagination({ current: 1, pageSize: searchPagination.pageSize });\n\n // Re-trigger search with new source if we have previous search values\n if (Object.keys(lastSearchValues).length > 0) {\n handleSearch(lastSearchValues, activeSource, { current: 1, pageSize: searchPagination.pageSize });\n }\n }, [searchPagination.pageSize, lastSearchValues, handleSearch, selectedSource]);\n\n const handleSearchPageChange = useCallback((current, pageSize) => {\n const nextPageSize = Number(pageSize) > 0 ? Number(pageSize) : searchPagination.pageSize;\n const nextCurrent = Number(current) > 0 ? Number(current) : 1;\n if (Object.keys(lastSearchValues).length === 0) {\n setSearchPagination({ current: nextCurrent, pageSize: nextPageSize });\n return;\n }\n handleSearch(lastSearchValues, selectedSource, { current: nextCurrent, pageSize: nextPageSize });\n }, [handleSearch, lastSearchValues, searchPagination.pageSize, selectedSource]);\n\n const handleSearchPageSizeChange = useCallback((pageSize) => {\n const nextPageSize = Number(pageSize) > 0 ? Number(pageSize) : searchPagination.pageSize;\n if (Object.keys(lastSearchValues).length === 0) {\n setSearchPagination({ current: 1, pageSize: nextPageSize });\n return;\n }\n handleSearch(lastSearchValues, selectedSource, { current: 1, pageSize: nextPageSize });\n }, [handleSearch, lastSearchValues, searchPagination.pageSize, selectedSource]);\n\n // Submit-time duplicate (\"already present\") coming back from the\n // authoritative server-side check. The record was NOT created, so the form\n // must behave exactly like a failed client-side validation: values kept,\n // form open, collapsed sections expanded, error shown under the offending\n // field, and that field scrolled to + focused (shared\n // utils/scrollToFirstFormError, same as onFinishFailed).\n //\n // The name used is the one the SERVER returned — the frontend field key,\n // which is not necessarily the stored field it maps to.\n const applyDuplicateFieldErrors = (source) => {\n const duplicates = extractDuplicateFieldErrors(source, { uniqueRules: uniqueRuleIndex });\n if (duplicates.length === 0) return false;\n\n // item.name is the FULL antd path: a plain key for an ordinary field, and\n // [group, rowIndex, key] for a field inside a repeatable (addRow) group,\n // so the error lands on the row the user actually typed into.\n form.setFields(duplicates.map((item) => ({ name: item.name ?? item.field, errors: [item.message] })));\n setCollapsed({});\n scrollToFirstFormError({\n errorFields: duplicates.map((item) => {\n const name = item.name ?? item.field;\n return { name: Array.isArray(name) ? name : [name], errors: [item.message] };\n }),\n }, form);\n return true;\n };\n\n\n // confirmLevelRule — the submit-time half of group.levelRule.\n //\n // The rule, its levels and its wording are all admin config; nothing here\n // names a qualification. Region-resolved, so a market that requires a\n // different rung is honoured.\n //\n // Returns TRUE to continue. A failure to evaluate also returns true: a\n // hierarchy check must never be the reason a submit cannot happen at all.\n const confirmLevelRule = useCallback(async (values) => {\n try {\n const region = getDefaults().region;\n const resolved = groups.map((group) => resolveRegionRules(group, region));\n const verdict = levelRuleVerdict(resolved, values);\n if (verdict.severity === 'allow') return true;\n\n if (verdict.severity === 'block') {\n openFormNotice({\n tone: 'duplicate',\n title: 'This qualification history is incomplete',\n body: verdict.message,\n okText: 'Go back',\n });\n return false;\n }\n // openFormDecision resolves TRUE for its OK button and FALSE for\n // Cancel — but here OK (\"Add it now\") means \"stop, let me go add\n // the row myself\" (continue = false) and Cancel (\"Submit anyway\")\n // means proceed (continue = true). That is the OPPOSITE of the\n // dialog's own resolve value, so it must be inverted here; passing\n // it straight through made \"Add it now\" silently submit anyway and\n // \"Submit anyway\" silently do nothing.\n const addItNow = await openFormDecision({\n tone: 'suggestion',\n title: 'Add the earlier qualification too?',\n body: verdict.message,\n okText: 'Add it now',\n cancelText: 'Submit anyway',\n });\n return !addItNow;\n } catch (err) {\n console.warn('[levelRule] check skipped:', err);\n return true;\n }\n }, [groups]);\n\n const submit = async (values) => {\n if (isSearch) {\n await handleSearch(values);\n return;\n }\n\n // The authoritative duplicate gate. The upload-time check is a courtesy\n // — it fires before the form is complete and only when a file was read\n // — so the decision is taken again here, against the finished values,\n // where it can actually stop a second copy being created.\n // 'clear' and 'existing' both continue: 'existing' means the user has\n // already been sent to the record we have, so this submit is moot.\n if (!embedded) {\n const verdict = await duplicates.prompt({ reason: 'submit' });\n if (verdict !== 'clear') return;\n }\n\n // Qualification hierarchy (admin config: group.levelRule). A Master's\n // with no Bachelor's beneath it is usually an incomplete record — but\n // not always, and the recruiter looking at the CV knows better than a\n // config does. So ASK by default and let them proceed; only a rule\n // explicitly marked severity:\"block\" refuses.\n if (!(await confirmLevelRule(values))) return;\n\n // A host page can own the confirm step (e.g. Quick Submit's Pontoon\n // attestation / preview modal) and POST the record itself. It still gets\n // the CONFIG-DRIVEN payload here — identical to what the native submit\n // below would send — so payloadMode (\"skip\"), payloadKey remapping,\n // dataType coercion and the showIf payload gating all still apply.\n // Passing only `values` (raw antd form state, as before) meant a page\n // with a custom onSubmit silently bypassed the entire Form Groups\n // config. `values` is still the first argument for callers that need the\n // raw state for display (preview cards, file lists).\n if (onSubmit) {\n await onSubmit(values, {\n moduleName,\n groups,\n // A host that POSTs the record itself (Quick Submit, Resubmit)\n // was silently skipping the shared document registry, because\n // this branch returns before the registration below ever runs.\n // The uploaded résumé therefore existed on the submission\n // record but nowhere in `documents`, so nothing could link it\n // to the candidate. Handing the host the SAME registration the\n // native path uses closes that gap without it having to know\n // how files are collected.\n registerDocuments: async (recordId, opts = {}) => {\n const parts = collectFileParts(values, groups, { module: opts.module ?? moduleName });\n if (!parts.length || !recordId) return [];\n return uploadModuleDocuments(opts.module ?? moduleName, recordId, parts);\n },\n extraPayload: effectiveExtraPayload ?? {},\n // Host-owned saves (opt-in): new files as [{ formKey, file,\n // documentModule? }]. fileParts = indexed keys exactly as\n // /module/update takes them; allFileParts = flat keys (registry).\n fileParts: collectFileParts(values, groups, { indexed: true, module: moduleName }),\n allFileParts: collectFileParts(values, groups, { module: moduleName }),\n payload: {\n ...(effectiveExtraPayload ?? {}),\n ...buildPayload(values, groups, { module: moduleName }),\n },\n });\n return;\n }\n\n if (!moduleName) {\n console.log('Form values:', values);\n return;\n }\n\n // Everything after a successful save: toast, then the success step,\n // the embedded host callback or the afterSubmit navigation. The\n // generic save below and an action-only wizard save (saveVia\n // 'action') both end here, so both behave the same after saving.\n const completeAfterSave = (newRecordId, clickedAfterSubmit) => {\n // Admin-configurable success toast (group.submitMessages); defaults to\n // \"<Module> has added successfully\" for every module, new ones included.\n const successText = submitSuccessMessage(groups, moduleName, 'add');\n if (successText) message.success(successText);\n\n // Embedded (quick \"Add More\" modal): hand the new id back to the caller\n // so it can refetch its option list and select the new record — never\n // navigate away from the host form.\n if (embedded && onSuccess) {\n onSuccess(newRecordId, values);\n return;\n }\n\n // A configured Success step is an AFTER-save screen, never a page\n // someone can advance to before the create request succeeds. Keep\n // the user in the wizard and reveal it only now.\n if (wizardSuccessStepIndex >= 0) {\n form.resetFields();\n goToWizardStep(wizardSuccessStepIndex);\n return;\n }\n\n form.resetFields();\n\n // A clicked extra button (formActions) overrides the group's default\n // afterSubmit for this submit; the plain Create button leaves the ref\n // null and keeps the existing behavior.\n const afterSubmit = clickedAfterSubmit ?? resolveAfterSubmit(groups);\n if (!afterSubmit) {\n // No admin-configured behavior: return to wherever this form was\n // opened FROM, falling back to cancelPath on a cold deep-link.\n //\n // This replaced a hardcoded module→route map (jobs→/jobs,\n // candidates→/candidates, …) — four module names living in a\n // component that is otherwise entirely config-driven, and which\n // silently did nothing at all for every other module.\n goBackOrTo(navigate, { cancelPath });\n } else if (afterSubmit.mode === 'back') {\n goBackOrTo(navigate, { cancelPath });\n } else if (afterSubmit.mode === 'route' || afterSubmit.mode === 'detail') {\n const target = safeNavTarget(afterSubmit.target, newRecordId, values);\n if (target) navigate(target);\n }\n // afterSubmit.mode === 'stay' (or an unresolvable target): no navigation.\n };\n\n try {\n setSubmitLoading(true);\n // saveVia 'action': the wizard's onFinish server action IS the save.\n // The generic create/update, file attach and document registry do\n // not run (an action receives JSON values; files are not sent). Its\n // answer is the saved record: recordId → success step / afterSubmit.\n if (wizardEnabled && !WizardAdapter && wizardRuntime.saveViaAction) {\n const clicked = pendingAfterSubmitRef.current;\n await wizardRuntime.saveThroughAction(values, (savedId) => completeAfterSave(savedId, clicked));\n return;\n }\n // A wizard whose server action already created the record (a draft,\n // e.g. actions.onNext 'draft.save') saves INTO that record: creating\n // again would leave a second copy. No draft id: the create below,\n // exactly as before.\n const wizardDraftId = wizardEnabled && !WizardAdapter ? wizardRuntime.draftRecordId : '';\n const response = wizardDraftId\n ? await updateRecord(moduleName, wizardDraftId,\n { ...(effectiveExtraPayload ?? {}), ...buildPayload(values, groups, { module: moduleName }) },\n collectFileParts(values, groups, { indexed: true, module: moduleName }))\n : await createModuleRecord(moduleName, buildDynamicFormData(values, groups, effectiveExtraPayload ?? {}, moduleName));\n const success = response?.status !== false;\n\n if (!success) {\n // A duplicate reported in a 200 envelope ({status:false}) is the\n // same failure as a 409 — handle it the same way.\n if (applyDuplicateFieldErrors(response)) return;\n message.error(submitErrorMessage(groups, moduleName, 'add',\n response?.error || response?.message || response?.data));\n return;\n }\n\n // Repeatable (addRow) document files are attached in a follow-up update\n // through the reliable indexed path (documents[0], documents[1], …). The\n // rows themselves were created on insert (metadata is in the create JSON),\n // so this only uploads each file to its row by index. Runs only when the\n // form actually carried addRow file uploads, so plain records and jobs\n // stay single-request.\n const addRowFileParts = collectFileParts(values, groups, { scope: 'addRow', indexed: true, module: moduleName });\n const newRecordId = wizardDraftId || (response?.id ?? response?.data?.id ?? response?.data?._id ?? response?._id);\n if (!wizardDraftId && addRowFileParts.length > 0 && newRecordId) {\n try {\n await updateRecord(moduleName, newRecordId, { ...(effectiveExtraPayload ?? {}), ...buildPayload(values, groups, { module: moduleName }) }, addRowFileParts);\n } catch (uploadErr) {\n console.error('Document file attach (post-create update) failed:', uploadErr);\n message.warning('Record created, but attaching document files failed. Edit the record to re-upload.');\n }\n }\n\n // Common document registry — the module record is created FIRST (the\n // Create API above generated its reference id), then every uploaded\n // file (single or multiple, flat or addRow) is registered in the\n // shared \"documents\" collection against that id, keyed by module name\n // + the form field it was uploaded under (resume, jobDescription, …).\n // Best-effort: the record already exists, so a registry failure only\n // warns and never rolls back the create.\n const allFileParts = collectFileParts(values, groups, { module: moduleName });\n if (allFileParts.length > 0 && newRecordId) {\n try {\n await uploadModuleDocuments(moduleName, newRecordId, allFileParts);\n } catch (docErr) {\n console.error('Document registry upload failed:', docErr);\n message.warning('Record created, but saving its document records failed.');\n }\n }\n\n // A wizard runs its finish step's server action (actions.onFinish)\n // first; when that fails the record is already saved, the error\n // stays in the step with \"Try again\", and this runs once the retry\n // succeeds.\n const clickedAfterSubmit = pendingAfterSubmitRef.current;\n const completeAfterSaveNow = () => completeAfterSave(newRecordId, clickedAfterSubmit);\n if (wizardEnabled && !WizardAdapter) {\n wizardRuntime.markSaved(newRecordId, values);\n if (!(await wizardRuntime.afterSave(newRecordId, values, completeAfterSaveNow))) return;\n }\n completeAfterSaveNow();\n } catch (err) {\n console.error(`Failed to create ${moduleName}:`, err);\n // Authoritative server-side uniqueness check: keep every value the\n // user entered, keep the form open, mark the field and take them to\n // it. No success toast, no navigation.\n if (applyDuplicateFieldErrors(err)) return;\n message.error(submitErrorMessage(groups, moduleName, 'add',\n err?.data?.error || err?.data?.message || err?.message));\n } finally {\n setSubmitLoading(false);\n pendingAfterSubmitRef.current = null;\n }\n };\n\n const getFieldDependencies = (field, currentName, prefixFor) => {\n const rules = field.validations ?? field.validation ?? field.rules ?? [];\n // maxFromField is listed separately because its referenced field may live\n // OUTSIDE this row: the dependency path has to be built with the same\n // scoping the rule itself uses, not the sibling assumption below.\n const scoped = rules\n .filter((rule) => (typeof rule === 'string' ? rule : rule?.type) === 'maxFromField')\n .map((rule) => maxFromFieldDependency(rule, currentName, prefixFor))\n .filter(Boolean);\n return [...scoped, ...rules\n .filter((rule) => {\n const type = typeof rule === 'string' ? rule : rule?.type;\n return ['dateAfterField', 'greaterThanField', 'strictGreaterThanField',\n 'strictLessThanField', 'lessThanOrEqualField', 'maxFieldWithFallback',\n 'dateBeforeField', 'timeAfterField', 'timeBeforeField'].includes(type);\n })\n .map((rule) => {\n const compareFields = String(rule.value ?? rule.compareField ?? rule.field ?? '')\n .split(',').map((item) => item.trim()).filter(Boolean);\n return compareFields.map((compareField) => getSiblingFieldName(currentName, compareField));\n })\n .flat()\n .filter(Boolean)];\n };\n\n // Evaluate a Show Condition. `prefixFor` resolves the sibling path prefix for\n // a referenced field key (row-first for a group's own field, else top-level);\n // it may also be a precomputed prefix array/null for legacy single-condition\n // callers. A showIf can be a single leaf ({field,operator,value}) OR carry a\n // `conditions` array combined by `logic` (\"and\" default | \"or\") — the\n // multi-condition \"add more\" form — and a leaf + conditions combine too.\n const resolvePrefix = (prefixFor, key) => (typeof prefixFor === 'function' ? prefixFor(key) : prefixFor);\n const evalShowIfLeaf = (cond, getFieldValue, prefixFor) => {\n if (!cond?.field) return true;\n const prefix = resolvePrefix(prefixFor, cond.field);\n const path = prefix != null\n ? [...(Array.isArray(prefix) ? prefix : [prefix]), cond.field]\n : [cond.field];\n const val = getFieldValue(path);\n switch (cond.operator) {\n case 'eq': return String(val ?? '') === String(cond.value ?? '');\n case 'neq': return String(val ?? '') !== String(cond.value ?? '');\n case 'truthy': return val !== undefined && val !== null && val !== '' && val !== false;\n case 'falsy': return val === undefined || val === null || val === '' || val === false;\n // notEmpty targets an addRow GROUP's own Form.List name (cond.field is\n // that group's name, e.g. \"submission_referral_details\") — true once the\n // group has at least one row. Lets a flat field elsewhere in the form\n // (e.g. \"referral rate\") only appear/require once a referral row exists.\n case 'notEmpty': return Array.isArray(val) ? val.length > 0 : Boolean(val);\n // in/notIn: cond.value is a comma-separated list (e.g. \"W2-Fulltime,W2-Contract\").\n case 'in': return String(cond.value ?? '').split(',').map((v) => v.trim()).includes(String(val ?? ''));\n case 'notIn': return !String(cond.value ?? '').split(',').map((v) => v.trim()).includes(String(val ?? ''));\n default: return true;\n }\n };\n const evaluateShowIf = (showIf, getFieldValue, prefixFor) => {\n if (!showIf) return true;\n const conditions = Array.isArray(showIf.conditions) ? showIf.conditions.filter((c) => c?.field) : [];\n if (conditions.length) {\n const results = conditions.map((c) => evalShowIfLeaf(c, getFieldValue, prefixFor));\n const orLogic = String(showIf.logic ?? 'and').toLowerCase() === 'or';\n let combined = orLogic ? results.some(Boolean) : results.every(Boolean);\n // A top-level leaf alongside conditions is folded in with the same logic.\n if (showIf.field) {\n const leaf = evalShowIfLeaf(showIf, getFieldValue, prefixFor);\n combined = orLogic ? (combined || leaf) : (combined && leaf);\n }\n return combined;\n }\n return evalShowIfLeaf(showIf, getFieldValue, prefixFor);\n };\n // True when a field carries any Show Condition (single leaf or multi-condition).\n const hasShowIf = (showIf) => Boolean(showIf?.field || showIf?.conditions?.some?.((c) => c?.field));\n\n const [combineToggles, setCombineToggles] = useState({});\n\n const fieldKey = (field) => String(field?.field ?? '');\n\n // Who is filling this form — drives admin-configured field autoValueRules\n // (display only; the gateway enforces the same rules server-side).\n const actingIdentity = useMemo(() => getActingIdentity(), []);\n\n const renderField = (field, namePrefix, listName, opts = {}) => {\n // Split dotted keys into array form so AntD Form nests values correctly:\n // \"passport.passportNumber\" → ['passport','passportNumber']\n const fieldParts = typeof field.field === 'string' && field.field.includes('.')\n ? field.field.split('.')\n : null;\n const parsedField = fieldParts ?? field.field;\n const name = namePrefix !== undefined\n ? [namePrefix, ...(fieldParts ?? [field.field])]\n : parsedField;\n // Inside a Form.List the relative name [rowIndex, fieldName] is correct for\n // Form.Item registration, but form.getFieldValue / cross-field validators need\n // the absolute path [listName, rowIndex, fieldName] to find the value in the\n // form store. Build that here so validators and validateFields use the right path.\n // listName is normally a single Form.List name (string), but a DOUBLY-nested\n // list (a repeat field's subFields rendered inside an addRow group row) passes\n // the full absolute path array of its own list — spread it instead of wrapping.\n const absoluteName = (listName !== undefined && namePrefix !== undefined)\n ? [...(Array.isArray(listName) ? listName : [listName]), ...(Array.isArray(name) ? name : [name])]\n : name;\n // Checkbox.Group (when options are configured) uses value=[]; single boolean checkbox uses checked=bool.\n const isCheckboxGroup = field.type === 'checkbox' && (\n (field.options && field.options.length > 0) ||\n (field.dataSource && field.dataSource !== 'static')\n );\n const valuePropName = (!isCheckboxGroup && field.type === 'checkbox') ? 'checked' : 'value';\n // Inline (combined) fields show no per-box label — the combined card prints a\n // single label and the boxes sit side by side (e.g. From / To / Currency).\n // hideLabel: the group renders one shared header row above all addRow rows\n // instead of repeating each field's label on every row (e.g. Languages Known).\n const permissionLocked = Boolean(field.editablePermission)\n && !roleAllowsAction(field.editablePermission, moduleName);\n // Sibling path prefix for evaluateShowIf/labelWhen: [listName, rowIndex]\n // in a Form.List, null for ordinary top-level fields.\n const showIfPrefix = (listName !== undefined && namePrefix !== undefined)\n ? [...(Array.isArray(listName) ? listName : [listName]), namePrefix]\n : null;\n // A condition may reference a sibling IN this row, or any top-level\n // field (e.g. contractType). Row prefix only applies when the referenced\n // key is one of this group's own fields; unknown membership (no\n // rowFieldKeys passed) keeps the historical row-first behavior.\n const prefixFor = (conditionKey) => (\n showIfPrefix && (!opts.rowFieldKeys || opts.rowFieldKeys.has(conditionKey))\n ? showIfPrefix\n : null\n );\n // An admin-configured override checkbox rides the LABEL, so \"this value\n // may exceed its limit\" reads as a qualifier on the field's name rather\n // than as another input. See form/validationOverride.js.\n const overrideCfg = overrideConfig(field);\n const overrideFlag = overrideCfg ? overrideFlagPath(field, absoluteName, prefixFor) : null;\n const baseFieldLabel = (opts.inline || opts.hideLabel)\n ? ''\n : (!isCheckboxGroup && field.type === 'checkbox')\n ? ''\n : <ConfiguredFieldLabel form={form} field={field} siblingPrefix={field.labelWhen?.field ? prefixFor(field.labelWhen.field) : showIfPrefix} locked={permissionLocked} />;\n // A label-less presentation (inline/combined box, shared header row) has\n // nowhere to hang it; the combined block prints it once instead — see\n // renderCombinedPack.\n const fieldLabel = (overrideCfg && baseFieldLabel) ? (\n <span className=\"v1-label-with-override\">\n {baseFieldLabel}\n <ValidationOverrideCheckbox\n form={form}\n field={field}\n flagPath={overrideFlag}\n fieldPath={absoluteName}\n disabled={permissionLocked}\n />\n </span>\n ) : baseFieldLabel;\n const dependencies = getFieldDependencies(field, absoluteName, prefixFor);\n // Admin-set help text (field.tooltip, or the older infoEnabled/infoText\n // pair). It rides the label when there is one; a label-less field\n // (inline/combined box, or a group printing one shared header row) gets\n // it on the control instead — see fieldItem below — so EVERY control\n // type can carry a tooltip.\n const tooltipText = fieldTooltipText(field);\n const mdSpan = opts.inline ? 24 : ((field.type === 'file' && truthy(field.multiple)) || field.type === 'text-editor' ? 24 : (field.col ?? 12));\n\n // Config-driven default for the Add form: a top-level field (not inside a\n // Form.List) with a configured defaultValue mounts pre-selected. Any prefill\n // (initialRecord / quick-submit) runs through setFieldsValue, which overrides\n // initialValue — so this only affects a fresh Add with no incoming value.\n //\n // An autoValueRule for the acting user (e.g. Submit Source → \"External\"\n // for an employer-type user) outranks defaultValue: the field mounts\n // showing the value the gateway will enforce anyway. Display only — the\n // backend re-evaluates the same rules and has the final say.\n const autoValue = autoValueFor(field, actingIdentity);\n const initialValue = (namePrefix === undefined && field.type !== 'file'\n && autoValue.matched && autoValue.value !== undefined && autoValue.value !== '')\n ? autoValue.value\n : ((namePrefix === undefined && field.type !== 'file'\n && field.defaultValue !== undefined && field.defaultValue !== '')\n ? field.defaultValue : undefined);\n\n // AI Actions: admin-configured buttons (Generate/Parse-style) attached to\n // this field. \"click\" actions render as buttons beside the field; an\n // \"upload\" action (on a file field) fires automatically when a new file\n // is accepted, via the onAiUpload callback passed into FieldControl.\n const clickAiActions = (field.aiActions || []).filter((a) => a.trigger === 'click');\n const uploadAiAction = (field.aiActions || []).find((a) => a.trigger === 'upload');\n\n const fieldItem = (\n <Form.Item\n label={fieldLabel}\n name={name}\n extra={renderFieldHelp(field, prefillHints[field.field])}\n rules={getRules(field, form, absoluteName, isSearch, prefixFor, uniqueContext,\n inProgressRulesFor(field, opts.groupNameForActions))}\n required={isFieldRequired(field, form, absoluteName)}\n dependencies={dependencies}\n valuePropName={valuePropName}\n initialValue={initialValue}\n getValueFromEvent={field.type === 'file' ? (event) => (Array.isArray(event) ? event : event?.fileList) : undefined}\n validateTrigger={['onBlur', 'onChange']}\n {...(isSearch ? null : uniqueCheckItemProps(field, uniqueDebounceMs))}\n >\n <FieldControl\n key={field.refreshToken != null ? `${field.field}-refresh-${field.refreshToken}` : undefined}\n field={field}\n form={form}\n name={absoluteName}\n rowFieldKeys={opts.rowFieldKeys}\n moduleName={moduleName}\n scopeValues={{ clientId: effectiveClientId }}\n onAiUpload={uploadAiAction\n ? (file) => aiActions.runAction(opts.groupNameForActions, field, uploadAiAction, file)\n : undefined}\n onDuplicateBlur={handleDuplicateBlur}\n onRegionBlocked={handleRegionBlocked}\n onRowOrderChange={handleRowOrder}\n formDisabled={aiActions.busy}\n />\n </Form.Item>\n );\n\n // A label-less field (inline/combined box, or a group that prints one\n // shared header row) has nowhere to hang the label's info icon, so the\n // whole item becomes the tooltip target. The wrapping <span> is what\n // Tooltip attaches to — passing the Form.Item straight in would make\n // antd clone it for the ref, and Form.Item's clone is reserved for\n // injecting value/onChange into its control.\n const tooltippedItem = (tooltipText && !fieldLabel)\n ? <Tooltip title={tooltipText}><span className=\"v1-field-tooltip-wrap\">{fieldItem}</span></Tooltip>\n : fieldItem;\n\n const fieldItemWithActions = clickAiActions.length > 0 ? (() => {\n const positioned = groupActionsByPosition(clickAiActions);\n const group = (position) => (\n <AiActionButtonGroup\n key={position}\n position={position}\n actions={positioned[position]}\n aiActions={aiActions}\n groupName={opts.groupNameForActions}\n field={field}\n />\n );\n return (\n <div className=\"v1-ai-action-wrap\">\n {group('top-left')}\n {group('top-center')}\n {group('top-right')}\n {tooltippedItem}\n {group('bottom-left')}\n {group('bottom-center')}\n {group('bottom-right')}\n </div>\n );\n })() : tooltippedItem;\n\n // The verify carrier fields (verifyResultField \"isValid\" / verifyTimestampField\n // \"validatedAt\") are show:0, so they are NOT rendered as Form.Items above —\n // which means the value VerifyFieldButton sets via setFieldValue lives on an\n // UNREGISTERED path and antd's onFinish drops it, so \"verified\" was never\n // persisted (and so an edit form had nothing to prefill). Registering them as\n // hidden Form.Items — under the SAME relative name (row-indexed inside an\n // addRow Form.List) — makes the set value survive submit AND lets an edit\n // prefill populate it, so VerifyFieldButton shows \"Verified\" for an already-\n // verified email. omitEmpty on the field config keeps an unverified row from\n // writing a null/false carrier.\n const carrierName = (key) => (namePrefix !== undefined ? [namePrefix, key] : key);\n const verifyCarriers = field.verifyAction ? (\n <>\n {field.verifyResultField && (\n <Form.Item name={carrierName(field.verifyResultField)} hidden noStyle>\n <Input />\n </Form.Item>\n )}\n {field.verifyTimestampField && (\n <Form.Item name={carrierName(field.verifyTimestampField)} hidden noStyle>\n <Input />\n </Form.Item>\n )}\n </>\n ) : null;\n\n const fieldItemWithVerify = field.verifyAction ? (\n <div className=\"v1-verify-field-row\">\n {fieldItemWithActions}\n <VerifyFieldButton form={form} field={field} absoluteName={absoluteName} />\n {verifyCarriers}\n </div>\n ) : fieldItemWithActions;\n\n // The override flag lives on a path nothing else registers, so — exactly\n // like the verify carriers above — it needs a hidden Form.Item or antd's\n // onFinish drops it and an edit has nothing to prefill from.\n const fieldItemWithOverride = overrideCfg ? (\n <>\n {fieldItemWithVerify}\n <Form.Item\n name={namePrefix !== undefined\n ? [namePrefix, overrideFlag[overrideFlag.length - 1]]\n : overrideFlag[overrideFlag.length - 1]}\n valuePropName=\"checked\"\n hidden\n noStyle\n >\n <Checkbox />\n </Form.Item>\n </>\n ) : fieldItemWithVerify;\n\n // Inside a combined block, each box's width follows its combineWidth weight\n // (flex-grow), so the pack can be sized by ratio (e.g. 2:1, 1:2:3). Unset → 1.\n const inlineStyle = opts.inline\n ? { flex: `${Number(field.combineWidth) > 0 ? Number(field.combineWidth) : 1} 1 0`, maxWidth: 'none' }\n : undefined;\n\n\n const autoFillWatcher = field.autoFillFromApi ? (\n <AutoFillFromApiWatcher\n key={`${field.field}-autoFillFromApi`}\n form={form}\n config={field.autoFillFromApi}\n watchPath={absoluteName}\n />\n ) : null;\n\n const prefillWatcher = field.prefillWhen?.length ? (\n <PrefillWhenWatcher\n key={`${field.field}-prefillWhen`}\n form={form}\n rules={field.prefillWhen}\n watchPaths={prefillWhenWatchPaths(field.prefillWhen, absoluteName, resolveScopedFieldPath, prefixFor)}\n targetPath={absoluteName}\n resetOnNoMatch={field.prefillWhenReset !== false}\n />\n ) : null;\n\n // A show:0 field only reaches here because it has prefillWhen (see\n // the visibleFields filter above) — it exists purely to derive and\n // hold a value via the watcher, never to be seen or directly edited.\n if (field.show === 0) {\n return (\n <Fragment key={field.field}>\n {prefillWatcher}\n {autoFillWatcher}\n <Form.Item name={name} hidden noStyle>\n <input type=\"hidden\" />\n </Form.Item>\n </Fragment>\n );\n }\n\n // colWhen: live grid width, so a field can shrink when a condition\n // reveals a sibling next to it. Inline (combined) cells are flex-sized\n // by combineWidth, so they keep their fixed span.\n const hasColWhen = !opts.inline && colWhenRules(field).length > 0;\n const spanFor = (getFieldValue) => (hasColWhen\n ? resolveColSpan(field, mdSpan, (rule) => getFieldValue(conditionFieldPath(rule, prefixFor(rule.field))))\n : mdSpan);\n\n if (hasShowIf(field.showIf) || hasColWhen) {\n return (\n <Fragment key={field.field}>\n {prefillWatcher}\n {autoFillWatcher}\n <Form.Item shouldUpdate noStyle>\n {({ getFieldValue }) =>\n (!hasShowIf(field.showIf) || evaluateShowIf(field.showIf, getFieldValue, prefixFor))\n ? <Col xs={24} md={spanFor(getFieldValue)} style={inlineStyle} className={opts.inline ? 'v1-combine-cell' : undefined}>{fieldItemWithOverride}</Col>\n : null\n }\n </Form.Item>\n </Fragment>\n );\n }\n return (\n <Fragment key={field.field}>\n {prefillWatcher}\n {autoFillWatcher}\n <Col xs={24} md={mdSpan} style={inlineStyle} className={opts.inline ? 'v1-combine-cell' : undefined}>{fieldItemWithOverride}</Col>\n </Fragment>\n );\n };\n\n // renderAddRowField — field-level \"addRow\": repeats a SINGLE field's control\n // with the same add/remove + min/initial/max config the group-level addRow\n // uses (Form.List), but each list item IS the field's value directly (no\n // sub-key row object). Config keys mirror the group ones: field.minRows /\n // field.initialRows / field.maxRows / field.addLabel.\n // • minRows — delete is disabled once the list reaches this count.\n // • initialRows— empty inputs shown on a fresh Add (falls back to minRows).\n // • maxRows — the \"Add\" button hides once the list reaches this count.\n // Required (field.req) is enforced at the LIST level (>=1 non-empty entry) —\n // per-item rules skip \"required\" so an empty-but-present item never blocks.\n // Each item renders through singleFieldOf(field) so a repeatable select/\n // multi field shows a SINGLE control per item, not a multi-select.\n // Only used for a top-level field (namePrefix === undefined) — a field with\n // addRow=true inside an addRow GROUP renders as a normal single-value field\n // (no nested repeats).\n const renderAddRowField = (field) => {\n const fieldParts = typeof field.field === 'string' && field.field.includes('.')\n ? field.field.split('.')\n : [field.field];\n const permissionLocked = Boolean(field.editablePermission)\n && !roleAllowsAction(field.editablePermission, moduleName);\n const fieldLabel = <FieldLabel field={field} label={field.label} locked={permissionLocked} />;\n const itemField = singleFieldOf(field);\n // subFields → repeat a GROUP of fields per row (each row is an object of\n // the sub-fields, e.g. question + answer) instead of a single scalar.\n // Rows render through the same renderFields the group-level addRow uses.\n const hasSubFields = Array.isArray(field.subFields) && field.subFields.length > 0;\n // Sub-fields are always shown + editable (the admin exposes no show/edit\n // toggle for them). Force both so a sub-field never renders disabled: the\n // Go FormGroupField serializes show/edit as 0 when unset (no omitempty),\n // which editable() would otherwise read as \"not editable\".\n const subFieldsToRender = hasSubFields\n ? field.subFields.map((sf) => ({ ...sf, show: 1, edit: 1 }))\n : null;\n const minRows = Math.max(0, Number(field.minRows ?? 0) || 0);\n const maxRows = field.maxRows !== undefined && field.maxRows !== '' && Number(field.maxRows) > 0\n ? Number(field.maxRows) : 0;\n // Prefill source (quick-submit / initialRecord) — the Form.List mounts\n // only once the form is ready, so this initialValue is correct at mount.\n const prefillSource = pickPrefillValue(initialRecord ?? prefillFlatRecord ?? {}, field);\n const initialValue = buildRepeatFieldInitial(field, prefillSource);\n\n return (\n <Col key={field.field} xs={24} md={24}>\n <Form.Item label={fieldLabel} required={isFieldRequired(field)} colon={false} className=\"v1-combine-field\">\n <Form.List\n name={fieldParts}\n initialValue={initialValue}\n rules={[{\n validator: async (_, items = []) => {\n if (isFieldRequired(field)) {\n const filled = hasSubFields\n ? items.some((v) => hasMeaningfulValue(v))\n : items.some((v) => v !== undefined && v !== null && v !== '' && !(Array.isArray(v) && v.length === 0));\n if (!filled) throw new Error('Mandatory Field');\n }\n if (minRows > 0 && items.length < minRows) {\n throw new Error(`Keep at least ${minRows} ${hasSubFields ? 'row' : 'value'}${minRows > 1 ? 's' : ''}.`);\n }\n },\n }]}\n >\n {(items, { add, remove }, { errors }) => (\n <div className=\"v1-addrow-wrapper\">\n {items.map(({ key: itemKey, name: itemName }) => (\n <div key={itemKey} className=\"v1-addrow-item\">\n <Button\n type=\"text\" danger icon={<DeleteOutlined />}\n onClick={() => remove(itemName)}\n disabled={items.length <= minRows}\n className=\"v1-addrow-delete-btn\"\n />\n <div className=\"v1-addrow-fields\">\n {hasSubFields ? (\n <Row gutter={[24, 0]} align=\"top\">\n {renderFields(subFieldsToRender, itemName, fieldParts[0], false, field.field)}\n </Row>\n ) : (\n <Form.Item\n name={[itemName]}\n noStyle\n valuePropName={field.type === 'checkbox' && !(field.options?.length) ? 'checked' : 'value'}\n getValueFromEvent={field.type === 'file' ? (event) => (Array.isArray(event) ? event : event?.fileList) : undefined}\n rules={getRules(itemField, form, [...fieldParts, itemName], isSearch)}\n >\n <FieldControl\n field={itemField}\n form={form}\n name={[...fieldParts, itemName]}\n moduleName={moduleName}\n scopeValues={{ clientId: effectiveClientId }}\n formDisabled={aiActions.busy}\n />\n </Form.Item>\n )}\n </div>\n </div>\n ))}\n {(!maxRows || items.length < maxRows) && (\n <Button type=\"link\" icon={<PlusOutlined />} onClick={() => add()} className=\"v1-addrow-add-btn\">\n {field.addLabel ?? `Add ${field.label ?? 'Value'}`}\n </Button>\n )}\n <Form.ErrorList errors={errors} />\n </div>\n )}\n </Form.List>\n </Form.Item>\n </Col>\n );\n };\n\n // renderNestedRepeatField — a repeat field (field.addRow) that lives INSIDE\n // an addRow group row. It nests its own Form.List under the current row so\n // every row owns an independent set of repeat values (the payload shape\n // group[rowIndex].repeatField[repeatIndex], e.g. educationDetails[0].subjects).\n // Also handles the field.subFields case (repeat a GROUP of sub-fields\n // together per row, e.g. question + answer) nested the same way — each item\n // renders the sub-fields through the same renderFields the top-level\n // subFields branch (renderAddRowField) uses, so a select/lookup sub-field\n // gets the exact same config-driven dropdown loading as any other field.\n // namePrefix is the outer row's index (from the group Form.List), listName\n // is the group's Form.List name (string) or, for a doubly-nested case, its\n // absolute path array. The nested list's `name` is relative to that list\n // context ([rowIndex, ...fieldParts]); item controls use the absolute path\n // for validators/FieldControl.\n const renderNestedRepeatField = (field, namePrefix, listName) => {\n const fieldParts = typeof field.field === 'string' && field.field.includes('.')\n ? field.field.split('.')\n : [field.field];\n const permissionLocked = Boolean(field.editablePermission)\n && !roleAllowsAction(field.editablePermission, moduleName);\n const fieldLabel = <FieldLabel field={field} label={field.label} locked={permissionLocked} />;\n const itemField = singleFieldOf(field);\n const hasSubFields = Array.isArray(field.subFields) && field.subFields.length > 0;\n const subFieldsToRender = hasSubFields\n ? field.subFields.map((sf) => ({ ...sf, show: 1, edit: 1 }))\n : null;\n const minRows = Math.max(0, Number(field.minRows ?? 0) || 0);\n const maxRows = field.maxRows !== undefined && field.maxRows !== '' && Number(field.maxRows) > 0\n ? Number(field.maxRows) : 0;\n // Relative name (group-list context prefixes the group name); the parent\n // row's initialValue already carries any stored values for this key, so a\n // fresh row falls back to config-driven empty inputs while an edited row\n // inherits its stored values (antd ignores this initialValue when the\n // store already holds a value at this path).\n const listNameRel = [namePrefix, ...fieldParts];\n const nestedAbsoluteListName = [...(Array.isArray(listName) ? listName : [listName]), namePrefix, ...fieldParts];\n const initialValue = buildRepeatFieldInitial(field, undefined);\n return (\n <Col key={`${listName}-${namePrefix}-${field.field}`} xs={24} md={hasSubFields ? 24 : (field.col ?? 24)}>\n <Form.Item label={fieldLabel} required={isFieldRequired(field)} colon={false} className=\"v1-combine-field\">\n <Form.List\n name={listNameRel}\n initialValue={initialValue}\n rules={hasSubFields ? [{\n validator: async (_, items = []) => {\n if (isFieldRequired(field)) {\n const filled = items.some((v) => hasMeaningfulValue(v));\n if (!filled) throw new Error('Mandatory Field');\n }\n if (minRows > 0 && items.length < minRows) {\n throw new Error(`Keep at least ${minRows} row${minRows > 1 ? 's' : ''}.`);\n }\n },\n }] : []}\n >\n {(items, { add, remove }, { errors }) => (\n <div className=\"v1-addrow-wrapper\">\n {items.map(({ key: itemKey, name: itemName }) => {\n const absoluteName = [...nestedAbsoluteListName, itemName];\n return (\n <div key={itemKey} className=\"v1-addrow-item\">\n <Button\n type=\"text\" danger icon={<DeleteOutlined />}\n onClick={() => remove(itemName)}\n disabled={items.length <= minRows}\n className=\"v1-addrow-delete-btn\"\n />\n <div className=\"v1-addrow-fields\">\n {hasSubFields ? (\n <Row gutter={[24, 0]} align=\"top\">\n {renderFields(subFieldsToRender, itemName, nestedAbsoluteListName, false, field.field)}\n </Row>\n ) : (\n <Form.Item\n name={[itemName]}\n noStyle\n valuePropName={field.type === 'checkbox' && !(field.options?.length) ? 'checked' : 'value'}\n getValueFromEvent={field.type === 'file' ? (event) => (Array.isArray(event) ? event : event?.fileList) : undefined}\n rules={getRules(itemField, form, absoluteName, isSearch)}\n >\n <FieldControl\n field={itemField}\n form={form}\n name={absoluteName}\n moduleName={moduleName}\n scopeValues={{ clientId: effectiveClientId }}\n formDisabled={aiActions.busy}\n />\n </Form.Item>\n )}\n </div>\n </div>\n );\n })}\n {(!maxRows || items.length < maxRows) && (\n <Button type=\"link\" icon={<PlusOutlined />} onClick={() => add()} className=\"v1-addrow-add-btn\">\n {field.addLabel ?? `Add ${field.label ?? 'Value'}`}\n </Button>\n )}\n <Form.ErrorList errors={errors} />\n </div>\n )}\n </Form.List>\n </Form.Item>\n </Col>\n );\n };\n\n\n// registerHiddenFields — a show:0 field still needs a Form.Item.\n//\n// A hidden field is not decoration: it is a CARRIER. The engine deliberately\n// keeps show:0 fields in the group (see normalizeGroups) precisely so their\n// values participate — the job's client rate rides onto a submission that way\n// (jobClientRate.*, filled by prefillFromModule), and a verify result rides on\n// isValid/validatedAt.\n//\n// But a value set with setFieldsValue on a path NOTHING has registered is not\n// reliably part of the form: onFinish drops it, and a cross-field rule reading\n// it through getFieldValue can come back empty. That is why the verify carriers\n// were already registered by hand at their own call site. Doing it here covers\n// EVERY config-declared hidden field instead of the two someone remembered,\n// which is what makes a rule like \"rate may not exceed the job's client rate\"\n// actually fire — before this it silently found no ceiling and passed anything.\n//\n// Rendered `hidden` (never visible), unstyled, and outside the layout grid, so\n// nothing about the form's appearance changes.\nconst renderHiddenCarriers = (fields, namePrefix) => fields\n .filter((f) => f.field && f.show !== undefined && !truthy(f.show))\n .map((f) => {\n const parts = String(f.field).includes('.') ? String(f.field).split('.') : f.field;\n const name = namePrefix !== undefined\n ? [namePrefix, ...(Array.isArray(parts) ? parts : [parts])]\n : parts;\n return (\n <Form.Item key={`hidden-${f.field}`} name={name} hidden noStyle>\n <Input />\n </Form.Item>\n );\n });\n\n const renderFields = (fields, namePrefix, listName, hideLabel = false, groupNameForActions) => {\n const used = new Set();\n const out = [];\n // Keys of THIS group's own fields — conditions (showIf/labelWhen/\n // prefillWhen) referencing a field OUTSIDE the group (e.g. the top-level\n // contractType from inside the addRow employer group) must resolve\n // against the top-level form, not the row.\n const rowFieldKeys = new Set(fields.map((f) => f.field).filter(Boolean));\n // Hidden (show:0) fields stay in `fields` so buildPayload can see them\n // (see normalizeGroups) — they just never get a Form.Item here.\n const visibleFields = fields.filter((f) => (\n f.show === undefined || truthy(f.show) || (f.show === 0 && Boolean(f.prefillWhen?.length))\n ));\n out.push(...renderHiddenCarriers(fields, namePrefix));\n visibleFields.forEach((field) => {\n if (truthy(field.addRow) && namePrefix === undefined) {\n out.push(renderAddRowField(field));\n return;\n }\n // A repeat field INSIDE an addRow group row (namePrefix defined) gets\n // its own nested Form.List so each row keeps independent repeat values\n // (educationDetails[rowIndex].subjects[]) — including a subFields\n // repeat-GROUP (e.g. question+answer pairs per education row).\n if (truthy(field.addRow) && namePrefix !== undefined) {\n out.push(renderNestedRepeatField(field, namePrefix, listName));\n return;\n }\n const combineKey = field.combineKey?.trim?.();\n if (!combineKey) {\n out.push(renderField(field, namePrefix, listName, { hideLabel, groupNameForActions, rowFieldKeys }));\n return;\n }\n const packKey = `${listName ?? 'root'}:${namePrefix ?? 'root'}:${combineKey}`;\n if (used.has(packKey)) return;\n const pack = visibleFields.filter((f) => f.combineKey === combineKey);\n pack.forEach((f) => used.add(`${listName ?? 'root'}:${namePrefix ?? 'root'}:${f.combineKey}`));\n\n const labelField = pack.find((f) => f.combineLabel) ?? field;\n const siblingPrefix = (listName !== undefined && namePrefix !== undefined)\n ? [...(Array.isArray(listName) ? listName : [listName]), namePrefix]\n : null;\n // A combined pack prints ONE shared label, so an override checkbox\n // configured on ANY member belongs beside that shared label — the\n // per-field path in renderField cannot fire here (inline members are\n // label-less by design). First member that declares one wins.\n const packOverrideField = pack.find((f) => overrideConfig(f)) ?? null;\n const packPrefixForOverride = (conditionKey) => (\n siblingPrefix && (!rowFieldKeys || rowFieldKeys.has(conditionKey)) ? siblingPrefix : null\n );\n const packOverrideAbsName = packOverrideField\n ? ((listName !== undefined && namePrefix !== undefined)\n ? [...(Array.isArray(listName) ? listName : [listName]), namePrefix,\n ...(String(packOverrideField.field).includes('.')\n ? String(packOverrideField.field).split('.')\n : [packOverrideField.field])]\n : (String(packOverrideField.field).includes('.')\n ? String(packOverrideField.field).split('.')\n : packOverrideField.field))\n : null;\n const baseCombinedLabel = <ConfiguredFieldLabel form={form} field={labelField} siblingPrefix={siblingPrefix} combined />;\n const label = packOverrideField ? (\n <span className=\"v1-label-with-override\">\n {baseCombinedLabel}\n <ValidationOverrideCheckbox\n form={form}\n field={packOverrideField}\n flagPath={overrideFlagPath(packOverrideField, packOverrideAbsName, packPrefixForOverride)}\n fieldPath={packOverrideAbsName}\n />\n </span>\n ) : baseCombinedLabel;\n const toggleTarget = pack.find((f) => f.combineToggleTarget)?.combineToggleTarget;\n const toggleLabel = pack.find((f) => f.combineToggleLabel)?.combineToggleLabel ?? 'Show range';\n const toggleStateKey = packKey;\n const wrapPack = pack.some((f) => truthy(f.combineWrap));\n const configuredSpan = Number(pack.find((f) => [12, 24].includes(Number(f.combineSpan)))?.combineSpan);\n const targetField = toggleTarget ? pack.find((f) => fieldKey(f) === toggleTarget) : null;\n const targetParts = targetField?.field?.includes?.('.') ? targetField.field.split('.') : [targetField?.field].filter(Boolean);\n const targetName = targetField\n ? ((listName !== undefined && namePrefix !== undefined)\n ? [listName, namePrefix, ...targetParts]\n : (targetParts.length > 1 ? targetParts : targetField.field))\n : null;\n\n // Layout mirrors the legacy combined field: one label, the boxes inline on\n // a single row, and the range toggle BELOW. Toggle off → only the primary\n // (target hidden); toggle on → the target box appears alongside. The wider\n // packs (with currency/unit) take a full row; a simple From/To pair is half.\n const primaryReq = pack.some((f) => isFieldRequired(f));\n const comboSpan = [12, 24].includes(configuredSpan)\n ? configuredSpan\n : (pack.length >= 3 ? 24 : 12);\n // A combined pack prints ONE shared label above its boxes, and that\n // label lives outside the per-field showIf gates. When every member\n // is hidden by its condition the boxes disappear but the labelled\n // shell stayed — e.g. an empty \"Contact Number\" on a W2 employer.\n // Gate the whole pack on \"is any member still visible\".\n const packPrefixFor = (conditionKey) => (\n siblingPrefix && (!rowFieldKeys || rowFieldKeys.has(conditionKey)) ? siblingPrefix : null\n );\n const packHasShowIf = pack.some((f) => hasShowIf(f.showIf));\n const anyPackMemberVisible = (getFieldValue) => pack.some(\n (f) => !hasShowIf(f.showIf) || evaluateShowIf(f.showIf, getFieldValue, packPrefixFor),\n );\n const packCol = (\n <Col key={packKey} xs={24} md={comboSpan}>\n <Form.Item label={label} required={primaryReq} colon={false} className=\"v1-combine-field\">\n <Form.Item noStyle shouldUpdate>\n {({ getFieldValue }) => {\n const hasTargetValue = targetName ? !empty(getFieldValue(targetName)) : false;\n const checked = combineToggles[toggleStateKey] ?? hasTargetValue;\n const visiblePack = toggleTarget && !checked\n ? pack.filter((f) => fieldKey(f) !== toggleTarget)\n : pack;\n return (\n <>\n <Row\n gutter={[8, 0]}\n align=\"top\"\n wrap={wrapPack}\n className={`v1-combine-row${wrapPack ? ' v1-combine-row-wrap' : ''}`}\n >\n {/* Combined-field mandatory cascade: if ANY field in a\n combined pack is required, every VISIBLE field in the\n pack is required too (e.g. Notice Period requires its\n Unit). Applied to visiblePack so a hidden range \"To\"\n stays optional until its toggle is on. */}\n {visiblePack.map((f) => renderField(primaryReq ? { ...f, req: 1 } : f, namePrefix, listName, { inline: true }))}\n </Row>\n {toggleTarget && (\n <div className=\"v1-combine-range\">\n <Switch\n size=\"small\"\n checked={checked}\n onChange={(next) => {\n if (!next && targetName) {\n form.setFieldValue(targetName, undefined);\n form.validateFields([targetName]).catch(() => { });\n }\n setCombineToggles((prev) => ({ ...prev, [toggleStateKey]: next }));\n }}\n />\n <Text type=\"secondary\" className=\"v1-combine-toggle-label\">{toggleLabel}</Text>\n </div>\n )}\n </>\n );\n }}\n </Form.Item>\n </Form.Item>\n </Col>\n );\n out.push(packHasShowIf ? (\n <Form.Item key={packKey} shouldUpdate noStyle>\n {({ getFieldValue }) => (anyPackMemberVisible(getFieldValue) ? packCol : null)}\n </Form.Item>\n ) : packCol);\n });\n return out;\n };\n\n // Derive fields from search results for ListView (same logic as JobsListPage)\n const searchFields = useMemo(() => {\n if (searchResults.fields?.length) return searchResults.fields;\n const firstRow = searchResults.rows[0];\n if (!firstRow) return [];\n\n return Object.keys(firstRow)\n .filter((key) => !key.startsWith('_') && typeof firstRow[key] !== 'object')\n .map((key) => ({\n value: key,\n field: key,\n label: key.replace(/([A-Z])/g, ' $1').replace(/^./, (char) => char.toUpperCase()),\n isVisible: true,\n }));\n }, [searchResults.fields, searchResults.rows]);\n\n // Determine view mode based on source type: show list view for external sources,\n // card view for internal sources\n const getViewModeFromRecords = (records) => {\n if (!Array.isArray(records) || records.length === 0) return 'card';\n\n const hasExternalSource = records.some((record) => {\n const sourceFields = [\n record?.sourceType,\n record?.profileSource,\n record?.selectedSource,\n record?.customFields?.sourceType,\n record?.customFields?.profileSource,\n ];\n\n return sourceFields.some((value) => {\n if (value === null || value === undefined) return false;\n const normalized = String(value).trim().toLowerCase();\n if (!normalized) return false;\n return !['all', 'internal'].includes(normalized);\n });\n });\n\n return hasExternalSource ? 'list' : 'card';\n };\n\n const defaultViewMode = useMemo(() => {\n return getViewModeFromRecords(searchResults.rows);\n }, [searchResults.rows]);\n\n const searchFieldsWithActions = useMemo(() => {\n const sourceActions = getAvailableSourceActions({\n rows: searchResults.rows,\n selectedSource,\n });\n if (!sourceActions.length) return searchFields;\n\n const actionFields = new Set(sourceActions.map((action) => action.field));\n const fieldsWithoutActions = searchFields.filter(\n (field) => field.cardRole !== 'action' && !actionFields.has(field.value),\n );\n return [\n ...fieldsWithoutActions,\n ...sourceActions.map((action) => ({\n value: action.field,\n field: action.field,\n label: action.label ?? 'Action',\n cardRole: 'action',\n isVisible: true,\n tableHidden: true,\n sorter: false,\n render: (_value, record) => {\n if (!sourceActionAppliesToRecord(action, record, selectedSource)) return null;\n const actionKey = getSourceActionInstanceKey(action, record);\n const state = sourceActionState[actionKey] ?? {};\n const missingActionId = !actionKey;\n const disabled = missingActionId || state.completed;\n\n return (\n <Button\n type=\"primary\"\n size=\"small\"\n loading={state.loading}\n disabled={disabled}\n onClick={() => handleSourceAction(action, record)}\n >\n {state.completed ? action.completedLabel : action.buttonLabel}\n </Button>\n );\n },\n })),\n ];\n }, [handleSourceAction, searchFields, searchResults.rows, selectedSource, sourceActionState]);\n\n // Merge page-level context (e.g. { jobId }) into every search-result row\n // action's popupState, so a popup it opens (via ListView's action.route\n // handling) receives that context too — see the searchActionContext prop.\n const searchResultActions = useMemo(() => {\n if (!searchActionContext) return searchResults.actions;\n const mergeContext = (action) => ({\n ...action,\n popupState: { ...searchActionContext, ...action.popupState },\n ...(action.children ? { children: action.children.map(mergeContext) } : {}),\n });\n return (searchResults.actions ?? []).map(mergeContext);\n }, [searchResults.actions, searchActionContext]);\n\n // renderGroupBody builds a group's inner controls (the addRow Form.List or\n // the flat field Row) WITHOUT its Card chrome, so a group flagged\n // `mergeInto: \"<hostGroupName>\"` can render inside another group's card\n // (e.g. Rate Details inside Employer) while keeping its own payload,\n // appendHistory and showIf semantics completely unchanged — the merge is\n // presentation only.\n const renderGroupBody = (group) => {\n const groupName = group.name ?? group.id ?? '';\n // group.linkGroup: when this group is linked to others, the LEADER owns\n // the Add button + minRows/requireOne validator for the whole set; every\n // member (leader + followers) still gets its own Form.List/Card/rows, and\n // add/remove always go through every member via listControlsRef so row\n // counts stay equal by construction. Unlinked groups (linkedSet === null,\n // i.e. every group that predates this feature) fall through leaderGroup\n // === group, so minRows/rules/initialValue below compute exactly as before.\n const linkedSet = findLinkedSet(linkedGroupSets, groupName);\n const isFollower = Boolean(linkedSet) && linkedSet.leaderName !== groupName;\n const leaderGroup = linkedSet\n ? (groups.find((g) => g.name === linkedSet.leaderName) ?? group)\n : group;\n const minRows = Math.max(0, Number(leaderGroup.minRows ?? 0) || 0);\n const maxRows = Math.max(0, Number(leaderGroup.maxRows ?? 0) || 0);\n const linkedMemberNames = linkedSet ? linkedSet.memberNames : [groupName];\n const addLinkedRow = () => {\n // New rows start from the group's admin-configured defaults (same\n // seed the initial rows get), not empty.\n linkedMemberNames.forEach((name) => {\n const member = groups.find((g) => g.name === name) ?? group;\n listControlsRef.current[name]?.add(rowDefaultsFor(member));\n });\n };\n const removeLinkedRow = (rowName) => {\n linkedMemberNames.forEach((name) => listControlsRef.current[name]?.remove(rowName));\n };\n // Opt-in (wizardContent.addRowView 'table', wizard only): rows as a\n // table — one header of labels, one line per row. Cards stay default.\n const tableRows = wizardEnabled && Boolean(group.addRow) && wizardAddRowView(group, groups) === 'table';\n const sharedLabels = truthy(group.sharedRowLabels) || tableRows;\n const body = group.addRow ? (\n <Form.List\n name={groupName}\n initialValue={addRowInitials[groupName] ?? []}\n rules={isFollower ? [] : [\n {\n validator: async (_, rows = []) => {\n // A group switched OFF via its own toggle (e.g. \"Fresher\" hiding\n // Work Experience) is not rendered at all — don't force rows on it.\n const switchedOn = truthy(group.toggleEnabled) && group.toggleField\n && Boolean(form.getFieldValue(group.toggleField));\n if (switchedOn) return;\n if (minRows > 0 && rows.length < minRows) {\n throw new Error(`Keep at least ${minRows} row${minRows > 1 ? 's' : ''}.`);\n }\n if (truthy(group.requireOne)) {\n const invalid = rows.some((row) => !hasMeaningfulValue(row));\n if (invalid) throw new Error('Fill at least one field in each added row.');\n }\n },\n },\n ]}\n >\n {(rows, { add, remove, move }, { errors }) => {\n // `move` joins the registry so the newest-first prompt can\n // reorder a row the user just marked as ongoing. Form.List's\n // own move preserves every row's values; rebuilding the\n // array by hand would not.\n listControlsRef.current[groupName] = { add, remove, move };\n return (\n <div className={tableRows ? 'v1-addrow-wrapper v1-addrow-wrapper--table' : 'v1-addrow-wrapper'}>\n <div className=\"v1-addrow-topbar\">\n {!isFollower ? (\n (!maxRows || rows.length < maxRows) && (\n <Button\n type=\"link\"\n icon={<PlusOutlined />}\n onClick={addLinkedRow}\n className=\"v1-addrow-add-btn\"\n >\n {group.addLabel ?? `Add ${group.label ?? 'Row'}`}\n </Button>\n )\n ) : (\n <Text type=\"secondary\" className=\"v1-addrow-linked-hint\">\n Rows added via {leaderGroup.label ?? leaderGroup.name}\n </Text>\n )}\n </div>\n\n {sharedLabels && rows.length > 0 && (\n <Row gutter={[24, 0]} className=\"v1-addrow-header\">\n {group.fields.filter((f) => f.show === undefined || truthy(f.show)).map((field) => (\n <Col key={fieldKey(field)} md={field.col ?? 12} className=\"v1-addrow-header-label\">\n {field.label}\n </Col>\n ))}\n </Row>\n )}\n\n {rows.map(({ key: rowKey, name }) => (\n <div key={rowKey} className=\"v1-addrow-item\">\n <Button\n type=\"text\"\n danger\n icon={<DeleteOutlined />}\n onClick={() => removeLinkedRow(name)}\n disabled={rows.length <= minRows}\n className=\"v1-addrow-delete-btn\"\n />\n\n <div className=\"v1-addrow-fields\">\n <Row gutter={[24, 0]} align=\"top\">\n {renderFields(group.fields, name, groupName, sharedLabels, groupName)}\n </Row>\n </div>\n </div>\n ))}\n <Form.ErrorList errors={errors} />\n </div>\n );\n }}\n </Form.List>\n ) : (\n <Row gutter={[24, 0]}>{renderFields(group.fields, undefined, undefined, false, groupName)}</Row>\n );\n\n return body;\n };\n\n // Groups rendered INSIDE another group's card (group.mergeInto). A child\n // keeps its own showIf gate and gets a light section title; everything else\n // (payload, validation, Form.List names) is untouched.\n const mergedChildrenOf = (group) => groups.filter(\n (g) => g !== group && g.mergeInto && String(g.mergeInto) === String(group.name),\n );\n const isMergedChild = (group) => Boolean(\n group.mergeInto && groups.some((g) => g !== group && String(g.name) === String(group.mergeInto)),\n );\n\n // A merged child renders BEFORE the host's own fields when it declares\n // `mergePosition: \"top\"`. Needed whenever the child holds the field the\n // host's fields are conditioned on — Contract Type gates every Employer\n // field, so rendering it underneath them reads backwards and invites the\n // user to fill a disabled card first.\n const mergedAt = (group, position) => mergedChildrenOf(group).filter(\n (child) => (String(child.mergePosition ?? 'bottom') === position),\n );\n\n\n const renderGroup = (group, index) => {\n const key = group.name ?? group.id ?? String(index);\n const body = renderGroupBody(group);\n const mergedTop = mergedAt(group, 'top');\n const mergedChildren = mergedAt(group, 'bottom');\n\n // One renderer for both slots, so a merged child behaves identically\n // whichever side of the host body it sits on.\n const renderMergedChild = (child) => {\n const section = (\n <div key={child.name} className=\"v1-merged-group\">\n <div className=\"v1-merged-group-title\">{child.label ?? child.name}</div>\n {renderGroupBody(child)}\n </div>\n );\n const gated = child.showIf?.field\n ? <GroupShowIfGate key={child.name} form={form} showIf={child.showIf} render={() => section} />\n : section;\n // Its OWN disabled state, not the host's — see GroupDisabledProvider.\n return (\n <GroupDisabledProvider key={child.name} form={form} group={child} inheritParent={false}>\n {gated}\n </GroupDisabledProvider>\n );\n };\n\n return (\n <Card\n key={key}\n className=\"v1-card v1-edit-card\"\n title={<SectionTitle icon={sectionIcons[index % sectionIcons.length]} title={isSearch ? (searchFormLabel || group.label) : (group.label ?? group.name ?? 'Details')} />}\n extra={(\n <Space size={8} align=\"center\" className=\"v1-group-actions\">\n <GroupInfoMessage group={group} />\n <GroupToggleControl group={group} />\n {/* Opt-in only (group.allowCollapse). Without it there is\n no chevron and the section cannot be collapsed — the\n behaviour every form had before this was configurable. */}\n {truthy(group.allowCollapse) && (\n <Button\n type=\"text\"\n size=\"small\"\n aria-expanded={!collapsed[key]}\n aria-label={collapsed[key] ? 'Expand section' : 'Collapse section'}\n icon={collapsed[key] ? <DownOutlined /> : <UpOutlined />}\n onClick={(event) => {\n event.stopPropagation();\n toggle(key);\n }}\n />\n )}\n </Space>\n )}\n >\n <Form.Item noStyle shouldUpdate>\n {({ getFieldValue }) => {\n const switchedOn = truthy(group.toggleEnabled) && group.toggleField && Boolean(getFieldValue(group.toggleField));\n return (\n <div style={{ display: collapsed[key] || switchedOn ? 'none' : 'block' }}>\n {mergedTop.map(renderMergedChild)}\n {body}\n {mergedChildren.map(renderMergedChild)}\n </div>\n );\n }}\n </Form.Item>\n </Card>\n );\n };\n\n return (\n <main>\n {breadcrumbItems.length > 0 && <AppBreadcrumb items={breadcrumbItems} />}\n {wizardEnabled && WizardAdapter ? (\n <WizardAdapter\n {...(wizardAdapterProps ?? {})}\n mode=\"add\"\n moduleName={moduleName}\n configuredSteps={wizardSteps}\n configuredGroups={wizardConfigGroups}\n />\n ) : <div className=\"v1-edit-page\">\n {hasClientScope && !presetClientId && !linkedClientId && (\n <Card className=\"v1-card v1-edit-card v1-client-gate-card\">\n <Space direction=\"vertical\" size={12} style={{ width: '100%' }}>\n <SectionTitle icon={<UserOutlined />} title=\"Select Client\" />\n {clientGateMessage && <Text type=\"secondary\">{clientGateMessage}</Text>}\n <Row gutter={[16, 0]}>\n <Col xs={24} md={14}>\n <Select\n showSearch\n allowClear\n placeholder=\"Select client\"\n style={{ width: '100%' }}\n value={effectiveClientId || undefined}\n optionFilterProp=\"label\"\n options={clientOptions.map((c) => ({\n value: c._id ?? c.id,\n label: c.clientName ?? c.name ?? c.clientRefrenceId ?? c._id,\n })).filter((c) => c.value)}\n onChange={handleClientGateChange}\n dropdownRender={clientGateQuick.footer\n ? (menu) => (<>{menu}{clientGateQuick.footer}</>)\n : undefined}\n />\n {clientGateQuick.modal}\n </Col>\n </Row>\n </Space>\n </Card>\n )}\n <div className=\"v1-page-inner\">\n {wizardEnabled && isFormReady && (\n <FormWizard\n steps={wizardSteps}\n current={activeWizardStep}\n errorStep={wizardRuntime.errorStep}\n onSelectCompleted={wizardShowingSuccess || wizardRuntime.busy ? undefined : goToWizardStep}\n />\n )}\n {/* Async work gets its OWN viewport-centred overlay.\n The wrapping Spin below centres its indicator inside the\n element it wraps — on a form this long that lands\n somewhere in the middle of the page, which after any\n scrolling is off screen entirely. Reading a résumé takes\n seconds, so the user is left looking at a frozen form\n with no visible sign that anything is happening.\n `fullscreen` pins it to the centre of the VIEWPORT with\n a scrim, so it is where the user is looking whatever\n they have scrolled to. */}\n <Spin\n fullscreen\n spinning={aiActions.busy || duplicates.checking}\n size=\"large\"\n tip={\n aiActions.busy\n ? (aiActions.loadingText || 'Reading the file…')\n : 'Checking whether we already have this person…'\n }\n />\n <Spin\n spinning={!isFormReady && !waitingForClientScope}\n description=\"Loading form fields…\"\n >\n <Form\n form={form}\n layout=\"vertical\"\n colon={false}\n className=\"v1-form\"\n // Disabled during the duplicate check too — it can\n // end by navigating away, and letting someone keep\n // typing into a form that is about to be abandoned\n // loses whatever they add in those seconds.\n disabled={aiActions.busy || duplicates.checking}\n requiredMark={(label, { required }) => (\n <>\n {label}\n {required && <span className=\"v1-required-mark\"> *</span>}\n </>\n )}\n // A wizard can finish on a step that mounts none of the\n // earlier steps' fields, so its submit reads the whole\n // store. The ordinary form keeps the exact onFinish values.\n onFinish={wizardEnabled ? submitWizard : submit}\n onFinishFailed={handleWizardSubmitFailed}\n >\n {isFormReady && (wizardEnabled ? (\n <WizardStepContent\n step={wizardSteps[activeWizardStep]}\n steps={wizardSteps}\n current={activeWizardStep}\n form={form}\n onGoToStep={goToWizardStep}\n moduleName={moduleName}\n notice={<WizardStepNotice runtime={wizardRuntime} current={activeWizardStep} />}\n actionResult={wizardRuntime.actionResult}\n savedRecord={wizardRuntime.savedRecord}\n stepBusy={wizardRuntime.busy === 'enter'}\n recordId={wizardRuntime.recordId}\n formContent={groups.filter((g) => !isMergedChild(g)).map((group, index) => {\n const stepIndex = wizardStepForGroup(wizardSteps, group, index);\n return (\n <div key={group.name ?? `grp-${index}`}\n className=\"v1-form-wizard__panel\"\n hidden={stepIndex !== activeWizardStep}>\n <GroupDisabledProvider form={form} group={group}>\n {group.showIf?.field\n ? <GroupShowIfGate form={form} showIf={group.showIf} render={() => renderGroup(group, index)} />\n : renderGroup(group, index)}\n </GroupDisabledProvider>\n </div>\n );\n })}\n />\n ) : groups.filter((g) => !isMergedChild(g)).map((group, index) => (\n <GroupDisabledProvider key={group.name ?? `grp-${index}`} form={form} group={group}>\n {group.showIf?.field\n ? <GroupShowIfGate form={form} showIf={group.showIf} render={() => renderGroup(group, index)} />\n : renderGroup(group, index)}\n </GroupDisabledProvider>\n )))}\n {isFormReady && !error && groups.length === 0 && (\n <Alert type=\"info\" showIcon message={isSearch ? \"No search configuration found.\" : \"No form fields are configured.\"} />\n )}\n {isFormReady && isSearch && (\n <div className=\"v1-search-form-actions\">\n <Space size={12}>\n <Button onClick={handleReset} disabled={!groups.length}>\n Reset\n </Button>\n <Button onClick={() => goBackOrTo(navigate, { cancelPath })}>\n Back\n </Button>\n <Button\n type=\"primary\"\n htmlType=\"submit\"\n disabled={submitLoading || !groups.length || searchDisabled}\n loading={submitLoading}\n >\n {submitText}\n </Button>\n </Space>\n </div>\n )}\n </Form>\n </Spin>\n </div>\n\n {!isSearch && !hideFooter && (\n <div className={embedded ? 'v1-footer v1-footer--embedded' : 'v1-footer'}>\n <Text type=\"secondary\">All Unsaved Changes will be lost if you cancel and reload.</Text>\n <Space size={12}>\n <Button onClick={() => (embedded && onCancel\n ? onCancel()\n : goBackOrTo(navigate, { cancelPath }))}>{wizardShowingSuccess ? 'Close' : 'Cancel'}</Button>\n {wizardEnabled && activeWizardStep > 0 && !wizardShowingSuccess && (\n <WizardBackButton disabled={Boolean(wizardRuntime.busy)} onClick={() => goToWizardStep(activeWizardStep - 1)} />\n )}\n {!wizardShowingSuccess && (!wizardEnabled || activeWizardStep === wizardSteps.length - 1 || wizardNextIsSuccess) ? formActions.map((action, index) => (\n <FormActionButton\n key={`${action.label ?? 'action'}-${index}`}\n form={form}\n groups={groups}\n action={action}\n disabled={!isFormReady || submitLoading || uniquePending > 0 || !groups.length}\n loading={submitLoading}\n onFire={() => {\n pendingAfterSubmitRef.current = action.afterSubmit ?? { mode: 'stay' };\n // Opt-in only — an action can force specific field\n // values right before submitting (e.g. a distinct\n // \"Schedule\" button implying scheduleForLater=true\n // without requiring the checkbox to be checked).\n if (action.setValuesBeforeSubmit) {\n form.setFieldsValue(action.setValuesBeforeSubmit);\n }\n form.submit();\n }}\n />\n )) : null}\n {wizardEnabled && activeWizardStep < wizardSteps.length - 1 && !wizardNextIsSuccess ? (\n <WizardNextButton onClick={advanceWizard}\n loading={wizardRuntime.busy === 'next'}\n disabled={!isFormReady || submitLoading || uniquePending > 0 || !groups.length || Boolean(wizardRuntime.busy)} />\n ) : !wizardShowingSuccess ? (\n <ValidationGatedSubmitButton\n form={form}\n groups={groups}\n onClick={() => { pendingAfterSubmitRef.current = null; form.submit(); }}\n disabled={!isFormReady || submitLoading || uniquePending > 0 || !groups.length || Boolean(wizardRuntime.busy)}\n loading={submitLoading || wizardRuntime.busy === 'finish'}\n >\n {submitText}\n </ValidationGatedSubmitButton>\n ) : null}\n </Space>\n </div>\n )}\n\n {/* Search results ListView — rendered inside AddFormV1 when in search mode */}\n {isSearch && searchResults.searched && (\n <ListView\n moduleName={moduleName}\n breadcrumbItems={[]}\n dataSource={searchResults.rows}\n fields={searchFieldsWithActions}\n total={searchResults.total}\n loading={searchResults.loading}\n current={searchPagination.current}\n pageSize={searchPagination.pageSize}\n showViewToggle\n activeView={viewMode}\n onViewChange={setViewMode}\n onPageChange={handleSearchPageChange}\n onPageSizeChange={handleSearchPageSizeChange}\n showSearch={false}\n tabs={tabs}\n selectedSource={selectedSource}\n onTabChange={handleTabChange}\n actions={searchResultActions}\n actionRules={searchResults.actionRules}\n />\n )}\n </div>}\n </main>\n );\n});\n"],"mappings":"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"}