@realtek/core-theme-live 0.0.461 → 0.0.462
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.
- package/dist-lib/{FileField-B8zHAP3t.js → FileField-D7P4Ezvq.js} +525 -501
- package/dist-lib/FileField-D7P4Ezvq.js.map +1 -0
- package/dist-lib/FileField-QeCSFxEn.cjs +3 -0
- package/dist-lib/FileField-QeCSFxEn.cjs.map +1 -0
- package/dist-lib/{LinkedRecordFileField-DeB4dO6C.cjs → LinkedRecordFileField-Bewdr9co.cjs} +2 -2
- package/dist-lib/{LinkedRecordFileField-DeB4dO6C.cjs.map → LinkedRecordFileField-Bewdr9co.cjs.map} +1 -1
- package/dist-lib/{LinkedRecordFileField-BQLakQg9.js → LinkedRecordFileField-d5p7sJCV.js} +2 -2
- package/dist-lib/{LinkedRecordFileField-BQLakQg9.js.map → LinkedRecordFileField-d5p7sJCV.js.map} +1 -1
- package/dist-lib/dropdownApi-BQInpe86.cjs +2 -0
- package/dist-lib/dropdownApi-BQInpe86.cjs.map +1 -0
- package/dist-lib/{dropdownApi-CKrs-Jwa.js → dropdownApi-uT-llqYT.js} +5 -5
- package/dist-lib/dropdownApi-uT-llqYT.js.map +1 -0
- package/dist-lib/index.cjs +7 -7
- package/dist-lib/index.cjs.map +1 -1
- package/dist-lib/index.js +8964 -8337
- package/dist-lib/index.js.map +1 -1
- package/dist-lib/style.css +1 -1
- package/package.json +1 -1
- package/dist-lib/FileField-B8zHAP3t.js.map +0 -1
- package/dist-lib/FileField-CEMkSyLL.cjs +0 -3
- package/dist-lib/FileField-CEMkSyLL.cjs.map +0 -1
- package/dist-lib/dropdownApi-C7L-0-2E.cjs +0 -2
- package/dist-lib/dropdownApi-C7L-0-2E.cjs.map +0 -1
- package/dist-lib/dropdownApi-CKrs-Jwa.js.map +0 -1
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require("./authApi-DiRtkJl2.cjs"),t=require("./FileField-CEMkSyLL.cjs"),n=require("./formGroupsCache-Bbz-28ws.cjs");async function r(t){let n=await e.o(e.x,`/candidate-versions?candidateId=${encodeURIComponent(t)}`),r=n?.data??n;if(!Array.isArray(r))throw Error(`Candidate versions could not be loaded`);return[...r].sort((e,t)=>Number(t.profileVersion)-Number(e.profileVersion))}var i=`authToken`,a=`authUser`,o=`authLoginSession`,s=[`access_token`,`refresh_token`,`id_token`,`token_type`,`expires_in`,`refresh_expires_in`,`menu`,`footermenu`,`menuPermission`,`default_values`,`roleId`,`companyName`,`preferred_Username`,`user_Email`,`userName`,`userId`,`tenantId`,`businessId`,`businessUnitId`,`activeKey`,`ct_project_id`,`ct_project_name`],c=`test-flows`,l=[{value:`module`,label:`Module`,isVisible:!0,type:`text`},{value:`flow`,label:`Flow`,isVisible:!0,type:`text`},{value:`step_order`,label:`Step Order`,isVisible:!0,type:`number`},{value:`keyword`,label:`Action`,isVisible:!0,type:`text`},{value:`description`,label:`Description`,isVisible:!0,type:`text`},{value:`target`,label:`Key`,isVisible:!0,type:`text`},{value:`tags`,label:`Tags`,isVisible:!0,type:`text`},{value:`value`,label:`Value`,isVisible:!0,type:`text`},{value:`expected`,label:`Expected`,isVisible:!0,type:`text`}],u=`lms-flows`,d=[{value:`module`,label:`Module`,isVisible:!0,type:`text`},{value:`flow`,label:`Flow`,isVisible:!0,type:`text`},{value:`step_order`,label:`Step Order`,isVisible:!0,type:`number`},{value:`keyword`,label:`Action`,isVisible:!0,type:`text`},{value:`description`,label:`Description`,isVisible:!0,type:`text`},{value:`target`,label:`Key`,isVisible:!0,type:`text`},{value:`tags`,label:`Tags`,isVisible:!0,type:`text`},{value:`value`,label:`Value`,isVisible:!0,type:`text`},{value:`expected`,label:`Expected`,isVisible:!0,type:`text`}],f=null;function p(e){return e?.token??e?.access_token??e?.accessToken??e?.jwt??e?.data?.token??e?.data?.access_token??e?.data?.accessToken??e?.data?.jwt}function m(e){if(!e||typeof e!=`string`)return null;try{let t=e.split(`.`)[1];if(!t)return null;let n=t.replace(/-/g,`+`).replace(/_/g,`/`),r=atob(n.padEnd(Math.ceil(n.length/4)*4,`=`));return JSON.parse(r)}catch(e){return console.error(`Unable to decode login token:`,e),null}}function h(){return localStorage.getItem(i)}async function g({jobId:t,limit:n=10,offset:r=0,sortBy:i=`new`,type:a=`myVendor`}){return await k(e.T,`/vendor/hotlist`,{method:`POST`,body:JSON.stringify({jobId:t,limit:n,offset:r,sortBy:i,type:a})})}async function _(t){let n=await k(e.S,`/get-bulkmail-details?jobId=${encodeURIComponent(t)}`);return n.data??n}async function v(t=[]){let n=[...new Set((t??[]).map(e=>String(e??``).trim()).filter(Boolean))];if(!n.length)return[];let r=await k(e.S,`/candidate-emails`,{method:`POST`,body:JSON.stringify({candidateIds:n})}),i=r?.data??r;return Array.isArray(i)?i:[]}async function y(t,n){let r=String(t??``).trim(),i=String(n??``).trim();if(!r||!i)return null;let a=await k(e.x,`/module/list?module=${encodeURIComponent(r)}&id=${encodeURIComponent(i)}`),o=a?.data?.data??a?.data??[];return Array.isArray(o)?o[0]??null:null}async function b(t,n=``){let r=String(t??``).trim();if(!r)return``;let i=await k(e.E,`/format-mail-content`,{method:`POST`,body:JSON.stringify({contents:r,subject:String(n??``)})});if(i?.status===!1)throw Error(i?.error||`Unable to format mail content`);return String(i?.html??i?.contents??i?.data?.html??i?.data?.contents??``).trim()}async function x({jobId:t,toMail:n,ccMail:r,bccMail:i,subject:a,contents:o,attachments:s=[]}){let c=localStorage.getItem(`tenantId`)||`93c782a4aa626175e5d11afa`,l=localStorage.getItem(`businessId`)||`83c782a4aa626175e5d11afa`,u=localStorage.getItem(`businessUnitId`)||`63b57588fd768a839dbc0f63`,d=new FormData;d.append(`json`,JSON.stringify({schemaVersion:1,tenantId:c,businessId:l,businessUnitId:u,jobId:t,toMail:n,ccMail:r,bccMail:i,contents:o,subject:a})),(s??[]).forEach(e=>{e instanceof File&&e.size>0&&String(e.name??``).trim()&&d.append(`attachments`,e,e.name)});let{"Content-Type":f,...p}=await O(),m=await fetch(`${e.S}/send-bulkmail`,{method:`POST`,headers:p,body:d});if(m.status===401&&S(),!m.ok)throw Error(`API ${m.status}: ${m.statusText}`);let h=await m.text();return h?JSON.parse(h):{}}function S(){localStorage.removeItem(i),localStorage.removeItem(a),s.forEach(e=>localStorage.removeItem(e)),sessionStorage.removeItem(o),window.dispatchEvent(new Event(`auth:logout`))}function C(e=``){let t=String(e??``).trim();return t===`myJobs`||t===`allJobs`||t===`fulfilled`?t:``}function w(e){let n=String(t.at(e)??``).trim().toLowerCase();return n===`job`||n===`jobs`}function T(e,t=30){let n=m(e),r=Number(n?.exp);return!Number.isFinite(r)||r<=0?!1:r*1e3<=Date.now()+t*1e3}async function E(){if(f)return f;let t=String(localStorage.getItem(`refresh_token`)??``).trim();if(!t)throw Object.assign(Error(`Session expired`),{status:401});return f=fetch(`${e.x}/generate-refresh-token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({refresh_token:t})}).then(async e=>{let t=await e.text(),n={};if(t)try{n=JSON.parse(t)}catch{n={error:t}}if(!e.ok)throw Object.assign(Error(n?.error??n?.message??`Token refresh failed: ${e.status}`),{status:e.status});let r=p(n);if(!r)throw Object.assign(Error(`Token refresh response did not contain an access token`),{status:401});return localStorage.setItem(i,r),localStorage.setItem(`access_token`,r),r}).finally(()=>{f=null}),f}async function D(){let e=h();if(e&&!T(e))return e;if(localStorage.getItem(`refresh_token`))try{return await E()}catch{}if(e)return e;let t=Error(`Authentication required`);throw t.status=401,t}async function O(){return{"Content-Type":`application/json`,Authorization:`Bearer ${await D()}`}}async function k(e,t,n={}){let r=async()=>{let r=await O();return fetch(`${e}${t}`,{...n,headers:{...r,...n.headers}})},i=await r();if(i.status===401&&localStorage.getItem(`refresh_token`))try{await E(),i=await r()}catch{}i.status===401&&S();let a=await i.text(),o={};if(a)try{o=JSON.parse(a)}catch{o={error:a}}if(!i.ok){let e=Error(o?.error??o?.message??`API ${i.status}: ${i.statusText}`);throw e.status=i.status,e}return o}async function A(e,t){let n=await k(e,t);return n.data??n}async function j(t){return A(e.D,t)}async function M(t){return A(e.x,t)}async function N(e){return e===c?l:e===u?d:j(`/filter-dropdown-fields?module=${encodeURIComponent(t.at(e))}`)}async function P(e,{configType:n,userId:r,roleId:i}={}){if(e===c)return l;if(e===u)return d;let a=new URLSearchParams({module:t.at(e)});return n&&a.set(`configType`,n),r!=null&&a.set(`userId`,String(r)),i!=null&&a.set(`roleId`,String(i)),M(`/admin/field-config?${a}`)}async function F({limit:e=10,offset:t=0,search:n=``,module:r=``,keyword:i=``,tags:a=``,active:o}={}){let s=new URLSearchParams({limit:String(e),offset:String(t)});return n&&s.append(`search`,n),r&&s.append(`module`,r),i&&s.append(`keyword`,i),a&&s.append(`tags`,a),o!=null&&o!==``&&s.append(`active`,String(o)),M(`/test-flows?${s.toString()}`)}async function I({limit:e=10,offset:t=0,search:n=``,module:r=``,keyword:i=``,tags:a=``,active:o}={}){let s=new URLSearchParams({limit:String(e),offset:String(t)});return n&&s.append(`search`,n),r&&s.append(`module`,r),i&&s.append(`keyword`,i),a&&s.append(`tags`,a),o!=null&&o!==``&&s.append(`active`,String(o)),M(`/lms-flows?${s.toString()}`)}async function L(n,r=10,i=0,a={}){let{scope:o=``,sort:s=``,sortDir:l=``,search:d=``,filters:f=[],queryParams:p={}}=a;if(n===c){let e=await F({limit:r,offset:i}),t=Array.isArray(e?.items)?e.items:[],n=Number(e?.total)||0;return{items:t,total:n,limit:r,offset:i,tabs:[{key:`all`,title:`Test Cases`,count:n}]}}if(n===u){let e=await I({limit:r,offset:i}),t=Array.isArray(e?.items)?e.items:[],n=Number(e?.total)||0;return{items:t,total:n,limit:r,offset:i,tabs:[{key:`all`,title:`LMS Cases`,count:n}]}}let m=new URLSearchParams({module:t.at(n),limit:String(r),offset:String(i)}),h=w(n)?C(o):String(o??``).trim();h&&m.set(`scope`,h),s&&m.set(`sort`,s),l&&m.set(`sortDir`,l),String(d??``).trim()&&m.set(`search`,String(d).trim());let g=U(f.filter(e=>e?.field));g.length&&m.set(`filters`,JSON.stringify(g)),Object.entries(p??{}).forEach(([e,t])=>{t!=null&&String(t).trim()!==``&&m.set(e,String(t))});let _=await k(e.x,`/module-data-list?${m.toString()}`),v=R(_),y=v.some(e=>V(e)),b=v.some(e=>H(e));if(y||b)try{let{transformDiceResponseToInternalFormat:e}=await Promise.resolve().then(()=>require("./diceCandidateMapper-BjMhHno3.cjs")).then(e=>e.t),t=e(_,_),n=t?.data?.data??[];return{items:n,total:B(_,h)||B(t,h)||n.length,limit:r,offset:i,tabs:t?.data?.tabs??_?.tabs??_?.data?.tabs??[],fields:t?.data?.fields??_?.fields??_?.data?.fields??[],tabField:t?.data?.tabField??_?.tabField??_?.data?.tabField??``,actionRules:t?.data?.actionRules??_?.data?.actionRules??[],actions:t?.data?.actions??_?.data?.actions??[],columnActions:t?.data?.columnActions??_?.data?.columnActions??[]}}catch(e){console.error(`[getModuleDataList] Dice transformation failed:`,e)}return _}function R(e){let t=e?.data??e,n=Array.isArray(t)?t:t?.rows??t?.records??t?.items??t?.list??t?.data??e?.items??e?.records??[];return Array.isArray(n)?n:[]}function z(...e){for(let t of e){let e=Number(t);if(Number.isFinite(e))return e}}function B(e,t=``){let n=e?.data??e,r=R(e),i=e?.count,a=n?.count,o=String(t??``).trim().toLowerCase();if(i&&typeof i==`object`){let e=z(o?i[o]:void 0,i.total,i.searchCount,i.count);if(e!==void 0)return e}if(a&&typeof a==`object`){let e=z(o?a[o]:void 0,a.total,a.searchCount,a.count);if(e!==void 0)return e}return z(e?.total,typeof i==`object`?void 0:i,e?.totalCount,n?.total,typeof a==`object`?void 0:a,n?.totalCount,r.length)??0}function V(e){let t=e?.skills??e?.technicalSkills??e?.primarySkills;return!Array.isArray(t)||t.length===0?!1:t.some(e=>e&&typeof e==`object`&&(`skill`in e||`lastUsed`in e))}function H(e){return[e?.sourceType,e?.profileSource,e?.selectedSource,e?.customFields?.sourceType,e?.customFields?.profileSource].flat().some(e=>String(e??``).trim().toLowerCase()===`dice`)||!!e?.customFields?.diceProfileData}function U(e){let t=[];for(let n of e){if(!n.field)continue;let e=n.operator===`or`?`or`:`and`;if(n.operator===`isEmpty`){t.push({field:n.field,op:`isEmpty`,operator:`and`});continue}if(n.operator===`notEmpty`){t.push({field:n.field,op:`notEmpty`,operator:`and`});continue}if(n.filterInputType===`text`){let r=typeof n.value==`string`?n.value.trim():``;r&&t.push({field:n.field,op:`contains`,value:r,operator:e});continue}if(n.from||n.to){n.from&&t.push({field:n.field,op:`gte`,value:String(n.from),operator:e}),n.to&&t.push({field:n.field,op:`lte`,value:String(n.to),operator:`and`});continue}Array.isArray(n.values)&&n.values.length>0&&t.push({field:n.field,op:`in`,values:n.values.map(String),operator:e,...Array.isArray(n.groupFields)&&n.groupFields.length>1?{groupFields:n.groupFields}:{}})}return t}async function W(e,n,r=``,i={}){let{limit:a=50,offset:o=0,dataSource:s,groupName:c,lookup:l,groupFields:u=[],groupSeparator:d=` `,arrayLabelField:f=``,arrayValueField:p=``,scope:m=``}=i,h=t.at(e),g=new URLSearchParams({module:h,field:n,value:r,limit:String(a),offset:String(o)});return s&&g.set(`dataSource`,s),m&&g.set(`scope`,w(e)?C(m):m),f&&g.set(`arrayLabelField`,f),p&&g.set(`arrayValueField`,p),Array.isArray(u)&&u.length>1&&(g.set(`groupFields`,u.join(`,`)),g.set(`groupSeparator`,d??` `)),s===`group`&&c&&g.set(`groupName`,c),s===`lookup`&&l?.collection&&(g.set(`lookupCollection`,l.collection),l.displayField&&g.set(`lookupField`,l.displayField)),String(h).trim().toLowerCase()===`sourcecandidates`?M(`/candidates/filter-dropdown-values?${g}`):j(`/filter-dropdown-values?${g}`)}function G(e){let t=e?.data??e,n=Array.isArray(t)?t:Array.isArray(t?.groups)?t.groups:Array.isArray(e?.groups)?e.groups:[],r=t?.recordMeta??e?.recordMeta;r&&typeof r==`object`&&(n.recordMeta=r);let i=t?.previewConfig??e?.previewConfig;return i&&typeof i==`object`&&(n.previewConfig=i),n}async function K({module:t,id:r,view:i,clientId:a,region:o,candidateVersionId:s}={}){if(!t)throw Error(`module is required to fetch form groups`);let c=await O(),l=new URLSearchParams({module:t});r&&l.set(`id`,String(r)),i&&l.set(`view`,String(i)),a&&l.set(`clientId`,String(a)),o&&l.set(`region`,String(o)),s&&l.set(`candidateVersionId`,s);let u=`${e.x}/admin/form-groups?${l.toString()}`;return G(await n.t(u,async()=>{let e=await fetch(u,{method:`GET`,headers:c});if(!e.ok){let t=Error(`API ${e.status}: ${e.statusText}`);throw t.status=e.status,t}return e.json()}))}async function q({searchQuery:t,candidateId:n}){let r=localStorage.getItem(`tenantId`)||`93c782a4aa626175e5d11afa`,i=localStorage.getItem(`businessId`)||`83c782a4aa626175e5d11afa`,a=localStorage.getItem(`businessUnitId`)||`63b57588fd768a839dbc0f63`,o=Number(localStorage.getItem(`userId`))||1;return k(e.T,`/joblist`,{method:`POST`,body:JSON.stringify({tenantId:r,businessId:i,businessUnitId:a,searchQuery:t,userId:o,candidateId:Array.isArray(n)?n:[n]})})}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return L}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return W}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return q}});
|
|
2
|
-
//# sourceMappingURL=dropdownApi-C7L-0-2E.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dropdownApi-C7L-0-2E.cjs","names":[],"sources":["../src/services/candidateVersionsApi.js","../src/services/dropdownApi.js"],"sourcesContent":["import { fetchJsonWithAuth } from './authApi';\nimport { AUTH_URL } from './apiConfig';\n\nexport async function getCandidateVersions(candidateId) {\n const json = await fetchJsonWithAuth(AUTH_URL, `/candidate-versions?candidateId=${encodeURIComponent(candidateId)}`);\n const rows = json?.data ?? json;\n if (!Array.isArray(rows)) throw new Error('Candidate versions could not be loaded');\n return [...rows].sort((a, b) => Number(b.profileVersion) - Number(a.profileVersion));\n}\n","// export const SUBMISSIONS_URL = BASE_URL;\n\nimport { AUTH_URL, JOBS_URL, CANDIDATES_URL, SUBMISSIONS_URL, PYOPS_URL } from './apiConfig';\nimport { fetchFormGroupsCached, invalidateFormGroupsCache } from './formGroupsCache';\nimport { getBaseModuleName } from '../utils/modulePath';\n\n\nconst AUTH_TOKEN_KEY = 'authToken';\nconst AUTH_USER_KEY = 'authUser';\nconst AUTH_LOGIN_SESSION_KEY = 'authLoginSession';\nconst LOGIN_STORAGE_KEYS = [\n 'access_token',\n 'refresh_token',\n 'id_token',\n 'token_type',\n 'expires_in',\n 'refresh_expires_in',\n 'menu',\n 'footermenu',\n 'menuPermission',\n 'default_values',\n 'roleId',\n 'companyName',\n 'preferred_Username',\n 'user_Email',\n 'userName',\n 'userId',\n 'tenantId',\n 'businessId',\n 'businessUnitId',\n 'activeKey',\n 'ct_project_id',\n 'ct_project_name',\n];\n\nconst CT_PROJECT_ID_KEY = 'ct_project_id';\nconst CT_PROJECT_NAME_KEY = 'ct_project_name';\n\nconst TEST_FLOW_MODULE = 'test-flows';\nconst TEST_FLOW_FIELDS = [\n { value: 'module', label: 'Module', isVisible: true, type: 'text' },\n { value: 'flow', label: 'Flow', isVisible: true, type: 'text' },\n { value: 'step_order', label: 'Step Order', isVisible: true, type: 'number' },\n { value: 'keyword', label: 'Action', isVisible: true, type: 'text' },\n { value: 'description', label: 'Description', isVisible: true, type: 'text' },\n { value: 'target', label: 'Key', isVisible: true, type: 'text' },\n { value: 'tags', label: 'Tags', isVisible: true, type: 'text' },\n { value: 'value', label: 'Value', isVisible: true, type: 'text' },\n { value: 'expected', label: 'Expected', isVisible: true, type: 'text' },\n];\n\nconst LMS_FLOW_MODULE = 'lms-flows';\nconst LMS_FLOW_FIELDS = [\n { value: 'module', label: 'Module', isVisible: true, type: 'text' },\n { value: 'flow', label: 'Flow', isVisible: true, type: 'text' },\n { value: 'step_order', label: 'Step Order', isVisible: true, type: 'number' },\n { value: 'keyword', label: 'Action', isVisible: true, type: 'text' },\n { value: 'description', label: 'Description', isVisible: true, type: 'text' },\n { value: 'target', label: 'Key', isVisible: true, type: 'text' },\n { value: 'tags', label: 'Tags', isVisible: true, type: 'text' },\n { value: 'value', label: 'Value', isVisible: true, type: 'text' },\n { value: 'expected', label: 'Expected', isVisible: true, type: 'text' },\n];\n\n// In-flight login promise — prevents multiple simultaneous login calls\nlet loginPromise = null;\nlet refreshPromise = null;\n\nfunction extractToken(json) {\n return (\n json?.token ??\n json?.access_token ??\n json?.accessToken ??\n json?.jwt ??\n json?.data?.token ??\n json?.data?.access_token ??\n json?.data?.accessToken ??\n json?.data?.jwt\n );\n}\n\nfunction extractUser(json) {\n return json?.user ?? json?.data?.user ?? json?.data?.profile ?? null;\n}\n\nfunction decodeJwtPayload(token) {\n if (!token || typeof token !== 'string') return null;\n\n try {\n const payload = token.split('.')[1];\n if (!payload) return null;\n\n const normalizedPayload = payload.replace(/-/g, '+').replace(/_/g, '/');\n const decodedPayload = atob(normalizedPayload.padEnd(Math.ceil(normalizedPayload.length / 4) * 4, '='));\n return JSON.parse(decodedPayload);\n } catch (error) {\n console.error('Unable to decode login token:', error);\n return null;\n }\n}\n\nfunction setLocalStorageJson(key, value) {\n if (value === undefined || value === null) return;\n localStorage.setItem(key, JSON.stringify(value));\n}\n\nfunction getLoginMenus(json, data) {\n return data?.menus ?? json?.menus ?? {\n menu: data?.menu ?? json?.menu,\n footermenu: data?.footermenu ?? json?.footermenu,\n };\n}\n\nfunction persistLoginResponse(json, token, user) {\n const data = json?.data ?? json;\n const tokenPayload = decodeJwtPayload(token) ?? {};\n const menus = getLoginMenus(json, data);\n const userName = (\n user?.userName ??\n user?.name ??\n data?.userName ??\n data?.name ??\n tokenPayload.userName ??\n tokenPayload.name ??\n tokenPayload.preferred_username ??\n tokenPayload.email\n );\n const preferredUsername = (\n user?.preferred_Username ??\n user?.preferred_username ??\n data?.preferred_Username ??\n data?.preferred_username ??\n tokenPayload.preferred_Username ??\n tokenPayload.preferred_username ??\n tokenPayload.email ??\n userName\n );\n const userEmail = user?.email ?? data?.email ?? tokenPayload.email ?? preferredUsername;\n\n localStorage.setItem('access_token', token);\n if (data?.refresh_token) localStorage.setItem('refresh_token', data.refresh_token);\n if (data?.id_token !== undefined) localStorage.setItem('id_token', data.id_token);\n if (data?.token_type) localStorage.setItem('token_type', data.token_type);\n if (data?.expires_in !== undefined) localStorage.setItem('expires_in', String(data.expires_in));\n if (data?.refresh_expires_in !== undefined) localStorage.setItem('refresh_expires_in', String(data.refresh_expires_in));\n if (userName) localStorage.setItem('userName', userName);\n if (preferredUsername) localStorage.setItem('preferred_Username', preferredUsername);\n if (userEmail) localStorage.setItem('user_Email', userEmail);\n if (data?.roleId ?? tokenPayload.role_id) localStorage.setItem('roleId', data?.roleId ?? tokenPayload.role_id);\n // Header organization name: the user's platform region name when set, else\n // the business company name (REQ-20260916-03). Cleared when the response has\n // none, so a previous user's organization never lingers in this browser.\n const companyName = String(data?.companyName ?? '').trim();\n if (companyName) localStorage.setItem('companyName', companyName);\n else localStorage.removeItem('companyName');\n if (tokenPayload.userId !== undefined) localStorage.setItem('userId', String(tokenPayload.userId));\n if (tokenPayload.tenantId) localStorage.setItem('tenantId', tokenPayload.tenantId);\n if (tokenPayload.businessId) localStorage.setItem('businessId', tokenPayload.businessId);\n if (tokenPayload.businessUnitId) localStorage.setItem('businessUnitId', tokenPayload.businessUnitId);\n\n setLocalStorageJson('menu', menus.menu);\n setLocalStorageJson('footermenu', menus.footermenu);\n setLocalStorageJson('menuPermission', data?.menuPermission);\n setLocalStorageJson('default_values', data?.default_values);\n}\n\nexport function getStoredToken() {\n // Keep authentication available in every tab. `sessionStorage` belongs to\n // only one tab, so gating the shared localStorage token with it caused new\n // tabs to be treated as logged out.\n return localStorage.getItem(AUTH_TOKEN_KEY);\n}\n\nexport async function getGroupedVendorHotlist({ jobId, limit = 10, offset = 0, sortBy = 'new', type = 'myVendor' }) {\n const json = await fetchJsonWithAuth(JOBS_URL, '/vendor/hotlist', {\n method: 'POST',\n body: JSON.stringify({ jobId, limit, offset, sortBy, type }),\n });\n return json;\n}\n\nexport async function getBulkMailDetails(jobId) {\n const json = await fetchJsonWithAuth(CANDIDATES_URL, `/get-bulkmail-details?jobId=${encodeURIComponent(jobId)}`);\n return json.data ?? json;\n}\n\nexport async function getCandidateEmailDetails(candidateIds = []) {\n const ids = [...new Set((candidateIds ?? []).map((id) => String(id ?? '').trim()).filter(Boolean))];\n if (!ids.length) return [];\n\n const json = await fetchJsonWithAuth(CANDIDATES_URL, '/candidate-emails', {\n method: 'POST',\n body: JSON.stringify({ candidateIds: ids }),\n });\n const rows = json?.data ?? json;\n return Array.isArray(rows) ? rows : [];\n}\n\n// Full, unfiltered record for any module by its own _id — bypasses list-view\n// field-visibility config, so a field the grid doesn't currently project\n// (e.g. a candidate's email on a submission row) can still be read.\nexport async function getModuleRecordById(moduleName, recordId) {\n const module = String(moduleName ?? '').trim();\n const id = String(recordId ?? '').trim();\n if (!module || !id) return null;\n\n const json = await fetchJsonWithAuth(AUTH_URL, `/module/list?module=${encodeURIComponent(module)}&id=${encodeURIComponent(id)}`);\n const rows = json?.data?.data ?? json?.data ?? [];\n return Array.isArray(rows) ? (rows[0] ?? null) : null;\n}\n\nexport async function formatMailContentForMail(contents, subject = '') {\n const input = String(contents ?? '').trim();\n if (!input) return '';\n\n const json = await fetchJsonWithAuth(PYOPS_URL, '/format-mail-content', {\n method: 'POST',\n body: JSON.stringify({ contents: input, subject: String(subject ?? '') }),\n });\n\n if (json?.status === false) {\n throw new Error(json?.error || 'Unable to format mail content');\n }\n\n return String(json?.html ?? json?.contents ?? json?.data?.html ?? json?.data?.contents ?? '').trim();\n}\n\n// Backward-compatible export for any host code that imported the previous name.\n// It now formats the existing mail body rather than generating/re-writing a JD.\nexport async function formatJobDescriptionForMail(contents, subject = '') {\n return formatMailContentForMail(contents, subject);\n}\n\nexport async function sendBulkMail({ jobId, toMail, ccMail, bccMail, subject, contents, attachments = [] }) {\n const tenantId = localStorage.getItem('tenantId') || '93c782a4aa626175e5d11afa';\n const businessId = localStorage.getItem('businessId') || '83c782a4aa626175e5d11afa';\n const businessUnitId = localStorage.getItem('businessUnitId') || '63b57588fd768a839dbc0f63';\n\n const formData = new FormData();\n formData.append('json', JSON.stringify({\n schemaVersion: 1,\n tenantId,\n businessId,\n businessUnitId,\n jobId,\n toMail,\n ccMail,\n bccMail,\n contents,\n subject,\n }));\n\n // Dynamic document placeholders are resolved to File objects by the mail\n // composer. Append them as multipart files so they are sent as real email\n // attachments instead of being rendered as text inside the mail body.\n (attachments ?? []).forEach((file) => {\n if (file instanceof File && file.size > 0 && String(file.name ?? '').trim()) {\n formData.append('attachments', file, file.name);\n }\n });\n\n // Exclude Content-Type so the browser sets multipart/form-data with the correct boundary\n const allHeaders = await authHeaders();\n const { 'Content-Type': _ct, ...headersWithoutContentType } = allHeaders;\n\n let res = await fetch(`${CANDIDATES_URL}/send-bulkmail`, {\n method: 'POST',\n headers: headersWithoutContentType,\n body: formData,\n });\n\n if (res.status === 401) logout();\n if (!res.ok) throw new Error(`API ${res.status}: ${res.statusText}`);\n const text = await res.text();\n return text ? JSON.parse(text) : {};\n}\n\n\nexport function logout() {\n localStorage.removeItem(AUTH_TOKEN_KEY);\n localStorage.removeItem(AUTH_USER_KEY);\n LOGIN_STORAGE_KEYS.forEach((key) => localStorage.removeItem(key));\n sessionStorage.removeItem(AUTH_LOGIN_SESSION_KEY);\n window.dispatchEvent(new Event('auth:logout'));\n}\n\n// ---- Role helpers ----\n// The login response carries the role NAME in `data.roleId`\n// (persistLoginResponse stores it in localStorage['roleId']). The access-token\n// claims only have a numeric `role_id`, so the stored role NAME is the reliable\n// signal for the tester check. JWT roles are kept as a fallback.\nexport function getCurrentRoleName() {\n return String(localStorage.getItem('roleId') ?? '').trim().toLowerCase();\n}\n\nexport function getUserRoles() {\n const token = localStorage.getItem(AUTH_TOKEN_KEY);\n const payload = decodeJwtPayload(token);\n\n const roles = new Set();\n\n const stored = getCurrentRoleName();\n if (stored) roles.add(stored);\n\n if (payload) {\n (payload?.realm_access?.roles ?? []).forEach((role) => roles.add(role));\n Object.values(payload?.resource_access ?? {}).forEach((client) => {\n (client?.roles ?? []).forEach((role) => roles.add(role));\n });\n [payload?.role, payload?.roleName, payload?.role_name].forEach((role) => {\n if (role) roles.add(role);\n });\n }\n\n return Array.from(roles).map((role) => String(role).toLowerCase());\n}\n\nexport function isTester() {\n return getCurrentRoleName() === 'tester' || getUserRoles().includes('tester');\n}\n\nfunction isEnabledPermission(value) {\n return value === true || value === 1 || value === '1';\n}\n\nexport function hasAllJobsPermission() {\n try {\n const permissions = JSON.parse(localStorage.getItem('menuPermission') || '{}');\n if (!permissions || typeof permissions !== 'object') return false;\n\n const jobsKey = Object.keys(permissions).find((key) => {\n const normalized = String(key).trim().toLowerCase();\n return normalized === 'job' || normalized === 'jobs';\n });\n const jobsPermissions = jobsKey ? permissions[jobsKey] : null;\n if (!jobsPermissions || typeof jobsPermissions !== 'object') return false;\n\n return isEnabledPermission(\n jobsPermissions.all_jobs\n ?? jobsPermissions.allJobs\n ?? jobsPermissions.alljobs,\n );\n } catch {\n return false;\n }\n}\n\nexport function resolveJobListScope(requestedScope = '') {\n const scope = String(requestedScope ?? '').trim();\n\n // Preserve the tab the user actually selected. The API is authoritative\n // for access control and already narrows an unauthorised allJobs request to\n // My Jobs. Re-checking permissions from localStorage here is unreliable:\n // login payloads differ across deployments, so a user whose API response\n // legitimately contains the All Jobs tab could still have that request\n // silently rewritten to myJobs by stale or differently-shaped cached data.\n if (scope === 'myJobs' || scope === 'allJobs' || scope === 'fulfilled') return scope;\n\n // With no explicit tab, let the API choose the permission-aware default.\n return '';\n}\n\nfunction isJobsModule(module) {\n const baseModule = String(getBaseModuleName(module) ?? '').trim().toLowerCase();\n return baseModule === 'job' || baseModule === 'jobs';\n}\n\n// ---- Selected project context (carried through the tester flow) ----\nexport function setSelectedProject(project) {\n if (!project) return;\n localStorage.setItem(CT_PROJECT_ID_KEY, String(project.id));\n localStorage.setItem(CT_PROJECT_NAME_KEY, String(project.name));\n}\n\nexport function getSelectedProject() {\n const id = localStorage.getItem(CT_PROJECT_ID_KEY);\n const name = localStorage.getItem(CT_PROJECT_NAME_KEY);\n if (!id || !name) return null;\n return { id: Number(id), name };\n}\n\nexport function clearSelectedProject() {\n localStorage.removeItem(CT_PROJECT_ID_KEY);\n localStorage.removeItem(CT_PROJECT_NAME_KEY);\n}\n\nexport async function login(credentials) {\n if (loginPromise) return loginPromise;\n\n loginPromise = fetch(`${AUTH_URL}/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(credentials),\n })\n .then(async (res) => {\n const json = await res.json();\n if (!res.ok) {\n const error = new Error(json?.message ?? json?.error ?? `Login failed: ${res.status}`);\n error.status = res.status;\n throw error;\n }\n\n const token = extractToken(json);\n if (!token) throw new Error('No token in login response');\n const user = extractUser(json);\n\n localStorage.setItem(AUTH_TOKEN_KEY, token);\n if (user) localStorage.setItem(AUTH_USER_KEY, JSON.stringify(user));\n persistLoginResponse(json, token, user);\n\n return { token, user, response: json };\n })\n .finally(() => {\n loginPromise = null;\n });\n\n return loginPromise;\n}\n\nfunction tokenExpiresSoon(token, skewSeconds = 30) {\n const payload = decodeJwtPayload(token);\n const exp = Number(payload?.exp);\n if (!Number.isFinite(exp) || exp <= 0) return false;\n return exp * 1000 <= Date.now() + skewSeconds * 1000;\n}\n\nasync function refreshAccessToken() {\n if (refreshPromise) return refreshPromise;\n const refreshToken = String(localStorage.getItem('refresh_token') ?? '').trim();\n if (!refreshToken) throw Object.assign(new Error('Session expired'), { status: 401 });\n refreshPromise = fetch(`${AUTH_URL}/generate-refresh-token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refresh_token: refreshToken }),\n }).then(async (res) => {\n const text = await res.text();\n let json = {};\n if (text) { try { json = JSON.parse(text); } catch { json = { error: text }; } }\n if (!res.ok) throw Object.assign(new Error(json?.error ?? json?.message ?? `Token refresh failed: ${res.status}`), { status: res.status });\n const token = extractToken(json);\n if (!token) throw Object.assign(new Error('Token refresh response did not contain an access token'), { status: 401 });\n localStorage.setItem(AUTH_TOKEN_KEY, token);\n localStorage.setItem('access_token', token);\n return token;\n }).finally(() => { refreshPromise = null; });\n return refreshPromise;\n}\n\nasync function ensureToken() {\n const token = getStoredToken();\n if (token && !tokenExpiresSoon(token)) return token;\n if (localStorage.getItem('refresh_token')) {\n try { return await refreshAccessToken(); } catch { /* final request handles logout */ }\n }\n if (token) return token;\n const error = new Error('Authentication required');\n error.status = 401;\n throw error;\n}\n\nasync function authHeaders() {\n const token = await ensureToken();\n return {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n };\n}\n\nexport async function fetchJsonWithAuth(baseUrl, path, options = {}) {\n const doRequest = async () => {\n const headers = await authHeaders();\n return fetch(`${baseUrl}${path}`, {\n ...options,\n headers: { ...headers, ...options.headers },\n });\n };\n\n let res = await doRequest();\n if (res.status === 401 && localStorage.getItem('refresh_token')) {\n try {\n await refreshAccessToken();\n res = await doRequest();\n } catch {\n // Final 401 handling below clears an actually invalid session.\n }\n }\n if (res.status === 401) logout();\n const text = await res.text();\n let json = {};\n if (text) { try { json = JSON.parse(text); } catch { json = { error: text }; } }\n if (!res.ok) {\n const error = new Error(json?.error ?? json?.message ?? `API ${res.status}: ${res.statusText}`);\n error.status = res.status;\n throw error;\n }\n return json;\n}\n\nexport async function apiGetWithAuth(baseUrl, path) {\n const json = await fetchJsonWithAuth(baseUrl, path);\n return json.data ?? json;\n}\n\nasync function apiGet(path) {\n return apiGetWithAuth(SUBMISSIONS_URL, path);\n}\n\nasync function authapiGet(path) {\n return apiGetWithAuth(AUTH_URL, path);\n}\n\nasync function authapiPost(path, payload) {\n const json = await fetchJsonWithAuth(AUTH_URL, path, {\n method: 'POST',\n body: JSON.stringify(payload),\n });\n return json.data ?? json;\n}\n\nasync function authapiPut(path, payload) {\n const json = await fetchJsonWithAuth(AUTH_URL, path, {\n method: 'PUT',\n body: JSON.stringify(payload),\n });\n return json.data ?? json;\n}\n\n/**\n * Fetch available filter fields for a module.\n * Returns: [{ label, value, type }, ...]\n */\nexport async function getDropdownFields(module) {\n if (module === TEST_FLOW_MODULE) return TEST_FLOW_FIELDS;\n if (module === LMS_FLOW_MODULE) return LMS_FLOW_FIELDS;\n\n // Dot-notation names (\"job.client\") target nested data client-side; the\n // backend only knows the base module.\n return apiGet(`/filter-dropdown-fields?module=${encodeURIComponent(getBaseModuleName(module))}`);\n}\n\nexport async function getFieldConfig(module, { configType, userId, roleId } = {}) {\n if (module === TEST_FLOW_MODULE) return TEST_FLOW_FIELDS;\n if (module === LMS_FLOW_MODULE) return LMS_FLOW_FIELDS;\n\n const params = new URLSearchParams({ module: getBaseModuleName(module) });\n if (configType) params.set('configType', configType);\n if (userId != null) params.set('userId', String(userId));\n if (roleId != null) params.set('roleId', String(roleId));\n return authapiGet(`/admin/field-config?${params}`);\n}\n\n\nexport async function getTestingOptions(type) {\n return authapiGet(`/testing-modules?type=${encodeURIComponent(type)}`);\n}\n\nexport async function addTestingOption({ name, type }) {\n return authapiPost('/testing-modules', { name, type });\n}\n\nexport async function addTestFlow(payload) {\n return authapiPost('/test-flows', payload);\n}\n\nexport async function getTestFlows({\n limit = 10,\n offset = 0,\n search = '',\n module = '',\n keyword = '',\n tags = '',\n active,\n} = {}) {\n const params = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n });\n if (search) params.append('search', search);\n if (module) params.append('module', module);\n if (keyword) params.append('keyword', keyword);\n if (tags) params.append('tags', tags);\n if (active !== undefined && active !== null && active !== '') {\n params.append('active', String(active));\n }\n\n return authapiGet(`/test-flows?${params.toString()}`);\n}\n\n// =====================================================================\n// Common Test Automation (znxt_test_automation)\n// Hierarchy: Project -> Module -> Submodule -> Test Flow\n// =====================================================================\n\n// ---- Projects ----\nexport async function getCTProjects({ activeOnly = false } = {}) {\n const params = new URLSearchParams();\n if (activeOnly) params.append('active', '1');\n const query = params.toString();\n return authapiGet(`/ct/projects${query ? `?${query}` : ''}`);\n}\n\nexport async function addCTProject(projectname) {\n return authapiPost('/ct/projects', { projectname });\n}\n\nexport async function setCTProjectStatus(id, active) {\n return authapiPut('/ct/projects/status', { id, active });\n}\n\n// ---- Modules ----\nexport async function getCTModules({ project = '', activeOnly = false } = {}) {\n const params = new URLSearchParams();\n if (project) params.append('project', project);\n if (activeOnly) params.append('active', '1');\n const query = params.toString();\n return authapiGet(`/ct/modules${query ? `?${query}` : ''}`);\n}\n\nexport async function addCTModule({ project, modulename }) {\n return authapiPost('/ct/modules', { project, modulename });\n}\n\nexport async function setCTModuleStatus(id, active) {\n return authapiPut('/ct/modules/status', { id, active });\n}\n\n// ---- Submodules ----\nexport async function getCTSubmodules({ project = '', module = '', activeOnly = false } = {}) {\n const params = new URLSearchParams();\n if (project) params.append('project', project);\n if (module) params.append('module', module);\n if (activeOnly) params.append('active', '1');\n const query = params.toString();\n return authapiGet(`/ct/submodules${query ? `?${query}` : ''}`);\n}\n\nexport async function addCTSubmodule({ project, modulename, submodulename }) {\n return authapiPost('/ct/submodules', { project, modulename, submodulename });\n}\n\nexport async function setCTSubmoduleStatus(id, active) {\n return authapiPut('/ct/submodules/status', { id, active });\n}\n\n// ---- Test Flows ----\nexport async function getCTFlows({\n project = '',\n module = '',\n submodule = '',\n product_parent_ID = '',\n module_parent_ID = '',\n submodule_parent_ID = '',\n actions = '',\n search = '',\n active,\n limit = 1000,\n offset = 0,\n} = {}) {\n const params = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n });\n const productParentID = product_parent_ID || project;\n const moduleParentID = module_parent_ID || module;\n const submoduleParentID = submodule_parent_ID || submodule;\n if (productParentID) params.append('product_parent_ID', productParentID);\n if (moduleParentID) params.append('module_parent_ID', moduleParentID);\n if (submoduleParentID) params.append('submodule_parent_ID', submoduleParentID);\n if (actions) params.append('actions', actions);\n if (search) params.append('search', search);\n if (active !== undefined && active !== null && active !== '') {\n params.append('active', String(active));\n }\n return authapiGet(`/ct/flows?${params.toString()}`);\n}\n\nexport async function addCTFlow(payload) {\n return authapiPost('/ct/flows', payload);\n}\n\nexport async function getCTNextStep({\n project,\n module,\n submodule,\n product_parent_ID,\n module_parent_ID,\n submodule_parent_ID,\n}) {\n const params = new URLSearchParams({\n product_parent_ID: String(product_parent_ID || project),\n module_parent_ID: String(module_parent_ID || module),\n submodule_parent_ID: String(submodule_parent_ID || submodule),\n });\n return authapiGet(`/ct/flows/next-step?${params.toString()}`);\n}\n\nexport async function addLmsFlow(payload) {\n return authapiPost('/lms-flows', payload);\n}\n\nexport async function getLmsFlows({\n limit = 10,\n offset = 0,\n search = '',\n module = '',\n keyword = '',\n tags = '',\n active,\n} = {}) {\n const params = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n });\n if (search) params.append('search', search);\n if (module) params.append('module', module);\n if (keyword) params.append('keyword', keyword);\n if (tags) params.append('tags', tags);\n if (active !== undefined && active !== null && active !== '') {\n params.append('active', String(active));\n }\n\n return authapiGet(`/lms-flows?${params.toString()}`);\n}\n\nexport async function getModuleDataList(module, limit = 10, offset = 0, options = {}) {\n const {\n scope = '',\n sort = '',\n sortDir = '',\n search = '',\n filters = [],\n queryParams = {},\n } = options;\n\n if (module === TEST_FLOW_MODULE) {\n const data = await getTestFlows({ limit, offset });\n const rows = Array.isArray(data?.items) ? data.items : [];\n const total = Number(data?.total) || 0;\n\n return {\n items: rows,\n total,\n limit,\n offset,\n tabs: [{ key: 'all', title: 'Test Cases', count: total }],\n };\n }\n\n if (module === LMS_FLOW_MODULE) {\n const data = await getLmsFlows({ limit, offset });\n const rows = Array.isArray(data?.items) ? data.items : [];\n const total = Number(data?.total) || 0;\n\n return {\n items: rows,\n total,\n limit,\n offset,\n tabs: [{ key: 'all', title: 'LMS Cases', count: total }],\n };\n }\n\n const params = new URLSearchParams({\n module: getBaseModuleName(module),\n limit: String(limit),\n offset: String(offset),\n });\n // The shared Jobs page uses the singular module name (`job`) while some\n // consumers use `jobs`. Both names target the same backend module and must\n // go through the same permission-aware My Jobs / All Jobs scope resolver.\n const normalizedScope = isJobsModule(module)\n ? resolveJobListScope(scope)\n : String(scope ?? '').trim();\n if (normalizedScope) params.set('scope', normalizedScope);\n if (sort) params.set('sort', sort);\n if (sortDir) params.set('sortDir', sortDir);\n // Server-side quick search across visible + lookup-resolved fields\n // (job title, client name, location, ...) — see /module-data-list.\n if (String(search ?? '').trim()) params.set('search', String(search).trim());\n\n const conditions = toFilterConditions(filters.filter((f) => f?.field));\n if (conditions.length) {\n params.set('filters', JSON.stringify(conditions));\n }\n\n Object.entries(queryParams ?? {}).forEach(([key, value]) => {\n if (value !== null && value !== undefined && String(value).trim() !== '') {\n params.set(key, String(value));\n }\n });\n\n const json = await fetchJsonWithAuth(AUTH_URL, `/module-data-list?${params.toString()}`);\n\n const responseData = getResponseRows(json);\n const hasObjectSkills = responseData.some((record) => hasObjectSkillItems(record));\n const hasDiceCandidates = responseData.some((record) => hasDiceSource(record));\n\n if (hasObjectSkills || hasDiceCandidates) {\n try {\n const { transformDiceResponseToInternalFormat } = await import('./diceCandidateMapper');\n const transformed = transformDiceResponseToInternalFormat(json, json);\n const transformedData = transformed?.data?.data ?? [];\n // const total = extractResponseTotal(json, scope || 'internal')\n // || extractResponseTotal(transformed, scope || 'internal')\n const total = extractResponseTotal(json, normalizedScope)\n || extractResponseTotal(transformed, normalizedScope)\n || transformedData.length;\n\n return {\n items: transformedData,\n total,\n limit,\n offset,\n tabs: transformed?.data?.tabs ?? json?.tabs ?? json?.data?.tabs ?? [],\n fields: transformed?.data?.fields ?? json?.fields ?? json?.data?.fields ?? [],\n tabField: transformed?.data?.tabField ?? json?.tabField ?? json?.data?.tabField ?? '',\n actionRules: transformed?.data?.actionRules ?? json?.data?.actionRules ?? [],\n actions: transformed?.data?.actions ?? json?.data?.actions ?? [],\n columnActions: transformed?.data?.columnActions ?? json?.data?.columnActions ?? [],\n };\n } catch (error) {\n console.error('[getModuleDataList] Dice transformation failed:', error);\n }\n }\n \n return json;\n}\n\nfunction getResponseRows(response) {\n const payload = response?.data ?? response;\n const rows = Array.isArray(payload)\n ? payload\n : payload?.rows\n ?? payload?.records\n ?? payload?.items\n ?? payload?.list\n ?? payload?.data\n ?? response?.items\n ?? response?.records\n ?? [];\n\n return Array.isArray(rows) ? rows : [];\n}\n\nfunction firstFiniteNumber(...values) {\n for (const value of values) {\n const number = Number(value);\n if (Number.isFinite(number)) return number;\n }\n\n return undefined;\n}\n\nfunction extractResponseTotal(response, scope = '') {\n const payload = response?.data ?? response;\n const rows = getResponseRows(response);\n const responseCount = response?.count;\n const payloadCount = payload?.count;\n const normalizedScope = String(scope ?? '').trim().toLowerCase();\n\n if (responseCount && typeof responseCount === 'object') {\n const total = firstFiniteNumber(\n normalizedScope ? responseCount[normalizedScope] : undefined,\n responseCount.total,\n responseCount.searchCount,\n responseCount.count,\n );\n if (total !== undefined) return total;\n }\n\n if (payloadCount && typeof payloadCount === 'object') {\n const total = firstFiniteNumber(\n normalizedScope ? payloadCount[normalizedScope] : undefined,\n payloadCount.total,\n payloadCount.searchCount,\n payloadCount.count,\n );\n if (total !== undefined) return total;\n }\n\n return firstFiniteNumber(\n response?.total,\n typeof responseCount !== 'object' ? responseCount : undefined,\n response?.totalCount,\n payload?.total,\n typeof payloadCount !== 'object' ? payloadCount : undefined,\n payload?.totalCount,\n rows.length,\n ) ?? 0;\n}\n\nfunction hasObjectSkillItems(record) {\n const skills = record?.skills ?? record?.technicalSkills ?? record?.primarySkills;\n if (!Array.isArray(skills) || skills.length === 0) return false;\n\n return skills.some((skill) => (\n skill\n && typeof skill === 'object'\n && ('skill' in skill || 'lastUsed' in skill)\n ));\n}\n\nfunction hasDiceSource(record) {\n const sourceFields = [\n record?.sourceType,\n record?.profileSource,\n record?.selectedSource,\n record?.customFields?.sourceType,\n record?.customFields?.profileSource,\n ].flat();\n \n return sourceFields.some(\n (value) => String(value ?? '').trim().toLowerCase() === 'dice',\n ) || Boolean(record?.customFields?.diceProfileData);\n}\n\nexport async function getJobSummary(startDate, endDate) {\n const params = new URLSearchParams();\n\n if (startDate) params.set('startDate', startDate);\n if (endDate) params.set('endDate', endDate);\n\n const query = params.toString();\n return apiGetWithAuth(JOBS_URL, `/job-summary${query ? `?${query}` : ''}`);\n}\n\nexport async function getCandidateSummary(startDate, endDate) {\n const params = new URLSearchParams();\n\n if (startDate) params.set('startDate', startDate);\n if (endDate) params.set('endDate', endDate);\n\n const query = params.toString();\n return apiGetWithAuth(CANDIDATES_URL, `/profile-summary${query ? `?${query}` : ''}`);\n}\n\nexport async function getSubmissionSummary(startDate, endDate) {\n const params = new URLSearchParams();\n\n if (startDate) params.set('startDate', startDate);\n if (endDate) params.set('endDate', endDate);\n\n const query = params.toString();\n return apiGetWithAuth(SUBMISSIONS_URL, `/profile-summary${query ? `?${query}` : ''}`);\n}\n\n// Converts frontend filter rows to the BE FilterCondition[] format.\n// BE ops: eq | ne | in | nin | contains | gt | gte | lt | lte | isEmpty | notEmpty\nfunction toFilterConditions(filterRows) {\n const conditions = [];\n for (const row of filterRows) {\n if (!row.field) continue;\n\n // The row connector ('and'/'or') between this row and the previous one.\n // 'isEmpty'/'notEmpty' rows use the operator slot for their op type, so they\n // don't have an explicit AND/OR connector — default them to 'and'.\n const rowConnector = row.operator === 'or' ? 'or' : 'and';\n\n if (row.operator === 'isEmpty') {\n conditions.push({ field: row.field, op: 'isEmpty', operator: 'and' });\n continue;\n }\n if (row.operator === 'notEmpty') {\n conditions.push({ field: row.field, op: 'notEmpty', operator: 'and' });\n continue;\n }\n\n // Text keyword search → contains (case-insensitive regex on the backend)\n if (row.filterInputType === 'text') {\n const val = typeof row.value === 'string' ? row.value.trim() : '';\n if (val) conditions.push({ field: row.field, op: 'contains', value: val, operator: rowConnector });\n continue;\n }\n\n // Date range — from/to set by DatePicker.RangePicker.\n // The row connector applies to the first (gte) condition; lte is always\n // AND'd with it so the two bounds stay paired in the backend fold.\n if (row.from || row.to) {\n if (row.from) conditions.push({ field: row.field, op: 'gte', value: String(row.from), operator: rowConnector });\n if (row.to) conditions.push({ field: row.field, op: 'lte', value: String(row.to), operator: 'and' });\n continue;\n }\n\n // Multi-value (dropdown / checkbox / boolean) → in\n if (Array.isArray(row.values) && row.values.length > 0) {\n conditions.push({\n field: row.field,\n op: 'in',\n values: row.values.map(String),\n operator: rowConnector,\n ...(Array.isArray(row.groupFields) && row.groupFields.length > 1 ? { groupFields: row.groupFields } : {}),\n });\n }\n }\n return conditions;\n}\n\n/**\n * Fetch distinct values for a specific field in a module.\n * Returns: [{ label, value }, ...]\n */\nexport async function getDropdownValues(module, field, search = '', meta = {}) {\n const {\n limit = 50,\n offset = 0,\n dataSource,\n groupName,\n lookup,\n groupFields = [],\n groupSeparator = ' ',\n arrayLabelField = '',\n arrayValueField = '',\n scope = '',\n } = meta;\n const baseModule = getBaseModuleName(module);\n const params = new URLSearchParams({\n module: baseModule,\n field,\n value: search,\n limit: String(limit),\n offset: String(offset),\n });\n if (dataSource) params.set('dataSource', dataSource);\n if (scope) params.set('scope', isJobsModule(module) ? resolveJobListScope(scope) : scope);\n if (arrayLabelField) params.set('arrayLabelField', arrayLabelField);\n if (arrayValueField) params.set('arrayValueField', arrayValueField);\n if (Array.isArray(groupFields) && groupFields.length > 1) {\n params.set('groupFields', groupFields.join(','));\n params.set('groupSeparator', groupSeparator ?? ' ');\n }\n if (dataSource === 'group' && groupName) params.set('groupName', groupName);\n if (dataSource === 'lookup' && lookup?.collection) {\n params.set('lookupCollection', lookup.collection);\n if (lookup.displayField) params.set('lookupField', lookup.displayField);\n }\n // Source Candidate Boolean Search is tenant-scoped and does not use the\n // generic submissions dropdown scope. Route only this module to its dedicated\n // candidate endpoint so the filter options come from the same collection and\n // scope as /candidates/boolean-search.\n if (String(baseModule).trim().toLowerCase() === 'sourcecandidates') {\n return authapiGet(`/candidates/filter-dropdown-values?${params}`);\n }\n return apiGet(`/filter-dropdown-values?${params}`);\n}\n\nexport async function getDashboardOnboardingCount(\n payload,\n limit = 10,\n offset = 0\n) {\n const headers = await authHeaders();\n\n const response = await fetch(\n `${SUBMISSIONS_URL}/dashboard-onboarding-count?offset=${offset}&limit=${limit}`,\n {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n }\n );\n\n const json = await response.json();\n return json.data ?? json;\n}\n\nexport async function getJobs({\n jobStatus = 'active',\n jobRecruitmentStatus = 'unread',\n limit = 50,\n offset = 0,\n userId = 1,\n sortBy = 'id',\n} = {}) {\n const headers = await authHeaders();\n\n const params = new URLSearchParams({\n jobStatus,\n jobRecruitmentStatus,\n limit: String(limit),\n offset: String(offset),\n userId: String(userId),\n sortBy,\n });\n\n const response = await fetch(\n `${JOBS_URL}/jobs?${params.toString()}`,\n {\n method: 'GET',\n headers,\n }\n );\n\n if (!response.ok) {\n throw new Error(`API ${response.status}: ${response.statusText}`);\n }\n\n const json = await response.json();\n return json.data ?? json;\n}\n\n\nfunction extractFormGroups(json) {\n const payload = json?.data ?? json;\n const groups = Array.isArray(payload) ? payload\n : Array.isArray(payload?.groups) ? payload.groups\n : Array.isArray(json?.groups) ? json.groups\n : [];\n // The backend attaches the loaded record's audit stamps (createdAt/updatedAt)\n // as recordMeta when an id was supplied. Ride it along on the groups array so\n // callers that only ever see the array (the detail header) can still show\n // \"Created on …\" without audit fields having to exist as form fields.\n const recordMeta = payload?.recordMeta ?? json?.recordMeta;\n if (recordMeta && typeof recordMeta === 'object') groups.recordMeta = recordMeta;\n const previewConfig = payload?.previewConfig ?? json?.previewConfig;\n if (previewConfig && typeof previewConfig === 'object') groups.previewConfig = previewConfig;\n return groups;\n}\n\nexport async function getFormGroups({\n module,\n id,\n view,\n clientId,\n region,\n candidateVersionId,\n} = {}) {\n if (!module) throw new Error('module is required to fetch form groups');\n\n const headers = await authHeaders();\n\n const params = new URLSearchParams({\n module,\n });\n\n // When an id is supplied, the backend embeds each field's actual record value\n // (field.value) in the response, so no separate detail-view call is needed.\n if (id) params.set('id', String(id));\n\n // `view=detail` opts into detail-view shaping: the backend resolves references\n // to { id, value }, shapes documents into full objects, AND applies the admin\n // Detail-Groups config (label/colour/prefix/hidden/lookups/merges). Without it\n // the admin's customizations never reach the detail view. Forwarded only when\n // provided, so add/edit-form callers keep the raw scalar values.\n if (view) params.set('view', String(view));\n if (clientId) params.set('clientId', String(clientId));\n if (region) params.set('region', String(region));\n if (candidateVersionId) params.set('candidateVersionId', candidateVersionId);\n\n // Shared with the form-side fetcher (services/formGroupsCache): the detail\n // header, the detail body and the form on the same page routinely ask for the\n // SAME payload, and these are 15-60 kB responses. Keyed by the finished URL,\n // which both fetchers build in the same parameter order, so an identical\n // question collapses to one request no matter which of them asked it — and a\n // different `view`/scope stays a different entry.\n const url = `${AUTH_URL}/admin/form-groups?${params.toString()}`;\n const json = await fetchFormGroupsCached(url, async () => {\n const response = await fetch(url, { method: 'GET', headers });\n if (!response.ok) {\n // `.status` is what isRecordUnavailableError (detail/recordAccess.js)\n // reads to decide whether a fetch failure means \"you cannot see this\n // record\" — the CENTERED CARD page, same treatment as AuthGuard's \"not\n // logged in\" screen — rather than the raw technical Alert. A bare\n // `new Error(...)` here left `.status` undefined, so a genuine 404 for\n // a cross-tenant record NEVER matched, and the detail page fell through\n // to showing \"Unable to load detail fields / API 404: Not Found\"\n // verbatim instead of the proper unavailable-record page.\n const error = new Error(`API ${response.status}: ${response.statusText}`);\n error.status = response.status;\n throw error;\n }\n return response.json();\n });\n return extractFormGroups(json);\n}\n\nexport async function getCandidateFormGroups(options = {}) {\n return getFormGroups({ module: 'candidates', ...options });\n}\n\nconst MODULE_EDIT_CONFIG = {\n job: {\n fetchUrl: (id) => `${JOBS_URL}/edit/detailed-view/${encodeURIComponent(id)}`,\n updateUrl: (id) => `${JOBS_URL}/edit/${encodeURIComponent(id)}`,\n },\n candidates: {\n fetchUrl: (id) => `${CANDIDATES_URL}/edit/detailed-view?_id=${encodeURIComponent(id)}`,\n updateUrl: (id) => `${CANDIDATES_URL}/update?_id=${encodeURIComponent(id)}`,\n },\n};\n\n\n\n\n\nexport async function getRecordForEdit(module, id) {\n if (!module) throw new Error('module is required');\n if (!id) throw new Error('id is required');\n\n const config = MODULE_EDIT_CONFIG[module];\n if (!config) throw new Error(`No edit config for module: ${module}`);\n\n const token = await ensureToken();\n const response = await fetch(config.fetchUrl(id), {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) throw new Error(`API ${response.status}: ${response.statusText}`);\n\n const json = await response.json();\n return json.data ?? json;\n}\n\n\n\n\n\n\nexport async function updateRecord(module, id, payload) {\n if (!module) throw new Error('module is required');\n if (!id) throw new Error('id is required');\n\n const config = MODULE_EDIT_CONFIG[module];\n if (!config) throw new Error(`No edit config for module: ${module}`);\n\n const token = await ensureToken();\n\n const formData = new FormData();\n formData.append('json', JSON.stringify(payload));\n\n const response = await fetch(config.updateUrl(id), {\n method: 'PUT',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n body: formData,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error('[updateRecord] Error response:', errorText);\n throw new Error(errorText || `API ${response.status}: ${response.statusText}`);\n }\n\n // A successful write makes every cached form-groups payload for this record\n // stale, and the caller usually reads one straight back.\n invalidateFormGroupsCache();\n\n const json = await response.json();\n return json.data ?? json;\n}\n\n\n\nexport async function uploadJobAttachment(recordId, file) {\n const token = await ensureToken();\n\n const formData = new FormData();\n formData.append('jobId', recordId);\n formData.append('file', file);\n\n const response = await fetch(`${JOBS_URL}/jobs/${recordId}/attachment`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n // DO NOT set Content-Type — browser sets it with boundary automatically\n },\n body: formData,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(errorText || `API ${response.status}: ${response.statusText}`);\n }\n\n const json = await response.json();\n return json.data ?? json;\n}\n\nexport async function addNotes({ notes, notesfor, receiver, notesRelatedId }) {\n const tenantId = localStorage.getItem('tenantId') || '93c782a4aa626175e5d11afa';\n const businessId = localStorage.getItem('businessId') || '83c782a4aa626175e5d11afa';\n const businessUnitId = localStorage.getItem('businessUnitId') || '63b57588fd768a839dbc0f63';\n\n return fetchJsonWithAuth(JOBS_URL, '/notes', {\n method: 'POST',\n body: JSON.stringify({\n schemaVersion: 1,\n tenantId,\n businessId,\n businessUnitId,\n notes,\n notesfor,\n receiver: receiver ?? [],\n notesRelatedId,\n }),\n });\n}\n\nexport async function getCandidateGroups() {\n return fetchJsonWithAuth(AUTH_URL, '/masters/dropdown?masterName=candidateGroups&offset=0&limit=50');\n}\n\nexport async function getSelfAssignData(jobId) {\n return apiGetWithAuth(JOBS_URL, `/self-assign?jobId=${encodeURIComponent(jobId)}`);\n}\n\nexport async function getManagerUsers() {\n const response = await apiGetWithAuth(JOBS_URL, '/users/manager');\n if (Array.isArray(response)) return response;\n return response ? [response] : [];\n}\n\nexport async function getRecruiterUsers(managerId = 0) {\n return apiGetWithAuth(JOBS_URL, `/users/recruiter/${encodeURIComponent(managerId)}`);\n}\n\nexport async function selfAssignJob({ multiJobId, userId, schemaVersion, closureRating, jobPayDetails, priority, priorityFrom, recruitersData }) {\n return fetchJsonWithAuth(JOBS_URL, '/assign?type=self', {\n method: 'PUT',\n body: JSON.stringify({\n multiJobId,\n userId: Number(userId),\n schemaVersion,\n closureRating,\n jobPayDetails,\n priority: String(priority ?? false),\n priorityFrom: priorityFrom ?? '',\n recruitersData: (recruitersData ?? []).map(Number).filter(Number.isInteger),\n }),\n });\n}\n\nexport async function assignJobToUser({ multiJobId, userId, schemaVersion, closureRating, jobPayDetails, priority, priorityFrom, recruitersData }) {\n return fetchJsonWithAuth(JOBS_URL, '/assign?type=other', {\n method: 'PUT',\n body: JSON.stringify({\n multiJobId,\n userId: Number(userId),\n schemaVersion,\n closureRating,\n jobPayDetails,\n priority: String(priority ?? false),\n priorityFrom: priorityFrom ?? '',\n recruitersData: (recruitersData ?? []).map(Number).filter(Number.isInteger),\n }),\n });\n}\n\nexport async function addToGroup({ candidateIds, groupId, groupName }) {\n return fetchJsonWithAuth(CANDIDATES_URL, '/actions/update-group', {\n method: 'PUT',\n body: JSON.stringify({ candidateIds, groupId, groupName }),\n });\n}\n\n\nexport async function getJobList({ searchQuery, candidateId }) {\n const tenantId = localStorage.getItem('tenantId') || '93c782a4aa626175e5d11afa';\n const businessId = localStorage.getItem('businessId') || '83c782a4aa626175e5d11afa';\n const businessUnitId = localStorage.getItem('businessUnitId') || '63b57588fd768a839dbc0f63';\n const userId = Number(localStorage.getItem('userId')) || 1;\n\n return fetchJsonWithAuth(JOBS_URL, '/joblist', {\n method: 'POST',\n body: JSON.stringify({\n tenantId,\n businessId,\n businessUnitId,\n searchQuery,\n userId,\n candidateId: Array.isArray(candidateId) ? candidateId : [candidateId],\n }),\n });\n}\n\nexport async function tagToJob({ multiJobId, applicantId, updateStatus }) {\n const tenantId = localStorage.getItem('tenantId') || '93c782a4aa626175e5d11afa';\n const businessId = localStorage.getItem('businessId') || '83c782a4aa626175e5d11afa';\n const businessUnitId = localStorage.getItem('businessUnitId') || '63b57588fd768a839dbc0f63';\n const userId = Number(localStorage.getItem('userId')) || 9;\n\n return fetchJsonWithAuth(JOBS_URL, '/source/hiringStgUpdate', {\n method: 'PUT',\n body: JSON.stringify({\n tenantId,\n businessId,\n businessUnitId,\n multiJobId: Array.isArray(multiJobId) ? multiJobId : [multiJobId],\n applicantId: Array.isArray(applicantId) ? applicantId : [applicantId],\n updateStatus: String(updateStatus ?? '').toLowerCase(),\n updateStatusType: 'call',\n responseType: 'responded',\n hiriringStatusChangeType: 'tagToJobs',\n comments: '',\n userId,\n }),\n });\n}\n\nexport async function deleteJobDetails(jobIds) {\n const tenantId = localStorage.getItem('tenantId') || '93c782a4aa626175e5d11afa';\n const businessId = localStorage.getItem('businessId') || '83c782a4aa626175e5d11afa';\n const businessUnitId = localStorage.getItem('businessUnitId') || '63b57588fd768a839dbc0f63';\n\n return fetchJsonWithAuth(JOBS_URL, '/delete', {\n method: 'POST',\n body: JSON.stringify({\n schemaVersion: 1,\n tenantId,\n businessId,\n businessUnitId,\n jobId: jobIds,\n }),\n });\n}\n\nexport async function deleteCandidateData(ids) {\n const results = await Promise.all(\n ids.map((id) => fetchJsonWithAuth(CANDIDATES_URL, `/delete?_id=${encodeURIComponent(id)}`, { method: 'PUT' }))\n );\n return results[results.length - 1] ?? {};\n}\n\nexport async function deleteModuleData(module, ids) {\n return fetchJsonWithAuth(AUTH_URL, '/module-data-delete', {\n method: 'POST',\n body: JSON.stringify({ module, ids }),\n });\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 searchCandidates(payload, offset = 0, limit = 10) {\n console.log('[searchCandidates] Called with payload:', JSON.stringify(payload).substring(0, 200));\n \n const json = await fetchJsonWithAuth(\n JOBS_URL,\n `/source/hiring-candidate-list?offset=${offset}&limit=${limit}`,\n { method: 'POST', body: JSON.stringify(payload) }\n );\n \n console.log('[searchCandidates] Response received:', JSON.stringify(json).substring(0, 200));\n \n // Transform Dice responses to match Internal candidate format\n const selectedSource = payload?.selectedSource ?? [];\n const hasDiceSource = Array.isArray(selectedSource) && selectedSource.some(s => String(s).toLowerCase() === 'dice');\n \n console.log('[searchCandidates] selectedSource:', selectedSource);\n console.log('[searchCandidates] hasDiceSource:', hasDiceSource);\n \n if (hasDiceSource) {\n try {\n console.log('[searchCandidates] Dice source detected, transforming response...');\n console.log('[searchCandidates] Raw response structure:', json?.data?.data?.[0] ? Object.keys(json.data.data[0]) : 'No data');\n console.log('[searchCandidates] Raw skills sample:', JSON.stringify(json?.data?.data?.[0]?.skills).substring(0, 150));\n \n const { transformDiceResponseToInternalFormat } = await import('./diceCandidateMapper');\n const transformed = transformDiceResponseToInternalFormat(json, json);\n \n console.log('[searchCandidates] Transformed skills sample:', JSON.stringify(transformed?.data?.data?.[0]?.skills).substring(0, 150));\n console.log('[searchCandidates] Transformation complete');\n \n return transformed;\n } catch (error) {\n console.error('[searchCandidates] Dice transformation failed, returning raw response:', error);\n console.error('[searchCandidates] Error stack:', error.stack);\n // Fall through to return raw response if transformation fails\n }\n } else {\n console.log('[searchCandidates] No Dice source, returning raw response');\n }\n \n return json;\n}\n\nexport async function getPipelineCount({ jobId, offset = 0, limit = 1, searchValue = '' }) {\n const json = await fetchJsonWithAuth(\n JOBS_URL,\n `/source/hiring-candidate-list/pipeline?hiringType=pipeline&jobId=${jobId}&limit=${limit}&offset=${offset}&searchValue=${encodeURIComponent(searchValue)}`\n );\n return json?.data?.count ?? 0;\n}\n\nexport async function getShortlistedCount({ jobId, offset = 0, limit = 1, searchQuery = '' }) {\n const json = await fetchJsonWithAuth(\n JOBS_URL,\n `/source/hiring-candidate-list/pipeline?hiringType=shortlisted&jobId=${jobId}&limit=${limit}&offset=${offset}&searchQuery=${encodeURIComponent(searchQuery)}`\n );\n return json?.data?.count ?? 0;\n}\n\nexport async function getSubmittedCandidates(jobId) {\n const json = await fetchJsonWithAuth(SUBMISSIONS_URL, `/job-submissions?jobId=${jobId}`);\n return json?.data ?? [];\n}\n\nexport async function getPipelineCandidates({ jobId, offset = 0, limit = 50, searchValue = '' }) {\n const json = await fetchJsonWithAuth(\n JOBS_URL,\n `/source/hiring-candidate-list/pipeline?hiringType=pipeline&jobId=${jobId}&limit=${limit}&offset=${offset}&searchValue=${encodeURIComponent(searchValue)}`\n );\n return json;\n}\n\nexport async function getShortlistedCandidates({ jobId, offset = 0, limit = 50, searchQuery = '' }) {\n const json = await fetchJsonWithAuth(\n JOBS_URL,\n `/source/hiring-candidate-list/pipeline?hiringType=shortlisted&jobId=${jobId}&limit=${limit}&offset=${offset}&searchQuery=${encodeURIComponent(searchQuery)}`\n );\n return json;\n}\n\nexport async function quickSubmitDetailedView({ _id, tenantId, businessId, businessUnitId }) {\n const params = new URLSearchParams({ _id, tenantId, businessId, businessUnitId });\n return apiGetWithAuth(CANDIDATES_URL, `/detailed-view?${params.toString()}`);\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dropdownApi-CKrs-Jwa.js","names":[],"sources":["../src/services/candidateVersionsApi.js","../src/services/dropdownApi.js"],"sourcesContent":["import { fetchJsonWithAuth } from './authApi';\nimport { AUTH_URL } from './apiConfig';\n\nexport async function getCandidateVersions(candidateId) {\n const json = await fetchJsonWithAuth(AUTH_URL, `/candidate-versions?candidateId=${encodeURIComponent(candidateId)}`);\n const rows = json?.data ?? json;\n if (!Array.isArray(rows)) throw new Error('Candidate versions could not be loaded');\n return [...rows].sort((a, b) => Number(b.profileVersion) - Number(a.profileVersion));\n}\n","// export const SUBMISSIONS_URL = BASE_URL;\n\nimport { AUTH_URL, JOBS_URL, CANDIDATES_URL, SUBMISSIONS_URL, PYOPS_URL } from './apiConfig';\nimport { fetchFormGroupsCached, invalidateFormGroupsCache } from './formGroupsCache';\nimport { getBaseModuleName } from '../utils/modulePath';\n\n\nconst AUTH_TOKEN_KEY = 'authToken';\nconst AUTH_USER_KEY = 'authUser';\nconst AUTH_LOGIN_SESSION_KEY = 'authLoginSession';\nconst LOGIN_STORAGE_KEYS = [\n 'access_token',\n 'refresh_token',\n 'id_token',\n 'token_type',\n 'expires_in',\n 'refresh_expires_in',\n 'menu',\n 'footermenu',\n 'menuPermission',\n 'default_values',\n 'roleId',\n 'companyName',\n 'preferred_Username',\n 'user_Email',\n 'userName',\n 'userId',\n 'tenantId',\n 'businessId',\n 'businessUnitId',\n 'activeKey',\n 'ct_project_id',\n 'ct_project_name',\n];\n\nconst CT_PROJECT_ID_KEY = 'ct_project_id';\nconst CT_PROJECT_NAME_KEY = 'ct_project_name';\n\nconst TEST_FLOW_MODULE = 'test-flows';\nconst TEST_FLOW_FIELDS = [\n { value: 'module', label: 'Module', isVisible: true, type: 'text' },\n { value: 'flow', label: 'Flow', isVisible: true, type: 'text' },\n { value: 'step_order', label: 'Step Order', isVisible: true, type: 'number' },\n { value: 'keyword', label: 'Action', isVisible: true, type: 'text' },\n { value: 'description', label: 'Description', isVisible: true, type: 'text' },\n { value: 'target', label: 'Key', isVisible: true, type: 'text' },\n { value: 'tags', label: 'Tags', isVisible: true, type: 'text' },\n { value: 'value', label: 'Value', isVisible: true, type: 'text' },\n { value: 'expected', label: 'Expected', isVisible: true, type: 'text' },\n];\n\nconst LMS_FLOW_MODULE = 'lms-flows';\nconst LMS_FLOW_FIELDS = [\n { value: 'module', label: 'Module', isVisible: true, type: 'text' },\n { value: 'flow', label: 'Flow', isVisible: true, type: 'text' },\n { value: 'step_order', label: 'Step Order', isVisible: true, type: 'number' },\n { value: 'keyword', label: 'Action', isVisible: true, type: 'text' },\n { value: 'description', label: 'Description', isVisible: true, type: 'text' },\n { value: 'target', label: 'Key', isVisible: true, type: 'text' },\n { value: 'tags', label: 'Tags', isVisible: true, type: 'text' },\n { value: 'value', label: 'Value', isVisible: true, type: 'text' },\n { value: 'expected', label: 'Expected', isVisible: true, type: 'text' },\n];\n\n// In-flight login promise — prevents multiple simultaneous login calls\nlet loginPromise = null;\nlet refreshPromise = null;\n\nfunction extractToken(json) {\n return (\n json?.token ??\n json?.access_token ??\n json?.accessToken ??\n json?.jwt ??\n json?.data?.token ??\n json?.data?.access_token ??\n json?.data?.accessToken ??\n json?.data?.jwt\n );\n}\n\nfunction extractUser(json) {\n return json?.user ?? json?.data?.user ?? json?.data?.profile ?? null;\n}\n\nfunction decodeJwtPayload(token) {\n if (!token || typeof token !== 'string') return null;\n\n try {\n const payload = token.split('.')[1];\n if (!payload) return null;\n\n const normalizedPayload = payload.replace(/-/g, '+').replace(/_/g, '/');\n const decodedPayload = atob(normalizedPayload.padEnd(Math.ceil(normalizedPayload.length / 4) * 4, '='));\n return JSON.parse(decodedPayload);\n } catch (error) {\n console.error('Unable to decode login token:', error);\n return null;\n }\n}\n\nfunction setLocalStorageJson(key, value) {\n if (value === undefined || value === null) return;\n localStorage.setItem(key, JSON.stringify(value));\n}\n\nfunction getLoginMenus(json, data) {\n return data?.menus ?? json?.menus ?? {\n menu: data?.menu ?? json?.menu,\n footermenu: data?.footermenu ?? json?.footermenu,\n };\n}\n\nfunction persistLoginResponse(json, token, user) {\n const data = json?.data ?? json;\n const tokenPayload = decodeJwtPayload(token) ?? {};\n const menus = getLoginMenus(json, data);\n const userName = (\n user?.userName ??\n user?.name ??\n data?.userName ??\n data?.name ??\n tokenPayload.userName ??\n tokenPayload.name ??\n tokenPayload.preferred_username ??\n tokenPayload.email\n );\n const preferredUsername = (\n user?.preferred_Username ??\n user?.preferred_username ??\n data?.preferred_Username ??\n data?.preferred_username ??\n tokenPayload.preferred_Username ??\n tokenPayload.preferred_username ??\n tokenPayload.email ??\n userName\n );\n const userEmail = user?.email ?? data?.email ?? tokenPayload.email ?? preferredUsername;\n\n localStorage.setItem('access_token', token);\n if (data?.refresh_token) localStorage.setItem('refresh_token', data.refresh_token);\n if (data?.id_token !== undefined) localStorage.setItem('id_token', data.id_token);\n if (data?.token_type) localStorage.setItem('token_type', data.token_type);\n if (data?.expires_in !== undefined) localStorage.setItem('expires_in', String(data.expires_in));\n if (data?.refresh_expires_in !== undefined) localStorage.setItem('refresh_expires_in', String(data.refresh_expires_in));\n if (userName) localStorage.setItem('userName', userName);\n if (preferredUsername) localStorage.setItem('preferred_Username', preferredUsername);\n if (userEmail) localStorage.setItem('user_Email', userEmail);\n if (data?.roleId ?? tokenPayload.role_id) localStorage.setItem('roleId', data?.roleId ?? tokenPayload.role_id);\n // Header organization name: the user's platform region name when set, else\n // the business company name (REQ-20260916-03). Cleared when the response has\n // none, so a previous user's organization never lingers in this browser.\n const companyName = String(data?.companyName ?? '').trim();\n if (companyName) localStorage.setItem('companyName', companyName);\n else localStorage.removeItem('companyName');\n if (tokenPayload.userId !== undefined) localStorage.setItem('userId', String(tokenPayload.userId));\n if (tokenPayload.tenantId) localStorage.setItem('tenantId', tokenPayload.tenantId);\n if (tokenPayload.businessId) localStorage.setItem('businessId', tokenPayload.businessId);\n if (tokenPayload.businessUnitId) localStorage.setItem('businessUnitId', tokenPayload.businessUnitId);\n\n setLocalStorageJson('menu', menus.menu);\n setLocalStorageJson('footermenu', menus.footermenu);\n setLocalStorageJson('menuPermission', data?.menuPermission);\n setLocalStorageJson('default_values', data?.default_values);\n}\n\nexport function getStoredToken() {\n // Keep authentication available in every tab. `sessionStorage` belongs to\n // only one tab, so gating the shared localStorage token with it caused new\n // tabs to be treated as logged out.\n return localStorage.getItem(AUTH_TOKEN_KEY);\n}\n\nexport async function getGroupedVendorHotlist({ jobId, limit = 10, offset = 0, sortBy = 'new', type = 'myVendor' }) {\n const json = await fetchJsonWithAuth(JOBS_URL, '/vendor/hotlist', {\n method: 'POST',\n body: JSON.stringify({ jobId, limit, offset, sortBy, type }),\n });\n return json;\n}\n\nexport async function getBulkMailDetails(jobId) {\n const json = await fetchJsonWithAuth(CANDIDATES_URL, `/get-bulkmail-details?jobId=${encodeURIComponent(jobId)}`);\n return json.data ?? json;\n}\n\nexport async function getCandidateEmailDetails(candidateIds = []) {\n const ids = [...new Set((candidateIds ?? []).map((id) => String(id ?? '').trim()).filter(Boolean))];\n if (!ids.length) return [];\n\n const json = await fetchJsonWithAuth(CANDIDATES_URL, '/candidate-emails', {\n method: 'POST',\n body: JSON.stringify({ candidateIds: ids }),\n });\n const rows = json?.data ?? json;\n return Array.isArray(rows) ? rows : [];\n}\n\n// Full, unfiltered record for any module by its own _id — bypasses list-view\n// field-visibility config, so a field the grid doesn't currently project\n// (e.g. a candidate's email on a submission row) can still be read.\nexport async function getModuleRecordById(moduleName, recordId) {\n const module = String(moduleName ?? '').trim();\n const id = String(recordId ?? '').trim();\n if (!module || !id) return null;\n\n const json = await fetchJsonWithAuth(AUTH_URL, `/module/list?module=${encodeURIComponent(module)}&id=${encodeURIComponent(id)}`);\n const rows = json?.data?.data ?? json?.data ?? [];\n return Array.isArray(rows) ? (rows[0] ?? null) : null;\n}\n\nexport async function formatMailContentForMail(contents, subject = '') {\n const input = String(contents ?? '').trim();\n if (!input) return '';\n\n const json = await fetchJsonWithAuth(PYOPS_URL, '/format-mail-content', {\n method: 'POST',\n body: JSON.stringify({ contents: input, subject: String(subject ?? '') }),\n });\n\n if (json?.status === false) {\n throw new Error(json?.error || 'Unable to format mail content');\n }\n\n return String(json?.html ?? json?.contents ?? json?.data?.html ?? json?.data?.contents ?? '').trim();\n}\n\n// Backward-compatible export for any host code that imported the previous name.\n// It now formats the existing mail body rather than generating/re-writing a JD.\nexport async function formatJobDescriptionForMail(contents, subject = '') {\n return formatMailContentForMail(contents, subject);\n}\n\nexport async function sendBulkMail({ jobId, toMail, ccMail, bccMail, subject, contents, attachments = [] }) {\n const tenantId = localStorage.getItem('tenantId') || '93c782a4aa626175e5d11afa';\n const businessId = localStorage.getItem('businessId') || '83c782a4aa626175e5d11afa';\n const businessUnitId = localStorage.getItem('businessUnitId') || '63b57588fd768a839dbc0f63';\n\n const formData = new FormData();\n formData.append('json', JSON.stringify({\n schemaVersion: 1,\n tenantId,\n businessId,\n businessUnitId,\n jobId,\n toMail,\n ccMail,\n bccMail,\n contents,\n subject,\n }));\n\n // Dynamic document placeholders are resolved to File objects by the mail\n // composer. Append them as multipart files so they are sent as real email\n // attachments instead of being rendered as text inside the mail body.\n (attachments ?? []).forEach((file) => {\n if (file instanceof File && file.size > 0 && String(file.name ?? '').trim()) {\n formData.append('attachments', file, file.name);\n }\n });\n\n // Exclude Content-Type so the browser sets multipart/form-data with the correct boundary\n const allHeaders = await authHeaders();\n const { 'Content-Type': _ct, ...headersWithoutContentType } = allHeaders;\n\n let res = await fetch(`${CANDIDATES_URL}/send-bulkmail`, {\n method: 'POST',\n headers: headersWithoutContentType,\n body: formData,\n });\n\n if (res.status === 401) logout();\n if (!res.ok) throw new Error(`API ${res.status}: ${res.statusText}`);\n const text = await res.text();\n return text ? JSON.parse(text) : {};\n}\n\n\nexport function logout() {\n localStorage.removeItem(AUTH_TOKEN_KEY);\n localStorage.removeItem(AUTH_USER_KEY);\n LOGIN_STORAGE_KEYS.forEach((key) => localStorage.removeItem(key));\n sessionStorage.removeItem(AUTH_LOGIN_SESSION_KEY);\n window.dispatchEvent(new Event('auth:logout'));\n}\n\n// ---- Role helpers ----\n// The login response carries the role NAME in `data.roleId`\n// (persistLoginResponse stores it in localStorage['roleId']). The access-token\n// claims only have a numeric `role_id`, so the stored role NAME is the reliable\n// signal for the tester check. JWT roles are kept as a fallback.\nexport function getCurrentRoleName() {\n return String(localStorage.getItem('roleId') ?? '').trim().toLowerCase();\n}\n\nexport function getUserRoles() {\n const token = localStorage.getItem(AUTH_TOKEN_KEY);\n const payload = decodeJwtPayload(token);\n\n const roles = new Set();\n\n const stored = getCurrentRoleName();\n if (stored) roles.add(stored);\n\n if (payload) {\n (payload?.realm_access?.roles ?? []).forEach((role) => roles.add(role));\n Object.values(payload?.resource_access ?? {}).forEach((client) => {\n (client?.roles ?? []).forEach((role) => roles.add(role));\n });\n [payload?.role, payload?.roleName, payload?.role_name].forEach((role) => {\n if (role) roles.add(role);\n });\n }\n\n return Array.from(roles).map((role) => String(role).toLowerCase());\n}\n\nexport function isTester() {\n return getCurrentRoleName() === 'tester' || getUserRoles().includes('tester');\n}\n\nfunction isEnabledPermission(value) {\n return value === true || value === 1 || value === '1';\n}\n\nexport function hasAllJobsPermission() {\n try {\n const permissions = JSON.parse(localStorage.getItem('menuPermission') || '{}');\n if (!permissions || typeof permissions !== 'object') return false;\n\n const jobsKey = Object.keys(permissions).find((key) => {\n const normalized = String(key).trim().toLowerCase();\n return normalized === 'job' || normalized === 'jobs';\n });\n const jobsPermissions = jobsKey ? permissions[jobsKey] : null;\n if (!jobsPermissions || typeof jobsPermissions !== 'object') return false;\n\n return isEnabledPermission(\n jobsPermissions.all_jobs\n ?? jobsPermissions.allJobs\n ?? jobsPermissions.alljobs,\n );\n } catch {\n return false;\n }\n}\n\nexport function resolveJobListScope(requestedScope = '') {\n const scope = String(requestedScope ?? '').trim();\n\n // Preserve the tab the user actually selected. The API is authoritative\n // for access control and already narrows an unauthorised allJobs request to\n // My Jobs. Re-checking permissions from localStorage here is unreliable:\n // login payloads differ across deployments, so a user whose API response\n // legitimately contains the All Jobs tab could still have that request\n // silently rewritten to myJobs by stale or differently-shaped cached data.\n if (scope === 'myJobs' || scope === 'allJobs' || scope === 'fulfilled') return scope;\n\n // With no explicit tab, let the API choose the permission-aware default.\n return '';\n}\n\nfunction isJobsModule(module) {\n const baseModule = String(getBaseModuleName(module) ?? '').trim().toLowerCase();\n return baseModule === 'job' || baseModule === 'jobs';\n}\n\n// ---- Selected project context (carried through the tester flow) ----\nexport function setSelectedProject(project) {\n if (!project) return;\n localStorage.setItem(CT_PROJECT_ID_KEY, String(project.id));\n localStorage.setItem(CT_PROJECT_NAME_KEY, String(project.name));\n}\n\nexport function getSelectedProject() {\n const id = localStorage.getItem(CT_PROJECT_ID_KEY);\n const name = localStorage.getItem(CT_PROJECT_NAME_KEY);\n if (!id || !name) return null;\n return { id: Number(id), name };\n}\n\nexport function clearSelectedProject() {\n localStorage.removeItem(CT_PROJECT_ID_KEY);\n localStorage.removeItem(CT_PROJECT_NAME_KEY);\n}\n\nexport async function login(credentials) {\n if (loginPromise) return loginPromise;\n\n loginPromise = fetch(`${AUTH_URL}/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(credentials),\n })\n .then(async (res) => {\n const json = await res.json();\n if (!res.ok) {\n const error = new Error(json?.message ?? json?.error ?? `Login failed: ${res.status}`);\n error.status = res.status;\n throw error;\n }\n\n const token = extractToken(json);\n if (!token) throw new Error('No token in login response');\n const user = extractUser(json);\n\n localStorage.setItem(AUTH_TOKEN_KEY, token);\n if (user) localStorage.setItem(AUTH_USER_KEY, JSON.stringify(user));\n persistLoginResponse(json, token, user);\n\n return { token, user, response: json };\n })\n .finally(() => {\n loginPromise = null;\n });\n\n return loginPromise;\n}\n\nfunction tokenExpiresSoon(token, skewSeconds = 30) {\n const payload = decodeJwtPayload(token);\n const exp = Number(payload?.exp);\n if (!Number.isFinite(exp) || exp <= 0) return false;\n return exp * 1000 <= Date.now() + skewSeconds * 1000;\n}\n\nasync function refreshAccessToken() {\n if (refreshPromise) return refreshPromise;\n const refreshToken = String(localStorage.getItem('refresh_token') ?? '').trim();\n if (!refreshToken) throw Object.assign(new Error('Session expired'), { status: 401 });\n refreshPromise = fetch(`${AUTH_URL}/generate-refresh-token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refresh_token: refreshToken }),\n }).then(async (res) => {\n const text = await res.text();\n let json = {};\n if (text) { try { json = JSON.parse(text); } catch { json = { error: text }; } }\n if (!res.ok) throw Object.assign(new Error(json?.error ?? json?.message ?? `Token refresh failed: ${res.status}`), { status: res.status });\n const token = extractToken(json);\n if (!token) throw Object.assign(new Error('Token refresh response did not contain an access token'), { status: 401 });\n localStorage.setItem(AUTH_TOKEN_KEY, token);\n localStorage.setItem('access_token', token);\n return token;\n }).finally(() => { refreshPromise = null; });\n return refreshPromise;\n}\n\nasync function ensureToken() {\n const token = getStoredToken();\n if (token && !tokenExpiresSoon(token)) return token;\n if (localStorage.getItem('refresh_token')) {\n try { return await refreshAccessToken(); } catch { /* final request handles logout */ }\n }\n if (token) return token;\n const error = new Error('Authentication required');\n error.status = 401;\n throw error;\n}\n\nasync function authHeaders() {\n const token = await ensureToken();\n return {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n };\n}\n\nexport async function fetchJsonWithAuth(baseUrl, path, options = {}) {\n const doRequest = async () => {\n const headers = await authHeaders();\n return fetch(`${baseUrl}${path}`, {\n ...options,\n headers: { ...headers, ...options.headers },\n });\n };\n\n let res = await doRequest();\n if (res.status === 401 && localStorage.getItem('refresh_token')) {\n try {\n await refreshAccessToken();\n res = await doRequest();\n } catch {\n // Final 401 handling below clears an actually invalid session.\n }\n }\n if (res.status === 401) logout();\n const text = await res.text();\n let json = {};\n if (text) { try { json = JSON.parse(text); } catch { json = { error: text }; } }\n if (!res.ok) {\n const error = new Error(json?.error ?? json?.message ?? `API ${res.status}: ${res.statusText}`);\n error.status = res.status;\n throw error;\n }\n return json;\n}\n\nexport async function apiGetWithAuth(baseUrl, path) {\n const json = await fetchJsonWithAuth(baseUrl, path);\n return json.data ?? json;\n}\n\nasync function apiGet(path) {\n return apiGetWithAuth(SUBMISSIONS_URL, path);\n}\n\nasync function authapiGet(path) {\n return apiGetWithAuth(AUTH_URL, path);\n}\n\nasync function authapiPost(path, payload) {\n const json = await fetchJsonWithAuth(AUTH_URL, path, {\n method: 'POST',\n body: JSON.stringify(payload),\n });\n return json.data ?? json;\n}\n\nasync function authapiPut(path, payload) {\n const json = await fetchJsonWithAuth(AUTH_URL, path, {\n method: 'PUT',\n body: JSON.stringify(payload),\n });\n return json.data ?? json;\n}\n\n/**\n * Fetch available filter fields for a module.\n * Returns: [{ label, value, type }, ...]\n */\nexport async function getDropdownFields(module) {\n if (module === TEST_FLOW_MODULE) return TEST_FLOW_FIELDS;\n if (module === LMS_FLOW_MODULE) return LMS_FLOW_FIELDS;\n\n // Dot-notation names (\"job.client\") target nested data client-side; the\n // backend only knows the base module.\n return apiGet(`/filter-dropdown-fields?module=${encodeURIComponent(getBaseModuleName(module))}`);\n}\n\nexport async function getFieldConfig(module, { configType, userId, roleId } = {}) {\n if (module === TEST_FLOW_MODULE) return TEST_FLOW_FIELDS;\n if (module === LMS_FLOW_MODULE) return LMS_FLOW_FIELDS;\n\n const params = new URLSearchParams({ module: getBaseModuleName(module) });\n if (configType) params.set('configType', configType);\n if (userId != null) params.set('userId', String(userId));\n if (roleId != null) params.set('roleId', String(roleId));\n return authapiGet(`/admin/field-config?${params}`);\n}\n\n\nexport async function getTestingOptions(type) {\n return authapiGet(`/testing-modules?type=${encodeURIComponent(type)}`);\n}\n\nexport async function addTestingOption({ name, type }) {\n return authapiPost('/testing-modules', { name, type });\n}\n\nexport async function addTestFlow(payload) {\n return authapiPost('/test-flows', payload);\n}\n\nexport async function getTestFlows({\n limit = 10,\n offset = 0,\n search = '',\n module = '',\n keyword = '',\n tags = '',\n active,\n} = {}) {\n const params = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n });\n if (search) params.append('search', search);\n if (module) params.append('module', module);\n if (keyword) params.append('keyword', keyword);\n if (tags) params.append('tags', tags);\n if (active !== undefined && active !== null && active !== '') {\n params.append('active', String(active));\n }\n\n return authapiGet(`/test-flows?${params.toString()}`);\n}\n\n// =====================================================================\n// Common Test Automation (znxt_test_automation)\n// Hierarchy: Project -> Module -> Submodule -> Test Flow\n// =====================================================================\n\n// ---- Projects ----\nexport async function getCTProjects({ activeOnly = false } = {}) {\n const params = new URLSearchParams();\n if (activeOnly) params.append('active', '1');\n const query = params.toString();\n return authapiGet(`/ct/projects${query ? `?${query}` : ''}`);\n}\n\nexport async function addCTProject(projectname) {\n return authapiPost('/ct/projects', { projectname });\n}\n\nexport async function setCTProjectStatus(id, active) {\n return authapiPut('/ct/projects/status', { id, active });\n}\n\n// ---- Modules ----\nexport async function getCTModules({ project = '', activeOnly = false } = {}) {\n const params = new URLSearchParams();\n if (project) params.append('project', project);\n if (activeOnly) params.append('active', '1');\n const query = params.toString();\n return authapiGet(`/ct/modules${query ? `?${query}` : ''}`);\n}\n\nexport async function addCTModule({ project, modulename }) {\n return authapiPost('/ct/modules', { project, modulename });\n}\n\nexport async function setCTModuleStatus(id, active) {\n return authapiPut('/ct/modules/status', { id, active });\n}\n\n// ---- Submodules ----\nexport async function getCTSubmodules({ project = '', module = '', activeOnly = false } = {}) {\n const params = new URLSearchParams();\n if (project) params.append('project', project);\n if (module) params.append('module', module);\n if (activeOnly) params.append('active', '1');\n const query = params.toString();\n return authapiGet(`/ct/submodules${query ? `?${query}` : ''}`);\n}\n\nexport async function addCTSubmodule({ project, modulename, submodulename }) {\n return authapiPost('/ct/submodules', { project, modulename, submodulename });\n}\n\nexport async function setCTSubmoduleStatus(id, active) {\n return authapiPut('/ct/submodules/status', { id, active });\n}\n\n// ---- Test Flows ----\nexport async function getCTFlows({\n project = '',\n module = '',\n submodule = '',\n product_parent_ID = '',\n module_parent_ID = '',\n submodule_parent_ID = '',\n actions = '',\n search = '',\n active,\n limit = 1000,\n offset = 0,\n} = {}) {\n const params = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n });\n const productParentID = product_parent_ID || project;\n const moduleParentID = module_parent_ID || module;\n const submoduleParentID = submodule_parent_ID || submodule;\n if (productParentID) params.append('product_parent_ID', productParentID);\n if (moduleParentID) params.append('module_parent_ID', moduleParentID);\n if (submoduleParentID) params.append('submodule_parent_ID', submoduleParentID);\n if (actions) params.append('actions', actions);\n if (search) params.append('search', search);\n if (active !== undefined && active !== null && active !== '') {\n params.append('active', String(active));\n }\n return authapiGet(`/ct/flows?${params.toString()}`);\n}\n\nexport async function addCTFlow(payload) {\n return authapiPost('/ct/flows', payload);\n}\n\nexport async function getCTNextStep({\n project,\n module,\n submodule,\n product_parent_ID,\n module_parent_ID,\n submodule_parent_ID,\n}) {\n const params = new URLSearchParams({\n product_parent_ID: String(product_parent_ID || project),\n module_parent_ID: String(module_parent_ID || module),\n submodule_parent_ID: String(submodule_parent_ID || submodule),\n });\n return authapiGet(`/ct/flows/next-step?${params.toString()}`);\n}\n\nexport async function addLmsFlow(payload) {\n return authapiPost('/lms-flows', payload);\n}\n\nexport async function getLmsFlows({\n limit = 10,\n offset = 0,\n search = '',\n module = '',\n keyword = '',\n tags = '',\n active,\n} = {}) {\n const params = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n });\n if (search) params.append('search', search);\n if (module) params.append('module', module);\n if (keyword) params.append('keyword', keyword);\n if (tags) params.append('tags', tags);\n if (active !== undefined && active !== null && active !== '') {\n params.append('active', String(active));\n }\n\n return authapiGet(`/lms-flows?${params.toString()}`);\n}\n\nexport async function getModuleDataList(module, limit = 10, offset = 0, options = {}) {\n const {\n scope = '',\n sort = '',\n sortDir = '',\n search = '',\n filters = [],\n queryParams = {},\n } = options;\n\n if (module === TEST_FLOW_MODULE) {\n const data = await getTestFlows({ limit, offset });\n const rows = Array.isArray(data?.items) ? data.items : [];\n const total = Number(data?.total) || 0;\n\n return {\n items: rows,\n total,\n limit,\n offset,\n tabs: [{ key: 'all', title: 'Test Cases', count: total }],\n };\n }\n\n if (module === LMS_FLOW_MODULE) {\n const data = await getLmsFlows({ limit, offset });\n const rows = Array.isArray(data?.items) ? data.items : [];\n const total = Number(data?.total) || 0;\n\n return {\n items: rows,\n total,\n limit,\n offset,\n tabs: [{ key: 'all', title: 'LMS Cases', count: total }],\n };\n }\n\n const params = new URLSearchParams({\n module: getBaseModuleName(module),\n limit: String(limit),\n offset: String(offset),\n });\n // The shared Jobs page uses the singular module name (`job`) while some\n // consumers use `jobs`. Both names target the same backend module and must\n // go through the same permission-aware My Jobs / All Jobs scope resolver.\n const normalizedScope = isJobsModule(module)\n ? resolveJobListScope(scope)\n : String(scope ?? '').trim();\n if (normalizedScope) params.set('scope', normalizedScope);\n if (sort) params.set('sort', sort);\n if (sortDir) params.set('sortDir', sortDir);\n // Server-side quick search across visible + lookup-resolved fields\n // (job title, client name, location, ...) — see /module-data-list.\n if (String(search ?? '').trim()) params.set('search', String(search).trim());\n\n const conditions = toFilterConditions(filters.filter((f) => f?.field));\n if (conditions.length) {\n params.set('filters', JSON.stringify(conditions));\n }\n\n Object.entries(queryParams ?? {}).forEach(([key, value]) => {\n if (value !== null && value !== undefined && String(value).trim() !== '') {\n params.set(key, String(value));\n }\n });\n\n const json = await fetchJsonWithAuth(AUTH_URL, `/module-data-list?${params.toString()}`);\n\n const responseData = getResponseRows(json);\n const hasObjectSkills = responseData.some((record) => hasObjectSkillItems(record));\n const hasDiceCandidates = responseData.some((record) => hasDiceSource(record));\n\n if (hasObjectSkills || hasDiceCandidates) {\n try {\n const { transformDiceResponseToInternalFormat } = await import('./diceCandidateMapper');\n const transformed = transformDiceResponseToInternalFormat(json, json);\n const transformedData = transformed?.data?.data ?? [];\n // const total = extractResponseTotal(json, scope || 'internal')\n // || extractResponseTotal(transformed, scope || 'internal')\n const total = extractResponseTotal(json, normalizedScope)\n || extractResponseTotal(transformed, normalizedScope)\n || transformedData.length;\n\n return {\n items: transformedData,\n total,\n limit,\n offset,\n tabs: transformed?.data?.tabs ?? json?.tabs ?? json?.data?.tabs ?? [],\n fields: transformed?.data?.fields ?? json?.fields ?? json?.data?.fields ?? [],\n tabField: transformed?.data?.tabField ?? json?.tabField ?? json?.data?.tabField ?? '',\n actionRules: transformed?.data?.actionRules ?? json?.data?.actionRules ?? [],\n actions: transformed?.data?.actions ?? json?.data?.actions ?? [],\n columnActions: transformed?.data?.columnActions ?? json?.data?.columnActions ?? [],\n };\n } catch (error) {\n console.error('[getModuleDataList] Dice transformation failed:', error);\n }\n }\n \n return json;\n}\n\nfunction getResponseRows(response) {\n const payload = response?.data ?? response;\n const rows = Array.isArray(payload)\n ? payload\n : payload?.rows\n ?? payload?.records\n ?? payload?.items\n ?? payload?.list\n ?? payload?.data\n ?? response?.items\n ?? response?.records\n ?? [];\n\n return Array.isArray(rows) ? rows : [];\n}\n\nfunction firstFiniteNumber(...values) {\n for (const value of values) {\n const number = Number(value);\n if (Number.isFinite(number)) return number;\n }\n\n return undefined;\n}\n\nfunction extractResponseTotal(response, scope = '') {\n const payload = response?.data ?? response;\n const rows = getResponseRows(response);\n const responseCount = response?.count;\n const payloadCount = payload?.count;\n const normalizedScope = String(scope ?? '').trim().toLowerCase();\n\n if (responseCount && typeof responseCount === 'object') {\n const total = firstFiniteNumber(\n normalizedScope ? responseCount[normalizedScope] : undefined,\n responseCount.total,\n responseCount.searchCount,\n responseCount.count,\n );\n if (total !== undefined) return total;\n }\n\n if (payloadCount && typeof payloadCount === 'object') {\n const total = firstFiniteNumber(\n normalizedScope ? payloadCount[normalizedScope] : undefined,\n payloadCount.total,\n payloadCount.searchCount,\n payloadCount.count,\n );\n if (total !== undefined) return total;\n }\n\n return firstFiniteNumber(\n response?.total,\n typeof responseCount !== 'object' ? responseCount : undefined,\n response?.totalCount,\n payload?.total,\n typeof payloadCount !== 'object' ? payloadCount : undefined,\n payload?.totalCount,\n rows.length,\n ) ?? 0;\n}\n\nfunction hasObjectSkillItems(record) {\n const skills = record?.skills ?? record?.technicalSkills ?? record?.primarySkills;\n if (!Array.isArray(skills) || skills.length === 0) return false;\n\n return skills.some((skill) => (\n skill\n && typeof skill === 'object'\n && ('skill' in skill || 'lastUsed' in skill)\n ));\n}\n\nfunction hasDiceSource(record) {\n const sourceFields = [\n record?.sourceType,\n record?.profileSource,\n record?.selectedSource,\n record?.customFields?.sourceType,\n record?.customFields?.profileSource,\n ].flat();\n \n return sourceFields.some(\n (value) => String(value ?? '').trim().toLowerCase() === 'dice',\n ) || Boolean(record?.customFields?.diceProfileData);\n}\n\nexport async function getJobSummary(startDate, endDate) {\n const params = new URLSearchParams();\n\n if (startDate) params.set('startDate', startDate);\n if (endDate) params.set('endDate', endDate);\n\n const query = params.toString();\n return apiGetWithAuth(JOBS_URL, `/job-summary${query ? `?${query}` : ''}`);\n}\n\nexport async function getCandidateSummary(startDate, endDate) {\n const params = new URLSearchParams();\n\n if (startDate) params.set('startDate', startDate);\n if (endDate) params.set('endDate', endDate);\n\n const query = params.toString();\n return apiGetWithAuth(CANDIDATES_URL, `/profile-summary${query ? `?${query}` : ''}`);\n}\n\nexport async function getSubmissionSummary(startDate, endDate) {\n const params = new URLSearchParams();\n\n if (startDate) params.set('startDate', startDate);\n if (endDate) params.set('endDate', endDate);\n\n const query = params.toString();\n return apiGetWithAuth(SUBMISSIONS_URL, `/profile-summary${query ? `?${query}` : ''}`);\n}\n\n// Converts frontend filter rows to the BE FilterCondition[] format.\n// BE ops: eq | ne | in | nin | contains | gt | gte | lt | lte | isEmpty | notEmpty\nfunction toFilterConditions(filterRows) {\n const conditions = [];\n for (const row of filterRows) {\n if (!row.field) continue;\n\n // The row connector ('and'/'or') between this row and the previous one.\n // 'isEmpty'/'notEmpty' rows use the operator slot for their op type, so they\n // don't have an explicit AND/OR connector — default them to 'and'.\n const rowConnector = row.operator === 'or' ? 'or' : 'and';\n\n if (row.operator === 'isEmpty') {\n conditions.push({ field: row.field, op: 'isEmpty', operator: 'and' });\n continue;\n }\n if (row.operator === 'notEmpty') {\n conditions.push({ field: row.field, op: 'notEmpty', operator: 'and' });\n continue;\n }\n\n // Text keyword search → contains (case-insensitive regex on the backend)\n if (row.filterInputType === 'text') {\n const val = typeof row.value === 'string' ? row.value.trim() : '';\n if (val) conditions.push({ field: row.field, op: 'contains', value: val, operator: rowConnector });\n continue;\n }\n\n // Date range — from/to set by DatePicker.RangePicker.\n // The row connector applies to the first (gte) condition; lte is always\n // AND'd with it so the two bounds stay paired in the backend fold.\n if (row.from || row.to) {\n if (row.from) conditions.push({ field: row.field, op: 'gte', value: String(row.from), operator: rowConnector });\n if (row.to) conditions.push({ field: row.field, op: 'lte', value: String(row.to), operator: 'and' });\n continue;\n }\n\n // Multi-value (dropdown / checkbox / boolean) → in\n if (Array.isArray(row.values) && row.values.length > 0) {\n conditions.push({\n field: row.field,\n op: 'in',\n values: row.values.map(String),\n operator: rowConnector,\n ...(Array.isArray(row.groupFields) && row.groupFields.length > 1 ? { groupFields: row.groupFields } : {}),\n });\n }\n }\n return conditions;\n}\n\n/**\n * Fetch distinct values for a specific field in a module.\n * Returns: [{ label, value }, ...]\n */\nexport async function getDropdownValues(module, field, search = '', meta = {}) {\n const {\n limit = 50,\n offset = 0,\n dataSource,\n groupName,\n lookup,\n groupFields = [],\n groupSeparator = ' ',\n arrayLabelField = '',\n arrayValueField = '',\n scope = '',\n } = meta;\n const baseModule = getBaseModuleName(module);\n const params = new URLSearchParams({\n module: baseModule,\n field,\n value: search,\n limit: String(limit),\n offset: String(offset),\n });\n if (dataSource) params.set('dataSource', dataSource);\n if (scope) params.set('scope', isJobsModule(module) ? resolveJobListScope(scope) : scope);\n if (arrayLabelField) params.set('arrayLabelField', arrayLabelField);\n if (arrayValueField) params.set('arrayValueField', arrayValueField);\n if (Array.isArray(groupFields) && groupFields.length > 1) {\n params.set('groupFields', groupFields.join(','));\n params.set('groupSeparator', groupSeparator ?? ' ');\n }\n if (dataSource === 'group' && groupName) params.set('groupName', groupName);\n if (dataSource === 'lookup' && lookup?.collection) {\n params.set('lookupCollection', lookup.collection);\n if (lookup.displayField) params.set('lookupField', lookup.displayField);\n }\n // Source Candidate Boolean Search is tenant-scoped and does not use the\n // generic submissions dropdown scope. Route only this module to its dedicated\n // candidate endpoint so the filter options come from the same collection and\n // scope as /candidates/boolean-search.\n if (String(baseModule).trim().toLowerCase() === 'sourcecandidates') {\n return authapiGet(`/candidates/filter-dropdown-values?${params}`);\n }\n return apiGet(`/filter-dropdown-values?${params}`);\n}\n\nexport async function getDashboardOnboardingCount(\n payload,\n limit = 10,\n offset = 0\n) {\n const headers = await authHeaders();\n\n const response = await fetch(\n `${SUBMISSIONS_URL}/dashboard-onboarding-count?offset=${offset}&limit=${limit}`,\n {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n }\n );\n\n const json = await response.json();\n return json.data ?? json;\n}\n\nexport async function getJobs({\n jobStatus = 'active',\n jobRecruitmentStatus = 'unread',\n limit = 50,\n offset = 0,\n userId = 1,\n sortBy = 'id',\n} = {}) {\n const headers = await authHeaders();\n\n const params = new URLSearchParams({\n jobStatus,\n jobRecruitmentStatus,\n limit: String(limit),\n offset: String(offset),\n userId: String(userId),\n sortBy,\n });\n\n const response = await fetch(\n `${JOBS_URL}/jobs?${params.toString()}`,\n {\n method: 'GET',\n headers,\n }\n );\n\n if (!response.ok) {\n throw new Error(`API ${response.status}: ${response.statusText}`);\n }\n\n const json = await response.json();\n return json.data ?? json;\n}\n\n\nfunction extractFormGroups(json) {\n const payload = json?.data ?? json;\n const groups = Array.isArray(payload) ? payload\n : Array.isArray(payload?.groups) ? payload.groups\n : Array.isArray(json?.groups) ? json.groups\n : [];\n // The backend attaches the loaded record's audit stamps (createdAt/updatedAt)\n // as recordMeta when an id was supplied. Ride it along on the groups array so\n // callers that only ever see the array (the detail header) can still show\n // \"Created on …\" without audit fields having to exist as form fields.\n const recordMeta = payload?.recordMeta ?? json?.recordMeta;\n if (recordMeta && typeof recordMeta === 'object') groups.recordMeta = recordMeta;\n const previewConfig = payload?.previewConfig ?? json?.previewConfig;\n if (previewConfig && typeof previewConfig === 'object') groups.previewConfig = previewConfig;\n return groups;\n}\n\nexport async function getFormGroups({\n module,\n id,\n view,\n clientId,\n region,\n candidateVersionId,\n} = {}) {\n if (!module) throw new Error('module is required to fetch form groups');\n\n const headers = await authHeaders();\n\n const params = new URLSearchParams({\n module,\n });\n\n // When an id is supplied, the backend embeds each field's actual record value\n // (field.value) in the response, so no separate detail-view call is needed.\n if (id) params.set('id', String(id));\n\n // `view=detail` opts into detail-view shaping: the backend resolves references\n // to { id, value }, shapes documents into full objects, AND applies the admin\n // Detail-Groups config (label/colour/prefix/hidden/lookups/merges). Without it\n // the admin's customizations never reach the detail view. Forwarded only when\n // provided, so add/edit-form callers keep the raw scalar values.\n if (view) params.set('view', String(view));\n if (clientId) params.set('clientId', String(clientId));\n if (region) params.set('region', String(region));\n if (candidateVersionId) params.set('candidateVersionId', candidateVersionId);\n\n // Shared with the form-side fetcher (services/formGroupsCache): the detail\n // header, the detail body and the form on the same page routinely ask for the\n // SAME payload, and these are 15-60 kB responses. Keyed by the finished URL,\n // which both fetchers build in the same parameter order, so an identical\n // question collapses to one request no matter which of them asked it — and a\n // different `view`/scope stays a different entry.\n const url = `${AUTH_URL}/admin/form-groups?${params.toString()}`;\n const json = await fetchFormGroupsCached(url, async () => {\n const response = await fetch(url, { method: 'GET', headers });\n if (!response.ok) {\n // `.status` is what isRecordUnavailableError (detail/recordAccess.js)\n // reads to decide whether a fetch failure means \"you cannot see this\n // record\" — the CENTERED CARD page, same treatment as AuthGuard's \"not\n // logged in\" screen — rather than the raw technical Alert. A bare\n // `new Error(...)` here left `.status` undefined, so a genuine 404 for\n // a cross-tenant record NEVER matched, and the detail page fell through\n // to showing \"Unable to load detail fields / API 404: Not Found\"\n // verbatim instead of the proper unavailable-record page.\n const error = new Error(`API ${response.status}: ${response.statusText}`);\n error.status = response.status;\n throw error;\n }\n return response.json();\n });\n return extractFormGroups(json);\n}\n\nexport async function getCandidateFormGroups(options = {}) {\n return getFormGroups({ module: 'candidates', ...options });\n}\n\nconst MODULE_EDIT_CONFIG = {\n job: {\n fetchUrl: (id) => `${JOBS_URL}/edit/detailed-view/${encodeURIComponent(id)}`,\n updateUrl: (id) => `${JOBS_URL}/edit/${encodeURIComponent(id)}`,\n },\n candidates: {\n fetchUrl: (id) => `${CANDIDATES_URL}/edit/detailed-view?_id=${encodeURIComponent(id)}`,\n updateUrl: (id) => `${CANDIDATES_URL}/update?_id=${encodeURIComponent(id)}`,\n },\n};\n\n\n\n\n\nexport async function getRecordForEdit(module, id) {\n if (!module) throw new Error('module is required');\n if (!id) throw new Error('id is required');\n\n const config = MODULE_EDIT_CONFIG[module];\n if (!config) throw new Error(`No edit config for module: ${module}`);\n\n const token = await ensureToken();\n const response = await fetch(config.fetchUrl(id), {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) throw new Error(`API ${response.status}: ${response.statusText}`);\n\n const json = await response.json();\n return json.data ?? json;\n}\n\n\n\n\n\n\nexport async function updateRecord(module, id, payload) {\n if (!module) throw new Error('module is required');\n if (!id) throw new Error('id is required');\n\n const config = MODULE_EDIT_CONFIG[module];\n if (!config) throw new Error(`No edit config for module: ${module}`);\n\n const token = await ensureToken();\n\n const formData = new FormData();\n formData.append('json', JSON.stringify(payload));\n\n const response = await fetch(config.updateUrl(id), {\n method: 'PUT',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n body: formData,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error('[updateRecord] Error response:', errorText);\n throw new Error(errorText || `API ${response.status}: ${response.statusText}`);\n }\n\n // A successful write makes every cached form-groups payload for this record\n // stale, and the caller usually reads one straight back.\n invalidateFormGroupsCache();\n\n const json = await response.json();\n return json.data ?? json;\n}\n\n\n\nexport async function uploadJobAttachment(recordId, file) {\n const token = await ensureToken();\n\n const formData = new FormData();\n formData.append('jobId', recordId);\n formData.append('file', file);\n\n const response = await fetch(`${JOBS_URL}/jobs/${recordId}/attachment`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n // DO NOT set Content-Type — browser sets it with boundary automatically\n },\n body: formData,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(errorText || `API ${response.status}: ${response.statusText}`);\n }\n\n const json = await response.json();\n return json.data ?? json;\n}\n\nexport async function addNotes({ notes, notesfor, receiver, notesRelatedId }) {\n const tenantId = localStorage.getItem('tenantId') || '93c782a4aa626175e5d11afa';\n const businessId = localStorage.getItem('businessId') || '83c782a4aa626175e5d11afa';\n const businessUnitId = localStorage.getItem('businessUnitId') || '63b57588fd768a839dbc0f63';\n\n return fetchJsonWithAuth(JOBS_URL, '/notes', {\n method: 'POST',\n body: JSON.stringify({\n schemaVersion: 1,\n tenantId,\n businessId,\n businessUnitId,\n notes,\n notesfor,\n receiver: receiver ?? [],\n notesRelatedId,\n }),\n });\n}\n\nexport async function getCandidateGroups() {\n return fetchJsonWithAuth(AUTH_URL, '/masters/dropdown?masterName=candidateGroups&offset=0&limit=50');\n}\n\nexport async function getSelfAssignData(jobId) {\n return apiGetWithAuth(JOBS_URL, `/self-assign?jobId=${encodeURIComponent(jobId)}`);\n}\n\nexport async function getManagerUsers() {\n const response = await apiGetWithAuth(JOBS_URL, '/users/manager');\n if (Array.isArray(response)) return response;\n return response ? [response] : [];\n}\n\nexport async function getRecruiterUsers(managerId = 0) {\n return apiGetWithAuth(JOBS_URL, `/users/recruiter/${encodeURIComponent(managerId)}`);\n}\n\nexport async function selfAssignJob({ multiJobId, userId, schemaVersion, closureRating, jobPayDetails, priority, priorityFrom, recruitersData }) {\n return fetchJsonWithAuth(JOBS_URL, '/assign?type=self', {\n method: 'PUT',\n body: JSON.stringify({\n multiJobId,\n userId: Number(userId),\n schemaVersion,\n closureRating,\n jobPayDetails,\n priority: String(priority ?? false),\n priorityFrom: priorityFrom ?? '',\n recruitersData: (recruitersData ?? []).map(Number).filter(Number.isInteger),\n }),\n });\n}\n\nexport async function assignJobToUser({ multiJobId, userId, schemaVersion, closureRating, jobPayDetails, priority, priorityFrom, recruitersData }) {\n return fetchJsonWithAuth(JOBS_URL, '/assign?type=other', {\n method: 'PUT',\n body: JSON.stringify({\n multiJobId,\n userId: Number(userId),\n schemaVersion,\n closureRating,\n jobPayDetails,\n priority: String(priority ?? false),\n priorityFrom: priorityFrom ?? '',\n recruitersData: (recruitersData ?? []).map(Number).filter(Number.isInteger),\n }),\n });\n}\n\nexport async function addToGroup({ candidateIds, groupId, groupName }) {\n return fetchJsonWithAuth(CANDIDATES_URL, '/actions/update-group', {\n method: 'PUT',\n body: JSON.stringify({ candidateIds, groupId, groupName }),\n });\n}\n\n\nexport async function getJobList({ searchQuery, candidateId }) {\n const tenantId = localStorage.getItem('tenantId') || '93c782a4aa626175e5d11afa';\n const businessId = localStorage.getItem('businessId') || '83c782a4aa626175e5d11afa';\n const businessUnitId = localStorage.getItem('businessUnitId') || '63b57588fd768a839dbc0f63';\n const userId = Number(localStorage.getItem('userId')) || 1;\n\n return fetchJsonWithAuth(JOBS_URL, '/joblist', {\n method: 'POST',\n body: JSON.stringify({\n tenantId,\n businessId,\n businessUnitId,\n searchQuery,\n userId,\n candidateId: Array.isArray(candidateId) ? candidateId : [candidateId],\n }),\n });\n}\n\nexport async function tagToJob({ multiJobId, applicantId, updateStatus }) {\n const tenantId = localStorage.getItem('tenantId') || '93c782a4aa626175e5d11afa';\n const businessId = localStorage.getItem('businessId') || '83c782a4aa626175e5d11afa';\n const businessUnitId = localStorage.getItem('businessUnitId') || '63b57588fd768a839dbc0f63';\n const userId = Number(localStorage.getItem('userId')) || 9;\n\n return fetchJsonWithAuth(JOBS_URL, '/source/hiringStgUpdate', {\n method: 'PUT',\n body: JSON.stringify({\n tenantId,\n businessId,\n businessUnitId,\n multiJobId: Array.isArray(multiJobId) ? multiJobId : [multiJobId],\n applicantId: Array.isArray(applicantId) ? applicantId : [applicantId],\n updateStatus: String(updateStatus ?? '').toLowerCase(),\n updateStatusType: 'call',\n responseType: 'responded',\n hiriringStatusChangeType: 'tagToJobs',\n comments: '',\n userId,\n }),\n });\n}\n\nexport async function deleteJobDetails(jobIds) {\n const tenantId = localStorage.getItem('tenantId') || '93c782a4aa626175e5d11afa';\n const businessId = localStorage.getItem('businessId') || '83c782a4aa626175e5d11afa';\n const businessUnitId = localStorage.getItem('businessUnitId') || '63b57588fd768a839dbc0f63';\n\n return fetchJsonWithAuth(JOBS_URL, '/delete', {\n method: 'POST',\n body: JSON.stringify({\n schemaVersion: 1,\n tenantId,\n businessId,\n businessUnitId,\n jobId: jobIds,\n }),\n });\n}\n\nexport async function deleteCandidateData(ids) {\n const results = await Promise.all(\n ids.map((id) => fetchJsonWithAuth(CANDIDATES_URL, `/delete?_id=${encodeURIComponent(id)}`, { method: 'PUT' }))\n );\n return results[results.length - 1] ?? {};\n}\n\nexport async function deleteModuleData(module, ids) {\n return fetchJsonWithAuth(AUTH_URL, '/module-data-delete', {\n method: 'POST',\n body: JSON.stringify({ module, ids }),\n });\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 searchCandidates(payload, offset = 0, limit = 10) {\n console.log('[searchCandidates] Called with payload:', JSON.stringify(payload).substring(0, 200));\n \n const json = await fetchJsonWithAuth(\n JOBS_URL,\n `/source/hiring-candidate-list?offset=${offset}&limit=${limit}`,\n { method: 'POST', body: JSON.stringify(payload) }\n );\n \n console.log('[searchCandidates] Response received:', JSON.stringify(json).substring(0, 200));\n \n // Transform Dice responses to match Internal candidate format\n const selectedSource = payload?.selectedSource ?? [];\n const hasDiceSource = Array.isArray(selectedSource) && selectedSource.some(s => String(s).toLowerCase() === 'dice');\n \n console.log('[searchCandidates] selectedSource:', selectedSource);\n console.log('[searchCandidates] hasDiceSource:', hasDiceSource);\n \n if (hasDiceSource) {\n try {\n console.log('[searchCandidates] Dice source detected, transforming response...');\n console.log('[searchCandidates] Raw response structure:', json?.data?.data?.[0] ? Object.keys(json.data.data[0]) : 'No data');\n console.log('[searchCandidates] Raw skills sample:', JSON.stringify(json?.data?.data?.[0]?.skills).substring(0, 150));\n \n const { transformDiceResponseToInternalFormat } = await import('./diceCandidateMapper');\n const transformed = transformDiceResponseToInternalFormat(json, json);\n \n console.log('[searchCandidates] Transformed skills sample:', JSON.stringify(transformed?.data?.data?.[0]?.skills).substring(0, 150));\n console.log('[searchCandidates] Transformation complete');\n \n return transformed;\n } catch (error) {\n console.error('[searchCandidates] Dice transformation failed, returning raw response:', error);\n console.error('[searchCandidates] Error stack:', error.stack);\n // Fall through to return raw response if transformation fails\n }\n } else {\n console.log('[searchCandidates] No Dice source, returning raw response');\n }\n \n return json;\n}\n\nexport async function getPipelineCount({ jobId, offset = 0, limit = 1, searchValue = '' }) {\n const json = await fetchJsonWithAuth(\n JOBS_URL,\n `/source/hiring-candidate-list/pipeline?hiringType=pipeline&jobId=${jobId}&limit=${limit}&offset=${offset}&searchValue=${encodeURIComponent(searchValue)}`\n );\n return json?.data?.count ?? 0;\n}\n\nexport async function getShortlistedCount({ jobId, offset = 0, limit = 1, searchQuery = '' }) {\n const json = await fetchJsonWithAuth(\n JOBS_URL,\n `/source/hiring-candidate-list/pipeline?hiringType=shortlisted&jobId=${jobId}&limit=${limit}&offset=${offset}&searchQuery=${encodeURIComponent(searchQuery)}`\n );\n return json?.data?.count ?? 0;\n}\n\nexport async function getSubmittedCandidates(jobId) {\n const json = await fetchJsonWithAuth(SUBMISSIONS_URL, `/job-submissions?jobId=${jobId}`);\n return json?.data ?? [];\n}\n\nexport async function getPipelineCandidates({ jobId, offset = 0, limit = 50, searchValue = '' }) {\n const json = await fetchJsonWithAuth(\n JOBS_URL,\n `/source/hiring-candidate-list/pipeline?hiringType=pipeline&jobId=${jobId}&limit=${limit}&offset=${offset}&searchValue=${encodeURIComponent(searchValue)}`\n );\n return json;\n}\n\nexport async function getShortlistedCandidates({ jobId, offset = 0, limit = 50, searchQuery = '' }) {\n const json = await fetchJsonWithAuth(\n JOBS_URL,\n `/source/hiring-candidate-list/pipeline?hiringType=shortlisted&jobId=${jobId}&limit=${limit}&offset=${offset}&searchQuery=${encodeURIComponent(searchQuery)}`\n );\n return json;\n}\n\nexport async function quickSubmitDetailedView({ _id, tenantId, businessId, businessUnitId }) {\n const params = new URLSearchParams({ _id, tenantId, businessId, businessUnitId });\n return apiGetWithAuth(CANDIDATES_URL, `/detailed-view?${params.toString()}`);\n}\n"],"mappings":"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"}
|