mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-26 02:46:32 +07:00
fix multiple
fix tab selalu muncul di payload fix rule overlap sekarang berdasarkan kondisi rangetype ubah calc input param not required, nambahin result button
This commit is contained in:
parent
0c0bbd6e26
commit
5cab6097a9
@ -23,7 +23,18 @@ export const searchFields = [
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const detailSections = [];
|
export const detailSections = [
|
||||||
|
{
|
||||||
|
class: "grid grid-cols-2 gap-4 items-center",
|
||||||
|
fields: [
|
||||||
|
{ key: "SiteID", label: "Site" },
|
||||||
|
{ key: "TestSiteCode", label: "Test Code" },
|
||||||
|
{ key: "TestSiteName", label: "Test Name" },
|
||||||
|
{ key: "TestType", label: "Test Type" },
|
||||||
|
{ key: "Description", label: "Description" },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export function testActions(masterDetail) {
|
export function testActions(masterDetail) {
|
||||||
return [
|
return [
|
||||||
|
|||||||
@ -41,7 +41,7 @@ export const testCalSchema = z
|
|||||||
level: z.preprocess((val) => (val ? Number(val) : 0), z.number())
|
level: z.preprocess((val) => (val ? Number(val) : 0), z.number())
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.min(1, 'Required'),
|
.optional(),
|
||||||
FormulaCode: z.string().optional()
|
FormulaCode: z.string().optional()
|
||||||
})
|
})
|
||||||
.superRefine((data, ctx) => {
|
.superRefine((data, ctx) => {
|
||||||
@ -303,7 +303,7 @@ export const testDefaultErrors = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const testCalDefaultErrors = {
|
export const testCalDefaultErrors = {
|
||||||
FormulaInput: 'Required',
|
FormulaInput: null,
|
||||||
FormulaCode: null,
|
FormulaCode: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -611,7 +611,7 @@ export const testCalFormFields = [
|
|||||||
{
|
{
|
||||||
key: 'FormulaInput',
|
key: 'FormulaInput',
|
||||||
label: 'Input Parameter',
|
label: 'Input Parameter',
|
||||||
required: true,
|
required: false,
|
||||||
type: 'selectmultiple',
|
type: 'selectmultiple',
|
||||||
optionsEndpoint: `${API.BASE_URL}${API.TEST}`,
|
optionsEndpoint: `${API.BASE_URL}${API.TEST}`,
|
||||||
valueKey: 'TestSiteCode',
|
valueKey: 'TestSiteCode',
|
||||||
@ -726,19 +726,18 @@ export const refNumFormFields = [
|
|||||||
{
|
{
|
||||||
type: 'row',
|
type: 'row',
|
||||||
columns: [
|
columns: [
|
||||||
// {
|
{
|
||||||
// key: 'NumRefType',
|
key: 'NumRefType',
|
||||||
// label: 'Reference Type',
|
label: 'Reference Type',
|
||||||
// required: false,
|
required: false,
|
||||||
// type: 'text'
|
type: 'text'
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
key: 'RangeType',
|
key: 'RangeType',
|
||||||
label: 'Range Type',
|
label: 'Range Type',
|
||||||
required: false,
|
required: false,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/range_type`,
|
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/range_type`,
|
||||||
fullWidth: false
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -1035,18 +1034,23 @@ export function buildTestPayload({ mainForm, activeFormStates, testType, refNumD
|
|||||||
payload[key] = refNumData;
|
payload[key] = refNumData;
|
||||||
} else if (key === 'refTxt' && refTxtData?.length > 0) {
|
} else if (key === 'refTxt' && refTxtData?.length > 0) {
|
||||||
payload[key] = refTxtData;
|
payload[key] = refTxtData;
|
||||||
} else if(key === 'group') {
|
} else if(key === 'group' && state.form?.Members?.length > 0) {
|
||||||
payload[key] = {
|
payload[key] = {
|
||||||
...state.form,
|
...state.form,
|
||||||
Members: state.form?.Members?.map((m) => m.value).filter(Boolean) ?? []
|
Members: state.form?.Members?.map((m) => m.value).filter(Boolean) ?? []
|
||||||
};
|
};
|
||||||
} else if (key === 'map' && mapData?.length > 0) {
|
} else if (key === 'map' && mapData?.length > 0) {
|
||||||
payload[key] = mapData;
|
payload[key] = mapData;
|
||||||
} else if (state?.form) {
|
} else if (key === 'cal') {
|
||||||
payload[key] = {
|
payload[key] = {
|
||||||
...state.form
|
...state.form
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
// else if ((key === 'cal' || key === 'map') && state?.form) {
|
||||||
|
// payload[key] = {
|
||||||
|
// ...state.form
|
||||||
|
// };
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
return cleanEmptyStrings(payload);
|
return cleanEmptyStrings(payload);
|
||||||
|
|||||||
@ -148,7 +148,7 @@
|
|||||||
});
|
});
|
||||||
console.log(payload);
|
console.log(payload);
|
||||||
|
|
||||||
// const result = await formState.save(masterDetail.mode);
|
// const result = await formState.save(masterDetail.mode, payload);
|
||||||
|
|
||||||
// toast('Test Created!');
|
// toast('Test Created!');
|
||||||
// masterDetail?.exitForm(true);
|
// masterDetail?.exitForm(true);
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
let props = $props();
|
let props = $props();
|
||||||
|
|
||||||
const operators = ['+', '-', '*', '/', '^', '(', ')'];
|
const operators = ['+', '-', '*', '/', '^', '(', ')'];
|
||||||
const logicalop = ['IF', 'THEN', 'ELSE', 'END', 'AND', 'OR', 'NOT', 'MIN', 'MAX'];
|
const logicalop = ['IF', 'THEN', 'ELSE', 'END', 'AND', 'OR', 'NOT', 'MIN', 'MAX', 'RESULT'];
|
||||||
const comparisonop = ['=', '!=', '<', '>', '<=', '>='];
|
const comparisonop = ['=', '!=', '<', '>', '<=', '>='];
|
||||||
|
|
||||||
let tokens = $state([]);
|
let tokens = $state([]);
|
||||||
|
|||||||
@ -33,6 +33,15 @@
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let disabledFlag = $derived.by(() => {
|
||||||
|
const refType = props.refNumState.form.NumRefType;
|
||||||
|
|
||||||
|
if (refType === 'RANGE') return true;
|
||||||
|
if (refType === 'THOLD') return false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
|
||||||
function snapshotForm() {
|
function snapshotForm() {
|
||||||
const f = props.refNumState.form;
|
const f = props.refNumState.form;
|
||||||
return {
|
return {
|
||||||
@ -85,6 +94,8 @@
|
|||||||
|
|
||||||
if (existingStart == null || existingEnd == null) return false;
|
if (existingStart == null || existingEnd == null) return false;
|
||||||
|
|
||||||
|
if (row.RangeType !== props.refNumState.form.RangeType) return false;
|
||||||
|
|
||||||
return !(newEnd < existingStart || newStart > existingEnd);
|
return !(newEnd < existingStart || newStart > existingEnd);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -213,6 +224,7 @@
|
|||||||
formState={props.refNumState}
|
formState={props.refNumState}
|
||||||
formFields={props.refNumFormFields}
|
formFields={props.refNumFormFields}
|
||||||
{disabledSign}
|
{disabledSign}
|
||||||
|
{disabledFlag}
|
||||||
bind:joinFields
|
bind:joinFields
|
||||||
/>
|
/>
|
||||||
<div class="flex gap-2 mt-1 ms-2">
|
<div class="flex gap-2 mt-1 ms-2">
|
||||||
@ -276,7 +288,7 @@
|
|||||||
>{numRefTypeBadge(row.NumRefType)}</Badge
|
>{numRefTypeBadge(row.NumRefType)}</Badge
|
||||||
>
|
>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell class="font-medium">{row.Flag}</Table.Cell>
|
<Table.Cell class="font-medium">{row.NumRefType === "RANGE" ? "AUTO" : row.Flag}</Table.Cell>
|
||||||
<Table.Cell class="font-medium">{row.Interpretation}</Table.Cell>
|
<Table.Cell class="font-medium">{row.Interpretation}</Table.Cell>
|
||||||
<Table.Cell class="font-medium">{row.Notes}</Table.Cell>
|
<Table.Cell class="font-medium">{row.Notes}</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
|
|||||||
@ -39,7 +39,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resetForm() {
|
function resetForm() {
|
||||||
|
const currentRefType = props.refTxtState.form.TxtRefType;
|
||||||
|
|
||||||
props.refTxtState.reset?.();
|
props.refTxtState.reset?.();
|
||||||
|
|
||||||
|
if (currentRefType) {
|
||||||
|
props.refTxtState.form.TxtRefType = currentRefType;
|
||||||
|
}
|
||||||
|
|
||||||
joinFields = {
|
joinFields = {
|
||||||
AgeStart: { DD: "", MM: "", YY: "" },
|
AgeStart: { DD: "", MM: "", YY: "" },
|
||||||
AgeEnd: { DD: "", MM: "", YY: "" },
|
AgeEnd: { DD: "", MM: "", YY: "" },
|
||||||
|
|||||||
@ -1,112 +0,0 @@
|
|||||||
<script>
|
|
||||||
import * as Select from '$lib/components/ui/select/index.js';
|
|
||||||
import { fruits } from '$lib/components/multiselect/multiselect-form-config';
|
|
||||||
import { Input } from '$lib/components/ui/input/index.js';
|
|
||||||
import { z } from 'zod';
|
|
||||||
import { Badge } from '$lib/components/ui/badge/index.js';
|
|
||||||
|
|
||||||
let value = $state([]);
|
|
||||||
let inputValue = $state('');
|
|
||||||
|
|
||||||
function hasExactKeyword(input, keyword) {
|
|
||||||
const regex = new RegExp(`\\b${keyword}\\b`, 'i');
|
|
||||||
return regex.test(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
const schema = z
|
|
||||||
.object({
|
|
||||||
selected: z.array(z.string()),
|
|
||||||
input: z.string()
|
|
||||||
})
|
|
||||||
.refine(
|
|
||||||
(data) => {
|
|
||||||
return data.selected.every((v) => hasExactKeyword(data.input, v));
|
|
||||||
},
|
|
||||||
{
|
|
||||||
message: 'Input must contain all selected values',
|
|
||||||
path: ['input']
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let errors = $state({});
|
|
||||||
|
|
||||||
$effect(() => {
|
|
||||||
const result = schema.safeParse({ selected: value, input: inputValue });
|
|
||||||
if (!result.success) {
|
|
||||||
const fieldErrors = {};
|
|
||||||
for (const issue of result.error.issues) {
|
|
||||||
fieldErrors[issue.path[0]] = issue.message;
|
|
||||||
}
|
|
||||||
errors = fieldErrors;
|
|
||||||
} else {
|
|
||||||
errors = {};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const selectedLabel = $derived(
|
|
||||||
value.length === 0
|
|
||||||
? 'Select a fruit'
|
|
||||||
: value.map((v) => fruits.find((f) => f.value === v)?.value).join(', ')
|
|
||||||
);
|
|
||||||
|
|
||||||
const hasErrors = $derived(Object.keys(errors).length > 0);
|
|
||||||
|
|
||||||
const inputStatus = $derived(
|
|
||||||
value
|
|
||||||
.filter((v) => v)
|
|
||||||
.map((v) => ({
|
|
||||||
value: v,
|
|
||||||
label: fruits.find((f) => f.value === v)?.label,
|
|
||||||
done: hasExactKeyword(inputValue, v)
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
|
|
||||||
function unselectAll() {
|
|
||||||
value = [];
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="flex flex-col gap-2">
|
|
||||||
<Select.Root type="multiple" name="favoriteFruit" bind:value>
|
|
||||||
<Select.Trigger class="w-full">
|
|
||||||
{selectedLabel}
|
|
||||||
</Select.Trigger>
|
|
||||||
<Select.Content>
|
|
||||||
<Select.Group>
|
|
||||||
<Select.Label>Fruits</Select.Label>
|
|
||||||
{#each fruits as fruit (fruit.value)}
|
|
||||||
<Select.Item value={fruit.value} label={fruit.label}>
|
|
||||||
{fruit.label}
|
|
||||||
</Select.Item>
|
|
||||||
{/each}
|
|
||||||
</Select.Group>
|
|
||||||
{#if value.length > 0}
|
|
||||||
<Select.Separator />
|
|
||||||
<button
|
|
||||||
class="w-full px-2 py-1.5 text-left text-sm hover:bg-accent hover:text-accent-foreground"
|
|
||||||
onclick={unselectAll}
|
|
||||||
>
|
|
||||||
Unselect All
|
|
||||||
</button>
|
|
||||||
{/if}
|
|
||||||
</Select.Content>
|
|
||||||
</Select.Root>
|
|
||||||
|
|
||||||
<Input bind:value={inputValue} />
|
|
||||||
{#if errors.input}
|
|
||||||
<div class="flex items-center gap-2 text-sm text-red-500">
|
|
||||||
<span>{errors.input}:</span>
|
|
||||||
<div class="flex gap-1">
|
|
||||||
{#each inputStatus as item (item.value)}
|
|
||||||
<Badge variant={item.done ? 'default' : 'destructive'}>
|
|
||||||
{item.value}
|
|
||||||
</Badge>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<button disabled={hasErrors} class="rounded bg-blue-500 px-4 py-2 text-white disabled:opacity-50">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
const { masterDetail, formFields, formActions, schema } = props.context;
|
const { masterDetail, formFields, formActions, schema } = props.context;
|
||||||
|
|
||||||
|
let test = $derived(masterDetail?.selectedItem?.data);
|
||||||
|
|
||||||
const handlers = {
|
const handlers = {
|
||||||
editTest: () => masterDetail.enterEdit("data"),
|
editTest: () => masterDetail.enterEdit("data"),
|
||||||
};
|
};
|
||||||
@ -47,7 +49,7 @@
|
|||||||
{#if masterDetail.selectedItem}
|
{#if masterDetail.selectedItem}
|
||||||
<div class="flex flex-col px-2 py-1 gap-2 h-full w-full">
|
<div class="flex flex-col px-2 py-1 gap-2 h-full w-full">
|
||||||
<TopbarWrapper
|
<TopbarWrapper
|
||||||
title={masterDetail.selectedItem.data.TestSiteName}
|
title={masterDetail.selectedItem?.data?.TestSiteName}
|
||||||
{actions}
|
{actions}
|
||||||
/>
|
/>
|
||||||
<div class="flex-1 min-h-0 overflow-y-auto space-y-4">
|
<div class="flex-1 min-h-0 overflow-y-auto space-y-4">
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
disabledResultTypes = [],
|
disabledResultTypes = [],
|
||||||
disabledReferenceTypes = [],
|
disabledReferenceTypes = [],
|
||||||
disabledSign = false,
|
disabledSign = false,
|
||||||
|
disabledFlag = false,
|
||||||
joinFields = $bindable(),
|
joinFields = $bindable(),
|
||||||
hiddenFields,
|
hiddenFields,
|
||||||
handleTestTypeChange,
|
handleTestTypeChange,
|
||||||
@ -158,6 +159,7 @@
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
readonly={key === 'NumRefType' || key === 'TxtRefType' || key === 'Level'}
|
readonly={key === 'NumRefType' || key === 'TxtRefType' || key === 'Level'}
|
||||||
|
disabled={key === 'Flag' && disabledFlag}
|
||||||
/>
|
/>
|
||||||
{:else if type === 'email'}
|
{:else if type === 'email'}
|
||||||
<Input
|
<Input
|
||||||
@ -545,37 +547,39 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<Button type="button" variant="outline" size="icon" onclick={onMoveCursorRight}>
|
<Button type="button" variant="outline" size="icon" onclick={onMoveCursorRight}>
|
||||||
<MoveRightIcon class="w-4 h-4" />
|
<MoveRightIcon class="w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="button" variant="outline" size="icon" onclick={onDeleteChar}>
|
<Button type="button" variant="outline" size="icon" onclick={onDeleteChar}>
|
||||||
<DeleteIcon class="w-4 h-4" />
|
<DeleteIcon class="w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="button" variant="outline" size="icon" onclick={onClearExpression}>
|
<Button type="button" variant="outline" size="icon" onclick={onClearExpression}>
|
||||||
<BrushCleaningIcon class="w-4 h-4" />
|
<BrushCleaningIcon class="w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="button" variant="outline" size="icon" onclick={onAddNewline} title="New line">
|
<Button type="button" variant="outline" size="icon" onclick={onAddNewline} title="New line">
|
||||||
<CornerDownLeftIcon class="w-4 h-4" />
|
<CornerDownLeftIcon class="w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{#if formState.form.FormulaInput?.length > 0}
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex flex-col gap-4">
|
{#if formState.form.FormulaInput?.length > 0}
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-4">
|
||||||
<Label class="uppercase tracking-wide">Selected Tests</Label>
|
<div class="flex flex-col gap-2">
|
||||||
<div class="flex flex-wrap gap-2">
|
<Label class="uppercase tracking-wide">Selected Tests</Label>
|
||||||
{#each formState.form.FormulaInput as item (item)}
|
<div class="flex flex-wrap gap-2">
|
||||||
<Button
|
{#each formState.form.FormulaInput as item (item)}
|
||||||
type="button"
|
<Button
|
||||||
variant="outline"
|
type="button"
|
||||||
class="h-auto w-auto p-2"
|
variant="outline"
|
||||||
onclick={() => onAddValue?.(item.value)}
|
class="h-auto w-auto p-2"
|
||||||
>
|
onclick={() => onAddValue?.(item.value)}
|
||||||
{item.value}
|
>
|
||||||
</Button>
|
{item.value}
|
||||||
{/each}
|
</Button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
<!-- Custom Literal Values -->
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<Label class="uppercase tracking-wide">Custom Values</Label>
|
<Label class="uppercase tracking-wide">Custom Values</Label>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
@ -673,7 +677,6 @@
|
|||||||
</Popover.Root>
|
</Popover.Root>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<Label class="uppercase tracking-wide">Logical Operators</Label>
|
<Label class="uppercase tracking-wide">Logical Operators</Label>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
@ -689,8 +692,6 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Comparison Operators -->
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<Label class="uppercase tracking-wide">Comparison Operators</Label>
|
<Label class="uppercase tracking-wide">Comparison Operators</Label>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
@ -706,8 +707,6 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Math Operators -->
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<Label class="uppercase tracking-wide">Math Operators</Label>
|
<Label class="uppercase tracking-wide">Math Operators</Label>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
@ -723,15 +722,15 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if tokens.length > 0}
|
{#if tokens.length > 0}
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<Label class="uppercase tracking-wide">Preview</Label>
|
<Label class="uppercase tracking-wide">Preview</Label>
|
||||||
<div class="border-2 border-dashed border-muted-foreground/30 rounded-lg">
|
<div class="border-2 border-dashed border-muted-foreground/30 rounded-lg">
|
||||||
<pre class="font-mono text-sm bg-muted/50 p-2 rounded">{expressionString}</pre>
|
<pre class="font-mono text-sm bg-muted/50 p-2 rounded">{expressionString}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user