| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- <template>
- <q-card-section class="code-step full-width no-padding q-mb-xl">
- <div class="text-text q-mb-xs text-left">
- <span class="font14 fontbold">{{ $t("auth.validation_code") }}</span>
- </div>
- <div class="code-boxes-wrapper" @click="focusCodeInput">
- <div
- v-for="i in 6"
- :key="i"
- :class="{ 'code-box--active': code.length === i - 1 }"
- class="code-box"
- >
- <span v-if="code[i - 1]" class="text-text">{{ code[i - 1] }}</span>
- <span v-else class="text-text-light text-h6">{{ placeholder }}</span>
- </div>
- </div>
- <q-input
- ref="codeInputRef"
- v-model="code"
- class="code-hidden-input"
- hide-bottom-space
- inputmode="numeric"
- lazy-rules
- mask="######"
- no-error-icon
- :error="!!serverErrors.code"
- :error-message="serverErrors.code"
- :rules="[inputRules.required]"
- @update:model-value="clearServerError('code')"
- />
- </q-card-section>
- </template>
- <script setup>
- import { inject, ref } from "vue";
- import { useInputRules } from "src/composables/useInputRules";
- const code = defineModel("code", {
- required: true,
- type: String,
- });
- defineProps({
- serverErrors: {
- type: Object,
- default: () => ({}),
- },
- });
- const clearServerError = inject("clearServerError", () => {});
- const { inputRules } = useInputRules();
- const codeInputRef = ref(null);
- const placeholder = "x";
- const focusCodeInput = () => {
- codeInputRef.value?.$el.querySelector("input")?.focus();
- };
- </script>
- <style lang="scss" scoped>
- .code-boxes-wrapper {
- cursor: text;
- display: grid;
- gap: 6px;
- grid-template-columns: repeat(6, minmax(0, 1fr));
- margin: 0 auto;
- max-width: 292px;
- width: 100%;
- .code-box {
- align-items: center;
- background-color: #f9fafb;
- border: 2px solid #e4e4e4;
- border-radius: 8px;
- color: var(--q-text);
- display: flex;
- aspect-ratio: 1;
- height: auto;
- justify-content: center;
- min-width: 0;
- transition: border-color 0.2s ease;
- width: 100%;
- &--active {
- border-color: var(--q-primary);
- }
- }
- }
- .code-step {
- max-width: 292px;
- }
- .code-hidden-input {
- height: 1px;
- left: -9999px;
- opacity: 0;
- overflow: hidden;
- pointer-events: none;
- position: fixed;
- top: 0;
- width: 1px;
- :deep(.q-field__control),
- :deep(.q-field__bottom) {
- height: 1px;
- min-height: 1px;
- }
- }
- </style>
|