Files
vitify-nuxt/pages/practitioner.vue
2025-04-22 10:56:56 +07:00

235 lines
6.4 KiB
Vue

<script setup lang="ts">
import type { DataTableHeaders } from '~/plugins/vuetify'
definePageMeta({
icon: 'mdi-table',
title: 'Data Praktisi',
drawerIndex: 3,
})
const search = ref('')
const dialogDelete = useTemplateRef('dialogDelete')
function showDialogDelete(name: string) {
dialogDelete.value
?.open('Are you sure you want to delete this dessert?')
.then(async (confirmed: boolean) => {
if (confirmed) {
try {
const index = desserts.value!.findIndex((v) => v.name === name)
desserts.value!.splice(index, 1)
Notify.success('Deleted')
} catch (e) {
Notify.error(e)
}
}
})
}
const practitioners = ref([])
const loading = ref(true)
const error = ref(null)
const snackbar = ref({
show: false,
text: '',
color: 'info',
})
// Mengambil data dari API
const fetchPractitioners = async () => {
try {
loading.value = true
error.value = null
const response = await fetch('/api/practitioner')
if (!response.ok) {
throw new Error(`Error: ${response.status} - ${response.statusText}`)
}
const data = await response.json()
console.log(data)
practitioners.value = data
} catch (err) {
console.error('Failed to fetch practitioners:', err)
error.value = `Gagal memuat data praktisi: ${err.message}`
showSnackbar('Gagal memuat data praktisi', 'error')
} finally {
loading.value = false
}
}
// Mendapatkan nomor telepon praktisi
const getPractitionerPhone = (practitioner) => {
if (!practitioner.telecom || practitioner.telecom.length === 0) {
return 'Tidak ada data'
}
const phone = practitioner.telecom.find((t) => t.system === 'phone')
return phone ? phone.value : 'Tidak ada data'
}
// Mendapatkan email praktisi
const getPractitionerEmail = (practitioner) => {
if (!practitioner.telecom || practitioner.telecom.length === 0) {
return 'Tidak ada data'
}
const email = practitioner.telecom.find((t) => t.system === 'email')
return email ? email.value : 'Tidak ada data'
}
// Menampilkan detail praktisi
const showDetail = (practitioner) => {
console.log('Menampilkan detail praktisi:', getPractitionerName(practitioner))
showSnackbar(`Detail ${getPractitionerName(practitioner)}`, 'primary')
// Di sini bisa ditambahkan navigasi ke halaman detail atau membuka dialog
}
// Menampilkan snackbar
const showSnackbar = (text, color = 'success') => {
snackbar.value = {
show: true,
text,
color,
}
}
// Panggil API saat komponen dimuat
onMounted(() => {
fetchPractitioners()
})
</script>
<template>
<v-container fluid>
<v-row>
<v-col>
<v-card>
<client-only>
<teleport to="#app-bar">
<v-text-field
v-model="search"
prepend-inner-icon="mdi-magnify"
label="Search"
single-line
hide-details
density="compact"
class="mr-2"
rounded="xl"
flat
variant="solo"
style="width: 250px"
/>
</teleport>
</client-only>
<v-container>
<h1 class="text-h4 mb-4">Daftar Praktisi</h1>
<v-alert v-if="error" type="error" class="mb-4">
{{ error }}
</v-alert>
<v-progress-circular
v-if="loading"
indeterminate
color="primary"
size="64"
class="my-8 mx-auto d-block"
></v-progress-circular>
<v-row v-else>
<v-col
v-for="(practitioner, index) in practitioners"
:key="index"
cols="12"
sm="6"
md="4"
>
<v-card
class="mx-auto mb-4"
max-width="400"
elevation="3"
shaped
>
<v-card-title class="text-h5">
{{ joinName(practitioner.name, ['official', 'usual']) }}
</v-card-title>
<v-card-text>
<v-row align="center" class="mx-0">
<DivAvatar
size="80"
class="mr-3"
:gender="practitioner.gender"
/>
<div>
<DivIconText
icon="mdi-map-marker"
:text="practitioner.birthPlace || 'Tidak ada data'"
/>
<DivIconText
icon="mdi-calendar"
:text="formatDate(practitioner.birthDate, 'full')"
/>
<DivIconText
icon="mdi-phone"
:text="
getContactPoints(
practitioner.telecom,
'phone',
).join(',')
"
/>
<DivIconText
icon="mdi-email"
:text="
getContactPoints(
practitioner.telecom,
'email',
).join(',')
"
/>
</div>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="primary"
text
@click="showDetail(practitioner)"
>
Detail
<v-icon small class="ml-1">mdi-arrow-right</v-icon>
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
<v-snackbar
v-model="snackbar.show"
:color="snackbar.color"
:timeout="3000"
>
{{ snackbar.text }}
</v-snackbar>
</v-container>
<DialogConfirm ref="dialogDelete" />
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<style scoped>
.v-card {
transition: transform 0.3s;
}
.v-card:hover {
transform: translateY(-5px);
}
</style>