mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-27 03:16:33 +07:00
16022025
fix ubah url parameter dari parent jadi ProvinceID fix tampilan input bisa fullWidth atau tidak dari form config
This commit is contained in:
parent
8f9e9ddffd
commit
671a360c4c
@ -29,6 +29,7 @@ const optionsMode = {
|
|||||||
|
|
||||||
cascade: async (field, selectOptions, loadingOptions, form, lastFetched) => {
|
cascade: async (field, selectOptions, loadingOptions, form, lastFetched) => {
|
||||||
const parentValue = field.dependsOn ? form?.[field.dependsOn] : null;
|
const parentValue = field.dependsOn ? form?.[field.dependsOn] : null;
|
||||||
|
// console.log(parentValue);
|
||||||
|
|
||||||
// If has dependency and parent changed, or not fetched yet
|
// If has dependency and parent changed, or not fetched yet
|
||||||
if (field.dependsOn) {
|
if (field.dependsOn) {
|
||||||
|
|||||||
18
src/lib/components/dictionary/account/api/account-api.js
Normal file
18
src/lib/components/dictionary/account/api/account-api.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { API } from '$lib/config/api.js';
|
||||||
|
import { getById, searchWithParams, create, update } from '$lib/api/api-client';
|
||||||
|
|
||||||
|
export async function getAccounts(searchQuery) {
|
||||||
|
return await searchWithParams(API.ACCOUNT, searchQuery)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAccount(searchQuery) {
|
||||||
|
return await getById(API.ACCOUNT, searchQuery)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createAccount(newAccountForm) {
|
||||||
|
return await create(API.ACCOUNT, newAccountForm)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editAccount(editAccountForm) {
|
||||||
|
return await update(API.ACCOUNT, editAccountForm)
|
||||||
|
}
|
||||||
@ -38,7 +38,13 @@ export const containerFormFields = [
|
|||||||
optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
|
optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
|
||||||
valueKey: "SiteID",
|
valueKey: "SiteID",
|
||||||
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`,
|
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`,
|
||||||
|
fullWidth: false,
|
||||||
},
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "row",
|
||||||
|
columns: [
|
||||||
{
|
{
|
||||||
key: "ConCode",
|
key: "ConCode",
|
||||||
label: "Container Code",
|
label: "Container Code",
|
||||||
@ -46,18 +52,18 @@ export const containerFormFields = [
|
|||||||
type: "text",
|
type: "text",
|
||||||
validateOn: ["input"]
|
validateOn: ["input"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "ConName",
|
||||||
|
label: "Container Name",
|
||||||
|
required: true,
|
||||||
|
type: "text",
|
||||||
|
validateOn: ["input"]
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "row",
|
type: "row",
|
||||||
columns: [
|
columns: [
|
||||||
{
|
|
||||||
key: "ConName",
|
|
||||||
label: "Container Name",
|
|
||||||
required: true,
|
|
||||||
type: "text",
|
|
||||||
validateOn: ["input"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "ConDesc",
|
key: "ConDesc",
|
||||||
label: "Description",
|
label: "Description",
|
||||||
@ -99,6 +105,7 @@ export const containerFormFields = [
|
|||||||
required: false,
|
required: false,
|
||||||
type: "select",
|
type: "select",
|
||||||
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/additive`,
|
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/additive`,
|
||||||
|
fullWidth: false
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,7 +112,7 @@ export const locationFormFields = [
|
|||||||
type: "select",
|
type: "select",
|
||||||
optionsEndpoint: `${API.BASE_URL}${API.CITY}`,
|
optionsEndpoint: `${API.BASE_URL}${API.CITY}`,
|
||||||
dependsOn: "Province",
|
dependsOn: "Province",
|
||||||
endpointParamKey: "Parent"
|
endpointParamKey: "ProvinceID"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "Street2",
|
key: "Street2",
|
||||||
@ -130,7 +130,8 @@ export const locationFormFields = [
|
|||||||
label: "ZIP",
|
label: "ZIP",
|
||||||
required: false,
|
required: false,
|
||||||
type: "text",
|
type: "text",
|
||||||
validateOn: ["input"]
|
validateOn: ["input"],
|
||||||
|
fullWidth: false
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@ -44,10 +44,10 @@ export const patientInitialForm = {
|
|||||||
Citizenship: "",
|
Citizenship: "",
|
||||||
Street_1: "",
|
Street_1: "",
|
||||||
City: "",
|
City: "",
|
||||||
CityID: "",
|
// CityID: "",
|
||||||
Street_2: "",
|
Street_2: "",
|
||||||
Province: "",
|
Province: "",
|
||||||
ProvinceID: "",
|
// ProvinceID: "",
|
||||||
Street_3: "",
|
Street_3: "",
|
||||||
ZIP: "",
|
ZIP: "",
|
||||||
Country: "",
|
Country: "",
|
||||||
@ -205,7 +205,7 @@ export const patientFormFields = [
|
|||||||
columns: [
|
columns: [
|
||||||
{ key: "Street_1", label: "Street 1", required: false, type: "text" },
|
{ key: "Street_1", label: "Street 1", required: false, type: "text" },
|
||||||
{
|
{
|
||||||
key: "ProvinceID",
|
key: "Province",
|
||||||
label: "Province",
|
label: "Province",
|
||||||
required: false,
|
required: false,
|
||||||
type: "select",
|
type: "select",
|
||||||
@ -218,13 +218,13 @@ export const patientFormFields = [
|
|||||||
columns: [
|
columns: [
|
||||||
{ key: "Street_2", label: "Street 2", required: false, type: "text" },
|
{ key: "Street_2", label: "Street 2", required: false, type: "text" },
|
||||||
{
|
{
|
||||||
key: "CityID",
|
key: "City",
|
||||||
label: "City",
|
label: "City",
|
||||||
required: false,
|
required: false,
|
||||||
type: "select",
|
type: "select",
|
||||||
optionsEndpoint: `${API.BASE_URL}${API.CITY}`,
|
optionsEndpoint: `${API.BASE_URL}${API.CITY}`,
|
||||||
dependsOn: "ProvinceID",
|
dependsOn: "Province",
|
||||||
endpointParamKey: "Parent"
|
endpointParamKey: "ProvinceID"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@ -63,6 +63,7 @@
|
|||||||
disabled: formState.isSaving.current
|
disabled: formState.isSaving.current
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
// $inspect(formState.selectOptions)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FormPageContainer title="Create Patient" {primaryAction} {secondaryActions} {actions}>
|
<FormPageContainer title="Create Patient" {primaryAction} {secondaryActions} {actions}>
|
||||||
|
|||||||
@ -84,8 +84,8 @@
|
|||||||
{
|
{
|
||||||
key: "City",
|
key: "City",
|
||||||
optionsEndpoint: `${API.BASE_URL}${API.CITY}`,
|
optionsEndpoint: `${API.BASE_URL}${API.CITY}`,
|
||||||
dependsOn: "ProvinceID",
|
dependsOn: "Province",
|
||||||
endpointParamKey: "Parent"
|
endpointParamKey: "ProvinceID"
|
||||||
},
|
},
|
||||||
formState.form
|
formState.form
|
||||||
);
|
);
|
||||||
|
|||||||
@ -204,19 +204,31 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#each group.rows as row}
|
{#each group.rows as row}
|
||||||
<div
|
<!-- <div
|
||||||
class="grid grid-cols-1 space-y-2 gap-6 md:gap-4"
|
class="grid grid-cols-1 space-y-2 gap-6 md:gap-4"
|
||||||
class:md:grid-cols-1={row.columns.length === 1}
|
class:md:grid-cols-1={row.columns.length === 1}
|
||||||
class:md:grid-cols-2={row.columns.length === 2}
|
class:md:grid-cols-2={row.columns.length === 2}
|
||||||
class:md:grid-cols-3={row.columns.length === 3}
|
class:md:grid-cols-3={row.columns.length === 3}
|
||||||
|
> -->
|
||||||
|
<div
|
||||||
|
class="grid grid-cols-1 space-y-2 gap-6 md:gap-4"
|
||||||
|
class:md:grid-cols-1={row.columns.length === 1 && row.columns[0].fullWidth !== false}
|
||||||
|
class:md:grid-cols-2={row.columns.length === 2 || (row.columns.length === 1 && row.columns[0].fullWidth === false)}
|
||||||
|
class:md:grid-cols-3={row.columns.length === 3}
|
||||||
>
|
>
|
||||||
{#each row.columns as col}
|
{#each row.columns as col}
|
||||||
{#if col.type === "group"}
|
{#if col.type === "group"}
|
||||||
<div
|
<!-- <div
|
||||||
class="grid grid-cols-1 gap-6 md:gap-2"
|
class="grid grid-cols-1 gap-6 md:gap-2"
|
||||||
class:md:grid-cols-1={col.columns.length === 1}
|
class:md:grid-cols-1={col.columns.length === 1}
|
||||||
class:md:grid-cols-2={col.columns.length === 2}
|
class:md:grid-cols-2={col.columns.length === 2}
|
||||||
class:md:grid-cols-3={col.columns.length === 3}
|
class:md:grid-cols-3={col.columns.length === 3}
|
||||||
|
> -->
|
||||||
|
<div
|
||||||
|
class="grid grid-cols-1 gap-6 md:gap-2"
|
||||||
|
class:md:grid-cols-1={col.columns.length === 1 && col.columns[0].fullWidth !== false}
|
||||||
|
class:md:grid-cols-2={col.columns.length === 2 || (col.columns.length === 1 && col.columns[0].fullWidth === false)}
|
||||||
|
class:md:grid-cols-3={col.columns.length === 3}
|
||||||
>
|
>
|
||||||
{#each col.columns as child}
|
{#each col.columns as child}
|
||||||
{@render Fieldset(child)}
|
{@render Fieldset(child)}
|
||||||
|
|||||||
210
src/lib/components/reusable/reusable-data-table copy.svelte
Normal file
210
src/lib/components/reusable/reusable-data-table copy.svelte
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
<script>
|
||||||
|
import { getCoreRowModel, getPaginationRowModel, getFilteredRowModel } from "@tanstack/table-core";
|
||||||
|
import {
|
||||||
|
createSvelteTable,
|
||||||
|
FlexRender,
|
||||||
|
} from "$lib/components/ui/data-table/index.js";
|
||||||
|
import * as Table from "$lib/components/ui/table/index.js";
|
||||||
|
import { Button } from "$lib/components/ui/button/index.js";
|
||||||
|
import * as Select from "$lib/components/ui/select/index.js";
|
||||||
|
import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
|
||||||
|
import ChevronLeftIcon from "@lucide/svelte/icons/chevron-left";
|
||||||
|
import ChevronsRightIcon from "@lucide/svelte/icons/chevrons-right";
|
||||||
|
import ChevronsLeftIcon from "@lucide/svelte/icons/chevrons-left";
|
||||||
|
import { Input } from "$lib/components/ui/input/index.js";
|
||||||
|
|
||||||
|
let props = $props();
|
||||||
|
|
||||||
|
let pagination = $state({ pageIndex: 0, pageSize: 10 });
|
||||||
|
let columnFilters = $state([]);
|
||||||
|
let globalFilter = $state("");
|
||||||
|
let activeRowId = $state(null);
|
||||||
|
|
||||||
|
let table = createSvelteTable({
|
||||||
|
get data() {
|
||||||
|
return props.data;
|
||||||
|
},
|
||||||
|
get columns() {
|
||||||
|
return props.columns;
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
get pagination() {
|
||||||
|
return pagination;
|
||||||
|
},
|
||||||
|
get columnFilters() {
|
||||||
|
return columnFilters;
|
||||||
|
},
|
||||||
|
get globalFilter() {
|
||||||
|
return globalFilter;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onPaginationChange: (updater) => {
|
||||||
|
if (typeof updater === "function") {
|
||||||
|
pagination = updater(pagination);
|
||||||
|
} else {
|
||||||
|
pagination = updater;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onColumnFiltersChange: (updater) => {
|
||||||
|
if (typeof updater === "function") {
|
||||||
|
columnFilters = updater(columnFilters);
|
||||||
|
} else {
|
||||||
|
columnFilters = updater;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onGlobalFilterChange: (value) => {
|
||||||
|
globalFilter = value;
|
||||||
|
},
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- ✅ Updated with scrollable body -->
|
||||||
|
<div class="h-full flex flex-col relative w-full">
|
||||||
|
{#if props.searchable ?? true}
|
||||||
|
<div class="flex items-center absolute top-[-2rem]">
|
||||||
|
<Input
|
||||||
|
placeholder="Filter all columns..."
|
||||||
|
value={globalFilter}
|
||||||
|
oninput={(e) => {
|
||||||
|
globalFilter = e.currentTarget.value;
|
||||||
|
}}
|
||||||
|
class="h-7 w-64 text-xs px-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- ✅ Container with flex column -->
|
||||||
|
<div class="rounded-md border h-full flex flex-col w-full overflow-hidden">
|
||||||
|
|
||||||
|
<!-- ✅ Wrapper untuk table dengan overflow -->
|
||||||
|
<div class="flex-1 overflow-auto">
|
||||||
|
<Table.Root>
|
||||||
|
<!-- ✅ Sticky Header -->
|
||||||
|
<Table.Header class="sticky top-0 bg-background z-10">
|
||||||
|
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
||||||
|
<Table.Row>
|
||||||
|
{#each headerGroup.headers as header (header.id)}
|
||||||
|
<Table.Head colspan={header.colSpan}>
|
||||||
|
{#if !header.isPlaceholder}
|
||||||
|
<FlexRender
|
||||||
|
content={header.column.columnDef.header}
|
||||||
|
context={header.getContext()}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</Table.Head>
|
||||||
|
{/each}
|
||||||
|
</Table.Row>
|
||||||
|
{/each}
|
||||||
|
</Table.Header>
|
||||||
|
|
||||||
|
<!-- ✅ Scrollable Body -->
|
||||||
|
<Table.Body>
|
||||||
|
{#each table.getRowModel().rows as row (row.id)}
|
||||||
|
<Table.Row
|
||||||
|
data-state={row.getIsSelected() && "selected"}
|
||||||
|
onclick={() => props.handleRowClick(row.original)}
|
||||||
|
class="cursor-pointer"
|
||||||
|
>
|
||||||
|
{#each row.getVisibleCells() as cell, i (cell.id)}
|
||||||
|
<Table.Cell class={`${i === 0 ? "border-l-4" : ""} ${i === 0 && activeRowId == row.original[props.rowIdKey] ? "border-primary" : "border-transparent"}`}>
|
||||||
|
<FlexRender
|
||||||
|
content={cell.column.columnDef.cell}
|
||||||
|
context={cell.getContext()}
|
||||||
|
/>
|
||||||
|
</Table.Cell>
|
||||||
|
{/each}
|
||||||
|
</Table.Row>
|
||||||
|
{:else}
|
||||||
|
<Table.Row>
|
||||||
|
<Table.Cell colspan={props.columns.length} class="h-24 text-center">
|
||||||
|
No results.
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
{/each}
|
||||||
|
</Table.Body>
|
||||||
|
</Table.Root>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ✅ Sticky Pagination Footer -->
|
||||||
|
<div class="flex items-center justify-between p-2 border-t bg-background">
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<p class="text-sm font-medium">Rows</p>
|
||||||
|
<Select.Root
|
||||||
|
allowDeselect={false}
|
||||||
|
type="single"
|
||||||
|
value={`${table.getState().pagination.pageSize}`}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
table.setPageSize(Number(value));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Select.Trigger class="h-7 w-[70px]">
|
||||||
|
{String(table.getState().pagination.pageSize)}
|
||||||
|
</Select.Trigger>
|
||||||
|
<Select.Content side="top">
|
||||||
|
{#each [5, 10, 15, 20, 25] as pageSize (pageSize)}
|
||||||
|
<Select.Item value={`${pageSize}`}>
|
||||||
|
{pageSize}
|
||||||
|
</Select.Item>
|
||||||
|
{/each}
|
||||||
|
</Select.Content>
|
||||||
|
</Select.Root>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex w-[100px] items-center justify-center text-sm font-medium">
|
||||||
|
Page {table.getState().pagination.pageIndex + 1} of
|
||||||
|
{table.getPageCount()}
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="hidden size-7 p-0 lg:flex"
|
||||||
|
onclick={() => table.setPageIndex(0)}
|
||||||
|
disabled={!table.getCanPreviousPage()}
|
||||||
|
>
|
||||||
|
<span class="sr-only">Go to first page</span>
|
||||||
|
<ChevronsLeftIcon />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="size-7 p-0"
|
||||||
|
onclick={() => table.previousPage()}
|
||||||
|
disabled={!table.getCanPreviousPage()}
|
||||||
|
>
|
||||||
|
<span class="sr-only">Go to previous page</span>
|
||||||
|
<ChevronLeftIcon />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="size-7 p-0"
|
||||||
|
onclick={() => table.nextPage()}
|
||||||
|
disabled={!table.getCanNextPage()}
|
||||||
|
>
|
||||||
|
<span class="sr-only">Go to next page</span>
|
||||||
|
<ChevronRightIcon />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="hidden size-7 p-0 lg:flex"
|
||||||
|
onclick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||||
|
disabled={!table.getCanNextPage()}
|
||||||
|
>
|
||||||
|
<span class="sr-only">Go to last page</span>
|
||||||
|
<ChevronsRightIcon />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* ✅ Ensure sticky header works properly */
|
||||||
|
:global(.sticky) {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1
src/routes/dictionary/account/+page.svelte
Normal file
1
src/routes/dictionary/account/+page.svelte
Normal file
@ -0,0 +1 @@
|
|||||||
|
acc
|
||||||
Loading…
x
Reference in New Issue
Block a user