199 lines
5.7 KiB
TypeScript
199 lines
5.7 KiB
TypeScript
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
|
|
import type { FormInstance } from 'ant-design-vue'
|
|
import { message } from 'ant-design-vue'
|
|
import type SmsOtpField from '@/components/SmsOtpField.vue'
|
|
import type { Login } from '@/models/login'
|
|
import {
|
|
authenticateWithFingerprint,
|
|
getToken,
|
|
loading,
|
|
setToken,
|
|
} from '@/utils'
|
|
import useCountdownTimer from '@/utils/useCountdownTimer'
|
|
import { loginCustomer, verifyToken } from '@/api/login'
|
|
import { useUserStore } from '@/store/userStore'
|
|
import { useWalletStore } from '@/store/walletStore'
|
|
import { useSettingsStore } from '@/store/settingsStore'
|
|
import { setTruth } from '@/app/authBoot'
|
|
import { completeLoginNavigation } from '@/layouts/composables/useMobileScrollReset'
|
|
import { normalizeAuthFormFields, persianToEnglishDigits } from '@/utils/persianDigits'
|
|
import { beginSmsOtpCapture, clearPendingSmsOtp } from '@/utils/webOtp'
|
|
import { usePwaInstall } from '@/composables/usePwaInstall'
|
|
import {
|
|
canRequestBrowserNotification,
|
|
requestBrowserNotificationPermission,
|
|
} from '@/utils/browserNotification'
|
|
|
|
export function useLoginForm() {
|
|
const { time, onFinish, reset } = useCountdownTimer('00:02:00', 'mm:ss')
|
|
const enableSendAgainCode = ref(false)
|
|
const stepTwoVerify = ref(false)
|
|
const formRef = ref<FormInstance>()
|
|
const userStore = useUserStore()
|
|
const walletStore = useWalletStore()
|
|
const refOtpInput = ref<InstanceType<typeof SmsOtpField> | null>(null)
|
|
const isSMS = ref(true)
|
|
const isRegister = ref<boolean | undefined>()
|
|
const { tryInstallOrOpenGuide, completeGuide } = usePwaInstall()
|
|
|
|
const userFormState = reactive<Login>({
|
|
provider: 'customer',
|
|
})
|
|
|
|
onFinish(() => {
|
|
enableSendAgainCode.value = true
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
// SmsOtpField cleans its own listener
|
|
})
|
|
|
|
async function reSendCode() {
|
|
userFormState.token = undefined
|
|
clearPendingSmsOtp()
|
|
refOtpInput.value?.clearInput?.()
|
|
enableSendAgainCode.value = false
|
|
normalizeAuthFormFields(userFormState)
|
|
beginSmsOtpCapture()
|
|
await loginCustomer(userFormState)
|
|
refOtpInput.value?.startWebOtp?.()
|
|
refOtpInput.value?.focusInput?.()
|
|
reset()
|
|
}
|
|
|
|
function setIsSMS(val: boolean) {
|
|
isSMS.value = val
|
|
if (!val) stepTwoVerify.value = false
|
|
userFormState.token = ''
|
|
userFormState.password = ''
|
|
}
|
|
|
|
async function enterFingerPrint() {
|
|
const fingerPrint = await authenticateWithFingerprint()
|
|
if (fingerPrint) {
|
|
setTruth()
|
|
await completeLoginNavigation()
|
|
} else {
|
|
message.error('خطا در اعتبارسنجی')
|
|
}
|
|
}
|
|
|
|
function handleOnChange(value: string) {
|
|
userFormState.token = persianToEnglishDigits(String(value ?? ''))
|
|
normalizeAuthFormFields(userFormState)
|
|
}
|
|
|
|
async function handleOnComplete(value: string) {
|
|
userFormState.token = persianToEnglishDigits(String(value ?? ''))
|
|
normalizeAuthFormFields(userFormState)
|
|
phoneVerification()
|
|
}
|
|
|
|
async function login(accessToken: string | undefined) {
|
|
setToken(accessToken)
|
|
await userStore.getMyInfo()
|
|
if (!userStore.userInfo) {
|
|
message.error('ورود انجام شد ولی دریافت اطلاعات کاربر ممکن نشد. اتصال سرور را بررسی کنید.')
|
|
return
|
|
}
|
|
await walletStore.getMyWallet()
|
|
setTruth()
|
|
await completeLoginNavigation()
|
|
}
|
|
|
|
function phoneVerification() {
|
|
return formRef.value?.validateFields().then(async () => {
|
|
try {
|
|
loading.value = true
|
|
normalizeAuthFormFields(userFormState)
|
|
if (isSMS.value) {
|
|
if (!stepTwoVerify.value) {
|
|
userFormState.token = undefined
|
|
userFormState.password = undefined
|
|
userFormState.provider = 'customer'
|
|
beginSmsOtpCapture()
|
|
const { id } = await loginCustomer(userFormState)
|
|
userFormState.id = id
|
|
stepTwoVerify.value = true
|
|
reset()
|
|
} else {
|
|
// نوتیف را در gesture شروع کن؛ await نکن تا ورود بلاک نشود
|
|
if (canRequestBrowserNotification()) {
|
|
void requestBrowserNotificationPermission()
|
|
}
|
|
const { access_token } = await verifyToken(userFormState)
|
|
await login(access_token)
|
|
}
|
|
} else {
|
|
userFormState.token = undefined
|
|
if (canRequestBrowserNotification()) {
|
|
void requestBrowserNotificationPermission()
|
|
}
|
|
const { access_token } = await loginCustomer(userFormState)
|
|
await login(access_token)
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
})
|
|
}
|
|
|
|
function editPhoneNumber() {
|
|
stepTwoVerify.value = false
|
|
}
|
|
|
|
async function isOpenRegister() {
|
|
const settingsStore = useSettingsStore()
|
|
await settingsStore.fetchSettings()
|
|
isRegister.value = settingsStore.settings.find(
|
|
(s) => s?.key === 'open_register' && s?.is_active === true,
|
|
)
|
|
}
|
|
|
|
function installWebApp() {
|
|
void tryInstallOrOpenGuide()
|
|
}
|
|
|
|
function proceedWithInstall() {
|
|
void completeGuide()
|
|
}
|
|
|
|
const submitLabel = computed(() => {
|
|
if (!isSMS.value) return 'ورود'
|
|
return stepTwoVerify.value ? 'ورود' : 'ارسال کد'
|
|
})
|
|
|
|
const showFingerprint = computed(
|
|
() => Boolean(getToken() && userStore.userInfo?.finger_print),
|
|
)
|
|
|
|
onMounted(async () => {
|
|
await isOpenRegister()
|
|
})
|
|
|
|
return {
|
|
time,
|
|
enableSendAgainCode,
|
|
stepTwoVerify,
|
|
formRef,
|
|
refOtpInput,
|
|
isSMS,
|
|
isRegister,
|
|
userFormState,
|
|
loading,
|
|
submitLabel,
|
|
showFingerprint,
|
|
setIsSMS,
|
|
reSendCode,
|
|
enterFingerPrint,
|
|
handleOnChange,
|
|
handleOnComplete,
|
|
phoneVerification,
|
|
editPhoneNumber,
|
|
installWebApp,
|
|
proceedWithInstall,
|
|
}
|
|
}
|