Files

277 lines
6.4 KiB
Vue

<script setup lang="ts">
// Components
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
import AppActionReportList from '~/components/app/action-report/list.vue'
import AppActionReportListHistory from '~/components/app/action-report/list-history.vue'
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
import { ButtonAction } from '~/components/pub/my-ui/form'
// config
import { config } from '~/components/app/action-report/list.cfg'
// types
import { ActionEvents } from '~/components/pub/my-ui/data/types'
import type { Encounter } from '~/models/encounter'
// Samples
import { sampleRows, type ActionReportData } from '~/components/app/action-report/sample'
import sampleReport from './sample'
// helpers
import { toast } from '~/components/pub/ui/toast'
// Props
interface Props {
encounter: Encounter
}
const props = defineProps<Props>()
const emits = defineEmits<{
(e: 'add'): void
(e: 'edit', id: number | string): void
(e: 'view', id: number | string): void
}>()
// states
const router = useRouter()
const route = useRoute()
const { goToEntry, backToList } = useQueryCRUDMode('mode')
const title = ref('')
const search = ref('')
const dateFrom = ref('')
const dateTo = ref('')
const isDialogOpen = ref<boolean>(false)
const isLoading = ref<boolean>(false)
// #region mock
// Handlers
import {
recId,
recAction,
recItem,
isReadonly,
isProcessing,
isFormEntryDialogOpen,
isRecordConfirmationOpen,
onResetState,
handleActionSave,
handleActionEdit,
handleActionRemove,
handleCancelForm,
} from '~/handlers/consultation.handler'
// #endregion
// filter + pencarian sederhana (client-side)
const filtered = computed(() => {
const q = search.value.trim().toLowerCase()
return sampleRows.filter((r: ActionReportData) => {
if (q) {
return r.nama.toLowerCase().includes(q) || r.noRm.toLowerCase().includes(q) || r.dokter.toLowerCase().includes(q)
}
return true
})
})
const goEdit = (id: number | string) => {
router.replace({
path: route.path,
query: {
...route.query,
mode: 'entry',
'record-id': id,
},
})
}
const goView = (id: number | string) => {
router.replace({
path: route.path,
query: {
...route.query,
mode: 'view',
'record-id': id,
},
})
}
provide('rec_id', recId)
provide('rec_action', recAction)
provide('rec_item', recItem)
provide('table_data_loader', isLoading)
async function onGetDetail(id: number | string) {
isLoading.value = true
const res = sampleReport
recItem.value = res
console.log(res)
isLoading.value = false
}
// #region watcher
watch([recId, recAction], (newVal) => {
const [id, action] = newVal
// Guard: jangan proses jika id = 0 atau action kosong
if (!id || !action) return
switch (action) {
case ActionEvents.showDetail:
// onGetDetail(recId.value)
goView(id)
title.value = 'Detail Konsultasi'
break
case ActionEvents.showEdit:
goEdit(id)
title.value = 'Edit Konsultasi'
break
case ActionEvents.showConfirmDelete:
isRecordConfirmationOpen.value = true
break
}
// Reset KEDUANYA menggunakan nextTick agar tidak trigger watcher lagi
nextTick(() => {
recId.value = 0
recAction.value = ''
})
})
// #endregion
</script>
<template>
<div class="mx-auto max-w-full">
<div class="border-b p-6">
<h1 class="text-2xl font-semibold">Laporan Tindakan</h1>
<p class="mt-1 text-sm text-gray-500">Infomasi laporan tindakan pasien</p>
</div>
<div class="flex flex-wrap items-center gap-3 border-b p-4">
<div class="flex items-center gap-2">
<input
v-model="search"
placeholder="Cari Nama / No.RM"
class="w-64 rounded border px-3 py-2"
/>
</div>
<div class="flex items-center gap-2">
<input
v-model="dateFrom"
type="date"
class="rounded border px-3 py-2"
/>
<span class="text-sm text-gray-500">-</span>
<input
v-model="dateTo"
type="date"
class="rounded border px-3 py-2"
/>
<ButtonAction
preset="custom"
title="Filter List Laporan Tindakan"
label="Filter"
icon="i-lucide-filter"
@click="
() => {
isDialogOpen = true
}
"
/>
</div>
<div class="ml-auto flex items-center gap-2">
<ButtonAction
preset="custom"
title="Riwayat Laporan Tindakan"
icon="i-lucide-history"
label="Riwayat Laporan Tindakan"
@click="
() => {
isDialogOpen = true
}
"
/>
<ButtonAction
preset="add"
title="Tambah Data Laporan Tindakan"
icon="i-lucide-plus"
label="Tambah Data"
@click="
() => {
goToEntry()
}
"
/>
</div>
</div>
<div class="overflow-x-auto p-4">
<AppActionReportList
:data="filtered"
:pagination-meta="{
recordCount: 2,
page: 1,
pageSize: 10,
totalPage: 1,
hasPrev: false,
hasNext: false,
}"
/>
</div>
</div>
<Dialog
v-model:open="isDialogOpen"
title="Arsip Riwayat Laporan Tindakan"
size="2xl"
prevent-outside
@update:open="
(value: any) => {
isDialogOpen = value
}
"
>
<AppActionReportListHistory
:data="filtered"
:pagination-meta="{
recordCount: 2,
page: 1,
pageSize: 10,
totalPage: 1,
hasPrev: false,
hasNext: false,
}"
/>
</Dialog>
<RecordConfirmation
v-model:open="isRecordConfirmationOpen"
action="delete"
:record="recItem"
@confirm="
() =>
handleActionRemove(
recItem.id,
() => {
router.go(0)
},
toast,
)
"
@cancel=""
>
<template #default="{ record }">
{{ console.log(JSON.stringify(record)) }}
<div class="space-y-1 text-sm">
<p
v-for="field in config.delKeyNames"
:key="field.key"
:v-if="record?.[field.key]"
>
<span class="font-semibold">{{ field.label }}:</span>
{{ record[field.key] }}
</p>
</div>
</template>
</RecordConfirmation>
</template>