Files
tgCrewAdmin/src/components/accountHelper.vue
2025-06-29 18:55:59 +03:00

249 lines
6.4 KiB
Vue

<template>
<q-stepper
v-model="step"
vertical
color="primary"
animated
flat
class="bg-transparent"
>
<q-step
:name="1"
:title="$t('account_helper__enter_email')"
:done="step > 1"
>
<q-input
v-model="login"
autofocus
dense
filled
:label = "$t('account_helper__email')"
:rules="validationRules.email"
lazy-rules
no-error-icon
@focus="($refs.emailInput as typeof QInput)?.resetValidation()"
ref="emailInput"
:disable="type === 'changePwd'"
/>
<q-stepper-navigation>
<q-btn
@click="handleSubmit"
color="primary"
:label="$t('continue')"
:disabled="!isEmailValid"
/>
</q-stepper-navigation>
</q-step>
<q-step
:name="2"
:title="$t('account_helper__confirm_email')"
:done="step > 2"
>
<div class="q-pb-md">{{$t('account_helper__confirm_email_message')}}</div>
<q-input
v-model="code"
dense
filled
autofocus
hide-bottom-space
:label = "$t('account_helper__code')"
num="30"
/>
<q-stepper-navigation>
<q-btn
@click="handleSubmit"
color="primary"
:label="$t('continue')"
:disable="code.length === 0"
/>
<q-btn
flat
@click="step = 1"
color="primary"
:label="$t('back')"
class="q-ml-sm"
/>
</q-stepper-navigation>
</q-step>
<q-step
:name="3"
:title="$t('account_helper__set_password')"
>
<q-input
v-model="password"
dense
filled
autofocus
:label = "$t('account_helper__password')"
:type="isPwd ? 'password' : 'text'"
hide-hint
:hint="passwordHint"
:rules="validationRules.password"
lazy-rules
no-error-icon
@focus="($refs.passwordInput as typeof QInput)?.resetValidation()"
ref="passwordInput"
>
<template #append>
<q-icon
color="grey-5"
:name="isPwd ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
class="cursor-pointer"
@click="isPwd = !isPwd"
/>
</template>
</q-input>
<q-stepper-navigation>
<q-btn
@click="handleSubmit"
color="primary"
:label="$t('account_helper__finish')"
:disabled = "!isPasswordValid"
/>
<q-btn
flat
@click="step = 2"
color="primary"
:label="$t('back')"
class="q-ml-sm"
/>
</q-stepper-navigation>
</q-step>
</q-stepper>
<pn-magic-overlay
v-if="showSuccessOverlay"
icon="mdi-check-circle-outline"
:message1="getHelperMessage1()"
:message2="getHelperMessage2()"
route-name="projects"
/>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { AxiosError } from 'axios'
import { useQuasar } from 'quasar'
import { useI18n } from "vue-i18n"
import { QInput } from 'quasar'
import { useAuthStore, type AuthFlowType } from 'stores/auth'
const flowType = computed<AuthFlowType>(() => {
return props.type === 'register'
? 'register'
: props.type === 'forgotPwd'
? 'forgot'
: props.type === 'changePwd'
? 'changePwd'
: 'changeMethod'
})
const $q = useQuasar()
const { t } = useI18n()
const authStore = useAuthStore()
const props = defineProps<{
type: 'register' | 'forgotPwd' | 'changePwd' | 'changeMethod'
email?: string
}>()
type ValidationRule = (val: string) => boolean | string
type Step = 1 | 2 | 3
const step = ref<Step>(1)
const login = ref<string>(props.email || '')
const code = ref<string>('')
const password = ref<string>('')
const showSuccessOverlay = ref(false)
const isPwd = ref<boolean>(true)
const validationRules = {
email: [(val: string) => /.+@.+\..+/.test(val) || t('login__incorrect_email')] as [ValidationRule],
password: [(val: string) => val.length >= 8 || t('login__password_require')] as [ValidationRule]
}
const isEmailValid = computed(() =>
validationRules.email.every(f => f(login.value) === true)
)
const isPasswordValid = computed(() =>
validationRules.password.every(f => f(password.value) === true)
)
const passwordHint = computed(() => {
const result = validationRules.password[0](password.value)
return typeof result === 'string' ? result : ''
})
const stepActions: Record<Step, () => Promise<void>> = {
1: async () => {
await authStore.initRegistration(flowType.value, login.value)
},
2: async () => {
await authStore.confirmCode(flowType.value, login.value, code.value)
},
3: async () => {
await authStore.setPassword(flowType.value, login.value, code.value, password.value)
if (flowType.value === 'register' || flowType.value === 'changeMethod') {
await authStore.loginWithCredentials(login.value, password.value)
}
}
}
const handleError = (err: AxiosError) => {
const error = err as AxiosError<{ error?: { message?: string } }>
const message = error.response?.data?.error?.message || t('unknown_error')
$q.notify({
message: `${t('error')}: ${message}`,
type: 'negative',
position: 'bottom',
timeout: 2500
})
if (step.value > 1) {
code.value = ''
password.value = ''
}
}
const handleSubmit = async () => {
try {
await stepActions[step.value]()
if (step.value < 3) {
step.value++
} else {
showSuccessOverlay.value = true
}
} catch (error) {
handleError(error as AxiosError)
}
}
const getHelperMessage1 = () => {
switch (flowType.value) {
case 'register': return 'account_helper__register_message1'
case 'forgot': return 'account_helper__forgot_password_message1'
case 'changePwd': return 'account_helper__change_password_message1'
case 'changeMethod': return 'account_helper__change_method_message1'
default: return ''
}
}
const getHelperMessage2 = () => {
switch (flowType.value) {
case 'register': return 'slogan'
case 'forgot':
case 'changePwd':
case 'changeMethod':
return 'account_helper__go_projects'
default: return ''
}
}
</script>
<style>
</style>