967 lines
27 KiB
JavaScript

import { API } from "$lib/config/api";
import EraserIcon from "@lucide/svelte/icons/eraser";
import { z } from "zod";
import { cleanEmptyStrings } from "$lib/utils/cleanEmptyStrings";
import { toDays } from "$lib/utils/ageUtils";
export const testSchema = z.object({
TestSiteCode: z.string().min(1, "Required"),
TestSiteName: z.string().min(1, "Required"),
Factor: z.string().optional(),
Unit2: z.string().optional(),
Decimal: z.preprocess((val) => {
if (val === "" || val === null || val === undefined) return undefined;
return Number(val);
},
z.number({invalid_type_error: "Must be a number"}).min(0, "Min 0").max(7, "Max 7").optional()
),
}).superRefine((data, ctx) => {
if (data.Factor && !data.Unit2) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Required",
path: ["Unit2"],
});
}
});
export const testCalSchema = z.object({
FormulaInput: z.array(z.string()),
FormulaCode: z.string()
}).refine(
(data) => {
if (data.FormulaInput.length === 0) return true;
function hasExactKeyword(input, keyword) {
const regex = new RegExp(`\\b${keyword}\\b`, 'i');
return regex.test(input);
}
return data.FormulaInput.every((v) => hasExactKeyword(data.FormulaCode, v));
},
{
message: 'Formula must contain all selected input parameters',
path: ['FormulaCode']
}
);
export const refNumSchema = z.object({
AgeStart: z.string().optional(),
AgeEnd: z.string().optional(),
Low: z.string().optional(),
High: z.string().optional(),
LowSign: z.string().optional(),
HighSign: z.string().optional(),
NumRefType: z.string().optional()
})
.superRefine((data, ctx) => {
const start = toDays(data.AgeStart);
const end = toDays(data.AgeEnd);
// if (start !== null && start > 0 && end !== null && end <= start) {
if (start !== null && end !== null && end <= start) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Age End must be greater than Age Start",
path: ["AgeEnd"],
});
}
})
.superRefine((data, ctx) => {
// console.log(data.NumRefType);
if (data.NumRefType === "RANGE") {
const low = Number(data.Low);
const high = Number(data.High);
if (
data.Low &&
data.High &&
!Number.isNaN(low) &&
!Number.isNaN(high) &&
(high <= low)
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "High value must be greater than Low value",
path: ["High"],
});
}
}
if (data.NumRefType === "THOLD") {
if (data.Low && !data.LowSign) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Math sign for Low is required",
path: ["LowSign"],
});
}
if (data.High && !data.HighSign) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Math sign for High is required",
path: ["HighSign"],
});
}
if (
data.LowSign &&
data.HighSign &&
data.LowSign === data.HighSign
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "High sign can't be the same as Low sign",
path: ["HighSign"],
});
}
}
})
export const refTxtSchema = z.object({
AgeStart: z.string().optional(),
AgeEnd: z.string().optional(),
})
.superRefine((data, ctx) => {
const start = toDays(data.AgeStart);
const end = toDays(data.AgeEnd);
if (start !== null && end !== null && end <= start) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Age End must be greater than Age Start",
path: ["AgeEnd"],
});
}
})
export const testMapSchema = z.object({
HostID: z.string().optional(),
ClientID: z.string().optional(),
})
.superRefine((data, ctx) => {
const hostID = data.HostID;
const clientID = data.ClientID;
if (hostID && clientID && hostID === clientID) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "ClientID must be different from HostID",
path: ["ClientID"],
});
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "HostID must be different from ClientID",
path: ["HostID"],
});
}
})
export const testInitialForm = {
TestSiteID: "",
SiteID: "",
TestSiteCode: "",
TestSiteName: "",
TestType: "",
Description: "",
DisciplineID: "",
DepartmentID: "",
ResultType: "",
RefType: "",
Vset: "",
Unit1: "",
Factor: "",
Unit2: "",
Decimal: "",
ReqQty: "",
ReqQtyUnit: "",
CollReq: "",
Method: "",
ExpectedTAT: "",
SeqScr: "",
SeqRpt: "",
VisibleScr: "",
VisibleRpt: "",
CountStat: "",
Level: "",
};
export const testCalInitialForm = {
TestCalID: "",
TestSiteID: "",
FormulaInput: "",
FormulaCode: ""
}
export const refNumInitialForm = {
RefNumID: "",
SiteID: "",
TestSiteID: "",
SpcType: "",
Sex: "",
Criteria: "",
AgeStart: "",
AgeEnd: "",
NumRefType: "",
RangeType: "",
LowSign: "",
Low: "",
HighSign: "",
High: "",
Display: "",
Flag: "",
Interpretation: "",
Notes: "",
}
export const refTxtInitialForm = {
RefTxtID: "",
SiteID: "",
TestSiteID: "",
SpcType: "",
Sex: "",
Criteria: "",
AgeStart: "",
AgeEnd: "",
TxtRefType: "",
RefTxt: "",
Flag: "",
Notes: "",
};
export const testMapInitialForm = {
TestMapID: "",
HostType: "",
HostID: "",
HostTestCode: "",
HostTestName: "",
ClientType: "",
ClientID: "",
ClientTestCode: "",
ClientTestName: "",
ConDefID: "",
}
export const testDefaultErrors = {
TestSiteCode: "Required",
TestSiteName: "Required",
Unit2: null,
Decimal: null,
};
export const testCalDefaultErrors = {};
export const refNumDefaultErrors = {
AgeStart: null,
AgeEnd: null,
Low: null,
High: null,
LowSign: null,
HighSign: null,
};
export const refTxtDefaultErrors = {
AgeStart: null,
AgeEnd: null,
};
export const testMapDefaultErrors = {
HostID: null,
ClientID: null,
}
export const testFormFields = [
{
title: "Basic Information",
rows: [
{
type: "row",
columns: [
{
key: "SiteID",
label: "Site ID",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
valueKey: "SiteID",
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`,
},
{
key: "TestSiteCode",
label: "Test Code",
required: true,
type: "text",
validateOn: ["input"]
}
]
},
{
type: "row",
columns: [
{
key: "TestSiteName",
label: "Test Name",
required: true,
type: "text",
validateOn: ["input"]
},
{
key: "TestType",
label: "Test Type",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/test_type`,
}
]
},
{
type: "row",
columns: [
{
key: "Description",
label: "Description",
required: false,
type: "textarea",
},
]
},
]
},
{
title: "Organizational Assignment",
rows: [
{
type: "row",
columns: [
{
key: "DisciplineID",
label: "Discipline",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.DISCIPLINE}`,
valueKey: "DisciplineID",
labelKey: "DisciplineName",
},
{
key: "DepartmentID",
label: "Department",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.DEPARTMENT}`,
valueKey: "DepartmentID",
labelKey: "DepartmentName",
},
]
},
]
},
{
title: "Result Configuration",
rows: [
{
type: "row",
columns: [
{
key: "ResultType",
label: "Result Type",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/result_type`,
},
{
key: "RefType",
label: "Reference Type",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/reference_type`,
}
]
},
{
type: "row",
columns: [
{
key: "VSet",
label: "Value Set",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}`,
fullWidth: false,
autoFetch: false
},
]
},
{
type: "row",
columns: [
{
key: "Unit1",
label: "Unit 1",
required: false,
type: "text",
},
{
key: "Factor",
label: "Factor",
required: false,
type: "text",
},
]
},
{
type: "row",
columns: [
{
key: "Unit2",
label: "Unit 2",
required: false,
type: "text",
},
{
key: "Decimal",
label: "Decimal",
required: false,
type: "number",
validateOn: ["input"]
},
]
},
{
type: "row",
columns: [
{
key: "ExpectedTAT",
label: "Expected TAT",
required: false,
type: "text",
fullWidth: false
},
]
},
]
},
{
title: "Specimen Requirements",
rows: [
{
type: "row",
columns: [
{
key: "ReqQty",
label: "Required Quantity",
required: false,
type: "text",
},
{
key: "CollReq",
label: "Collection Requirement",
required: false,
type: "text",
},
]
},
{
type: "row",
columns: [
{
key: "ReqQtyUnit",
label: "Quantity Unit",
required: false,
type: "text",
},
{
key: "Method",
label: "Method",
required: false,
type: "text",
},
]
},
]
},
{
title: "Display Settings",
rows: [
{
type: "row",
columns: [
{
key: "SeqScr",
label: "Sequence on Screen",
required: false,
type: "text",
},
{
key: "VisibleScr",
label: "Visible on Screen",
required: false,
type: "text",
},
]
},
{
type: "row",
columns: [
{
key: "SeqRpt",
label: "Sequence on Report",
required: false,
type: "text",
},
{
key: "VisibleRpt",
label: "Visible on Report",
required: false,
type: "text",
},
]
},
]
},
{
title: "Other Settings",
rows: [
{
type: "row",
columns: [
{
key: "CountStat",
label: "Statistic",
required: false,
type: "text",
},
{
key: "Level",
label: "Level",
required: false,
type: "text",
},
]
},
]
},
];
export const testCalFormFields = [
{
rows: [
{
type: "row",
columns: [
{
key: "FormulaInput",
label: "Input Parameter",
required: false,
type: "selectmultiple",
optionsEndpoint: `${API.BASE_URL}${API.TEST}`,
valueKey: "TestSiteID",
labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`,
},
]
},
{
type: "row",
columns: [
{
key: "FormulaCode",
label: "Formula",
required: false,
type: "textarea",
validateOn: ["input"]
}
]
},
]
},
];
export const refNumFormFields = [
{
rows: [
{
type: "row",
columns: [
{
key: "SiteID",
label: "Site",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
valueKey: "SiteID",
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`,
fullWidth: false
},
]
}
]
},
{
title: "Criteria Definition",
rows: [
{
type: "row",
columns: [
{
key: "Sex",
label: "Sex",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/sex`,
},
{
key: "SpcType",
label: "Specimen Type",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/specimen_type`,
},
]
},
{
type: "row",
columns: [
{
key: "AgeStart",
label: "Age Start",
required: false,
type: "agejoin",
validateOn: ["input"]
},
{
key: "AgeEnd",
label: "Age End",
required: false,
type: "agejoin",
validateOn: ["input"]
},
]
},
]
},
{
title: "Reference Range Configuration",
rows: [
{
type: "row",
columns: [
{
key: "NumRefType",
label: "Reference Type",
required: false,
type: "text",
},
{
key: "RangeType",
label: "Range Type",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/range_type`,
},
]
},
{
type: "row",
columns: [
{
key: "LowSign",
label: "Low Sign - Value",
required: false,
type: "signvalue",
txtKey: "Low",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/math_sign`,
validateOn: ["input"]
},
{
key: "HighSign",
label: "High Sign - Value",
required: false,
type: "signvalue",
txtKey: "High",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/math_sign`,
validateOn: ["input"]
},
]
},
]
},
{
title: "Flag & Interpretation",
rows: [
{
type: "row",
columns: [
{
key: "Flag",
label: "Flag",
required: false,
type: "text",
},
{
key: "Interpretation",
label: "Interpretation",
required: false,
type: "text",
},
]
},
{
type: "row",
columns: [
{
key: "Notes",
label: "Notes",
required: false,
type: "textarea",
},
]
},
]
},
];
export const refTxtFormFields = [
{
rows: [
{
type: "row",
columns: [
{
key: "SiteID",
label: "Site",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
valueKey: "SiteID",
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`,
fullWidth: false
},
]
}
]
},
{
title: "Criteria Definition",
rows: [
{
type: "row",
columns: [
{
key: "Sex",
label: "Sex",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/sex`,
},
{
key: "SpcType",
label: "Specimen Type",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/specimen_type`,
},
]
},
{
type: "row",
columns: [
{
key: "AgeStart",
label: "Age Start",
required: false,
type: "agejoin",
validateOn: ["input"]
},
{
key: "AgeEnd",
label: "Age End",
required: false,
type: "agejoin",
validateOn: ["input"]
},
]
},
]
},
{
title: "Reference Range Configuration",
rows: [
{
type: "row",
columns: [
{
key: "TxtRefType",
label: "Reference Type",
required: false,
type: "text",
fullWidth: false
},
]
},
{
type: "row",
columns: [
{
key: "RefTxt",
label: "Reference Text",
required: false,
type: "textarea",
},
]
},
]
},
{
title: "Flag & Notes",
rows: [
{
type: "row",
columns: [
{
key: "Flag",
label: "Flag",
required: false,
type: "text",
fullWidth: false
},
]
},
{
type: "row",
columns: [
{
key: "Notes",
label: "Notes",
required: false,
type: "textarea",
},
]
},
]
},
];
export const testMapFormFields = [
{
title: "Host & Client Information",
rows: [
{
type: "row",
columns: [
{
key: "HostType",
label: "Host Type",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/entity_type`,
},
{
key: "ClientType",
label: "Client Type",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/entity_type`,
},
]
},
{
type: "row",
columns: [
{
key: "HostID",
label: "Host ID",
required: false,
type: "text",
validateOn: ["input"]
},
{
key: "ClientID",
label: "Client ID",
required: false,
type: "text",
validateOn: ["input"]
}
]
},
{
type: "row",
columns: [
{
key: "HostTestCode",
label: "Host Test Code",
required: false,
type: "text",
},
{
key: "ClientTestCode",
label: "Client Test Code",
required: false,
type: "text",
}
]
},
{
type: "row",
columns: [
{
key: "HostTestName",
label: "Host Test Name",
required: false,
type: "text",
},
{
key: "ClientTestName",
label: "Client Test Name",
required: false,
type: "text",
}
]
},
{
type: "row",
columns: [
{
key: "ConDefID",
label: "Container Definition",
required: false,
type: "select",
optionsEndpoint: `${API.BASE_URL}${API.CONTAINER}`,
valueKey: "ConDefID",
labelKey: (item) => `${item.ConCode} - ${item.ConName}`,
fullWidth: false
},
]
},
]
},
]
export function getTestFormActions(handlers) {
return [
{
Icon: EraserIcon,
label: 'Clear Form',
onClick: handlers.clearForm,
},
];
}
export function buildTestPayload({
mainForm,
calForm,
refForm,
testType
}) {
let payload = {
...mainForm
};
if (testType === 'CALC') {
payload = {
...payload,
...calForm
};
} else if (testType === 'TEST' || 'PARAM') {
payload = {
...payload,
...refForm
}
}
return cleanEmptyStrings(payload);
}