mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-24 10:08:07 +07:00
continue dict test refnum/reftxt. add validation rule
This commit is contained in:
parent
a139c979e3
commit
795251d911
@ -6,6 +6,22 @@ import { cleanEmptyStrings } from "$lib/utils/cleanEmptyStrings";
|
||||
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({
|
||||
@ -101,6 +117,8 @@ export const refTxtInitialForm = {
|
||||
export const testDefaultErrors = {
|
||||
TestSiteCode: "Required",
|
||||
TestSiteName: "Required",
|
||||
Unit2: null,
|
||||
Decimal: null,
|
||||
};
|
||||
|
||||
export const testCalDefaultErrors = {};
|
||||
@ -224,8 +242,9 @@ export const testFormFields = [
|
||||
label: "Value Set",
|
||||
required: false,
|
||||
type: "select",
|
||||
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/v_category`,
|
||||
fullWidth: false
|
||||
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}`,
|
||||
fullWidth: false,
|
||||
autoFetch: false
|
||||
},
|
||||
]
|
||||
},
|
||||
@ -259,7 +278,8 @@ export const testFormFields = [
|
||||
key: "Decimal",
|
||||
label: "Decimal",
|
||||
required: false,
|
||||
type: "text",
|
||||
type: "number",
|
||||
validateOn: ["input"]
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
@ -11,10 +11,16 @@
|
||||
import RefNum from "./tabs/ref-num.svelte";
|
||||
import RefTxt from "./tabs/ref-txt.svelte";
|
||||
import Calculation from "./tabs/calculation.svelte";
|
||||
import { API } from "$lib/config/api";
|
||||
import { untrack } from "svelte";
|
||||
|
||||
let props = $props();
|
||||
|
||||
const { masterDetail, formFields, formActions, schema } = props.context;
|
||||
let previousTestType = $state('');
|
||||
|
||||
let previousRefType = $state('');
|
||||
|
||||
const { masterDetail, formFields, formActions, schema, initialForm } = props.context;
|
||||
|
||||
const { formState } = masterDetail;
|
||||
|
||||
@ -43,6 +49,12 @@
|
||||
|
||||
const actions = formActions(handlers);
|
||||
|
||||
const allColumns = formFields.flatMap(
|
||||
(section) => section.rows.flatMap(
|
||||
(row) => row.columns ?? []
|
||||
)
|
||||
);
|
||||
|
||||
let showConfirm = $state(false);
|
||||
|
||||
async function handleSave() {
|
||||
@ -127,6 +139,11 @@
|
||||
}
|
||||
});
|
||||
|
||||
let hiddenFields = $derived.by(() => {
|
||||
const resultType = formState?.form?.ResultType;
|
||||
return resultType !== "VSET" ? ["VSet"] : [];
|
||||
});
|
||||
|
||||
let refComponent = $derived.by(() => {
|
||||
const refType = formState.form.RefType;
|
||||
if (refType === 'RANGE' || refType === 'THOLD') return 'numeric';
|
||||
@ -134,6 +151,33 @@
|
||||
return null;
|
||||
});
|
||||
|
||||
const refTxtFormFieldsTransformed = $derived.by(() => {
|
||||
return refTxtFormFields.map(group => ({
|
||||
...group,
|
||||
rows: group.rows.map(row => ({
|
||||
...row,
|
||||
columns: row.columns.map(col => {
|
||||
if (col.key !== "RefTxt") return col;
|
||||
|
||||
if (formState.form.ResultType !== "VSET" || !formState.form.VSet) {
|
||||
return {
|
||||
...col,
|
||||
type: "textarea",
|
||||
optionsEndpoint: undefined
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...col,
|
||||
type: "select",
|
||||
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/${formState.form.VSet}`,
|
||||
fullWidth: false
|
||||
};
|
||||
})
|
||||
}))
|
||||
}));
|
||||
});
|
||||
|
||||
let activeTab = $state('definition');
|
||||
|
||||
$effect(() => {
|
||||
@ -142,6 +186,69 @@
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
for (const key of hiddenFields) {
|
||||
formState.form[key] = "";
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (formState.form.Factor && !formState.form.Unit2) {
|
||||
formState.errors.Unit2 = "Required";
|
||||
} else {
|
||||
formState.errors.Unit2 = null;
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const allColumns = formFields.flatMap(
|
||||
(section) => section.rows.flatMap(
|
||||
(row) => row.columns ?? []
|
||||
)
|
||||
);
|
||||
|
||||
untrack(() => {
|
||||
for (const col of allColumns) {
|
||||
if (!col.optionsEndpoint) continue;
|
||||
if (!col.optionsEndpoint || col.autoFetch === false) continue;
|
||||
|
||||
formState.fetchOptions?.(
|
||||
{
|
||||
key: col.key,
|
||||
optionsEndpoint: col.optionsEndpoint,
|
||||
valueKey: col.valueKey,
|
||||
labelKey: col.labelKey,
|
||||
},
|
||||
formState.form
|
||||
);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const currentTestType = formState.form.TestType;
|
||||
|
||||
if (previousTestType && currentTestType !== previousTestType) {
|
||||
calFormState.reset();
|
||||
refNumState.reset();
|
||||
refTxtState.reset();
|
||||
}
|
||||
|
||||
previousTestType = currentTestType;
|
||||
});
|
||||
|
||||
//masih error cek dulu
|
||||
$effect(() => {
|
||||
const currentRefType = formState.form.RefType;
|
||||
|
||||
if (previousRefType && currentRefType !== previousRefType) {
|
||||
console.log('rst');
|
||||
refNumState.reset();
|
||||
refTxtState.reset();
|
||||
}
|
||||
|
||||
previousRefType = currentRefType;
|
||||
});
|
||||
</script>
|
||||
|
||||
<FormPageContainer title="Create Test" {primaryAction} {secondaryActions} {actions}>
|
||||
@ -170,6 +277,7 @@
|
||||
mode="create"
|
||||
{disabledResultTypes}
|
||||
{disabledReferenceTypes}
|
||||
{hiddenFields}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="calculation">
|
||||
@ -186,7 +294,7 @@
|
||||
{#if refComponent === 'numeric'}
|
||||
<RefNum {refNumState} {refNumFormFields} refType={formState.form.RefType}/>
|
||||
{:else if refComponent === 'text'}
|
||||
<RefTxt {refTxtState} {refTxtFormFields} refType={formState.form.RefType}/>
|
||||
<RefTxt {refTxtState} refTxtFormFields={refTxtFormFieldsTransformed} refType={formState.form.RefType}/>
|
||||
{:else}
|
||||
<div class="h-full w-full flex items-center">
|
||||
<ReusableEmpty desc="Select a Reference Type" />
|
||||
|
||||
@ -99,7 +99,7 @@
|
||||
return found ? found.code : value;
|
||||
}
|
||||
|
||||
const txtRefTypeBadge = (type) => ({ TEXT: "TX", VSET: "V" }[type] ?? null);;
|
||||
const txtRefTypeBadge = (type) => ({ TEXT: "TX", VSET: "VS" }[type] ?? null);;
|
||||
|
||||
$effect(() => {
|
||||
if (props.refType) {
|
||||
|
||||
@ -19,9 +19,10 @@
|
||||
disabledResultTypes = [],
|
||||
disabledReferenceTypes = [],
|
||||
disabledSign = false,
|
||||
joinFields = $bindable()
|
||||
joinFields = $bindable(),
|
||||
hiddenFields,
|
||||
} = $props();
|
||||
|
||||
|
||||
let searchQuery = $state({});
|
||||
let dropdownOpen = $state({});
|
||||
|
||||
@ -77,6 +78,9 @@
|
||||
{#if required}
|
||||
<span class="text-destructive text-xl leading-none h-3.5">*</span>
|
||||
{/if}
|
||||
<!-- {#if required || dynamicRequiredFields.includes(key)}
|
||||
<span class="text-destructive text-xl leading-none h-3.5">*</span>
|
||||
{/if} -->
|
||||
</div>
|
||||
|
||||
<div class="relative flex flex-col items-center w-full">
|
||||
@ -94,7 +98,7 @@
|
||||
validateFieldAsync(key, mode, originalData?.[key]);
|
||||
}
|
||||
}}
|
||||
readonly={key === "NumRefType" || key === "TxtRefType"}
|
||||
readonly={key === "NumRefType" || key === "TxtRefType" || key === "Level"}
|
||||
/>
|
||||
{:else if type === "email"}
|
||||
<Input
|
||||
@ -125,6 +129,7 @@
|
||||
formState.validateField(key, formState.form[key], false);
|
||||
}
|
||||
}}
|
||||
onkeydown={(e) => ['e', 'E', '+', '-'].includes(e.key) && e.preventDefault()}
|
||||
/>
|
||||
{:else if type === "textarea"}
|
||||
<Textarea
|
||||
@ -218,7 +223,7 @@
|
||||
{#each filteredOptions as option}
|
||||
<Select.Item value={option.value}
|
||||
disabled={key === "ResultType" && disabledResultTypes.includes(option.value) ||
|
||||
key === "RefType" && disabledReferenceTypes.includes(option.value)}
|
||||
key === "RefType" && disabledReferenceTypes.includes(option.value)}
|
||||
>
|
||||
{option.label}
|
||||
</Select.Item>
|
||||
@ -394,10 +399,19 @@
|
||||
key === 'FormulaCode' ? 'top-20' : 'top-8'
|
||||
}`}
|
||||
>
|
||||
<!-- {#if formState.errors[key] || dynamicRequiredFields.includes(key)}
|
||||
<span class="text-destructive text-sm leading-none">
|
||||
{formState.errors[key]}
|
||||
</span>
|
||||
{/if} -->
|
||||
{#if formState.errors[key]}
|
||||
<span class="text-destructive text-sm leading-none">
|
||||
{formState.errors[key]}
|
||||
</span>
|
||||
<!-- {:else if dynamicRequiredFields.includes(key)}
|
||||
<span class="text-destructive text-sm leading-none">
|
||||
Required
|
||||
</span> -->
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@ -405,6 +419,52 @@
|
||||
{/snippet}
|
||||
|
||||
<div class="p-2 space-y-6">
|
||||
{#each formFields as group}
|
||||
<div class="space-y-6">
|
||||
{#if group.title}
|
||||
<div class="text-md 2xl:text-lg font-semibold italic">
|
||||
<span class="border-b-2 border-primary">{group.title}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#each group.rows as row}
|
||||
{@const visibleColumns = row.columns.filter(col => !hiddenFields?.includes(col.key))}
|
||||
|
||||
{#if visibleColumns.length > 0}
|
||||
<div
|
||||
class="grid grid-cols-1 space-y-2 gap-6 md:gap-4"
|
||||
class:md:grid-cols-1={visibleColumns.length === 1 && visibleColumns[0].fullWidth !== false}
|
||||
class:md:grid-cols-2={visibleColumns.length === 2 || (visibleColumns.length === 1 && visibleColumns[0].fullWidth === false)}
|
||||
class:md:grid-cols-3={visibleColumns.length === 3}
|
||||
>
|
||||
{#each visibleColumns as col}
|
||||
{#if col.type === "group"}
|
||||
{@const visibleChildColumns = col.columns.filter(child => !hiddenFields?.includes(child.key))}
|
||||
|
||||
{#if visibleChildColumns.length > 0}
|
||||
<div
|
||||
class="grid grid-cols-1 gap-6 md:gap-2"
|
||||
class:md:grid-cols-1={visibleChildColumns.length === 1 && visibleChildColumns[0].fullWidth !== false}
|
||||
class:md:grid-cols-2={visibleChildColumns.length === 2 || (visibleChildColumns.length === 1 && visibleChildColumns[0].fullWidth === false)}
|
||||
class:md:grid-cols-3={visibleChildColumns.length === 3}
|
||||
>
|
||||
{#each visibleChildColumns as child}
|
||||
{@render Fieldset(child)}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
{@render Fieldset(col)}
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<!-- <div class="p-2 space-y-6">
|
||||
{#each formFields as group}
|
||||
<div class="space-y-6">
|
||||
{#if group.title}
|
||||
@ -440,4 +500,4 @@
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div> -->
|
||||
@ -36,6 +36,9 @@ export async function load({ url }) {
|
||||
'/dictionary/workstation': {
|
||||
title: 'Workstation'
|
||||
},
|
||||
'/dictionary/test': {
|
||||
title: 'Test'
|
||||
},
|
||||
};
|
||||
|
||||
const config = routeConfig[url.pathname] || {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user