Files
simrsx-fe/app/components/content/bpjs/control-letter/list.vue
2025-10-27 14:01:58 +07:00

221 lines
5.8 KiB
Vue

<script setup lang="ts">
import type { HeaderPrep, RefExportNav, RefSearchNav } from '~/components/pub/my-ui/data/types'
import type { Summary } from '~/components/pub/my-ui/summary-card/type'
// #region Imports
import { Calendar, Hospital, UserCheck, UsersRound } from 'lucide-vue-next'
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
import { ActionEvents } from '~/components/pub/my-ui/data/types'
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
import Filter from '~/components/pub/my-ui/nav-header/filter.vue'
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
import SummaryCard from '~/components/pub/my-ui/summary-card/summary-card.vue'
import { usePaginatedList } from '~/composables/usePaginatedList'
import { getPatients, removePatient } from '~/services/patient.service'
import FilterDialog from '~/components/pub/my-ui/nav-header/filter-dialog.vue'
// #endregion
// #region State
const { data, isLoading, paginationMeta, searchInput, handlePageChange, handleSearch, fetchData } = usePaginatedList({
fetchFn: (params) => getPatients({ ...params, includes: ['person', 'person-Addresses'] }),
entityName: 'patient',
})
const refSearchNav: RefSearchNav = {
onClick: () => {
// open filter modal
isFormEntryDialogOpen.value = true
},
onInput: (val: string) => {
searchInput.value = val
},
onClear: () => {
searchInput.value = ''
},
}
const refExportNav: RefExportNav = {
onExportCsv: () => {
// open filter modal
console.log(`Export CSV Clicked`)
},
}
const isFormEntryDialogOpen = ref(false)
const isHistoryDialogOpen = ref(false)
const isRecordConfirmationOpen = ref(false)
const summaryLoading = ref(false)
const recId = ref<number>(0)
const recAction = ref<string>('')
const recItem = ref<any>(null)
const headerPrep: HeaderPrep = {
title: "Surat Kontrol",
icon: 'i-lucide-newspaper',
}
const filterPrep: HeaderPrep = {
title: "Surat Kontrol",
icon: 'i-lucide-newspaper',
}
// #endregion
// #region Lifecycle Hooks
onMounted(() => {
getPatientSummary()
})
// #endregion
// #region Functions
async function getPatientSummary() {
try {
summaryLoading.value = true
await new Promise((resolve) => setTimeout(resolve, 500))
} catch (error) {
console.error('Error fetching patient summary:', error)
} finally {
summaryLoading.value = false
}
}
function handleFiltering() {
console.log('Confirmed action: Filter')
}
// Handle confirmation result
async function handleConfirmDelete(record: any, action: string) {
console.log('Confirmed action:', action, 'for record:', record)
if (action === 'delete' && record?.id) {
try {
const result = await removePatient(record.id)
if (result.success) {
console.log('Patient deleted successfully')
// Refresh the list
await fetchData()
} else {
console.error('Failed to delete patient:', result)
// Handle error - show error message to user
}
} catch (error) {
console.error('Error deleting patient:', error)
// Handle error - show error message to user
}
}
}
function handleCancelConfirmation() {
// Reset record state when cancelled
recId.value = 0
recAction.value = ''
recItem.value = null
}
function exportCsv() {
console.log('Ekspor CSV dipilih')
// tambahkan logic untuk generate CSV
}
function exportExcel() {
console.log('Ekspor Excel dipilih')
// tambahkan logic untuk generate Excel
}
// #endregion
// #region Provide
provide('rec_id', recId)
provide('rec_action', recAction)
provide('rec_item', recItem)
provide('table_data_loader', isLoading)
// #endregion
// #region Watchers
watch([recId, recAction], () => {
switch (recAction.value) {
case ActionEvents.showProcess:
navigateTo('https://google.com', { external: true, open: { target: '_blank' } });
break
case ActionEvents.showDetail:
isHistoryDialogOpen.value = true
break
case ActionEvents.showConfirmDelete:
// Trigger confirmation modal open
isRecordConfirmationOpen.value = true
break
}
})
// #endregion
</script>
<template>
<Header :prep="{ ...headerPrep }" />
<!-- Disable dulu, ayahab kalo diminta beneran -->
<!-- <div class="my-4 flex flex-1 flex-col gap-4 md:gap-8">
<div class="grid gap-4 md:grid-cols-2 md:gap-8 lg:grid-cols-4">
<template v-if="summaryLoading">
<SummaryCard
v-for="n in 4"
:key="n"
is-skeleton
/>
</template>
<template v-else>
<SummaryCard
v-for="card in summaryData"
:key="card.title"
:stat="card"
/>
</template>
</div>
</div>
-->
<FilterDialog :prep="{ ...filterPrep }"
:ref-search-nav="refSearchNav"
:ref-export-nav="refExportNav"
:enable-search="false"
:enable-date-range="false"/>
<AppBpjsControlLetterList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
<Dialog
v-model:open="isFormEntryDialogOpen"
title="Filter"
>
<AppBpjsControlLetterFilter @submit="handleFiltering" />
</Dialog>
<Dialog
v-model:open="isHistoryDialogOpen"
title="Log History Surat Kontrol">
<AppBpjsControlLetterCommonHistoryDialog />
</Dialog>
<RecordConfirmation v-model:open="isRecordConfirmationOpen" action="delete" :record="recItem"
@confirm="handleConfirmDelete" @cancel="handleCancelConfirmation">
<template #default="{ record }">
<div class="text-sm">
<p>
<strong>ID:</strong>
{{ record?.id }}
</p>
<p v-if="record?.firstName">
<strong>Nama:</strong>
{{ record.firstName }}
</p>
<p v-if="record?.code">
<strong>Kode:</strong>
{{ record.cellphone }}
</p>
</div>
</template>
</RecordConfirmation>
</template>