update card, update design system, update layout anjungan
This commit is contained in:
@@ -0,0 +1,315 @@
|
||||
<template>
|
||||
<v-dialog
|
||||
:model-value="modelValue"
|
||||
@update:model-value="$emit('update:modelValue', $event)"
|
||||
max-width="600"
|
||||
transition="dialog-bottom-transition"
|
||||
scrollable
|
||||
>
|
||||
<v-card class="modal-card">
|
||||
<!-- Modal Header -->
|
||||
<div class="modal-header">
|
||||
<v-icon size="72" color="white" class="mb-3">mdi-qrcode-scan</v-icon>
|
||||
<h2 class="modal-title">Aktivasi Akun</h2>
|
||||
<p class="modal-subtitle">{{ patient.nama }}</p>
|
||||
<v-chip color="white" class="modal-chip" variant="flat" size="default">
|
||||
<span class="modal-chip-text">RM: {{ patient.rm }}</span>
|
||||
</v-chip>
|
||||
</div>
|
||||
|
||||
<!-- Modal Content -->
|
||||
<v-card-text class="pa-7">
|
||||
<v-text-field
|
||||
:model-value="phoneNumber"
|
||||
@update:model-value="$emit('update:phoneNumber', $event)"
|
||||
:disabled="qrGenerated"
|
||||
label="Nomor Telepon Pasien"
|
||||
placeholder="08xxxxxxxxxx"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
:color="qrGenerated ? 'grey' : 'primary-600'"
|
||||
:rules="[v => v.length >= 8 || 'Min. 8 digit']"
|
||||
prepend-inner-icon="mdi-phone"
|
||||
class="mb-3 phone-field"
|
||||
base-color="grey-darken-1"
|
||||
/>
|
||||
|
||||
<!-- Generate Button -->
|
||||
<v-btn
|
||||
v-if="!qrGenerated"
|
||||
:disabled="!isPhoneValid"
|
||||
color="secondary-600"
|
||||
block
|
||||
size="x-large"
|
||||
class="generate-btn"
|
||||
@click="$emit('generate')"
|
||||
rounded="xl"
|
||||
>
|
||||
<v-icon left size="32">mdi-qrcode-plus</v-icon>
|
||||
Generate QR Code
|
||||
</v-btn>
|
||||
|
||||
<!-- QR Code Container -->
|
||||
<div v-else class="qr-container">
|
||||
<div class="pulse-icon">
|
||||
<v-icon color="secondary-600" :size="isMobile ? 48 : 64">
|
||||
mdi-cellphone-check
|
||||
</v-icon>
|
||||
</div>
|
||||
|
||||
<h3 class="qr-title">Pindai QR Code</h3>
|
||||
<p class="qr-subtitle">Arahkan kamera smartphone ke QR code</p>
|
||||
|
||||
<div class="d-flex justify-center mb-3 mb-sm-4">
|
||||
<div class="qr-frame">
|
||||
<slot name="qr-code" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<!-- Modal Actions -->
|
||||
<v-card-actions v-if="qrGenerated" class="modal-actions">
|
||||
<v-btn
|
||||
color="secondary-600"
|
||||
variant="outlined"
|
||||
@click="$emit('reload')"
|
||||
prepend-icon="mdi-reload"
|
||||
size="x-large"
|
||||
class="modal-action-btn"
|
||||
rounded="xl"
|
||||
>
|
||||
Reload QR
|
||||
</v-btn>
|
||||
|
||||
<v-btn
|
||||
color="primary-600"
|
||||
variant="flat"
|
||||
@click="$emit('complete')"
|
||||
prepend-icon="mdi-check-circle"
|
||||
size="x-large"
|
||||
class="modal-action-btn-primary"
|
||||
rounded="xl"
|
||||
>
|
||||
Selesai
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
|
||||
<v-card-actions v-else class="modal-actions">
|
||||
<v-btn
|
||||
color="neutral-600"
|
||||
variant="text"
|
||||
@click="$emit('close')"
|
||||
size="x-large"
|
||||
block
|
||||
rounded="xl"
|
||||
class="modal-cancel-btn"
|
||||
>
|
||||
Batal
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
patient: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
phoneNumber: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
qrGenerated: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isMobile: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits([
|
||||
'update:modelValue',
|
||||
'update:phoneNumber',
|
||||
'generate',
|
||||
'reload',
|
||||
'complete',
|
||||
'close'
|
||||
]);
|
||||
|
||||
const isPhoneValid = computed(() => props.phoneNumber.length >= 8);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$neutral-100: #FFFFFF;
|
||||
$neutral-600: #89939E;
|
||||
$neutral-700: #717171;
|
||||
$primary-600: #FFA532;
|
||||
$secondary-200: #EDF5FF;
|
||||
$secondary-600: #0671E0;
|
||||
$secondary-700: #0053AD;
|
||||
$font-family-base: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
$font-weight-semibold: 600;
|
||||
$font-weight-bold: 700;
|
||||
$font-weight-extra-bold: 800;
|
||||
$font-weight-black: 900;
|
||||
|
||||
.modal-card {
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
background: linear-gradient(135deg, $secondary-600 0%, $secondary-700 100%);
|
||||
text-align: center;
|
||||
padding: 28px;
|
||||
box-shadow: 0 4px 12px rgba(6, 99, 199, 0.2);
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 32px;
|
||||
font-weight: $font-weight-black;
|
||||
color: $neutral-100;
|
||||
margin: 8px 0;
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
|
||||
.modal-subtitle {
|
||||
font-size: 20px;
|
||||
color: $neutral-100;
|
||||
opacity: 0.95;
|
||||
font-weight: $font-weight-semibold;
|
||||
margin: 0;
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
|
||||
.modal-chip {
|
||||
margin-top: 8px;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
|
||||
.modal-chip-text {
|
||||
color: $primary-600;
|
||||
font-weight: $font-weight-bold;
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
|
||||
.phone-field {
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
|
||||
.generate-btn {
|
||||
margin-top: 12px;
|
||||
font-weight: $font-weight-extra-bold;
|
||||
font-size: 18px;
|
||||
color: $neutral-100;
|
||||
box-shadow: 0 2px 8px rgba(6, 99, 199, 0.25);
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
|
||||
.qr-container {
|
||||
background: $secondary-200;
|
||||
border: 3px solid $secondary-600;
|
||||
border-radius: 16px;
|
||||
padding: 28px 16px;
|
||||
margin-top: 24px;
|
||||
box-shadow: 0 6px 20px rgba(6, 99, 199, 0.15);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.qr-container {
|
||||
padding: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.pulse-icon {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.qr-title {
|
||||
font-size: 24px;
|
||||
font-weight: $font-weight-black;
|
||||
color: $secondary-700;
|
||||
margin-bottom: 8px;
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.qr-title {
|
||||
font-size: 28px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.qr-subtitle {
|
||||
font-size: 13px;
|
||||
color: $neutral-700;
|
||||
margin-bottom: 16px;
|
||||
font-weight: $font-weight-semibold;
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.qr-subtitle {
|
||||
font-size: 14px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.qr-frame {
|
||||
padding: 16px;
|
||||
background: $neutral-100;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
||||
display: inline-block;
|
||||
border: 3px solid $secondary-600;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.qr-frame {
|
||||
padding: 24px;
|
||||
border-radius: 16px;
|
||||
border: 4px solid $secondary-600;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-actions {
|
||||
padding: 28px;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.modal-action-btn,
|
||||
.modal-action-btn-primary {
|
||||
font-weight: $font-weight-bold;
|
||||
font-size: 14px;
|
||||
text-transform: none;
|
||||
flex-grow: 1;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
|
||||
.modal-action-btn-primary {
|
||||
color: $neutral-100;
|
||||
font-weight: $font-weight-extra-bold;
|
||||
}
|
||||
|
||||
.modal-cancel-btn {
|
||||
font-weight: $font-weight-bold;
|
||||
font-size: 14px;
|
||||
text-transform: none;
|
||||
font-family: $font-family-base;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user