diff --git a/src/lib/components/dictionary/test/config/test-form-config.js b/src/lib/components/dictionary/test/config/test-form-config.js index 9f2d136..0ac6e67 100644 --- a/src/lib/components/dictionary/test/config/test-form-config.js +++ b/src/lib/components/dictionary/test/config/test-form-config.js @@ -73,6 +73,10 @@ export const testCalSchema = z } }); +export const testGroupSchema = z.object({ + Member: z.string().optional() + }); + export const refNumSchema = z .object({ AgeStart: z.string().optional(), @@ -212,6 +216,12 @@ export const testCalInitialForm = { FormulaCode: '' }; +export const testGroupInitialForm = { + TestGrpID: '', + TestSiteID: '', + Member: '', +} + export const refNumInitialForm = { RefNumID: '', SiteID: '', @@ -270,9 +280,13 @@ export const testDefaultErrors = { export const testCalDefaultErrors = { FormulaInput: 'Required', - FormulaCode: null + FormulaCode: null, }; +export const testGroupDefaultErrors = { + Member: null, +} + export const refNumDefaultErrors = { AgeStart: null, AgeEnd: null, @@ -597,6 +611,28 @@ export const testCalFormFields = [ } ]; +export const testGroupFormFields = [ + { + rows: [ + { + type: 'row', + columns: [ + { + key: 'Member', + label: 'Member Test', + required: false, + type: 'members', + optionsEndpoint: `${API.BASE_URL}${API.TEST}`, + valueKey: 'TestSiteCode', + labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`, + validateOn: ['input'] + } + ] + }, + ] + } +]; + export const refNumFormFields = [ { rows: [ @@ -1013,21 +1049,25 @@ export function getTestFormActions(handlers) { // return cleanEmptyStrings(payload); // } -export function buildTestPayload({ mainForm, activeFormStates, testType }) { - let payload = { - ...mainForm - }; +export function buildTestPayload({ mainForm, activeFormStates, testType, refNumData, refTxtData }) { + let payload = { + ...mainForm + }; - for (const key in activeFormStates) { + for (const key in activeFormStates) { const state = activeFormStates[key]; - if (state?.form) { + if (key === 'refNum' && refNumData?.length > 0) { + payload[key] = refNumData; + } else if (key === 'refTxt' && refTxtData?.length > 0) { + payload[key] = refTxtData; + + } else if (state?.form) { payload[key] = { ...state.form }; } } - - return cleanEmptyStrings(payload); + return cleanEmptyStrings(payload); } diff --git a/src/lib/components/dictionary/test/page/create-page.svelte b/src/lib/components/dictionary/test/page/create-page.svelte index 3154a92..b09f8e8 100644 --- a/src/lib/components/dictionary/test/page/create-page.svelte +++ b/src/lib/components/dictionary/test/page/create-page.svelte @@ -1,502 +1,524 @@ - - - {#if availableTabs.includes('definition')} - Definition - {/if} - {#if availableTabs.includes('calculation')} - Calculation - {/if} - {#if availableTabs.includes('group')} - Group - {/if} - {#if availableTabs.includes('reference')} - Reference - {/if} - {#if availableTabs.includes('map')} - Map - {/if} - - - + + + {#if availableTabs.includes('definition')} + Definition + {/if} + {#if availableTabs.includes('calculation')} + Calculation + {/if} + {#if availableTabs.includes('group')} + Group + {/if} + {#if availableTabs.includes('reference')} + Reference + {/if} + {#if availableTabs.includes('map')} + Map + {/if} + + + + + + + + + - - - - - group - - - - - -
- {#if refComponent === 'numeric'} - - {:else if refComponent === 'text'} - - {:else} -
- -
- {/if} -
-
-
- + + + + +
+ {#if refComponent === 'numeric'} + + {:else if refComponent === 'text'} + + {:else} +
+ +
+ {/if} +
+
+
\ No newline at end of file + bind:open={masterDetail.showExitConfirm} + onConfirm={masterDetail.confirmExit} +/> diff --git a/src/lib/components/dictionary/test/page/tabs/calculation.svelte b/src/lib/components/dictionary/test/page/tabs/calculation.svelte index 077d943..87945ba 100644 --- a/src/lib/components/dictionary/test/page/tabs/calculation.svelte +++ b/src/lib/components/dictionary/test/page/tabs/calculation.svelte @@ -9,154 +9,11 @@ import DictionaryFormRenderer from '$lib/components/reusable/form/dictionary-form-renderer.svelte'; let props = $props(); - - // const formState = props.calFormState; - - // let options = $state([]); - // let isLoading = $state(false); - // let errors = $state({}); - - // function hasExactKeyword(input, keyword) { - // const regex = new RegExp(`\\b${keyword}\\b`, 'i'); - // return regex.test(input); - // } - - // // 🔹 FETCH OPTIONS - // async function fetchTests() { - // isLoading = true; - // try { - // const res = await fetch(`${API.BASE_URL}${API.TEST}`); - // const data = await res.json(); - // console.log(data); - - // options = data.data.map((item) => ({ - // value: item.TestSiteCode, - // label: `${item.TestSiteCode} - ${item.TestSiteName}` - // })); - // } catch (err) { - // console.error('Failed to fetch tests', err); - // } finally { - // isLoading = false; - // } - // } - - // $effect(() => { - // fetchTests(); - // }); - - // // 🔹 VALIDATION - // $effect(() => { - // const result = testCalSchema.safeParse(formState.form); - - // if (!result.success) { - // const fieldErrors = {}; - // for (const issue of result.error.issues) { - // fieldErrors[issue.path[0]] = issue.message; - // } - // errors = fieldErrors; - // } else { - // errors = {}; - // } - // }); - - // // 🔹 Badge status - // const inputStatus = $derived.by(() => { - // const inputs = formState.form.FormulaInput || []; - // const code = formState.form.FormulaCode || ''; - - // return inputs.map((v) => ({ - // value: v, - // done: hasExactKeyword(code, v) - // })); - // }); - - // function unselectAll() { - // formState.form.FormulaInput = []; - // errors = {}; - // }
- - - diff --git a/src/lib/components/dictionary/test/page/tabs/group.svelte b/src/lib/components/dictionary/test/page/tabs/group.svelte new file mode 100644 index 0000000..75ecc4f --- /dev/null +++ b/src/lib/components/dictionary/test/page/tabs/group.svelte @@ -0,0 +1,25 @@ + + +
+ +
\ No newline at end of file diff --git a/src/lib/components/dictionary/test/page/tabs/ref-num.svelte b/src/lib/components/dictionary/test/page/tabs/ref-num.svelte index a5054e1..ada7670 100644 --- a/src/lib/components/dictionary/test/page/tabs/ref-num.svelte +++ b/src/lib/components/dictionary/test/page/tabs/ref-num.svelte @@ -1,307 +1,301 @@
-
- -
- {#if editingId !== null} - - - {:else} - - {/if} -
-
+
+ +
+ {#if editingId !== null} + + + {:else} + + {/if} +
+
- + -
- - - - Specimen Type - Sex - Age Range - Type - Range/Threshold - Flag - Interpretation - Notes - - - - - {#if tempNumeric.length === 0} - - - No data. Fill the form above and click Insert. - - - {:else} - {#each tempNumeric as row (row.id)} - - {row.SpcType ? getLabel("SpcType", row.SpcType) : "-"} - {row.Sex ? getLabel("Sex", row.Sex) : "-"} - {row.AgeStart} – {row.AgeEnd} - - {#if rangeTypeBadge(row.RangeType)} - {rangeTypeBadge(row.RangeType)} - {:else} - - - {/if} - - -
- {row.LowSign ? row.LowSign : ""} {row.Low || "null"} – - {row.HighSign ? row.HighSign : ""} {row.High || "null"} -
- {numRefTypeBadge(row.NumRefType)} -
- {row.Flag} - {row.Interpretation} - {row.Notes} - -
- - -
-
-
- {/each} - {/if} -
-
-
-
\ No newline at end of file +
+ + + + Specimen Type + Sex + Age Range + Type + Range/Threshold + Flag + Interpretation + Notes + + + + + {#if tempNumeric.length === 0} + + + No data. Fill the form above and click Insert. + + + {:else} + {#each tempNumeric as row (row.id)} + + {row.SpcType ? getLabel('SpcType', row.SpcType) : '-'} + {row.Sex ? getLabel('Sex', row.Sex) : '-'} + {row.AgeStart} – {row.AgeEnd} + + {#if rangeTypeBadge(row.RangeType)} + {rangeTypeBadge(row.RangeType)} + {:else} + - + {/if} + + +
+ {row.LowSign ? row.LowSign : ''} + {row.Low || 'null'} – + {row.HighSign ? row.HighSign : ''} + {row.High || 'null'} +
+ {numRefTypeBadge(row.NumRefType)} +
+ {row.Flag} + {row.Interpretation} + {row.Notes} + +
+ + +
+
+
+ {/each} + {/if} +
+
+
+ diff --git a/src/lib/components/dictionary/test/page/tabs/ref-txt.svelte b/src/lib/components/dictionary/test/page/tabs/ref-txt.svelte index 2bd687f..09eb594 100644 --- a/src/lib/components/dictionary/test/page/tabs/ref-txt.svelte +++ b/src/lib/components/dictionary/test/page/tabs/ref-txt.svelte @@ -10,9 +10,8 @@ import { untrack } from "svelte"; import { toDays } from "$lib/utils/ageUtils"; - let { resetRefTxt = $bindable(), ...props } = $props() + let { tempTxt = $bindable([]), resetRefTxt = $bindable(), ...props } = $props() - let tempTxt = $state([]); let editingId = $state(null); let idCounter = $state(0); diff --git a/src/lib/components/reusable/form/dictionary-form-renderer.svelte b/src/lib/components/reusable/form/dictionary-form-renderer.svelte index c628dd8..29fa9bd 100644 --- a/src/lib/components/reusable/form/dictionary-form-renderer.svelte +++ b/src/lib/components/reusable/form/dictionary-form-renderer.svelte @@ -15,6 +15,8 @@ import MoveRightIcon from '@lucide/svelte/icons/move-right'; import BrushCleaningIcon from '@lucide/svelte/icons/brush-cleaning'; import DeleteIcon from '@lucide/svelte/icons/delete'; + import Trash2Icon from '@lucide/svelte/icons/trash-2'; + import PlusIcon from '@lucide/svelte/icons/plus'; let { formState, @@ -27,7 +29,10 @@ hiddenFields, handleTestTypeChange, handleResultTypeChange, - handleRefTypeChange + handleRefTypeChange, + members = [], + onAddMember, + onRemoveMember, } = $props(); const operators = ['+', '-', '*', '/', '^', '(', ')']; @@ -610,6 +615,69 @@ {/if} + {:else if type === "members"} + {@const filteredOptions = getFilteredOptions(key)} +
+ {#each members as member, index (member.id)} + {@const selectedLabel = + formState.selectOptions?.[key]?.find( + (opt) => opt.value === member.value + )?.label || 'Choose'} +
+ + +
+ { + if (open && optionsEndpoint) { + formState.fetchOptions?.( + { key, optionsEndpoint, dependsOn, endpointParamKey, valueKey, labelKey }, + formState.form + ); + } + }} + > + + {selectedLabel} + + +
+ +
+ {#if formState.loadingOptions?.[key]} + Loading... + {:else} + {#if !required} + - None - + {/if} + {#each filteredOptions as option} + + {option.label} + + {/each} + {/if} +
+
+
+ +
+ {/each} + +
{:else}