diff --git a/app/assets/css/main.css b/app/assets/css/main.css index 1c7eaef2..4c488385 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -327,4 +327,14 @@ body { .rounded-sm { border-radius: var(--radius-sm); } + +/* Form Error Styling */ +.field-error-info { + @apply text-xs ml-1; + color: hsl(var(--destructive)); + /* font-size: 0.875rem; */ + margin-top: 0.25rem; + line-height: 1.25; +} + /* .rounded-md { border-radius: var */ diff --git a/app/components/app/divison/entry-form.vue b/app/components/app/divison/entry-form.vue new file mode 100644 index 00000000..3008d3c8 --- /dev/null +++ b/app/components/app/divison/entry-form.vue @@ -0,0 +1,125 @@ + + + diff --git a/app/components/app/divison/list-cfg.ts b/app/components/app/divison/list-cfg.ts new file mode 100644 index 00000000..58094521 --- /dev/null +++ b/app/components/app/divison/list-cfg.ts @@ -0,0 +1,86 @@ +import type { + Col, + KeyLabel, + RecComponent, + RecStrFuncComponent, + RecStrFuncUnknown, + Th, +} from '~/components/pub/custom-ui/data/types' +import { defineAsyncComponent } from 'vue' + +type SmallDetailDto = any + +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: 'Nama' }, + { label: 'Kode' }, + { label: 'Kelompok' }, + { label: '' }, + ], +] + +export const keys = [ + 'id', + 'firstName', + 'cellphone', + 'birth_place', + 'action', +] + +export const delKeyNames: KeyLabel[] = [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, +] + +export const funcParsed: RecStrFuncUnknown = { + name: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim() + }, + identity_number: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + if (recX.identity_number?.substring(0, 5) === 'BLANK') { + return '(TANPA NIK)' + } + return recX.identity_number + }, + inPatient_itemPrice: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID') + }, + outPatient_itemPrice: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID') + }, +} + +export const funcComponent: RecStrFuncComponent = { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, +} + +export const funcHtml: RecStrFuncUnknown = { + patient_address(_rec) { + return '-' + }, +} diff --git a/app/components/app/divison/list.vue b/app/components/app/divison/list.vue new file mode 100644 index 00000000..cf0d5ea2 --- /dev/null +++ b/app/components/app/divison/list.vue @@ -0,0 +1,35 @@ + + + diff --git a/app/components/app/installation/entry-form.vue b/app/components/app/installation/entry-form.vue new file mode 100644 index 00000000..0b3a0049 --- /dev/null +++ b/app/components/app/installation/entry-form.vue @@ -0,0 +1,124 @@ + + + diff --git a/app/components/app/installation/list-cfg.ts b/app/components/app/installation/list-cfg.ts new file mode 100644 index 00000000..6b8dc5ea --- /dev/null +++ b/app/components/app/installation/list-cfg.ts @@ -0,0 +1,68 @@ +import type { + Col, + KeyLabel, + RecComponent, + RecStrFuncComponent, + RecStrFuncUnknown, + Th, +} from '~/components/pub/custom-ui/data/types' +import { defineAsyncComponent } from 'vue' + +type SmallDetailDto = any + +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: 'Nama' }, { label: 'Kode' }, { label: 'Encounter Class' }, { label: '' }], +] + +export const keys = ['id', 'name', 'cellphone', 'religion_code', 'action'] + +export const delKeyNames: KeyLabel[] = [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, +] + +export const funcParsed: RecStrFuncUnknown = { + name: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return `${recX.firstName} ${recX.lastName || ''}`.trim() + }, + identity_number: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + if (recX.identity_number?.substring(0, 5) === 'BLANK') { + return '(TANPA NIK)' + } + return recX.identity_number + }, + inPatient_itemPrice: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID') + }, + outPatient_itemPrice: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID') + }, +} + +export const funcComponent: RecStrFuncComponent = { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, +} + +export const funcHtml: RecStrFuncUnknown = { + patient_address(_rec) { + return '-' + }, +} diff --git a/app/components/app/installation/list.vue b/app/components/app/installation/list.vue new file mode 100644 index 00000000..a6b19eb2 --- /dev/null +++ b/app/components/app/installation/list.vue @@ -0,0 +1,36 @@ + + + diff --git a/app/components/app/unit/entry-form.vue b/app/components/app/unit/entry-form.vue new file mode 100644 index 00000000..463a6683 --- /dev/null +++ b/app/components/app/unit/entry-form.vue @@ -0,0 +1,125 @@ + + + diff --git a/app/components/app/unit/list-cfg.ts b/app/components/app/unit/list-cfg.ts new file mode 100644 index 00000000..00423066 --- /dev/null +++ b/app/components/app/unit/list-cfg.ts @@ -0,0 +1,86 @@ +import type { + Col, + KeyLabel, + RecComponent, + RecStrFuncComponent, + RecStrFuncUnknown, + Th, +} from '~/components/pub/custom-ui/data/types' +import { defineAsyncComponent } from 'vue' + +type SmallDetailDto = any + +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: 'Nama' }, + { label: 'Kode' }, + { label: 'Instalasi' }, + { label: '' }, + ], +] + +export const keys = [ + 'id', + 'firstName', + 'cellphone', + 'birth_place', + 'action', +] + +export const delKeyNames: KeyLabel[] = [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, +] + +export const funcParsed: RecStrFuncUnknown = { + name: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim() + }, + identity_number: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + if (recX.identity_number?.substring(0, 5) === 'BLANK') { + return '(TANPA NIK)' + } + return recX.identity_number + }, + inPatient_itemPrice: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID') + }, + outPatient_itemPrice: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID') + }, +} + +export const funcComponent: RecStrFuncComponent = { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, +} + +export const funcHtml: RecStrFuncUnknown = { + patient_address(_rec) { + return '-' + }, +} diff --git a/app/components/app/unit/list.vue b/app/components/app/unit/list.vue new file mode 100644 index 00000000..1baaa6ba --- /dev/null +++ b/app/components/app/unit/list.vue @@ -0,0 +1,35 @@ + + + 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/list.vue b/app/components/flow/division/list.vue new file mode 100644 index 00000000..f4bf78e6 --- /dev/null +++ b/app/components/flow/division/list.vue @@ -0,0 +1,219 @@ + + + + + diff --git a/app/components/flow/installation/entry.ts b/app/components/flow/installation/entry.ts new file mode 100644 index 00000000..c003a029 --- /dev/null +++ b/app/components/flow/installation/entry.ts @@ -0,0 +1,37 @@ +import * as z from 'zod' + +export const installationConf = { + msg: { + placeholder: '---pilih encounter class (fhir7)', + }, + items: [ + { value: '1', label: 'Ambulatory', code: 'AMB' }, + { value: '2', label: 'Inpatient', code: 'IMP' }, + { value: '3', label: 'Emergency', code: 'EMER' }, + { value: '4', label: 'Observation', code: 'OBSENC' }, + { value: '5', label: 'Pre-admission', code: 'PRENC' }, + { value: '6', label: 'Short Stay', code: 'SS' }, + { value: '7', label: 'Virtual', code: 'VR' }, + { value: '8', label: 'Home Health', code: 'HH' }, + ], +} + +export const schemaConf = z.object({ + name: z + .string({ + required_error: 'Nama instalasi harus diisi', + }) + .min(3, 'Nama instalasi minimal 3 karakter'), + + code: z + .string({ + required_error: 'Kode instalasi harus diisi', + }) + .min(3, 'Kode instalasi minimal 3 karakter'), + + encounterClassCode: z + .string({ + required_error: 'Kelompok encounter class harus dipilih', + }) + .min(1, 'Kelompok encounter class harus dipilih'), +}) diff --git a/app/components/flow/installation/list.vue b/app/components/flow/installation/list.vue new file mode 100644 index 00000000..01a05baf --- /dev/null +++ b/app/components/flow/installation/list.vue @@ -0,0 +1,220 @@ + + + + + diff --git a/app/components/flow/unit/entry.ts b/app/components/flow/unit/entry.ts new file mode 100644 index 00000000..bf85a0ed --- /dev/null +++ b/app/components/flow/unit/entry.ts @@ -0,0 +1,63 @@ +import * as z from 'zod' + +export const unitConf = { + msg: { + placeholder: '--- pilih instalasi', + search: 'kode, nama instalasi', + empty: 'instalasi tidak ditemukan', + }, + items: [ + { value: '1', label: 'Instalasi Medis', code: 'MED' }, + { value: '2', label: 'Instalasi Keperawatan', code: 'NUR' }, + { value: '3', label: 'Instalasi Administrasi', code: 'ADM' }, + { value: '4', label: 'Instalasi Penunjang Non-Medis', code: 'SUP' }, + { value: '5', label: 'Instalasi Pendidikan & Pelatihan', code: 'EDU' }, + { value: '6', label: 'Instalasi Farmasi', code: 'PHA' }, + { value: '7', label: 'Instalasi Radiologi', code: 'RAD' }, + { value: '8', label: 'Instalasi Laboratorium', code: 'LAB' }, + { value: '9', label: 'Instalasi Keuangan', code: 'FIN' }, + { value: '10', label: 'Instalasi SDM', code: 'HR' }, + { value: '11', label: 'Instalasi Teknologi Informasi', code: 'ITS' }, + { value: '12', label: 'Instalasi Pemeliharaan & Sarana', code: 'MNT' }, + { value: '13', label: 'Instalasi Gizi / Catering', code: 'CAT' }, + { value: '14', label: 'Instalasi Keamanan', code: 'SEC' }, + { value: '15', label: 'Instalasi Gawat Darurat', code: 'EMR' }, + { value: '16', label: 'Instalasi Bedah Sentral', code: 'SUR' }, + { value: '17', label: 'Instalasi Rawat Jalan', code: 'OUT' }, + { value: '18', label: 'Instalasi Rawat Inap', code: 'INP' }, + { value: '19', label: 'Instalasi Rehabilitasi Medik', code: 'REB' }, + { value: '20', label: 'Instalasi Penelitian & Pengembangan', code: 'RSH' }, + ], +} + +export const schemaConf = z.object({ + name: z + .string({ + required_error: 'Nama unit harus diisi', + }) + .min(1, 'Nama unit harus diisi'), + + code: z + .string({ + required_error: 'Kode unit harus diisi', + }) + .min(1, 'Kode unit harus diisi'), + parentId: z.preprocess( + (input: unknown) => { + if (typeof input === 'string') { + // Handle empty string case + if (input.trim() === '') { + return 0 + } + return Number(input) + } + + return input + }, + z + .number({ + required_error: 'Instalasi induk harus dipilih', + }) + .refine((num) => num > 0, 'Instalasi induk harus dipilih'), + ), +}) diff --git a/app/components/flow/unit/list.vue b/app/components/flow/unit/list.vue new file mode 100644 index 00000000..404da13e --- /dev/null +++ b/app/components/flow/unit/list.vue @@ -0,0 +1,219 @@ + + + + + diff --git a/app/components/pub/base/data-table/data-table.vue b/app/components/pub/base/data-table/data-table.vue index 6524aaa8..eb59b9b9 100644 --- a/app/components/pub/base/data-table/data-table.vue +++ b/app/components/pub/base/data-table/data-table.vue @@ -1,19 +1,39 @@ diff --git a/app/components/pub/custom-ui/form/label.vue b/app/components/pub/custom-ui/form/label.vue index 179cee89..f8272352 100644 --- a/app/components/pub/custom-ui/form/label.vue +++ b/app/components/pub/custom-ui/form/label.vue @@ -1,6 +1,7 @@ + + diff --git a/app/components/pub/custom-ui/nav-header/header.vue b/app/components/pub/custom-ui/nav-header/header.vue index 2f8ebb4e..621691d2 100644 --- a/app/components/pub/custom-ui/nav-header/header.vue +++ b/app/components/pub/custom-ui/nav-header/header.vue @@ -1,18 +1,142 @@