ProfileFavoriteCodeDialog.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <template>
  2. <q-dialog ref="dialogRef">
  3. <div class="code-dialog-wrapper column items-center">
  4. <q-card class="code-card bg-white">
  5. <q-card-section class="q-pt-lg q-pb-none q-px-lg text-center">
  6. <p class="code-title text-primary font16 fontbold">
  7. {{ $t('profile.favorites.code_title') }}
  8. </p>
  9. <p class="code-subtitle text-grey-7 font12 fontregular q-mt-sm">
  10. {{ $t('profile.favorites.code_subtitle') }}
  11. </p>
  12. </q-card-section>
  13. <q-card-section class="q-px-lg q-pt-md q-pb-none">
  14. <q-input
  15. v-model="code"
  16. autofocus
  17. class="code-input"
  18. input-class="text-center text-text font16 fontbold"
  19. mask="XXXXXX"
  20. outlined
  21. :disable="loading"
  22. :error="!!errorMessage"
  23. :error-message="errorMessage"
  24. :placeholder="$t('profile.favorites.code_placeholder')"
  25. @keyup.enter="confirm"
  26. @update:model-value="onCodeInput"
  27. />
  28. </q-card-section>
  29. <q-card-actions class="row q-px-lg q-pb-lg q-gutter-x-sm justify-center">
  30. <q-btn
  31. class="col code-btn font12 fontbold"
  32. color="grey-6"
  33. no-caps
  34. rounded
  35. text-color="grey-2"
  36. unelevated
  37. :disable="loading"
  38. :label="$t('profile.favorites.code_cancel')"
  39. @click="onDialogCancel"
  40. />
  41. <q-btn
  42. class="col code-btn font12 fontbold"
  43. color="secondary"
  44. no-caps
  45. rounded
  46. unelevated
  47. :disable="!isValid"
  48. :label="$t('profile.favorites.code_confirm')"
  49. :loading="loading"
  50. @click="confirm"
  51. />
  52. </q-card-actions>
  53. </q-card>
  54. </div>
  55. </q-dialog>
  56. </template>
  57. <script setup>
  58. import { computed, ref } from 'vue';
  59. import { useDialogPluginComponent } from 'quasar';
  60. import { useI18n } from 'vue-i18n';
  61. import { createClientFavoriteProviderByCode } from 'src/api/clientFavoriteProvider';
  62. import { userStore } from 'src/stores/user';
  63. defineEmits([...useDialogPluginComponent.emits]);
  64. const { dialogRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
  65. const { t } = useI18n();
  66. const store = userStore();
  67. const CODE_LENGTH = 6;
  68. const code = ref('');
  69. const errorMessage = ref('');
  70. const loading = ref(false);
  71. const isValid = computed(() => code.value.length === CODE_LENGTH && !loading.value);
  72. const onCodeInput = (value) => {
  73. code.value = String(value ?? '').toUpperCase();
  74. errorMessage.value = '';
  75. };
  76. const confirm = async () => {
  77. if (!isValid.value) {
  78. return;
  79. }
  80. const clientId = store.user?.client_id;
  81. if (!clientId) {
  82. errorMessage.value = t('profile.favorites.code_error');
  83. return;
  84. }
  85. loading.value = true;
  86. try {
  87. const favorite = await createClientFavoriteProviderByCode(clientId, code.value);
  88. onDialogOK(favorite);
  89. } catch (error) {
  90. errorMessage.value = error?.response?.status === 422
  91. ? (error?.response?.data?.message ?? t('profile.favorites.code_error'))
  92. : '';
  93. } finally {
  94. loading.value = false;
  95. }
  96. };
  97. </script>
  98. <style scoped lang="scss">
  99. .code-dialog-wrapper {
  100. width: 320px;
  101. max-width: 90vw;
  102. }
  103. .code-card {
  104. width: 100%;
  105. border-radius: 20px;
  106. box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
  107. }
  108. .code-title {
  109. line-height: 1.4;
  110. margin: 0;
  111. }
  112. .code-subtitle {
  113. line-height: 1.4;
  114. margin: 0;
  115. }
  116. .code-input :deep(input) {
  117. letter-spacing: 4px;
  118. text-transform: uppercase;
  119. }
  120. .code-input :deep(input::placeholder) {
  121. color: #bbbbbb;
  122. font-weight: 400;
  123. letter-spacing: 4px;
  124. opacity: 1;
  125. }
  126. .code-input :deep(input::selection) {
  127. background: rgba(139, 92, 246, 0.2);
  128. color: #555555;
  129. }
  130. .code-btn {
  131. padding: 6px 12px;
  132. }
  133. </style>