mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-22 09:35:34 +07:00
continue contact edit & edit function
This commit is contained in:
parent
ec14173256
commit
6afc0067e2
@ -76,6 +76,7 @@ export async function searchWithPath(endpoint, searchQuery) {
|
||||
}
|
||||
|
||||
export async function create(endpoint, formData) {
|
||||
console.log(cleanEmptyStrings(formData));
|
||||
try {
|
||||
const res = await fetch(`${API.BASE_URL}${endpoint}`, {
|
||||
method: 'POST',
|
||||
|
||||
@ -11,15 +11,13 @@ export function useForm({schema, initialForm, defaultErrors = {}, mode = 'create
|
||||
state.isSaving.current = true
|
||||
|
||||
try {
|
||||
// const payload = { ...state.form };
|
||||
const payload = customPayload || { ...state.form };
|
||||
let result;
|
||||
// const { ProvinceID, CityID, ...rest } = state.form;
|
||||
// const payload = customPayload || rest;
|
||||
// const result = currentMode === 'edit' ? await editEndpoint(payload, idKey) : await saveEndpoint(payload);
|
||||
|
||||
if (currentMode === 'edit') {
|
||||
const id = payload[idKey];
|
||||
result = await editEndpoint(payload, id);
|
||||
const { [idKey]: _, ...body } = payload;
|
||||
result = await editEndpoint(body, id);
|
||||
} else {
|
||||
result = await saveEndpoint(payload);
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ export async function getAccount(searchQuery) {
|
||||
}
|
||||
|
||||
export async function createAccount(newAccountForm) {
|
||||
console.log(newAccountForm);
|
||||
return await create(API.ACCOUNT, newAccountForm)
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,10 @@ import { z } from "zod";
|
||||
export const accountSchema = z.object({
|
||||
Initial: z.string().min(1, "Required"),
|
||||
AccountName: z.string().min(1, "Required"),
|
||||
EmailAddress1: z.string().trim().optional().refine((val) => !val || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val),"Invalid email format"),
|
||||
EmailAddress2: z.string().trim().optional().refine((val) => !val || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val),"Invalid email format"),
|
||||
ZIP: z.string().regex(/^$|^[0-9]+$/, "Can only contain numbers"),
|
||||
Phone: z.string().max(14, "Max 14 chars").regex(/^$|^[0-9]+$/, "Can only contain numbers"),
|
||||
});
|
||||
|
||||
export const accountInitialForm = {
|
||||
@ -12,13 +16,13 @@ export const accountInitialForm = {
|
||||
ParentAccount: '',
|
||||
AccountName: '',
|
||||
Initial: '',
|
||||
Street_1: '',
|
||||
Street_2: '',
|
||||
Street_3: '',
|
||||
Country: '',
|
||||
Province: '',
|
||||
City: '',
|
||||
ZIP: '',
|
||||
Street_1: '',
|
||||
Street_2: '',
|
||||
Street_3: '',
|
||||
EmailAddress1: '',
|
||||
EmailAddress2: '',
|
||||
Phone: '',
|
||||
@ -28,6 +32,10 @@ export const accountInitialForm = {
|
||||
export const accountDefaultErrors = {
|
||||
Initial: "Required",
|
||||
AccountName: "Required",
|
||||
EmailAddress1: null,
|
||||
EmailAddress2: null,
|
||||
ZIP: null,
|
||||
Phone: null,
|
||||
};
|
||||
|
||||
export const accountFormFields = [
|
||||
@ -162,6 +170,7 @@ export const accountFormFields = [
|
||||
label: "Phone",
|
||||
required: false,
|
||||
type: "text",
|
||||
validateOn: ["input"]
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
@ -13,7 +13,6 @@ export const searchFields = [
|
||||
|
||||
export const detailSections = [
|
||||
{
|
||||
title: "",
|
||||
class: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
||||
groups: [
|
||||
{
|
||||
@ -35,7 +34,8 @@ export const detailSections = [
|
||||
{ key: "MobilePhone1", label: "Mobile Phone 1" },
|
||||
{ key: "MobilePhone2", label: "Mobile Phone 2" },
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -45,6 +45,12 @@ export const detailSections = [
|
||||
{ key: "SubSpecialty", label: "Sub Specialty" },
|
||||
]
|
||||
},
|
||||
{
|
||||
class: "grid grid-cols-2 gap-4 items-center",
|
||||
fields: [
|
||||
{ key: "Details", label: "Details", fullWidth: true },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export function contactActions(masterDetail) {
|
||||
|
||||
@ -232,7 +232,13 @@ export const contactDetailFormFields = [
|
||||
type: "row",
|
||||
columns: [
|
||||
{ key: "JobTitle", label: "Job Title", required: false, type: "text" },
|
||||
{ key: "ContactEmail", label: "Email", required: false, type: "text" },
|
||||
{
|
||||
key: "ContactEmail",
|
||||
label: "Email",
|
||||
required: false,
|
||||
type: "text",
|
||||
validateOn: ["input"],
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -256,6 +262,7 @@ export function buildContactPayload({
|
||||
let payload = {
|
||||
...mainForm,
|
||||
Details: tempDetailContact.map((item) => ({
|
||||
ContactDetID: item.ContactDetID,
|
||||
SiteID: item.SiteID,
|
||||
ContactCode: item.ContactCode,
|
||||
ContactEmail: item.ContactEmail,
|
||||
|
||||
@ -11,12 +11,15 @@
|
||||
import * as Card from "$lib/components/ui/card/index.js";
|
||||
import { Badge } from "$lib/components/ui/badge/index.js";
|
||||
import TopbarWrapper from "$lib/components/topbar/topbar-wrapper.svelte";
|
||||
import { contactDetailInitialForm, contactDetailFormFields } from "$lib/components/dictionary/contact/config/contact-form-config";
|
||||
import { contactDetailSchema, contactDetailInitialForm, contactDetailDefaultErrors, contactDetailFormFields, buildContactPayload } from "$lib/components/dictionary/contact/config/contact-form-config";
|
||||
import { Button } from "$lib/components/ui/button/index.js";
|
||||
import { useForm } from "$lib/components/composable/use-form.svelte";
|
||||
import XIcon from "@lucide/svelte/icons/x";
|
||||
import Edit2Icon from "@lucide/svelte/icons/edit-2";
|
||||
import { getChangedFields } from "$lib/utils/getChangedFields";
|
||||
// import { getChangedFields } from "$lib/utils/getChangedFields";
|
||||
import * as Table from '$lib/components/ui/table/index.js';
|
||||
import PencilIcon from "@lucide/svelte/icons/pencil";
|
||||
import Trash2Icon from "@lucide/svelte/icons/trash-2";
|
||||
|
||||
let props = $props();
|
||||
|
||||
@ -24,33 +27,24 @@
|
||||
|
||||
const { formState } = masterDetail;
|
||||
|
||||
const detailFormState = useForm({
|
||||
schema: null,
|
||||
const contactDetailFormState = useForm({
|
||||
schema: contactDetailSchema,
|
||||
initialForm: contactDetailInitialForm,
|
||||
defaultErrors: {},
|
||||
mode: 'create',
|
||||
modeOpt: 'default',
|
||||
saveEndpoint: null,
|
||||
editEndpoint: null,
|
||||
defaultErrors: contactDetailDefaultErrors,
|
||||
});
|
||||
|
||||
let showDetailForm = $state(false);
|
||||
|
||||
let editingDetailIndex = $state(null);
|
||||
|
||||
let isEditingDetail = $derived(editingDetailIndex !== null);
|
||||
|
||||
const helpers = useDictionaryForm(formState);
|
||||
|
||||
let showConfirm = $state(false);
|
||||
|
||||
let editingId = $state(null);
|
||||
let idCounter = $state(0);
|
||||
let tempMap = $state([]);
|
||||
let tempDetailContact = $state([]);
|
||||
let deletedDetailIds = $state([]);
|
||||
|
||||
function getLabel(fieldKey, value) {
|
||||
if (!detailFormState.selectOptions?.[fieldKey]) return value;
|
||||
const option = detailFormState.selectOptions[fieldKey].find(opt => opt.value === value);
|
||||
if (!contactDetailFormState.selectOptions?.[fieldKey]) return value;
|
||||
const option = contactDetailFormState.selectOptions[fieldKey].find(opt => opt.value === value);
|
||||
return option?.label || value || "-";
|
||||
}
|
||||
|
||||
@ -80,7 +74,7 @@
|
||||
group.rows.forEach(row => {
|
||||
row.columns.forEach(col => {
|
||||
if (col.type === "select" && col.optionsEndpoint) {
|
||||
detailFormState.fetchOptions(col, detailFormState.form);
|
||||
contactDetailFormState.fetchOptions(col, contactDetailFormState.form);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -88,49 +82,116 @@
|
||||
});
|
||||
});
|
||||
|
||||
let editedDetails = $state(masterDetail.selectedItem?.data?.Details || []);
|
||||
// let editedDetails = $state(masterDetail.selectedItem?.data?.Details || []);
|
||||
|
||||
function diffDetails(current, original) {
|
||||
const originalMap = new Map(
|
||||
original.map(item => [item.ContactDetID, item])
|
||||
);
|
||||
|
||||
const updated = [];
|
||||
|
||||
for (const item of current) {
|
||||
const orig = originalMap.get(item.ContactDetID);
|
||||
if (!orig) continue;
|
||||
|
||||
// console.log('ITEM:', item);
|
||||
// console.log('ORIG:', orig);
|
||||
// console.log('KEYS current:', Object.keys(item));
|
||||
// console.log('KEYS original:', Object.keys(orig));
|
||||
|
||||
const changed = Object.keys(item).some(
|
||||
key => item[key] !== orig[key]
|
||||
);
|
||||
|
||||
if (changed) updated.push(item);
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
function getChangedFields(original, current) {
|
||||
const changed = {};
|
||||
for (const key in current) {
|
||||
if (JSON.stringify(current[key]) !== JSON.stringify(original[key])) {
|
||||
changed[key] = current[key];
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
async function handleEdit() {
|
||||
const originalDetails = masterDetail.selectedItem?.data?.Details || [];
|
||||
const currentPayload = buildContactPayload({
|
||||
mainForm: formState.form,
|
||||
tempDetailContact
|
||||
});
|
||||
const originalPayload = buildContactPayload({
|
||||
mainForm: masterDetail.formSnapshot,
|
||||
tempDetailContact: masterDetail.formSnapshot.Details
|
||||
});
|
||||
const updatedDetails = diffDetails(
|
||||
currentPayload.Details,
|
||||
originalPayload.Details
|
||||
);
|
||||
const finalPayload = {
|
||||
...getChangedFields(originalPayload, currentPayload),
|
||||
Details: {
|
||||
created: tempDetailContact.filter(r => !r.ContactDetID),
|
||||
updated: updatedDetails,
|
||||
deleted: deletedDetailIds.map(id => ({
|
||||
ContactDetID: id
|
||||
}))
|
||||
}
|
||||
};
|
||||
|
||||
const currentPayload = $state.snapshot({ ...formState.form, Details: editedDetails });
|
||||
const originalPayload = $state.snapshot({ ...masterDetail.formSnapshot, Details: originalDetails });
|
||||
console.log('Current Payload:', editedDetails);
|
||||
console.log('Original Payload:', originalDetails);
|
||||
console.log(finalPayload);
|
||||
// console.log('Original Payload:', JSON.stringify(originalPayload));
|
||||
// console.log('Current Payload:', JSON.stringify(currentPayload));
|
||||
// console.log('Changed Fields:', getChangedFields(originalPayload, currentPayload));
|
||||
// console.log(originalPayload.Details);
|
||||
// console.log(currentPayload.Details);
|
||||
// console.log('Diff:', diffDetails(currentPayload.Details, originalPayload.Details));
|
||||
|
||||
// const originalDetails = masterDetail.selectedItem?.data?.Details || [];
|
||||
|
||||
// const currentPayload = $state.snapshot({ ...formState.form, Details: editedDetails });
|
||||
// const originalPayload = $state.snapshot({ ...masterDetail.formSnapshot, Details: originalDetails });
|
||||
// console.log('Current Payload:', editedDetails);
|
||||
// console.log('Original Payload:', originalDetails);
|
||||
|
||||
// const customPayload = {
|
||||
// ...formState.form,
|
||||
// Details: masterDetail.selectedItem?.data?.Details || []
|
||||
// };
|
||||
// console.log('Custom Payload for Edit:', JSON.stringify(customPayload));
|
||||
// const result = await formState.save(masterDetail.mode, customPayload);
|
||||
// // const customPayload = {
|
||||
// // ...formState.form,
|
||||
// // Details: masterDetail.selectedItem?.data?.Details || []
|
||||
// // };
|
||||
// // console.log('Custom Payload for Edit:', JSON.stringify(customPayload));
|
||||
// // const result = await formState.save(masterDetail.mode, customPayload);
|
||||
|
||||
// ***
|
||||
const changedFields = getChangedFields(originalPayload, currentPayload);
|
||||
console.log('Changed Fields:', JSON.stringify(changedFields));
|
||||
// // ***
|
||||
// const changedFields = getChangedFields(originalPayload, currentPayload);
|
||||
// console.log('Changed Fields:', JSON.stringify(changedFields));
|
||||
|
||||
// if (Object.keys(changedFields).length === 0) {
|
||||
// toast('No changes detected');
|
||||
// return;
|
||||
// }
|
||||
// // if (Object.keys(changedFields).length === 0) {
|
||||
// // toast('No changes detected');
|
||||
// // return;
|
||||
// // }
|
||||
|
||||
// const payload = {
|
||||
// ContactID: formState.form.ContactID,
|
||||
// ...changedFields
|
||||
// };
|
||||
// // const payload = {
|
||||
// // ContactID: formState.form.ContactID,
|
||||
// // ...changedFields
|
||||
// // };
|
||||
|
||||
// console.log('Custom Payload for Edit:', payload);
|
||||
// ***
|
||||
// // console.log('Custom Payload for Edit:', payload);
|
||||
// // ***
|
||||
|
||||
// const result = await formState.save(masterDetail.mode, payload);
|
||||
// // const result = await formState.save(masterDetail.mode, payload);
|
||||
|
||||
// if (result.status === 'success') {
|
||||
// console.log('Contact updated successfully');
|
||||
// toast('Contact Updated!');
|
||||
// masterDetail.exitForm(true);
|
||||
// } else {
|
||||
// console.error('Failed to update contact:', result.message);
|
||||
// }
|
||||
// // if (result.status === 'success') {
|
||||
// // console.log('Contact updated successfully');
|
||||
// // toast('Contact Updated!');
|
||||
// // masterDetail.exitForm(true);
|
||||
// // } else {
|
||||
// // console.error('Failed to update contact:', result.message);
|
||||
// // }
|
||||
}
|
||||
|
||||
const primaryAction = $derived({
|
||||
@ -142,71 +203,114 @@
|
||||
|
||||
const secondaryActions = [];
|
||||
|
||||
const actionsDetail = [
|
||||
{
|
||||
Icon: PlusIcon,
|
||||
label: 'Add Contact Detail',
|
||||
onClick: () => addDetail(),
|
||||
},
|
||||
];
|
||||
|
||||
function addDetail() {
|
||||
editingDetailIndex = null; // Mode create baru
|
||||
detailFormState.reset(); // Reset form ke initialForm
|
||||
detailFormState.setForm({ ...contactDetailInitialForm }); // Set form kosong
|
||||
showDetailForm = true;
|
||||
function snapshotForm() {
|
||||
return untrack(() => {
|
||||
const f = contactDetailFormState.form;
|
||||
return {
|
||||
SiteID: f.SiteID ?? "",
|
||||
ContactCode: f.ContactCode ?? "",
|
||||
ContactEmail: f.ContactEmail ?? "",
|
||||
Department: f.Department ?? "",
|
||||
OccupationID: f.OccupationID ?? "",
|
||||
JobTitle: f.JobTitle ?? "",
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function saveDetail() {
|
||||
// Ambil current form dari detailFormState.form
|
||||
const newDetail = { ...detailFormState.form };
|
||||
|
||||
if (isEditingDetail) {
|
||||
// Mode edit: update detail yang ada
|
||||
masterDetail.selectedItem.data.Details[editingDetailIndex] = newDetail;
|
||||
toast('Contact Detail Updated!');
|
||||
} else {
|
||||
// Mode create: tambah detail baru
|
||||
if (!masterDetail.selectedItem.data.Details) {
|
||||
masterDetail.selectedItem.data.Details = [];
|
||||
}
|
||||
masterDetail.selectedItem.data.Details.push(newDetail);
|
||||
toast('Contact Detail Added!');
|
||||
function resetContactDetailForm() {
|
||||
contactDetailFormState.reset();
|
||||
editingId = null;
|
||||
}
|
||||
|
||||
function handleInsertDetail() {
|
||||
const row = {
|
||||
id: ++idCounter,
|
||||
ContactDetID: null,
|
||||
...snapshotForm()
|
||||
};
|
||||
|
||||
tempDetailContact = [...tempDetailContact, row];
|
||||
|
||||
resetContactDetailForm();
|
||||
}
|
||||
|
||||
async function handleEditDetail(row) {
|
||||
editingId = row.id;
|
||||
|
||||
untrack(() => {
|
||||
const f = contactDetailFormState.form;
|
||||
|
||||
f.SiteID = row.SiteID;
|
||||
f.ContactCode = row.ContactCode;
|
||||
f.ContactEmail = row.ContactEmail;
|
||||
f.Department = row.Department;
|
||||
f.OccupationID = row.OccupationID;
|
||||
f.JobTitle = row.JobTitle;
|
||||
});
|
||||
}
|
||||
|
||||
// function handleUpdateDetail() {
|
||||
// tempDetailContact = tempDetailContact.map((row) =>
|
||||
// row.id === editingId ?
|
||||
// {
|
||||
// ...row,
|
||||
// ...snapshotForm()
|
||||
// } : row
|
||||
// );
|
||||
// resetContactDetailForm();
|
||||
// }
|
||||
|
||||
function handleUpdateDetail() {
|
||||
const updated = snapshotForm();
|
||||
|
||||
tempDetailContact = tempDetailContact.map((row) =>
|
||||
row.id === editingId
|
||||
?
|
||||
{
|
||||
...row,
|
||||
...updated,
|
||||
ContactDetID: row.ContactDetID ?? null
|
||||
} : row
|
||||
);
|
||||
|
||||
resetContactDetailForm();
|
||||
}
|
||||
|
||||
function handleCancelEditDetail() {
|
||||
resetContactDetailForm();
|
||||
}
|
||||
$inspect(deletedDetailIds)
|
||||
function handleRemoveDetail(id) {
|
||||
const row = tempDetailContact.find(r => r.id === id);
|
||||
if (row?.ContactDetID) {
|
||||
deletedDetailIds.push(row.ContactDetID);
|
||||
}
|
||||
|
||||
// Reset form dan tutup form
|
||||
detailFormState.reset();
|
||||
detailFormState.setForm({ ...contactDetailInitialForm });
|
||||
editingDetailIndex = null;
|
||||
showDetailForm = false;
|
||||
}
|
||||
|
||||
function editDetail(index) {
|
||||
const detailToEdit = masterDetail.selectedItem.data.Details[index];
|
||||
editingDetailIndex = index; // Set mode edit dengan index
|
||||
detailFormState.setForm({ ...detailToEdit }); // Load data ke form
|
||||
showDetailForm = true;
|
||||
}
|
||||
|
||||
function cancelDetail() {
|
||||
detailFormState.reset();
|
||||
detailFormState.setForm({ ...contactDetailInitialForm });
|
||||
editingDetailIndex = null;
|
||||
showDetailForm = false;
|
||||
}
|
||||
|
||||
function removeDetail(index) {
|
||||
masterDetail.selectedItem.data.Details = masterDetail.selectedItem.data.Details.filter((_, i) => i !== index);
|
||||
toast('Contact Detail Removed!');
|
||||
|
||||
// Jika sedang mengedit detail yang dihapus, reset form
|
||||
if (editingDetailIndex === index) {
|
||||
cancelDetail();
|
||||
} else if (editingDetailIndex !== null && editingDetailIndex > index) {
|
||||
// Adjust index jika mengedit detail setelah yang dihapus
|
||||
editingDetailIndex--;
|
||||
tempDetailContact = tempDetailContact.filter((row) => row.id !== id);
|
||||
if (editingId === id) {
|
||||
resetContactDetailForm();
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
const mainForm = formState.form;
|
||||
if (mainForm.Details && Array.isArray(mainForm.Details)) {
|
||||
tempDetailContact = mainForm.Details.map((row, index) => ({
|
||||
id: row.id ?? index + 1,
|
||||
...row,
|
||||
}));
|
||||
}
|
||||
})
|
||||
|
||||
$effect(() => {
|
||||
const maxId = tempDetailContact.reduce((max, row) => {
|
||||
const rowId = typeof row.id === 'number' ? row.id : 0;
|
||||
return rowId > max ? rowId : max;
|
||||
}, 0);
|
||||
|
||||
if (maxId > idCounter) {
|
||||
idCounter = maxId;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<FormPageContainer title="Edit Contact" {primaryAction} {secondaryActions}>
|
||||
@ -215,96 +319,82 @@
|
||||
formFields={formFields}
|
||||
mode="edit"
|
||||
/>
|
||||
|
||||
<Separator class="my-4"/>
|
||||
<div class="flex flex-col px-2 py-1 gap-2 h-fit w-full">
|
||||
<TopbarWrapper
|
||||
title="Contact Detail"
|
||||
actions={actionsDetail}
|
||||
|
||||
<div>
|
||||
<DictionaryFormRenderer
|
||||
formState={contactDetailFormState}
|
||||
formFields={contactDetailFormFields}
|
||||
mode="create"
|
||||
/>
|
||||
<div class="flex flex-col gap-4">
|
||||
{#if showDetailForm}
|
||||
<Card.Root class="w-full gap-2 2xl:gap-4 py-2 2xl:py-4">
|
||||
<Card.Content class="space-y-3">
|
||||
<DictionaryFormRenderer
|
||||
formState={detailFormState}
|
||||
formFields={contactDetailFormFields}
|
||||
/>
|
||||
</Card.Content>
|
||||
<Card.Footer class="flex justify-end flex-end gap-2">
|
||||
<Button size="sm" onclick={saveDetail}>
|
||||
{isEditingDetail ? 'Update Detail' : 'Save Detail'}
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" onclick={cancelDetail}>Cancel</Button>
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
<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}>Insert</Button>
|
||||
{/if}
|
||||
{#each masterDetail.selectedItem?.data?.Details as contactdetail, index}
|
||||
<Card.Root class="w-full gap-2 2xl:gap-4 py-2 2xl:py-4">
|
||||
<Card.Header>
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="space-y-1">
|
||||
<Card.Title class="text-sm font-medium">
|
||||
{contactdetail.ContactCode || "null"}
|
||||
</Card.Title>
|
||||
<Card.Description class="text-sm font-medium">
|
||||
{contactdetail.ContactEmail || "null"}
|
||||
</Card.Description>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<Badge variant="outline" class="text-xs">
|
||||
{getLabel('SiteID', contactdetail.SiteID)}
|
||||
</Badge>
|
||||
<div>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost" class="size-7"
|
||||
onclick={() => editDetail(index)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<Separator />
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.Row class="hover:bg-transparent">
|
||||
<Table.Head>Site</Table.Head>
|
||||
<Table.Head>Code</Table.Head>
|
||||
<Table.Head>Department</Table.Head>
|
||||
<Table.Head>Occupation</Table.Head>
|
||||
<Table.Head>Job Title</Table.Head>
|
||||
<Table.Head>Email</Table.Head>
|
||||
<Table.Head class="w-[80px]"></Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#if tempDetailContact.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 tempDetailContact as row (row.id)}
|
||||
<Table.Row>
|
||||
<Table.Cell>{row.SiteID}</Table.Cell>
|
||||
<Table.Cell>{row.ContactCode}</Table.Cell>
|
||||
<Table.Cell>{row.Department}</Table.Cell>
|
||||
<Table.Cell>{row.OccupationID}</Table.Cell>
|
||||
<Table.Cell>{row.JobTitle}</Table.Cell>
|
||||
<Table.Cell>{row.ContactEmail}</Table.Cell>
|
||||
<Table.Cell class="w-[80px]">
|
||||
<div class="flex gap-1">
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
class="h-7 w-7 cursor-pointer"
|
||||
onclick={() => handleEditDetail(row)}
|
||||
>
|
||||
<Edit2Icon class="h-4 w-4" />
|
||||
<PencilIcon class="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost" class="size-7"
|
||||
onclick={() => removeDetail(index)}
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
class="h-7 w-7 cursor-pointer"
|
||||
onclick={() => handleRemoveDetail(row.id)}
|
||||
>
|
||||
<XIcon class="h-4 w-4" />
|
||||
<Trash2Icon class="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Content class="space-y-3">
|
||||
<div class="grid grid-cols-3 gap-3">
|
||||
<div class="space-y-1">
|
||||
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
Department
|
||||
</p>
|
||||
<p class="text-sm font-medium">
|
||||
{getLabel('Department', contactdetail.Department)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
Job Title
|
||||
</p>
|
||||
<p class="text-sm font-medium">
|
||||
{contactdetail.JobTitle || "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
Occupation
|
||||
</p>
|
||||
<p class="text-sm font-medium">
|
||||
<!-- {contactdetail.OccupationID || "-"} -->
|
||||
{getLabel('OccupationID', contactdetail.OccupationID)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
{/each}
|
||||
</div>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
{/if}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
</FormPageContainer>
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
import PlusIcon from "@lucide/svelte/icons/plus";
|
||||
import * as Card from "$lib/components/ui/card/index.js";
|
||||
import { Badge } from "$lib/components/ui/badge/index.js";
|
||||
import * as Table from "$lib/components/ui/table/index.js";
|
||||
|
||||
let props = $props();
|
||||
|
||||
@ -41,6 +42,46 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#snippet DetailsTable({ value, label })}
|
||||
<div class="space-y-1.5 w-full">
|
||||
<dt class="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
{label}
|
||||
</dt>
|
||||
<dd>
|
||||
{#if value && Array.isArray(value) && value.length > 0}
|
||||
<div class="border rounded-md">
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.Head>Site</Table.Head>
|
||||
<Table.Head>Code</Table.Head>
|
||||
<Table.Head>Department</Table.Head>
|
||||
<Table.Head>Occupation</Table.Head>
|
||||
<Table.Head>Job Title</Table.Head>
|
||||
<Table.Head>Email</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each value as row, i}
|
||||
<Table.Row>
|
||||
<Table.Cell>{row.SiteID}</Table.Cell>
|
||||
<Table.Cell>{row.ContactCode}</Table.Cell>
|
||||
<Table.Cell>{row.Department}</Table.Cell>
|
||||
<Table.Cell>{row.OccupationID}</Table.Cell>
|
||||
<Table.Cell>{row.JobTitle}</Table.Cell>
|
||||
<Table.Cell>{row.ContactEmail}</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
{:else}
|
||||
<span class="text-sm font-medium">-</span>
|
||||
{/if}
|
||||
</dd>
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
{#snippet Fieldset({ value, label, isUTCDate = false })}
|
||||
<div class="space-y-1.5">
|
||||
<dt class="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
@ -62,7 +103,7 @@
|
||||
title={masterDetail.selectedItem.data.NameFirst}
|
||||
{actions}
|
||||
/>
|
||||
<div class="flex-1 min-h-0 overflow-y-auto space-y-4">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto">
|
||||
{#each detailSections as section}
|
||||
<div class="p-4">
|
||||
{#if section.groups}
|
||||
@ -84,11 +125,26 @@
|
||||
{:else}
|
||||
<div class={section.class}>
|
||||
{#each section.fields as field}
|
||||
{@render Fieldset({
|
||||
label: field.label,
|
||||
value: getFieldValue(field),
|
||||
isUTCDate: field.isUTCDate
|
||||
})}
|
||||
{#if field.fullWidth}
|
||||
<div class="col-span-2">
|
||||
{#if field.key === "Details"}
|
||||
{@render DetailsTable({ label: field.label, value: getFieldValue(field) })}
|
||||
{:else}
|
||||
{@render Fieldset({ label: field.label, value: getFieldValue(field), isUTCDate: field.isUTCDate })}
|
||||
{/if}
|
||||
</div>
|
||||
{:else if field.key === "Details"}
|
||||
{@render DetailsTable({
|
||||
label: field.label,
|
||||
value: getFieldValue(field),
|
||||
})}
|
||||
{:else}
|
||||
{@render Fieldset({
|
||||
label: field.label,
|
||||
value: getFieldValue(field),
|
||||
isUTCDate: field.isUTCDate
|
||||
})}
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
@ -96,62 +152,6 @@
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<div class="flex flex-col px-2 py-1 gap-2 h-full w-full">
|
||||
<TopbarWrapper
|
||||
title="Contact Detail"
|
||||
actions={actionsDetail}
|
||||
/>
|
||||
<div class="flex flex-col gap-4">
|
||||
{#each masterDetail.selectedItem?.data?.Details as contactdetail}
|
||||
<Card.Root class="w-full gap-2 2xl:gap-4 py-2 2xl:py-4">
|
||||
<Card.Header>
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="space-y-1">
|
||||
<Card.Title class="text-sm font-medium">
|
||||
{contactdetail.ContactCode}
|
||||
</Card.Title>
|
||||
<Card.Description class="text-sm font-medium">
|
||||
{contactdetail.ContactEmail}
|
||||
</Card.Description>
|
||||
</div>
|
||||
<Badge variant="secondary" class="text-xs">
|
||||
Site {contactdetail.SiteID}
|
||||
</Badge>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Content class="space-y-3">
|
||||
<div class="grid grid-cols-3 gap-3">
|
||||
<div class="space-y-1">
|
||||
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
Department
|
||||
</p>
|
||||
<p class="text-sm font-medium">
|
||||
{contactdetail.Department || "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
Job Title
|
||||
</p>
|
||||
<p class="text-sm font-medium">
|
||||
{contactdetail.JobTitle || "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
Occupation
|
||||
</p>
|
||||
<p class="text-sm font-medium">
|
||||
{contactdetail.OccupationID || "-"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<ReusableEmpty icon={UserXIcon} desc="Select a contact to see details"/>
|
||||
{/if}
|
||||
@ -13,6 +13,6 @@ export async function createContainer(newContainerForm) {
|
||||
return await create(API.CONTAINER, newContainerForm)
|
||||
}
|
||||
|
||||
export async function editContainer(editContainerForm) {
|
||||
return await update(API.CONTAINER, editContainerForm)
|
||||
export async function editContainer(editContainerForm, id) {
|
||||
return await update(API.CONTAINER, editContainerForm, id)
|
||||
}
|
||||
@ -28,9 +28,9 @@ export const detailSections = [
|
||||
{
|
||||
class: "grid grid-cols-2 gap-4 items-center",
|
||||
fields: [
|
||||
{ key: "ConClass", label: "Container Class" },
|
||||
{ key: "ConClassLabel", label: "Container Class" },
|
||||
{ key: "Color", label: "Color" },
|
||||
{ key: "Additive", label: "Additive" },
|
||||
{ key: "AdditiveLabel", label: "Additive" },
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
import { untrack } from "svelte";
|
||||
import { API } from "$lib/config/api";
|
||||
import ReusableAlertDialog from "$lib/components/reusable/reusable-alert-dialog.svelte";
|
||||
import { getChangedFields } from "$lib/utils/getChangedFields";
|
||||
|
||||
let props = $props();
|
||||
|
||||
@ -38,7 +39,24 @@
|
||||
});
|
||||
|
||||
async function handleEdit() {
|
||||
const result = await formState.save(masterDetail.mode);
|
||||
const currentPayload = formState.form;
|
||||
const originalPayload = masterDetail.formSnapshot;
|
||||
|
||||
const changedFields = getChangedFields(originalPayload, currentPayload);
|
||||
|
||||
if (Object.keys(changedFields).length === 0) {
|
||||
toast('No changes detected');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
ConDefID: formState.form.ConDefID,
|
||||
...changedFields
|
||||
};
|
||||
|
||||
console.log('Payload:', payload);
|
||||
|
||||
const result = await formState.save(masterDetail.mode, payload);
|
||||
|
||||
if (result.status === 'success') {
|
||||
console.log('Container updated successfully');
|
||||
@ -46,6 +64,8 @@
|
||||
masterDetail.exitForm(true);
|
||||
} else {
|
||||
console.error('Failed to update container:', result.message);
|
||||
const errorMessages = result.messages ? Object.values(result.messages).join('\n') : 'Failed to update container';
|
||||
toast.error(errorMessages)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,6 @@ export async function createLocation(newLocationForm) {
|
||||
return await create(API.LOCATION, newLocationForm)
|
||||
}
|
||||
|
||||
export async function editLocation(editLocationForm) {
|
||||
return await update(API.LOCATION, editLocationForm)
|
||||
export async function editLocation(editLocationForm, id) {
|
||||
return await update(API.LOCATION, editLocationForm, id)
|
||||
}
|
||||
@ -43,7 +43,8 @@ export const detailSections = [
|
||||
fields: [
|
||||
{ key: "Province", label: "Province" },
|
||||
{ key: "City", label: "City" },
|
||||
{ key: "PostCode", label: "ZIP" },
|
||||
{ key: "PostCode", label: "Post Code" },
|
||||
{ key: "Email", label: "Email" },
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -51,8 +52,10 @@ export const detailSections = [
|
||||
fields: [
|
||||
{ key: "Street1", label: "Street 1" },
|
||||
{ key: "Street2", label: "Street 2" },
|
||||
{ key: "Phone", label: "Phone" },
|
||||
{ key: "Mobile", label: "Mobile" },
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@ -7,24 +7,28 @@ export const locationSchema = z.object({
|
||||
LocFull: z.string().min(1, "Required"),
|
||||
Email: z.string().trim().optional().refine((val) => !val || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val),"Invalid email format"),
|
||||
Phone: z.string().max(14, "Max 14 chars").regex(/^$|^[0-9]+$/, "Can only contain numbers"),
|
||||
ZIP: z.string().regex(/^$|^[0-9]+$/, "Can only contain numbers"),
|
||||
Mobile: z.string().max(14, "Max 14 chars").regex(/^$|^[0-9]+$/, "Can only contain numbers"),
|
||||
PostCode: z.string().regex(/^$|^[0-9]+$/, "Can only contain numbers"),
|
||||
});
|
||||
|
||||
export const locationInitialForm = {
|
||||
LocationID: '',
|
||||
LocCode: '',
|
||||
LocType: '',
|
||||
LocFull: '',
|
||||
SiteID: '',
|
||||
LocCode: '',
|
||||
Parent: '',
|
||||
LocFull: '',
|
||||
Description: '',
|
||||
LocType: '',
|
||||
Street1: '',
|
||||
Street2: '',
|
||||
Phone: '',
|
||||
Email: '',
|
||||
City: '',
|
||||
Province: '',
|
||||
ZIP: '',
|
||||
City: '',
|
||||
PostCode: '',
|
||||
GeoLocationSystem: '',
|
||||
GeoLocationData: '',
|
||||
Phone: '',
|
||||
Mobile: '',
|
||||
Email: '',
|
||||
};
|
||||
|
||||
export const locationDefaultErrors = {
|
||||
@ -32,7 +36,8 @@ export const locationDefaultErrors = {
|
||||
LocFull: "Required",
|
||||
Email: null,
|
||||
Phone: null,
|
||||
ZIP: null,
|
||||
Mobile: null,
|
||||
PostCode: null,
|
||||
};
|
||||
|
||||
export const locationFormFields = [
|
||||
@ -52,17 +57,26 @@ export const locationFormFields = [
|
||||
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`,
|
||||
},
|
||||
{
|
||||
key: "LocCode",
|
||||
label: "Location Code",
|
||||
required: true,
|
||||
type: "text",
|
||||
validateOn: ["input"]
|
||||
key: "Parent",
|
||||
label: "Parent",
|
||||
required: false,
|
||||
type: "select",
|
||||
optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
|
||||
valueKey: "SiteID",
|
||||
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`,
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "row",
|
||||
columns: [
|
||||
{
|
||||
key: "LocCode",
|
||||
label: "Location Code",
|
||||
required: true,
|
||||
type: "text",
|
||||
validateOn: ["input"]
|
||||
},
|
||||
{
|
||||
key: "LocType",
|
||||
label: "Location Type",
|
||||
@ -70,13 +84,25 @@ export const locationFormFields = [
|
||||
type: "select",
|
||||
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/location_type`,
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "row",
|
||||
columns: [
|
||||
{
|
||||
key: "LocFull",
|
||||
label: "Location Name",
|
||||
required: true,
|
||||
type: "text",
|
||||
validateOn: ["input"]
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "Description",
|
||||
label: "Description",
|
||||
required: false,
|
||||
type: "text",
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
@ -126,8 +152,8 @@ export const locationFormFields = [
|
||||
type: "row",
|
||||
columns: [
|
||||
{
|
||||
key: "ZIP",
|
||||
label: "ZIP",
|
||||
key: "PostCode",
|
||||
label: "Post Code",
|
||||
required: false,
|
||||
type: "text",
|
||||
validateOn: ["input"],
|
||||
@ -150,13 +176,20 @@ export const locationFormFields = [
|
||||
type: "text",
|
||||
validateOn: ["input"]
|
||||
},
|
||||
{
|
||||
key: "Mobile",
|
||||
label: "Mobile",
|
||||
required: false,
|
||||
type: "text",
|
||||
validateOn: ["input"]
|
||||
},
|
||||
{
|
||||
key: "Email",
|
||||
label: "Email",
|
||||
required: false,
|
||||
type: "text",
|
||||
validateOn: ["input"]
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
import { untrack } from "svelte";
|
||||
import { API } from "$lib/config/api";
|
||||
import ReusableAlertDialog from "$lib/components/reusable/reusable-alert-dialog.svelte";
|
||||
import { getChangedFields } from "$lib/utils/getChangedFields";
|
||||
|
||||
let props = $props();
|
||||
|
||||
@ -50,7 +51,24 @@
|
||||
});
|
||||
|
||||
async function handleEdit() {
|
||||
const result = await formState.save(masterDetail.mode);
|
||||
const currentPayload = formState.form;
|
||||
const originalPayload = masterDetail.formSnapshot;
|
||||
|
||||
const changedFields = getChangedFields(originalPayload, currentPayload);
|
||||
|
||||
if (Object.keys(changedFields).length === 0) {
|
||||
toast('No changes detected');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
LocationID: formState.form.LocationID,
|
||||
...changedFields
|
||||
};
|
||||
|
||||
console.log('Payload:', payload);
|
||||
|
||||
const result = await formState.save(masterDetail.mode, payload);
|
||||
|
||||
if (result.status === 'success') {
|
||||
console.log('Location updated successfully');
|
||||
@ -58,6 +76,8 @@
|
||||
masterDetail.exitForm(true);
|
||||
} else {
|
||||
console.error('Failed to update location:', result.message);
|
||||
const errorMessages = result.messages ? Object.values(result.messages).join('\n') : 'Failed to update location';
|
||||
toast.error(errorMessages)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,6 @@ export async function createOccupation(newOccupationForm) {
|
||||
return await create(API.OCCUPATION, newOccupationForm)
|
||||
}
|
||||
|
||||
export async function editOccupation(editOccupationForm) {
|
||||
return await update(API.OCCUPATION, editOccupationForm)
|
||||
export async function editOccupation(editOccupationForm, id) {
|
||||
return await update(API.OCCUPATION, editOccupationForm, id)
|
||||
}
|
||||
@ -6,6 +6,7 @@
|
||||
import { untrack } from "svelte";
|
||||
import { API } from "$lib/config/api";
|
||||
import ReusableAlertDialog from "$lib/components/reusable/reusable-alert-dialog.svelte";
|
||||
import { getChangedFields } from "$lib/utils/getChangedFields";
|
||||
|
||||
let props = $props();
|
||||
|
||||
@ -38,7 +39,24 @@
|
||||
});
|
||||
|
||||
async function handleEdit() {
|
||||
const result = await formState.save(masterDetail.mode);
|
||||
const currentPayload = formState.form;
|
||||
const originalPayload = masterDetail.formSnapshot;
|
||||
|
||||
const changedFields = getChangedFields(originalPayload, currentPayload);
|
||||
|
||||
if (Object.keys(changedFields).length === 0) {
|
||||
toast('No changes detected');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
OccupationID: formState.form.OccupationID,
|
||||
...changedFields
|
||||
};
|
||||
|
||||
console.log('Payload:', payload);
|
||||
|
||||
const result = await formState.save(masterDetail.mode, payload);
|
||||
|
||||
if (result.status === 'success') {
|
||||
console.log('Occupation updated successfully');
|
||||
@ -46,6 +64,8 @@
|
||||
masterDetail.exitForm(true);
|
||||
} else {
|
||||
console.error('Failed to update occupation:', result.message);
|
||||
const errorMessages = result.messages ? Object.values(result.messages).join('\n') : 'Failed to update occupation';
|
||||
toast.error(errorMessages)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ export const detailSections = [
|
||||
{ key: "ClientTypeLabel", label: "Client Type" },
|
||||
{ key: "HostID", label: "Host ID" },
|
||||
{ key: "ClientID", label: "Client ID" },
|
||||
{ key: "details", label: "Details", fullWidth: true },
|
||||
{ key: "Details", label: "Details", fullWidth: true },
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
@ -16,7 +16,7 @@ export const API = {
|
||||
PATVISIT: '/api/patvisit',
|
||||
VISITLIST: '/api/patvisit/patient/',
|
||||
COUNTER: '/api/counter',
|
||||
CONTAINER: '/api/specimen/containerdef',
|
||||
CONTAINER: '/api/specimen/container',
|
||||
PROVINCE: '/api/areageo/provinces',
|
||||
CITY: '/api/areageo/cities',
|
||||
ACCOUNT: '/api/organization/account',
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
modeOpt: 'cascade',
|
||||
saveEndpoint: createAccount,
|
||||
editEndpoint: editAccount,
|
||||
idKey: 'AccountID',
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
modeOpt: 'default',
|
||||
saveEndpoint: createContainer,
|
||||
editEndpoint: editContainer,
|
||||
idKey: 'ConDefID',
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
modeOpt: 'cascade',
|
||||
saveEndpoint: createLocation,
|
||||
editEndpoint: editLocation,
|
||||
idKey: 'LocationID',
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
modeOpt: 'default',
|
||||
saveEndpoint: createOccupation,
|
||||
editEndpoint: editOccupation,
|
||||
idKey: 'OccupationID',
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user