From d913724d62ddb7ace0e350ae1005dcb057612748 Mon Sep 17 00:00:00 2001 From: Khafid Prayoga Date: Wed, 20 Aug 2025 14:50:17 +0700 Subject: [PATCH] feat(satusehat): add patient list components and integration - Implement badge components for patient and status display - Create list component with configurable table columns - Add entry form for new patient registration - Integrate with existing SatuSehat service flow --- .../app/satusehat/badge-patient.vue | 13 +++ app/components/app/satusehat/badge-status.vue | 29 ++++++ app/components/app/satusehat/badge.vue | 36 ++++++++ app/components/app/satusehat/entry-form.vue | 47 ++++++++++ app/components/app/satusehat/list-cfg.ts | 89 +++++++++++++++++++ app/components/app/satusehat/list.vue | 19 ++++ app/components/app/satusehat/picker.vue | 0 app/components/app/satusehat/search.vue | 0 app/components/flow/satusehat/list.vue | 51 ++++++++++- app/components/pub/base/data-table.vue | 15 ++-- 10 files changed, 286 insertions(+), 13 deletions(-) create mode 100644 app/components/app/satusehat/badge-patient.vue create mode 100644 app/components/app/satusehat/badge-status.vue create mode 100644 app/components/app/satusehat/badge.vue create mode 100644 app/components/app/satusehat/entry-form.vue create mode 100644 app/components/app/satusehat/list-cfg.ts create mode 100644 app/components/app/satusehat/list.vue create mode 100644 app/components/app/satusehat/picker.vue create mode 100644 app/components/app/satusehat/search.vue diff --git a/app/components/app/satusehat/badge-patient.vue b/app/components/app/satusehat/badge-patient.vue new file mode 100644 index 00000000..41202aaf --- /dev/null +++ b/app/components/app/satusehat/badge-patient.vue @@ -0,0 +1,13 @@ + + + diff --git a/app/components/app/satusehat/badge-status.vue b/app/components/app/satusehat/badge-status.vue new file mode 100644 index 00000000..5ff492f0 --- /dev/null +++ b/app/components/app/satusehat/badge-status.vue @@ -0,0 +1,29 @@ + + + diff --git a/app/components/app/satusehat/badge.vue b/app/components/app/satusehat/badge.vue new file mode 100644 index 00000000..197cb084 --- /dev/null +++ b/app/components/app/satusehat/badge.vue @@ -0,0 +1,36 @@ + + + diff --git a/app/components/app/satusehat/entry-form.vue b/app/components/app/satusehat/entry-form.vue new file mode 100644 index 00000000..5768c6a0 --- /dev/null +++ b/app/components/app/satusehat/entry-form.vue @@ -0,0 +1,47 @@ + + + diff --git a/app/components/app/satusehat/list-cfg.ts b/app/components/app/satusehat/list-cfg.ts new file mode 100644 index 00000000..d7d43cae --- /dev/null +++ b/app/components/app/satusehat/list-cfg.ts @@ -0,0 +1,89 @@ +import type { Col, KeyLabel, RecComponent, RecStrFuncComponent, RecStrFuncUnknown, Th } from '../../pub/nav/types' +import { defineAsyncComponent } from 'vue' + +type SmallDetailDto = any + +export const rowType = { + 1: 'Patient', + 2: 'Encounter', + 3: 'Observation', +} + +export const rowStatus = { + 0: 'Gagal', + 1: 'Pending', + 2: 'Terkirim', +} + +const action = defineAsyncComponent(() => import('~/components/pub/nav/dropdown-action-dud.vue')) +const patientBadge = defineAsyncComponent(() => import('./badge-patient.vue')) +const statusBadge = defineAsyncComponent(() => import('./badge-status.vue')) + +export const cols: Col[] = [ + { width: 100 }, + { width: 100 }, + { width: 100 }, + { width: 100 }, + { width: 100 }, + { width: 100 }, + { width: 100 }, +] + +export const header: Th[][] = [ + [ + { label: 'ID' }, + { label: 'Jenis' }, + { label: 'Pasien' }, + { label: 'Status' }, + { label: 'Terakhir Update' }, + { label: 'FHIR ID' }, + { label: '' }, + ], +] + +export const keys = ['id', 'resource_type', 'patient', 'status', 'updated_at', 'fhir_id', '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.middleName || ''} ${recX.lastName || ''}` + }, +} + +export const funcComponent: RecStrFuncComponent = { + patient(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: patientBadge, + } + return res + }, + status(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: statusBadge, + } + return res + }, + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + } + return res + }, +} + +export const funcHtml: RecStrFuncUnknown = { + patient_address(_rec) { + return '-' + }, +} diff --git a/app/components/app/satusehat/list.vue b/app/components/app/satusehat/list.vue new file mode 100644 index 00000000..5b8778d9 --- /dev/null +++ b/app/components/app/satusehat/list.vue @@ -0,0 +1,19 @@ + + + diff --git a/app/components/app/satusehat/picker.vue b/app/components/app/satusehat/picker.vue new file mode 100644 index 00000000..e69de29b diff --git a/app/components/app/satusehat/search.vue b/app/components/app/satusehat/search.vue new file mode 100644 index 00000000..e69de29b diff --git a/app/components/flow/satusehat/list.vue b/app/components/flow/satusehat/list.vue index e65e02d8..2f3ee437 100644 --- a/app/components/flow/satusehat/list.vue +++ b/app/components/flow/satusehat/list.vue @@ -4,6 +4,42 @@ import type { Summary } from '~/components/pub/base/summary-card.type' import type { HeaderPrep, RefSearchNav } from '~/components/pub/nav/types' import { CircleCheckBig, CircleDashed, CircleX, Send } from 'lucide-vue-next' +const data = ref([ + { + id: 'RSC001', + resource_type: 'Encounter', + patient: { + name: 'Ahmad Wepe', + mrn: 'RM001234', + }, + status: 2, + updated_at: '2025-03-12', + fhir_id: 'ENC-00123', + }, + { + id: 'RSC002', + resource_type: 'Encounter', + patient: { + name: 'Siti Aminah', + mrn: 'RM001235', + }, + status: 1, + updated_at: '2025-03-10', + fhir_id: 'ENC-001235', + }, + { + id: 'RSC003', + resource_type: 'Encounter', + patient: { + name: 'Budi Antono', + mrn: 'RM001236', + }, + status: 0, + updated_at: '2025-03-11', + fhir_id: 'ENC-001236', + }, +]) + const refSearchNav: RefSearchNav = { onClick: () => { // open filter modal @@ -16,12 +52,16 @@ const refSearchNav: RefSearchNav = { }, } +const recId = ref(0) +const recAction = ref('') +const recItem = ref(null) + // Loading state management const isLoading = reactive({ satusehatConn: true, }) -const hreaderPrep: HeaderPrep = { +const headerPrep: HeaderPrep = { title: 'SATUSEHAT Integration', icon: 'i-lucide-box', addNav: { @@ -74,7 +114,7 @@ const summaryData: Summary[] = [ async function callSatuSehat() { try { - await new Promise((resolve) => setTimeout(resolve, 3000)) + await new Promise((resolve) => setTimeout(resolve, 500)) service.status = 'connected' // service.status = 'error' service.sessionActive = true @@ -87,10 +127,14 @@ async function callSatuSehat() { onMounted(() => { callSatuSehat() }) + +provide('rec_id', recId) +provide('rec_action', recAction) +provide('rec_item', recItem) + diff --git a/app/components/pub/base/data-table.vue b/app/components/pub/base/data-table.vue index b913affc..31fa7050 100644 --- a/app/components/pub/base/data-table.vue +++ b/app/components/pub/base/data-table.vue @@ -14,13 +14,11 @@ defineProps<{