Files
web-antrean/components/features/antrean/QueueCreationDialog.vue
T
2026-01-05 09:26:14 +07:00

231 lines
5.2 KiB
Vue

<template>
<v-dialog v-model="dialogModel" max-width="600px">
<v-card class="dialog-card">
<v-card-title class="dialog-header" :class="`dialog-header-${type}`">
<v-icon class="mr-2">{{ icon }}</v-icon>
<span>{{ title }}</span>
<v-spacer />
<v-btn icon @click="dialogModel = false" size="small" class="close-btn">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="pa-4">
<!-- patient info card -->
<div v-if="patient" class="patient-card mb-4">
<h4 class="card-title">Informasi Pasien</h4>
<v-row>
<v-col cols="6">
<div class="info-label">Nama</div>
<div class="info-value">{{ patient.namaPasien }}</div>
</v-col>
<v-col cols="6">
<div class="info-label">No. RM</div>
<div class="info-value">{{ patient.noRM }}</div>
</v-col>
</v-row>
</div>
<!-- search field -->
<v-text-field
v-model="searchModel"
prepend-inner-icon="mdi-magnify"
:label="searchLabel"
variant="outlined"
density="comfortable"
hide-details
class="mb-4 search-field"
/>
<!-- options grid -->
<v-row>
<v-col
v-for="option in filteredOptions"
:key="option.id"
cols="6"
>
<v-card
class="option-card"
:class="`option-card-${type}`"
@click="$emit('select', option)"
elevation="0"
>
<v-card-text class="text-center pa-4">
<v-icon :size="32" :color="iconColor" class="mb-2">
{{ icon }}
</v-icon>
<div class="option-title">{{ option.name }}</div>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-dialog>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({
modelValue: {
type: Boolean,
required: true
},
type: {
type: String,
default: 'klinik', // 'klinik' | 'penunjang'
validator: (value) => ['klinik', 'penunjang'].includes(value)
},
title: {
type: String,
required: true
},
icon: {
type: String,
required: true
},
patient: {
type: Object,
default: null
},
options: {
type: Array,
default: () => []
},
searchQuery: {
type: String,
default: ''
},
searchLabel: {
type: String,
default: 'Cari...'
}
});
const emit = defineEmits(['update:modelValue', 'update:searchQuery', 'select']);
const dialogModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
});
const searchModel = computed({
get: () => props.searchQuery,
set: (value) => emit('update:searchQuery', value)
});
const filteredOptions = computed(() => {
if (!searchModel.value) return props.options;
const search = searchModel.value.toLowerCase();
return props.options.filter(opt =>
opt.name.toLowerCase().includes(search)
);
});
const iconColor = computed(() => {
return props.type === 'klinik' ? 'secondary-600' : 'accent-600';
});
</script>
<style scoped lang="scss">
$neutral-100: #FFFFFF;
$neutral-300: #F5F7FA;
$neutral-500: #ABBED1;
$neutral-700: #717171;
$neutral-900: #212121;
$secondary-600: #0671E0;
$secondary-700: #0053AD;
$accent-600: #8B5CF6;
$accent-700: #7C3AED;
$font-family-base: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
$font-weight-regular: 400;
$font-weight-semibold: 600;
.dialog-card {
font-family: $font-family-base;
}
.dialog-header {
color: $neutral-100;
padding: 20px 24px;
font-size: 18px;
font-weight: $font-weight-semibold;
display: flex;
align-items: center;
}
.dialog-header-klinik {
background: linear-gradient(135deg, $secondary-600 0%, $secondary-700 100%);
}
.dialog-header-penunjang {
background: linear-gradient(135deg, $accent-600 0%, $accent-700 100%);
}
.close-btn {
color: $neutral-100 !important;
}
.patient-card {
background: $neutral-300;
padding: 16px;
border-radius: 12px;
border: 1px solid $neutral-500;
}
.card-title {
font-size: 14px;
font-weight: $font-weight-semibold;
color: $neutral-900;
margin-bottom: 12px;
font-family: $font-family-base;
}
.info-label {
font-size: 12px;
line-height: 16px;
color: $neutral-700;
margin-bottom: 4px;
font-family: $font-family-base;
}
.info-value {
font-size: 14px;
line-height: 20px;
font-weight: $font-weight-semibold;
color: $neutral-900;
font-family: $font-family-base;
}
.search-field {
font-family: $font-family-base;
}
.option-card {
cursor: pointer;
transition: all 0.2s ease;
border: 2px solid $neutral-500;
background: $neutral-100;
}
.option-card-klinik:hover {
border-color: $secondary-600;
background: var(--color-secondary-200);
transform: translateY(-2px);
}
.option-card-penunjang:hover {
border-color: $accent-600;
background: var(--color-accent-200);
transform: translateY(-2px);
}
.option-title {
font-size: 14px;
line-height: 20px;
font-weight: $font-weight-semibold;
color: $neutral-900;
font-family: $font-family-base;
}
</style>