diff --git a/app/components/app/divison/list-cfg.ts b/app/components/app/divison/list-cfg.ts index 45cfcd6f..509b47ee 100644 --- a/app/components/app/divison/list-cfg.ts +++ b/app/components/app/divison/list-cfg.ts @@ -10,29 +10,32 @@ import { defineAsyncComponent } from 'vue' type SmallDetailDto = any -const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue')) +const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-ud.vue')) export const cols: Col[] = [ - {}, - {}, - {}, - {}, + { width: 100 }, + { }, + { }, + { }, + { width: 50 }, ] export const header: Th[][] = [ [ { label: 'Id' }, - { label: 'Kode' }, { label: 'Nama' }, + { label: 'Kode' }, { label: 'Kelompok' }, + { label: '' }, ], ] export const keys = [ 'id', - 'cellphone', 'firstName', + 'cellphone', 'birth_place', + 'action', ] export const delKeyNames: KeyLabel[] = [ diff --git a/app/components/flow/division/entry.ts b/app/components/flow/division/entry.ts new file mode 100644 index 00000000..60617c45 --- /dev/null +++ b/app/components/flow/division/entry.ts @@ -0,0 +1,58 @@ +import * as z from 'zod' + +export const division = { + msg: { + placeholder: '---pilih divisi utama', + search: 'kode, nama divisi', + empty: 'divisi tidak ditemukan', + }, + items: [ + { value: '1', label: 'Medical', code: 'MED' }, + { value: '2', label: 'Nursing', code: 'NUR' }, + { value: '3', label: 'Admin', code: 'ADM' }, + { value: '4', label: 'Support', code: 'SUP' }, + { value: '5', label: 'Education', code: 'EDU' }, + { value: '6', label: 'Pharmacy', code: 'PHA' }, + { value: '7', label: 'Radiology', code: 'RAD' }, + { value: '8', label: 'Laboratory', code: 'LAB' }, + { value: '9', label: 'Finance', code: 'FIN' }, + { value: '10', label: 'Human Resources', code: 'HR' }, + { value: '11', label: 'IT Services', code: 'ITS' }, + { value: '12', label: 'Maintenance', code: 'MNT' }, + { value: '13', label: 'Catering', code: 'CAT' }, + { value: '14', label: 'Security', code: 'SEC' }, + { value: '15', label: 'Emergency', code: 'EMR' }, + { value: '16', label: 'Surgery', code: 'SUR' }, + { value: '17', label: 'Outpatient', code: 'OUT' }, + { value: '18', label: 'Inpatient', code: 'INP' }, + { value: '19', label: 'Rehabilitation', code: 'REB' }, + { value: '20', label: 'Research', code: 'RSH' }, + ], +} + +export const schema = z.object({ + name: z.string({ + required_error: 'Nama wajib diisi', + }).min(1, 'Nama divisi wajib diisi'), + + code: z.string({ + required_error: 'Kode wajib diisi', + }).min(1, 'Kode divisi wajib diisi'), + + parentId: z.preprocess( + (input: unknown) => { + if (typeof input === 'string') { + // Handle empty string case + if (input.trim() === '') { + return undefined + } + return Number(input) + } + + return input + }, + z.number({ + required_error: 'Kelompok wajib dipilih', + }).min(1, 'Kelompok wajib dipilih'), + ), +}) diff --git a/app/components/flow/division/entry.vue b/app/components/flow/division/entry.vue deleted file mode 100644 index cdd237ac..00000000 --- a/app/components/flow/division/entry.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - diff --git a/app/components/flow/division/list.vue b/app/components/flow/division/list.vue index 28f514b6..96b3a66a 100644 --- a/app/components/flow/division/list.vue +++ b/app/components/flow/division/list.vue @@ -2,8 +2,11 @@ import type { DataTableLoader } from '~/components/pub/base/data-table/type' import type { HeaderPrep } from '~/components/pub/custom-ui/data/types' import type { PaginationMeta } from '~/components/pub/custom-ui/pagination/pagination.type' +import { toTypedSchema } from '@vee-validate/zod' import { refDebounced, useUrlSearchParams } from '@vueuse/core' +import Combobox from '~/components/pub/custom-ui/form/combobox.vue' import Header from '~/components/pub/custom-ui/nav-header/header.vue' +import { division as divisionConf, schema as schemaConf } from './entry' import { defaultQuery, querySchema } from './schema.query' // #region State & Computed @@ -11,6 +14,7 @@ const data = ref([]) const isLoading = reactive({ isTableLoading: false, }) +const isDialogOpen = ref(false) // URL state management const queryParams = useUrlSearchParams('history', { @@ -33,6 +37,11 @@ const paginationMeta = reactive({ hasPrev: false, }) +// Table action rowId provider +const recId = ref(0) +const recAction = ref('') +const recItem = ref(null) + // Search model with debounce const searchInput = ref(params.value.q || '') const debouncedSearch = refDebounced(searchInput, 500) // 500ms debounce @@ -58,11 +67,17 @@ const headerPrep: HeaderPrep = { addNav: { label: 'Tambah Divisi', icon: 'i-lucide-send', - // todo: open modal form - onClick: () => navigateTo('/org-src/division/add'), + onClick: () => { + isDialogOpen.value = true + }, }, } +const formSchema = toTypedSchema(schemaConf) + +provide('rec_id', recId) +provide('rec_action', recAction) +provide('rec_item', recItem) provide('table_data_loader', isLoading) // #endregion @@ -127,6 +142,54 @@ function handlePageChange(page: number) { // #endregion region // #region Utilities & event handlers + +function clearForm(setValues: (values: Record) => void) { + // Manually clear all form fields + setValues({ + name: '', + code: '', + parentId: '', + }) +} + +function onCancelForm(setValues: (values: Record) => void) { + isDialogOpen.value = false + setTimeout(() => { + clearForm(setValues) + }, 500) +} + +async function onSubmitForm(values: any, setValues: (values: Record) => void) { + let isSuccess = false + try { + // TODO: Implement form submission logic + console.log('Form submitted:', values) + + // Simulate API call + // const response = await xfetch('/api/v1/division', { + // method: 'POST', + // body: JSON.stringify(values) + // }) + + // If successful, mark as success and close dialog + isDialogOpen.value = false + isSuccess = true + + // TODO: Show success message + console.log('Division created successfully') + } catch (error: unknown) { + console.warn('Error submitting form:', error) + isSuccess = false + // Don't close dialog or reset form on error + // TODO: Show error message to user + } finally { + if (isSuccess) { + setTimeout(() => { + clearForm(setValues) + }, 500) + } + } +} // #endregion // #region Watchers @@ -161,6 +224,67 @@ watch(debouncedSearch, (newValue) => {
+
+ + + + Tambah Divisi + + + + + + + Nama + + + + + + + + + + Kode + + + + + + + + + + Kelompok + + + + + + + + + + + + + +
+
diff --git a/app/components/pub/custom-ui/form/combobox.vue b/app/components/pub/custom-ui/form/combobox.vue index 74da7025..12171c85 100644 --- a/app/components/pub/custom-ui/form/combobox.vue +++ b/app/components/pub/custom-ui/form/combobox.vue @@ -8,6 +8,7 @@ interface Item { } const props = defineProps<{ + id: string modelValue?: string items: Item[] placeholder?: string @@ -61,6 +62,7 @@ function onSelect(item: Item) {