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
This commit is contained in:
No files matched your search
@@ -0,0 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
rec: any
|
||||
idx?: number
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col justify-center">
|
||||
<p class="font-semibold text-sm">{{ props.rec.patient.name }}</p>
|
||||
<p class="text-xs text-muted-foreground">{{ props.rec.patient.mrn }}</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import Badge from './badge.vue'
|
||||
import { rowStatus } from './list-cfg'
|
||||
|
||||
const props = defineProps<{
|
||||
rec: { status: number }
|
||||
idx?: number
|
||||
}>()
|
||||
|
||||
const variants = {
|
||||
0: 'error',
|
||||
1: 'warning',
|
||||
2: 'info',
|
||||
} as const
|
||||
|
||||
const statusText = computed(() => {
|
||||
return rowStatus[props.rec.status as keyof typeof rowStatus]
|
||||
})
|
||||
|
||||
const badgeStatus = computed((): 'error' | 'warning' | 'success' | 'info' => {
|
||||
return variants[props.rec.status as keyof typeof variants] ?? 'info'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex">
|
||||
<Badge :status="badgeStatus" :text="statusText" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
import { cva } from 'class-variance-authority'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
interface BadgeProps {
|
||||
status: 'success' | 'info' | 'warning' | 'error'
|
||||
text: string
|
||||
}
|
||||
|
||||
const props = defineProps<BadgeProps>()
|
||||
|
||||
const badgeVariants = cva(
|
||||
'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
success: 'rounded-full border-transparent bg-green-500 text-white hover:bg-green-600',
|
||||
info: 'rounded-full border-transparent bg-blue-500 text-white hover:bg-blue-600',
|
||||
warning: 'rounded-full border-transparent bg-yellow-500 text-white hover:bg-yellow-600',
|
||||
error: 'rounded-full border-transparent bg-red-500 text-white hover:bg-red-600',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'info',
|
||||
},
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex">
|
||||
<div :class="cn(badgeVariants({ variant: props.status }))">
|
||||
{{ props.text }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import Block from '~/components/pub/form/block.vue'
|
||||
import FieldGroup from '~/components/pub/form/field-group.vue'
|
||||
import Field from '~/components/pub/form/field.vue'
|
||||
import Label from '~/components/pub/form/label.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form id="entry-form">
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<Icon name="i-lucide-user" class="me-2" />
|
||||
<span class="font-semibold">Tambah</span> Pasien
|
||||
</div>
|
||||
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<Block>
|
||||
<FieldGroup :column="3">
|
||||
<Label>Nama</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup :column="3">
|
||||
<Label>Nama</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup :column="3">
|
||||
<Label>Nomor RM</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup>
|
||||
<Label dynamic>Alamat</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Block>
|
||||
</div>
|
||||
<div class="my-2 flex justify-end py-2">
|
||||
<PubNavFooterCsd />
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
@@ -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 '-'
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PubBaseDataTable
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
Reference in New Issue
Block a user