120 lines
3.6 KiB
Vue
120 lines
3.6 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { useAuthStore } from '@/stores/auth'
|
|
import BaseInput from '@/components/ui/BaseInput.vue'
|
|
import FormErrorBanner from '@/components/ui/FormErrorBanner.vue'
|
|
import BaseButton from '@/components/ui/BaseButton.vue'
|
|
import AuthThemeToggle from '@/components/ui/AuthThemeToggle.vue'
|
|
import { normalizePhone, toPersianDigits } from '@/utils/format'
|
|
import { validatePhone } from '@/utils/validation'
|
|
import {
|
|
FORM_VALIDATION_SUMMARY,
|
|
clearFieldError,
|
|
hasFieldErrors,
|
|
type FieldErrors,
|
|
} from '@/utils/formErrors'
|
|
|
|
const router = useRouter()
|
|
const auth = useAuthStore()
|
|
|
|
const phone = ref('')
|
|
const fieldErrors = ref<FieldErrors>({})
|
|
const formError = ref('')
|
|
|
|
const displayPhone = computed(() => (phone.value ? toPersianDigits(phone.value) : ''))
|
|
|
|
function phoneErrorMessage(value: string): string {
|
|
if (!value) return 'شماره موبایل را وارد کنید.'
|
|
if (!validatePhone(value)) return 'شماره موبایل معتبر نیست. (مثال: ۰۹۱۲۱۲۳۴۵۶۷)'
|
|
return ''
|
|
}
|
|
|
|
function clearPhoneError() {
|
|
fieldErrors.value = clearFieldError(fieldErrors.value, 'phone')
|
|
if (!hasFieldErrors(fieldErrors.value)) formError.value = ''
|
|
}
|
|
|
|
function onPhoneInput(value: string) {
|
|
phone.value = normalizePhone(value)
|
|
clearPhoneError()
|
|
}
|
|
|
|
function onPhoneBlur() {
|
|
if (!phone.value) return
|
|
const message = phoneErrorMessage(phone.value)
|
|
if (message) {
|
|
fieldErrors.value = { ...fieldErrors.value, phone: message }
|
|
}
|
|
}
|
|
|
|
async function submit() {
|
|
fieldErrors.value = {}
|
|
formError.value = ''
|
|
|
|
const normalized = normalizePhone(phone.value)
|
|
phone.value = normalized
|
|
|
|
const message = phoneErrorMessage(normalized)
|
|
if (message) {
|
|
fieldErrors.value = { phone: message }
|
|
formError.value = FORM_VALIDATION_SUMMARY
|
|
return
|
|
}
|
|
|
|
const result = await auth.requestOtp(normalized, { isRegister: false })
|
|
if (result.success) {
|
|
router.push({ name: 'otp', query: { phone: normalized, mode: 'login' } })
|
|
} else {
|
|
formError.value = result.message ?? 'خطا در ارسال کد تأیید.'
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="page page-shell auth-page">
|
|
<AuthThemeToggle />
|
|
|
|
<div class="page__scroll flex flex-col justify-center py-6">
|
|
<div class="auth-header">
|
|
<div class="text-5xl mb-3">🧵</div>
|
|
<h1 class="page-title">ورود به سامانه</h1>
|
|
<p class="page-subtitle">سامانه سفارش عمده پارچه</p>
|
|
</div>
|
|
|
|
<form class="card" @submit.prevent="submit">
|
|
<FormErrorBanner :message="formError" />
|
|
|
|
<BaseInput
|
|
:model-value="displayPhone"
|
|
label="شماره موبایل"
|
|
type="tel"
|
|
inputmode="numeric"
|
|
autocomplete="tel"
|
|
dir="ltr"
|
|
align="center"
|
|
maxlength="11"
|
|
placeholder="۰۹۱۲۳۴۵۶۷۸۹"
|
|
:error="fieldErrors.phone"
|
|
hint="کد تأیید به این شماره ارسال میشود"
|
|
@update:model-value="onPhoneInput"
|
|
@blur="onPhoneBlur"
|
|
/>
|
|
<BaseButton block type="submit" :loading="auth.loading">دریافت کد تأیید</BaseButton>
|
|
</form>
|
|
|
|
<div class="mt-6 w-full max-w-[var(--form-max-width)] text-center">
|
|
<p class="m-0 text-sm text-muted">
|
|
حساب کاربری ندارید؟
|
|
<RouterLink
|
|
to="/register"
|
|
class="ms-1 font-bold text-primary no-underline hover:underline"
|
|
>
|
|
ثبت نام کنید
|
|
</RouterLink>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|