mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-22 17:19:52 +07:00
404 lines
17 KiB
Svelte
404 lines
17 KiB
Svelte
<script>
|
|
import { useDictionaryForm } from "$lib/components/composable/use-dictionary-form.svelte";
|
|
import FormPageContainer from "$lib/components/reusable/form/form-page-container.svelte";
|
|
import DictionaryFormRenderer from "$lib/components/reusable/form/dictionary-form-renderer.svelte";
|
|
import { toast } from "svelte-sonner";
|
|
import ReusableAlertDialog from "$lib/components/reusable/reusable-alert-dialog.svelte";
|
|
import { useForm } from "$lib/components/composable/use-form.svelte";
|
|
import { testMapDetailSchema, testMapDetailInitialForm, testMapDetailDefaultErrors, testMapDetailFormFields, buildTestMapPayload } from "$lib/components/dictionary/testmap/config/testmap-form-config";
|
|
import { Separator } from "$lib/components/ui/separator/index.js";
|
|
import PencilIcon from "@lucide/svelte/icons/pencil";
|
|
import Trash2Icon from "@lucide/svelte/icons/trash-2";
|
|
import * as Table from "$lib/components/ui/table/index.js";
|
|
import { Button } from "$lib/components/ui/button/index.js";
|
|
import { untrack } from "svelte";
|
|
import { API } from '$lib/config/api';
|
|
import { onMount } from "svelte";
|
|
import * as Tooltip from "$lib/components/ui/tooltip/index.js";
|
|
|
|
let props = $props();
|
|
|
|
const { masterDetail, formFields, formActions, schema } = props.context;
|
|
|
|
const { formState } = masterDetail;
|
|
|
|
let editingId = $state(null);
|
|
let idCounter = $state(0);
|
|
let tempMap = $state([]);
|
|
let showDeleteConfirm = $state(false);
|
|
let selectedRow = $state({});
|
|
|
|
const testMapDetailFormState = useForm({
|
|
schema: testMapDetailSchema,
|
|
initialForm: testMapDetailInitialForm,
|
|
defaultErrors: testMapDetailDefaultErrors,
|
|
});
|
|
|
|
const helpers = useDictionaryForm(formState);
|
|
|
|
const handlers = {
|
|
clearForm: () => {
|
|
formState.reset();
|
|
resetTestMapDetailForm();
|
|
tempMap = [];
|
|
}
|
|
};
|
|
|
|
const actions = formActions(handlers);
|
|
|
|
let showConfirm = $state(false);
|
|
|
|
function snapshotForm() {
|
|
return untrack(() => {
|
|
const f = testMapDetailFormState.form;
|
|
return {
|
|
HostTestCode: f.HostTestCode ?? "",
|
|
HostTestName: f.HostTestName ?? "",
|
|
ClientTestCode: f.ClientTestCode ?? "",
|
|
ClientTestName: f.ClientTestName ?? "",
|
|
ConDefID: f.ConDefID ?? "",
|
|
};
|
|
});
|
|
}
|
|
|
|
function resetTestMapDetailForm() {
|
|
testMapDetailFormState.reset();
|
|
editingId = null;
|
|
}
|
|
|
|
function handleInsertDetail() {
|
|
const row = {
|
|
id: ++idCounter,
|
|
...snapshotForm()
|
|
};
|
|
|
|
tempMap = [...tempMap, row];
|
|
|
|
resetTestMapDetailForm();
|
|
}
|
|
|
|
async function handleEditDetail(row) {
|
|
editingId = row.id;
|
|
|
|
untrack(() => {
|
|
const f = testMapDetailFormState.form;
|
|
|
|
f.HostTestCode = row.HostTestCode;
|
|
f.HostTestName = row.HostTestName;
|
|
f.ClientTestCode = row.ClientTestCode;
|
|
f.ClientTestName = row.ClientTestName;
|
|
f.ConDefID = row.ConDefID;
|
|
});
|
|
}
|
|
|
|
function handleUpdateDetail() {
|
|
tempMap = tempMap.map((row) =>
|
|
row.id === editingId ? { id: row.id, ...snapshotForm() } : row
|
|
);
|
|
resetTestMapDetailForm();
|
|
}
|
|
|
|
function handleCancelEditDetail() {
|
|
resetTestMapDetailForm();
|
|
}
|
|
|
|
function handleRemoveDetail(id) {
|
|
tempMap = tempMap.filter((row) => row.id !== id);
|
|
if (editingId === id) {
|
|
resetTestMapDetailForm();
|
|
}
|
|
}
|
|
|
|
async function handleSave() {
|
|
const mainForm = masterDetail.formState.form;
|
|
|
|
const payload = buildTestMapPayload({
|
|
mainForm,
|
|
tempMap,
|
|
});
|
|
console.log(payload)
|
|
// const result = await formState.save(masterDetail.mode, payload);
|
|
|
|
// if (result.status === 'success') {
|
|
// toast('Test Map Created!');
|
|
// masterDetail?.exitForm(true);
|
|
// } else {
|
|
// console.error('Failed to save test map');
|
|
// const errorMessages = result.messages ? Object.values(result.messages).join('\n') : 'Failed to save test map';
|
|
// toast.error(errorMessages)
|
|
// }
|
|
}
|
|
|
|
const primaryAction = $derived({
|
|
label: 'Save',
|
|
onClick: handleSave,
|
|
disabled: helpers.hasErrors || formState.isSaving.current,
|
|
loading: formState.isSaving.current
|
|
});
|
|
|
|
const secondaryActions = [];
|
|
|
|
const mapFormFieldsTransformed = $derived.by(() => {
|
|
return formFields.map((group) => ({
|
|
...group,
|
|
rows: group.rows.map((row) => ({
|
|
...row,
|
|
columns: row.columns.map((col) => {
|
|
if (col.key === 'HostID') {
|
|
if (formState.form.HostType === 'HIS') {
|
|
return {
|
|
...col,
|
|
type: 'select',
|
|
optionsEndpoint: `${API.BASE_URL}${API.HOSTAPP}`,
|
|
valueKey: 'HostAppID',
|
|
labelKey: 'HostAppName'
|
|
}
|
|
} else if (formState.form.HostType === 'SITE') {
|
|
return {
|
|
...col,
|
|
type: 'select',
|
|
optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
|
|
valueKey: 'SiteID',
|
|
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`
|
|
};
|
|
} else if (formState.form.HostType === 'WST') {
|
|
return {
|
|
...col,
|
|
type: 'select',
|
|
optionsEndpoint: `${API.BASE_URL}${API.WORKSTATION}`,
|
|
valueKey: 'WorkstationID',
|
|
labelKey: 'WorkstationName'
|
|
};
|
|
} else if (formState.form.HostType === 'INST') {
|
|
return {
|
|
...col,
|
|
type: 'select',
|
|
optionsEndpoint: `${API.BASE_URL}${API.EQUIPMENT}`,
|
|
valueKey: 'EID',
|
|
labelKey: 'InstrumentName'
|
|
}
|
|
}
|
|
return { ...col, type: 'text', optionsEndpoint: undefined };
|
|
}
|
|
|
|
if (col.key === 'ClientID') {
|
|
if (formState.form.ClientType === 'HIS') {
|
|
return {
|
|
...col,
|
|
type: 'select',
|
|
optionsEndpoint: `${API.BASE_URL}${API.HOSTAPP}`,
|
|
valueKey: 'HostAppID',
|
|
labelKey: 'HostAppName'
|
|
}
|
|
} else if (formState.form.ClientType === 'SITE') {
|
|
return {
|
|
...col,
|
|
type: 'select',
|
|
optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
|
|
valueKey: 'SiteID',
|
|
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`
|
|
};
|
|
} else if (formState.form.ClientType === 'WST') {
|
|
return {
|
|
...col,
|
|
type: 'select',
|
|
optionsEndpoint: `${API.BASE_URL}${API.WORKSTATION}`,
|
|
valueKey: 'WorkstationID',
|
|
labelKey: 'WorkstationName'
|
|
};
|
|
} else if (formState.form.ClientType === 'INST') {
|
|
return {
|
|
...col,
|
|
type: 'select',
|
|
optionsEndpoint: `${API.BASE_URL}${API.EQUIPMENT}`,
|
|
valueKey: 'EID',
|
|
labelKey: 'InstrumentName'
|
|
}
|
|
}
|
|
return { ...col, type: 'text', optionsEndpoint: undefined };
|
|
}
|
|
|
|
return col;
|
|
})
|
|
}))
|
|
}));
|
|
});
|
|
|
|
const mapDetailFormFieldsTransformed = $derived.by(() => {
|
|
return testMapDetailFormFields.map((group) => ({
|
|
...group,
|
|
rows: group.rows.map((row) => ({
|
|
...row,
|
|
columns: row.columns.map((col) => {
|
|
if (col.key === 'HostTestCode') {
|
|
if (formState.form.HostType === 'SITE' && formState.form.HostID) {
|
|
return {
|
|
...col,
|
|
type: 'select',
|
|
optionsEndpoint: `${API.BASE_URL}${API.TEST}?SiteID=${formState.form.HostID}`,
|
|
valueKey: 'TestSiteCode',
|
|
labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`
|
|
};
|
|
}
|
|
return { ...col, type: 'text', optionsEndpoint: undefined };
|
|
}
|
|
|
|
if (col.key === 'ClientTestCode') {
|
|
if (formState.form.ClientType === 'SITE' && formState.form.ClientID) {
|
|
return {
|
|
...col,
|
|
type: 'select',
|
|
optionsEndpoint: `${API.BASE_URL}${API.TEST}?SiteID=${formState.form.ClientID}`,
|
|
valueKey: 'TestSiteCode',
|
|
labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`
|
|
};
|
|
}
|
|
return { ...col, type: 'text', optionsEndpoint: undefined };
|
|
}
|
|
|
|
return col
|
|
})
|
|
}))
|
|
}))
|
|
})
|
|
|
|
function getLabel(fieldKey, value) {
|
|
const opts = testMapDetailFormState.selectOptions[fieldKey] ?? [];
|
|
const found = opts.find((o) => o.value == value);
|
|
return found ? found.rawItem.ConName : value;
|
|
}
|
|
|
|
onMount(() => {
|
|
masterDetail.registerExtraState({
|
|
key: 'tempMap',
|
|
get: () => tempMap,
|
|
reset: () => { tempMap = []; idCounter = 0; editingId = null; },
|
|
});
|
|
});
|
|
$inspect(testMapDetailFormState.selectOptions)
|
|
</script>
|
|
|
|
<FormPageContainer title="Create Test Map" {primaryAction} {secondaryActions} {actions}>
|
|
<DictionaryFormRenderer
|
|
{formState}
|
|
formFields={mapFormFieldsTransformed}
|
|
mode="create"
|
|
/>
|
|
<div class="mt-2">
|
|
<DictionaryFormRenderer
|
|
formState={testMapDetailFormState}
|
|
formFields={mapDetailFormFieldsTransformed}
|
|
mode="create"
|
|
/>
|
|
</div>
|
|
<div class="flex flex-col gap-4">
|
|
<div class="flex gap-2 mt-1 ms-2">
|
|
{#if editingId !== null}
|
|
<Button size="sm" class="cursor-pointer" onclick={handleUpdateDetail}>
|
|
Update
|
|
</Button>
|
|
<Button size="sm" variant="outline" class="cursor-pointer" onclick={handleCancelEditDetail}>
|
|
Cancel
|
|
</Button>
|
|
{:else}
|
|
<Button size="sm" class="cursor-pointer" onclick={handleInsertDetail}
|
|
disabled={Object.values(testMapDetailFormState.errors).some(v => v !== null)}>
|
|
Insert
|
|
</Button>
|
|
{/if}
|
|
</div>
|
|
|
|
<div>
|
|
<Separator />
|
|
<Table.Root>
|
|
<Table.Header>
|
|
<Table.Row class="hover:bg-transparent">
|
|
<Table.Head>Host Test Code</Table.Head>
|
|
<Table.Head>Host Test Name</Table.Head>
|
|
<Table.Head>Client Test Code</Table.Head>
|
|
<Table.Head>Client Test Name</Table.Head>
|
|
<Table.Head>Container</Table.Head>
|
|
<Table.Head class="w-[80px]"></Table.Head>
|
|
</Table.Row>
|
|
</Table.Header>
|
|
<Table.Body>
|
|
{#if tempMap.length === 0}
|
|
<Table.Row>
|
|
<Table.Cell colspan={9} class="text-center text-muted-foreground py-6">
|
|
No data. Fill the form above and click Insert.
|
|
</Table.Cell>
|
|
</Table.Row>
|
|
{:else}
|
|
{#each tempMap as row (row.id)}
|
|
<Table.Row
|
|
class="cursor-pointer hover:bg-muted/50"
|
|
>
|
|
<Table.Cell>{row.HostTestCode}</Table.Cell>
|
|
<Table.Cell>{row.HostTestName}</Table.Cell>
|
|
<Table.Cell>{row.ClientTestCode}</Table.Cell>
|
|
<Table.Cell>{row.ClientTestName}</Table.Cell>
|
|
<Table.Cell>{row.ConDefID ? getLabel('ConDefID', row.ConDefID) : '-'}</Table.Cell>
|
|
<Table.Cell>
|
|
<div class="flex gap-1">
|
|
<Tooltip.Provider>
|
|
<Tooltip.Root>
|
|
<Tooltip.Trigger>
|
|
<Button
|
|
size="icon"
|
|
variant="outline"
|
|
class="h-7 w-7 cursor-pointer"
|
|
onclick={() => handleEditDetail(row)}
|
|
>
|
|
<PencilIcon class="h-3.5 w-3.5" />
|
|
</Button>
|
|
</Tooltip.Trigger>
|
|
<Tooltip.Content>
|
|
<p>Edit</p>
|
|
</Tooltip.Content>
|
|
</Tooltip.Root>
|
|
</Tooltip.Provider>
|
|
<Tooltip.Provider>
|
|
<Tooltip.Root>
|
|
<Tooltip.Trigger>
|
|
<Button
|
|
size="icon"
|
|
variant="outline"
|
|
class="h-7 w-7 cursor-pointer"
|
|
onclick={() => {
|
|
selectedRow = row;
|
|
showDeleteConfirm = true;
|
|
}}
|
|
>
|
|
<Trash2Icon class="h-3.5 w-3.5" />
|
|
</Button>
|
|
</Tooltip.Trigger>
|
|
<Tooltip.Content>
|
|
<p>Delete</p>
|
|
</Tooltip.Content>
|
|
</Tooltip.Root>
|
|
</Tooltip.Provider>
|
|
</div>
|
|
</Table.Cell>
|
|
</Table.Row>
|
|
{/each}
|
|
{/if}
|
|
</Table.Body>
|
|
</Table.Root>
|
|
</div>
|
|
</div>
|
|
</FormPageContainer>
|
|
|
|
<ReusableAlertDialog
|
|
bind:open={masterDetail.showExitConfirm}
|
|
onConfirm={masterDetail.confirmExit}
|
|
/>
|
|
|
|
<ReusableAlertDialog
|
|
bind:open={showDeleteConfirm}
|
|
title="Delete Test Code?"
|
|
description="Are you sure you want to disable this test code ({selectedRow.HostTestCode})?"
|
|
confirmText="Delete"
|
|
onConfirm={() => {
|
|
handleRemoveDetail(selectedRow.id);
|
|
}}
|
|
/> |