|
@@ -0,0 +1,162 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <q-dialog ref="dialogRef">
|
|
|
|
|
+ <div class="code-dialog-wrapper column items-center">
|
|
|
|
|
+ <q-card class="code-card bg-white">
|
|
|
|
|
+ <q-card-section class="q-pt-lg q-pb-none q-px-lg text-center">
|
|
|
|
|
+ <p class="code-title text-primary font16 fontbold">
|
|
|
|
|
+ {{ $t('profile.favorites.code_title') }}
|
|
|
|
|
+ </p>
|
|
|
|
|
+
|
|
|
|
|
+ <p class="code-subtitle text-grey-7 font12 fontregular q-mt-sm">
|
|
|
|
|
+ {{ $t('profile.favorites.code_subtitle') }}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ </q-card-section>
|
|
|
|
|
+
|
|
|
|
|
+ <q-card-section class="q-px-lg q-pt-md q-pb-none">
|
|
|
|
|
+ <q-input
|
|
|
|
|
+ v-model="code"
|
|
|
|
|
+ autofocus
|
|
|
|
|
+ class="code-input"
|
|
|
|
|
+ input-class="text-center text-text font16 fontbold"
|
|
|
|
|
+ mask="XXXXXX"
|
|
|
|
|
+ outlined
|
|
|
|
|
+ :disable="loading"
|
|
|
|
|
+ :error="!!errorMessage"
|
|
|
|
|
+ :error-message="errorMessage"
|
|
|
|
|
+ :placeholder="$t('profile.favorites.code_placeholder')"
|
|
|
|
|
+ @keyup.enter="confirm"
|
|
|
|
|
+ @update:model-value="onCodeInput"
|
|
|
|
|
+ />
|
|
|
|
|
+ </q-card-section>
|
|
|
|
|
+
|
|
|
|
|
+ <q-card-actions class="row q-px-lg q-pb-lg q-gutter-x-sm justify-center">
|
|
|
|
|
+ <q-btn
|
|
|
|
|
+ class="col code-btn font12 fontbold"
|
|
|
|
|
+ color="grey-6"
|
|
|
|
|
+ no-caps
|
|
|
|
|
+ rounded
|
|
|
|
|
+ text-color="grey-2"
|
|
|
|
|
+ unelevated
|
|
|
|
|
+ :disable="loading"
|
|
|
|
|
+ :label="$t('profile.favorites.code_cancel')"
|
|
|
|
|
+ @click="onDialogCancel"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ <q-btn
|
|
|
|
|
+ class="col code-btn font12 fontbold"
|
|
|
|
|
+ color="secondary"
|
|
|
|
|
+ no-caps
|
|
|
|
|
+ rounded
|
|
|
|
|
+ unelevated
|
|
|
|
|
+ :disable="!isValid"
|
|
|
|
|
+ :label="$t('profile.favorites.code_confirm')"
|
|
|
|
|
+ :loading="loading"
|
|
|
|
|
+ @click="confirm"
|
|
|
|
|
+ />
|
|
|
|
|
+ </q-card-actions>
|
|
|
|
|
+ </q-card>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </q-dialog>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { computed, ref } from 'vue';
|
|
|
|
|
+import { useDialogPluginComponent } from 'quasar';
|
|
|
|
|
+import { useI18n } from 'vue-i18n';
|
|
|
|
|
+
|
|
|
|
|
+import { createClientFavoriteProviderByCode } from 'src/api/clientFavoriteProvider';
|
|
|
|
|
+import { userStore } from 'src/stores/user';
|
|
|
|
|
+
|
|
|
|
|
+defineEmits([...useDialogPluginComponent.emits]);
|
|
|
|
|
+
|
|
|
|
|
+const { dialogRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
|
|
|
|
|
+
|
|
|
|
|
+const { t } = useI18n();
|
|
|
|
|
+const store = userStore();
|
|
|
|
|
+
|
|
|
|
|
+const CODE_LENGTH = 6;
|
|
|
|
|
+
|
|
|
|
|
+const code = ref('');
|
|
|
|
|
+const errorMessage = ref('');
|
|
|
|
|
+const loading = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+const isValid = computed(() => code.value.length === CODE_LENGTH && !loading.value);
|
|
|
|
|
+
|
|
|
|
|
+const onCodeInput = (value) => {
|
|
|
|
|
+ code.value = String(value ?? '').toUpperCase();
|
|
|
|
|
+
|
|
|
|
|
+ errorMessage.value = '';
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const confirm = async () => {
|
|
|
|
|
+ if (!isValid.value) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const clientId = store.user?.client_id;
|
|
|
|
|
+
|
|
|
|
|
+ if (!clientId) {
|
|
|
|
|
+ errorMessage.value = t('profile.favorites.code_error');
|
|
|
|
|
+
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const favorite = await createClientFavoriteProviderByCode(clientId, code.value);
|
|
|
|
|
+
|
|
|
|
|
+ onDialogOK(favorite);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ errorMessage.value = error?.response?.status === 422
|
|
|
|
|
+ ? (error?.response?.data?.message ?? t('profile.favorites.code_error'))
|
|
|
|
|
+ : '';
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+.code-dialog-wrapper {
|
|
|
|
|
+ width: 320px;
|
|
|
|
|
+ max-width: 90vw;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.code-card {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ border-radius: 20px;
|
|
|
|
|
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.code-title {
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.code-subtitle {
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.code-input :deep(input) {
|
|
|
|
|
+ letter-spacing: 4px;
|
|
|
|
|
+ text-transform: uppercase;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.code-input :deep(input::placeholder) {
|
|
|
|
|
+ color: #bbbbbb;
|
|
|
|
|
+ font-weight: 400;
|
|
|
|
|
+ letter-spacing: 4px;
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.code-input :deep(input::selection) {
|
|
|
|
|
+ background: rgba(139, 92, 246, 0.2);
|
|
|
|
|
+ color: #555555;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.code-btn {
|
|
|
|
|
+ padding: 6px 12px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|