| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- <template>
- <q-dialog v-model="open" persistent>
- <q-card class="verification-dialog">
- <q-card-section class="column items-center text-center q-gutter-y-md">
- <q-spinner-dots v-if="busy" color="primary" size="48px" />
- <q-icon v-else :color="iconColor" :name="icon" size="48px" />
- <div class="font16 fontbold text-text">{{ title }}</div>
- <div
- v-for="(line, index) in lines"
- :key="index"
- class="font14 text-text-secondary"
- >
- {{ line }}
- </div>
- <div
- v-if="showAttempts"
- class="font12 text-text-secondary"
- >
- {{ $t("verification.attempts_left", { count: attemptsLeft }) }}
- </div>
- </q-card-section>
- <q-card-actions align="right" class="q-pb-md q-px-md">
- <q-btn
- v-close-popup
- color="primary"
- flat
- no-caps
- rounded
- :label="$t('common.actions.close')"
- @click="onClose"
- />
- <q-btn
- v-if="showAction"
- color="primary"
- no-caps
- rounded
- unelevated
- :label="actionLabel"
- :loading="loading"
- @click="start"
- />
- </q-card-actions>
- </q-card>
- </q-dialog>
- </template>
- <script setup>
- import { computed, watch } from "vue";
- import { useI18n } from "vue-i18n";
- import {
- useIdentityVerification,
- VERIFICATION_STATUS,
- } from "src/composables/useIdentityVerification";
- defineOptions({
- name: "IdentityVerificationDialog",
- });
- const emit = defineEmits(["approved"]);
- const open = defineModel({
- required: true,
- type: Boolean,
- });
- const { t } = useI18n();
- const {
- attemptsLeft,
- canRetry,
- hasOpenSession,
- isApproved,
- loading,
- polling,
- refresh,
- start,
- status,
- } = useIdentityVerification();
- watch(open, (visible) => {
- if (visible) refresh().catch(() => {});
- }, { immediate: true });
- watch(isApproved, (approved) => {
- if (approved && open.value) emit("approved");
- });
- const busy = computed(() => loading.value || polling.value);
- const icon = computed(() => {
- switch (status.value) {
- case VERIFICATION_STATUS.APPROVED:
- return "mdi-check-circle-outline";
- case VERIFICATION_STATUS.DECLINED:
- return "mdi-alert-circle-outline";
- case VERIFICATION_STATUS.IN_REVIEW:
- return "mdi-clock-outline";
- default:
- return "mdi-card-account-details-outline";
- }
- });
- const iconColor = computed(() =>
- status.value === VERIFICATION_STATUS.APPROVED ? "positive" : "primary",
- );
- const title = computed(() => {
- if (busy.value) return t("verification.title");
- switch (status.value) {
- case VERIFICATION_STATUS.APPROVED:
- return t("verification.approved_title");
- case VERIFICATION_STATUS.DECLINED:
- return t("verification.declined_title");
- case VERIFICATION_STATUS.IN_REVIEW:
- return t("verification.in_review_title");
- case VERIFICATION_STATUS.PENDING:
- return t("verification.in_progress_title");
- default:
- return t("verification.title");
- }
- });
- const lines = computed(() => {
- if (busy.value) {
- return [loading.value ? t("verification.opening") : t("verification.checking")];
- }
- switch (status.value) {
- case VERIFICATION_STATUS.APPROVED:
- return [t("verification.approved")];
- case VERIFICATION_STATUS.DECLINED:
- return canRetry.value
- ? [t("verification.declined")]
- : [t("verification.attempts_exhausted")];
- case VERIFICATION_STATUS.IN_REVIEW:
- return [t("verification.in_review")];
- case VERIFICATION_STATUS.PENDING:
- return hasOpenSession.value
- ? [t("verification.resume_hint")]
- : [t("verification.in_progress")];
- default:
- return [t("verification.intro"), t("verification.documents_hint")];
- }
- });
- const showAction = computed(() => {
- if (busy.value || isApproved.value) return false;
- if (status.value === VERIFICATION_STATUS.DECLINED) return canRetry.value;
- if (status.value === VERIFICATION_STATUS.PENDING) return hasOpenSession.value;
- return [
- VERIFICATION_STATUS.NOT_STARTED,
- VERIFICATION_STATUS.EXPIRED,
- ].includes(status.value);
- });
- const actionLabel = computed(() => {
- if (status.value === VERIFICATION_STATUS.DECLINED) return t("verification.retry");
- if (status.value === VERIFICATION_STATUS.PENDING) return t("verification.resume");
- return t("verification.start");
- });
- const showAttempts = computed(
- () => showAction.value && Number.isFinite(attemptsLeft.value),
- );
- const onClose = () => {
- open.value = false;
- };
- </script>
- <style lang="scss" scoped>
- .verification-dialog {
- border-radius: 16px;
- max-width: 420px;
- width: 90vw;
- }
- </style>
|