fix: user status
Deploy banu-front / deploy (push) Failing after 7s

This commit is contained in:
sajjadtalkhabi
2026-06-11 16:57:17 +03:30
parent 130266b416
commit a007db0d50
17 changed files with 123 additions and 119 deletions
+6 -7
View File
@@ -39,16 +39,15 @@ export const STUDENT_REGISTRATION = Object.freeze({
export const STUDENT_REGISTRATION_ORDER = Object.freeze(Object.values(STUDENT_REGISTRATION)) export const STUDENT_REGISTRATION_ORDER = Object.freeze(Object.values(STUDENT_REGISTRATION))
// User lifecycle states (Set User Status endpoint): // User lifecycle states (Set User Status endpoint):
// pending just registered // pending registered, phone not yet OTP-verified
// verified phone OTP-confirmed // verified phone OTP-verified and registration steps completed (awaiting admin)
// approved full access // approved approved by admin (full access)
// blocked no access (existing tokens revoked) // blocked blocked by admin (no access; existing tokens revoked)
export const USER_STATUS = Object.freeze({ export const USER_STATUS = Object.freeze({
pending: 'در انتظار', pending: 'تأیید نشده',
verified: 'تأیید تلفن', verified: 'در انتظار تأیید',
approved: 'تأیید شده', approved: 'تأیید شده',
blocked: 'مسدود', blocked: 'مسدود',
rejected: 'رد شده',
}) })
export const MARITAL_STATUS = Object.freeze({ export const MARITAL_STATUS = Object.freeze({
@@ -21,11 +21,11 @@
<div class="verification-item__date"> <div class="verification-item__date">
<span class="verification-item__date-label">تاریخ ثبت نام:</span> <span class="verification-item__date-label">تاریخ ثبت نام:</span>
<span class="verification-item__date-value"> <span class="verification-item__date-value">
{{ user.faSubmittedAt || formatJalaaliDate(user.submittedAt) || '—' }} {{ formatJalaaliDate(user.createdAt) || '—' }}
</span> </span>
</div> </div>
<div <div
v-if="user.status === 'pending'" v-if="user.status === 'verified'"
class="verification-item__badge verification-item__badge--pending" class="verification-item__badge verification-item__badge--pending"
> >
<span class="verification-item__dot" /> <span class="verification-item__dot" />
@@ -92,9 +92,7 @@ const props = defineProps({
const emit = defineEmits(['show-details', 'show-reject-reason', 'verify-user']) const emit = defineEmits(['show-details', 'show-reject-reason', 'verify-user'])
const fullName = computed( const fullName = computed(() => `${props.user.name || ''}`.trim() || '—')
() => `${props.user.firstName || ''} ${props.user.lastName || ''}`.trim() || '—'
)
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -77,15 +77,12 @@ import TextField from '@/components/form/TextField.vue'
import { rejectionReasonSchema } from '../../../schema' import { rejectionReasonSchema } from '../../../schema'
import SelectField from '@/components/form/SelectField.vue' import SelectField from '@/components/form/SelectField.vue'
import TextareaField from '@/components/form/TextareaField.vue' import TextareaField from '@/components/form/TextareaField.vue'
import { import { adminUsersKeys, useChangeAdminUserStatusMutation } from '@/services/query/admin-users'
adminPendingStudentsKeys,
useChangePendingStudentStatusMutation,
} from '@/services/query/admin-pending-students'
defineOptions({ name: 'RejectReasonModal' }) defineOptions({ name: 'RejectReasonModal' })
const queryClient = useQueryClient() const queryClient = useQueryClient()
const changeStatusMutation = useChangePendingStudentStatusMutation() const changeStatusMutation = useChangeAdminUserStatusMutation()
const DEFAULT_FORM = { rejectionReason: '', adminNote: '' } const DEFAULT_FORM = { rejectionReason: '', adminNote: '' }
@@ -105,16 +102,14 @@ const handleChange = (key, value) => {
const onSubmit = async (data, close) => { const onSubmit = async (data, close) => {
const { isValid, payload } = await validate(form.value) const { isValid, payload } = await validate(form.value)
console.log(errors)
if (!isValid) return if (!isValid) return
const id = data?.id const id = data?.id
if (!id) return if (!id) return
await changeStatusMutation.mutateAsync({ await changeStatusMutation.mutateAsync({
id, id,
payload: { status: 'rejected', ...payload }, payload: { status: 'blocked', ...payload },
}) })
await queryClient.invalidateQueries({ queryKey: adminPendingStudentsKeys.all }) await queryClient.invalidateQueries({ queryKey: adminUsersKeys.all })
form.value = structuredClone({ ...DEFAULT_FORM }) form.value = structuredClone({ ...DEFAULT_FORM })
resetErrors() resetErrors()
close() close()
@@ -7,7 +7,7 @@
min-width="auto" min-width="auto"
:show-close-button="true" :show-close-button="true"
> >
<template #default="{ data, close }"> <template #default>
<div v-if="!user" class="user-verification-details"> <div v-if="!user" class="user-verification-details">
<p class="user-verification-details__loading">در حال بارگذاری</p> <p class="user-verification-details__loading">در حال بارگذاری</p>
</div> </div>
@@ -203,39 +203,19 @@
class="user-verification-details__video" class="user-verification-details__video"
/> />
</section> </section>
<div class="user-verification-details__divider" />
<div class="user-verification-details__actions">
<BaseButton
text="ذخیره به صورت PDF"
:loading="pdfLoading"
custom-class="user-verification-details__pdf-btn"
@click="onSaveAsPdf(data, close)"
>
<template #appendIcon>
<SvgIcon name="arrow-left" :size="18" color="#fff" />
</template>
</BaseButton>
</div>
</div> </div>
</template> </template>
</BasicModal> </BasicModal>
</template> </template>
<script setup> <script setup>
import { computed, ref } from 'vue' import { computed } from 'vue'
import useModal from '@/composables/useModal' import useModal from '@/composables/useModal'
import BasicModal from '@/components/BasicModal.vue' import BasicModal from '@/components/BasicModal.vue'
import BaseButton from '@/components/BaseButton.vue'
import SvgIcon from '@/components/icons/SvgIcon.vue'
import { formatJalaaliDate } from '@/utils/date-utils' import { formatJalaaliDate } from '@/utils/date-utils'
import LineTitleBlock from '@/components/LineTitleBlock.vue' import LineTitleBlock from '@/components/LineTitleBlock.vue'
import { useAdminUserQuery } from '@/services/query/admin-users'
import LineInfoBlock from '@/components/blocks/LineInfoBlock.vue' import LineInfoBlock from '@/components/blocks/LineInfoBlock.vue'
import {
usePendingStudentQuery,
useDownloadPendingStudentPdfMutation,
} from '@/services/query/admin-pending-students'
import { import {
AUDIENCE_CONFLICT_RESPONSE, AUDIENCE_CONFLICT_RESPONSE,
COMPETING_PROPAGATOR_RESPONSE, COMPETING_PROPAGATOR_RESPONSE,
@@ -258,7 +238,7 @@ const modalData = computed(() => getModal('UserVerificationDetailsModal')?.data
const userId = computed(() => modalData.value.id ?? null) const userId = computed(() => modalData.value.id ?? null)
const userIdRef = computed(() => userId.value) const userIdRef = computed(() => userId.value)
const { data: fetched } = usePendingStudentQuery(userIdRef, { const { data: fetched } = useAdminUserQuery(userIdRef, {
enabled: () => !!userIdRef.value, enabled: () => !!userIdRef.value,
}) })
@@ -293,31 +273,6 @@ const faithProduction = computed(() =>
const leaderMessage = computed(() => const leaderMessage = computed(() =>
verificationMedia.value.find((m) => m.type === VERIFICATION_MEDIA_TYPE.LEADER_MESSAGE) verificationMedia.value.find((m) => m.type === VERIFICATION_MEDIA_TYPE.LEADER_MESSAGE)
) )
const pdfLoading = ref(false)
const pdfMutation = useDownloadPendingStudentPdfMutation()
const onSaveAsPdf = async (data, close) => {
if (!user.value?.id) return
pdfLoading.value = true
try {
const response = await pdfMutation.mutateAsync(user.value.id)
const url = response?.data?.downloadUrl || response?.downloadUrl
if (url) {
const link = document.createElement('a')
link.href = url
link.target = '_blank'
link.download = 'profile.pdf'
document.body.append(link)
link.click()
link.remove()
}
close()
} finally {
pdfLoading.value = false
}
data
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -54,12 +54,12 @@ import VerificationItem from '@/features/admin/users/components/verifications/Ve
import VerificationsFilters from '@/features/admin/users/components/verifications/VerificationsFilters.vue' import VerificationsFilters from '@/features/admin/users/components/verifications/VerificationsFilters.vue'
import RejectReasonModal from '@/features/admin/users/components/verifications/modals/RejectReasonModal.vue' import RejectReasonModal from '@/features/admin/users/components/verifications/modals/RejectReasonModal.vue'
import RejectReasonDetailsModal from '@/features/admin/users/components/verifications/modals/RejectReasonDetailsModal.vue' import RejectReasonDetailsModal from '@/features/admin/users/components/verifications/modals/RejectReasonDetailsModal.vue'
import UserVerificationDetailsModal from '@/features/admin/users/components/verifications/modals/UserVerificationDetailsModal.vue'
import { import {
adminPendingStudentsKeys, adminUsersKeys,
useChangePendingStudentStatusMutation, useAdminUsersListQuery,
usePendingStudentsListQuery, useChangeAdminUserStatusMutation,
} from '@/services/query/admin-pending-students' } from '@/services/query/admin-users'
import UserVerificationDetailsModal from '@/features/admin/users/components/verifications/modals/UserVerificationDetailsModal.vue'
const queryClient = useQueryClient() const queryClient = useQueryClient()
const { openModal, isModal } = useModal() const { openModal, isModal } = useModal()
@@ -67,7 +67,9 @@ const { openModal, isModal } = useModal()
const filters = ref({ name: '', nationalCode: '', fromDate: '', toDate: '' }) const filters = ref({ name: '', nationalCode: '', fromDate: '', toDate: '' })
const { pagination, setPage, reset: resetPagination } = usePagination({ page: 1, perPage: 10 }) const { pagination, setPage, reset: resetPagination } = usePagination({ page: 1, perPage: 10 })
const { data, isLoading } = usePendingStudentsListQuery(filters, pagination, { const listFilters = computed(() => ({ ...filters.value, status: 'verified' }))
const { data, isLoading } = useAdminUsersListQuery(listFilters, pagination, {
keepPreviousData: true, keepPreviousData: true,
}) })
@@ -81,7 +83,7 @@ const paginationMeta = computed(() => ({
const onFilterApply = () => resetPagination() const onFilterApply = () => resetPagination()
const onFilterReset = () => resetPagination() const onFilterReset = () => resetPagination()
const changeStatusMutation = useChangePendingStudentStatusMutation() const changeStatusMutation = useChangeAdminUserStatusMutation()
const onVerifyUser = ({ id, status }) => { const onVerifyUser = ({ id, status }) => {
if (status === 'rejected') { if (status === 'rejected') {
@@ -91,7 +93,7 @@ const onVerifyUser = ({ id, status }) => {
changeStatusMutation.mutate( changeStatusMutation.mutate(
{ id, payload: { status } }, { id, payload: { status } },
{ {
onSuccess: () => queryClient.invalidateQueries({ queryKey: adminPendingStudentsKeys.all }), onSuccess: () => queryClient.invalidateQueries({ queryKey: adminUsersKeys.all }),
} }
) )
} }
@@ -56,7 +56,7 @@ import TextField from '@/components/form/TextField.vue'
import { loginWithCodeSchema } from '@/features/auth/schema' import { loginWithCodeSchema } from '@/features/auth/schema'
import AuthHeading from '@/features/auth/components/AuthHeading.vue' import AuthHeading from '@/features/auth/components/AuthHeading.vue'
import AuthCopyright from '@/features/auth/components/AuthCopyright.vue' import AuthCopyright from '@/features/auth/components/AuthCopyright.vue'
import { useForgotPasswordMutation, useLoginWithCodeMutation } from '@/services/query/auth' import { useForgotPasswordMutation, useRequestLoginOtpMutation } from '@/services/query/auth'
const props = defineProps({ const props = defineProps({
mode: { type: String, default: 'loginWithCode' }, mode: { type: String, default: 'loginWithCode' },
@@ -71,20 +71,20 @@ const form = ref({ phone: '' })
const { validate, validateAt, errors } = useYup(schema) const { validate, validateAt, errors } = useYup(schema)
const { savePhoneNumber } = useAuth() const { savePhoneNumber } = useAuth()
const loginCodeMutation = useLoginWithCodeMutation() const requestLoginOtpMutation = useRequestLoginOtpMutation()
const forgotPasswordMutation = useForgotPasswordMutation() const forgotPasswordMutation = useForgotPasswordMutation()
const loading = computed( const loading = computed(
() => loginCodeMutation.isPending.value || forgotPasswordMutation.isPending.value () => requestLoginOtpMutation.isPending.value || forgotPasswordMutation.isPending.value
) )
const onSubmit = async () => { const onSubmit = async () => {
const { isValid, payload } = await validate(form.value) const { isValid, payload } = await validate(form.value)
if (!isValid) return if (!isValid) return
if (isForgotPassword.value) { if (isForgotPassword.value) {
await forgotPasswordMutation.mutateAsync(payload) await forgotPasswordMutation.mutateAsync({ phone: payload.phone })
} else { } else {
await loginCodeMutation.mutateAsync(payload) await requestLoginOtpMutation.mutateAsync({ phone: payload.phone })
} }
savePhoneNumber(payload.phone) savePhoneNumber(payload.phone)
emit('next', { phone: payload.phone, mode: props.mode }) emit('next', { phone: payload.phone, mode: props.mode })
+21 -12
View File
@@ -55,10 +55,12 @@ import TextField from '@/components/form/TextField.vue'
import { verifyCodeSchema } from '@/features/auth/schema' import { verifyCodeSchema } from '@/features/auth/schema'
import AuthHeading from '@/features/auth/components/AuthHeading.vue' import AuthHeading from '@/features/auth/components/AuthHeading.vue'
import AuthCopyright from '@/features/auth/components/AuthCopyright.vue' import AuthCopyright from '@/features/auth/components/AuthCopyright.vue'
import { usePasswordReset } from '@/features/auth/composables/usePasswordReset'
import { useRedirectAfterLogin } from '@/features/auth/composables/useRedirectAfterLogin' import { useRedirectAfterLogin } from '@/features/auth/composables/useRedirectAfterLogin'
import { import {
useForgotPasswordMutation, useForgotPasswordMutation,
useLoginWithCodeMutation, useRequestLoginOtpMutation,
useVerifyLoginOtpMutation,
useResendVerificationCodeMutation, useResendVerificationCodeMutation,
useVerifyCodeMutation, useVerifyCodeMutation,
useVerifyForgotPasswordCodeMutation, useVerifyForgotPasswordCodeMutation,
@@ -76,15 +78,16 @@ const form = ref({ verifyCode: '' })
const { validate, validateAt, errors } = useYup(schema) const { validate, validateAt, errors } = useYup(schema)
const { applySession } = useAuth() const { applySession } = useAuth()
const { setResetTicket } = usePasswordReset()
const router = useRouter() const router = useRouter()
const redirectAfterLogin = useRedirectAfterLogin() const redirectAfterLogin = useRedirectAfterLogin()
const verifyLoginMutation = useLoginWithCodeMutation() const verifyLoginMutation = useVerifyLoginOtpMutation()
const verifySignupMutation = useVerifyCodeMutation() const verifySignupMutation = useVerifyCodeMutation()
const verifyForgotMutation = useVerifyForgotPasswordCodeMutation() const verifyForgotMutation = useVerifyForgotPasswordCodeMutation()
const resendCodeMutation = useResendVerificationCodeMutation() const resendCodeMutation = useResendVerificationCodeMutation()
const forgotMutation = useForgotPasswordMutation() const forgotMutation = useForgotPasswordMutation()
const loginCodeMutation = useLoginWithCodeMutation() const requestLoginOtpMutation = useRequestLoginOtpMutation()
const submitting = computed( const submitting = computed(
() => () =>
@@ -97,37 +100,43 @@ const resending = computed(
() => () =>
resendCodeMutation.isPending.value || resendCodeMutation.isPending.value ||
forgotMutation.isPending.value || forgotMutation.isPending.value ||
loginCodeMutation.isPending.value requestLoginOtpMutation.isPending.value
) )
const onSubmit = async () => { const onSubmit = async () => {
const { isValid, payload } = await validate(form.value) const { isValid, payload } = await validate(form.value)
if (!isValid) return if (!isValid) return
const body = { phone: props.phoneNumber, verifyCode: payload.verifyCode } const code = payload.verifyCode
if (props.mode === 'loginWithCode') { if (props.mode === 'loginWithCode') {
const response = await verifyLoginMutation.mutateAsync(body) const response = await verifyLoginMutation.mutateAsync({
phone: props.phoneNumber,
code,
deviceName: 'web',
})
applySession(response?.data ?? response) applySession(response?.data ?? response)
redirectAfterLogin() redirectAfterLogin()
return return
} }
if (props.mode === 'forgotPassword') { if (props.mode === 'forgotPassword') {
await verifyForgotMutation.mutateAsync(body) const response = await verifyForgotMutation.mutateAsync({ phone: props.phoneNumber, code })
const data = response?.data ?? response
setResetTicket({ phone: props.phoneNumber, token: data?.resetToken })
router.push({ name: 'reset-password' }) router.push({ name: 'reset-password' })
return return
} }
await verifySignupMutation.mutateAsync(body) await verifySignupMutation.mutateAsync({ phone: props.phoneNumber, verifyCode: code })
emit('verified', body) emit('verified', { phone: props.phoneNumber, verifyCode: code })
} }
const onResend = async () => { const onResend = async () => {
if (!props.phoneNumber) return if (!props.phoneNumber) return
const body = { phoneNumber: props.phoneNumber } const body = { phone: props.phoneNumber }
if (props.mode === 'forgotPassword') await forgotMutation.mutateAsync(body) if (props.mode === 'forgotPassword') await forgotMutation.mutateAsync(body)
else if (props.mode === 'loginWithCode') await loginCodeMutation.mutateAsync(body) else if (props.mode === 'loginWithCode') await requestLoginOtpMutation.mutateAsync(body)
else await resendCodeMutation.mutateAsync(body) else await resendCodeMutation.mutateAsync({ phoneNumber: props.phoneNumber })
} }
</script> </script>
@@ -0,0 +1,20 @@
import { ref } from 'vue'
const phone = ref('')
const token = ref('')
export const usePasswordReset = () => {
const setResetTicket = ({ phone: phoneNumber, token: resetToken }) => {
if (phoneNumber) phone.value = phoneNumber
if (resetToken) token.value = resetToken
}
const clearResetTicket = () => {
phone.value = ''
token.value = ''
}
return { phone, token, setResetTicket, clearResetTicket }
}
export default usePasswordReset
+14 -7
View File
@@ -52,6 +52,7 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { useRouter } from 'vue-router'
import useYup from '@/composables/useYup' import useYup from '@/composables/useYup'
import useAuth from '@/composables/useAuth' import useAuth from '@/composables/useAuth'
import BaseButton from '@/components/BaseButton.vue' import BaseButton from '@/components/BaseButton.vue'
@@ -63,15 +64,16 @@ import AuthShell from '@/features/auth/components/AuthShell.vue'
import { useResetPasswordMutation } from '@/services/query/auth' import { useResetPasswordMutation } from '@/services/query/auth'
import AuthHeading from '@/features/auth/components/AuthHeading.vue' import AuthHeading from '@/features/auth/components/AuthHeading.vue'
import AuthCopyright from '@/features/auth/components/AuthCopyright.vue' import AuthCopyright from '@/features/auth/components/AuthCopyright.vue'
import { useRedirectAfterLogin } from '@/features/auth/composables/useRedirectAfterLogin' import { usePasswordReset } from '@/features/auth/composables/usePasswordReset'
const { user, applySession } = useAuth() const { user } = useAuth()
const redirectAfterLogin = useRedirectAfterLogin() const { phone: resetPhone, token: resetToken, clearResetTicket } = usePasswordReset()
const router = useRouter()
const schema = resetPasswordSchema const schema = resetPasswordSchema
const form = ref({ const form = ref({
phone: user.value?.phone || '', phone: resetPhone.value || user.value?.phone || '',
password: '', password: '',
passwordConfirmation: '', passwordConfirmation: '',
}) })
@@ -82,9 +84,14 @@ const resetMutation = useResetPasswordMutation()
const onSubmit = async () => { const onSubmit = async () => {
const { isValid, payload } = await validate(form.value) const { isValid, payload } = await validate(form.value)
if (!isValid) return if (!isValid) return
const response = await resetMutation.mutateAsync(payload) await resetMutation.mutateAsync({
applySession(response?.data ?? response) phone: form.value.phone,
redirectAfterLogin() token: resetToken.value,
password: payload.password,
passwordConfirmation: payload.passwordConfirmation,
})
clearResetTicket()
router.push({ name: 'login' })
} }
</script> </script>
@@ -226,7 +226,6 @@ import { studentProfileSchema, studentResetPasswordSchema } from '@/features/stu
import { import {
authKeys, authKeys,
useGetMeQuery, useGetMeQuery,
useResetPasswordMutation,
useUpdateProfileMutation, useUpdateProfileMutation,
useUploadMediaMutation, useUploadMediaMutation,
} from '@/services/query/auth' } from '@/services/query/auth'
@@ -339,7 +338,7 @@ const onAvatarCropped = async (file) => {
const onAvatarError = (msg) => toast.error(msg) const onAvatarError = (msg) => toast.error(msg)
const updateMutation = useUpdateProfileMutation() const updateMutation = useUpdateProfileMutation()
const resetPasswordMutation = useResetPasswordMutation() const resetPasswordMutation = useUpdateProfileMutation()
const onSubmit = async () => { const onSubmit = async () => {
const { isValid, payload } = await validate(form.value) const { isValid, payload } = await validate(form.value)
@@ -369,7 +368,10 @@ const onResetPassword = async () => {
}) })
if (!isValid) return if (!isValid) return
try { try {
await resetPasswordMutation.mutateAsync(payload) await resetPasswordMutation.mutateAsync({
password: payload.password,
passwordConfirmation: payload.passwordConfirmation,
})
passwordForm.value.password = '' passwordForm.value.password = ''
passwordForm.value.passwordConfirmation = '' passwordForm.value.passwordConfirmation = ''
resetPasswordErrors() resetPasswordErrors()
+3 -1
View File
@@ -9,7 +9,9 @@ import { endpoints } from '@/services/api/endpoints'
export const apiLogin = (payload) => http.post(endpoints.login, payload) export const apiLogin = (payload) => http.post(endpoints.login, payload)
export const apiLoginWithCode = (payload) => http.post(endpoints.loginWithCode2Step, payload) export const apiRequestLoginOtp = (payload) => http.post(endpoints.requestLoginOtp, payload)
export const apiVerifyLoginOtp = (payload) => http.post(endpoints.verifyLoginOtp, payload)
export const apiRegister = (payload) => http.post(endpoints.register, payload) export const apiRegister = (payload) => http.post(endpoints.register, payload)
+6 -5
View File
@@ -8,15 +8,16 @@ export const endpoints = {
updateProfile: '/me', updateProfile: '/me',
registerData: '/me/register-data', registerData: '/me/register-data',
// FE-only — NOT in backend Postman doc; kept so existing UI/mock layer works. requestLoginOtp: '/auth/login/otp/request',
verifyLoginOtp: '/auth/login/otp/verify',
forgotPassword: '/auth/password/forgot',
verifyForgotPasswordCode: '/auth/password/verify-otp',
resetPassword: '/auth/password/reset',
resendVerificationCodeForRegister: '/resend-verification-code', resendVerificationCodeForRegister: '/resend-verification-code',
verifyCode: '/verify-code', verifyCode: '/verify-code',
completeProfile: '/complete-profile', completeProfile: '/complete-profile',
getRegistrationQuestionVideo: '/verification-registration-media', getRegistrationQuestionVideo: '/verification-registration-media',
loginWithCode2Step: '/login-with-code',
forgotPassword: '/forgot-password',
verifyForgotPasswordCode: '/verify-forgot-password-code',
resetPassword: '/reset-password',
// ─── Geo ─────────────────────────────────────────────────────────────────── // ─── Geo ───────────────────────────────────────────────────────────────────
provinceList: '/provinces', provinceList: '/provinces',
@@ -6,7 +6,7 @@ const pick = (arr, i) => arr[i % arr.length]
const makeStudent = (i) => { const makeStudent = (i) => {
const firstName = pick(firstNames, i) const firstName = pick(firstNames, i)
const lastName = pick(lastNames, i + 2) const lastName = pick(lastNames, i + 2)
const status = i % 3 === 0 ? 'rejected' : 'pending' const status = i % 3 === 0 ? 'rejected' : 'verified'
const submittedAt = new Date(Date.now() - i * 86_400_000).toISOString() const submittedAt = new Date(Date.now() - i * 86_400_000).toISOString()
return { return {
id: 500 + i, id: 500 + i,
+1 -1
View File
@@ -86,7 +86,7 @@ const makeUser = (i, overrides = {}) => {
fullName: `${firstName} ${lastName}`, fullName: `${firstName} ${lastName}`,
phoneNumber, phoneNumber,
nationalCode: String(1_000_000_000 + i * 7).padStart(10, '0'), nationalCode: String(1_000_000_000 + i * 7).padStart(10, '0'),
status: i % 5 === 0 ? 'pending' : 'approved', status: i % 5 === 0 ? 'pending' : i % 3 === 0 ? 'verified' : 'approved',
roleId: roles.find((r) => r.name === role)?.id, roleId: roles.find((r) => r.name === role)?.id,
address: { address: {
address: 'آدرس نمونه', address: 'آدرس نمونه',
+1
View File
@@ -21,6 +21,7 @@ register('GET', endpoints.getApprovedUsers, ({ query }) => {
nationalCode: 'includes', nationalCode: 'includes',
phoneNumber: 'includes', phoneNumber: 'includes',
roleId: (item, v) => String(item.roleId) === String(v), roleId: (item, v) => String(item.roleId) === String(v),
status: (item, v) => String(item.status) === String(v),
}) })
list = filterDateRange(list, query) list = filterDateRange(list, query)
const { data: items, meta } = paginate(list, query) const { data: items, meta } = paginate(list, query)
+14 -4
View File
@@ -9,7 +9,13 @@ register('POST', endpoints.login, () => ({
data: { user: currentMe, token: fakeToken }, data: { user: currentMe, token: fakeToken },
})) }))
register('POST', endpoints.loginWithCode2Step, () => ({ register('POST', endpoints.requestLoginOtp, () => ({
success: true,
message: 'If the phone is registered, a code has been sent.',
data: null,
}))
register('POST', endpoints.verifyLoginOtp, () => ({
data: { user: currentMe, token: fakeToken }, data: { user: currentMe, token: fakeToken },
})) }))
@@ -26,15 +32,19 @@ register('POST', endpoints.resendVerificationCodeForRegister, () => ({
})) }))
register('POST', endpoints.forgotPassword, () => ({ register('POST', endpoints.forgotPassword, () => ({
data: { message: 'کد بازیابی ارسال شد' }, success: true,
message: 'If the phone is registered, a code has been sent.',
data: null,
})) }))
register('POST', endpoints.verifyForgotPasswordCode, () => ({ register('POST', endpoints.verifyForgotPasswordCode, () => ({
data: { token: fakeToken }, data: { reset_token: fakeToken },
})) }))
register('POST', endpoints.resetPassword, () => ({ register('POST', endpoints.resetPassword, () => ({
data: { message: 'رمز عبور با موفقیت تغییر کرد' }, success: true,
message: 'Password updated.',
data: null,
})) }))
register('POST', endpoints.logout, () => ({ data: { message: 'خروج موفق' } })) register('POST', endpoints.logout, () => ({ data: { message: 'خروج موفق' } }))
+5 -2
View File
@@ -7,7 +7,8 @@ import {
apiGetRegisterData, apiGetRegisterData,
apiGetRegistrationQuestionVideo, apiGetRegistrationQuestionVideo,
apiLogin, apiLogin,
apiLoginWithCode, apiRequestLoginOtp,
apiVerifyLoginOtp,
apiLogout, apiLogout,
apiRegister, apiRegister,
apiResendVerificationCode, apiResendVerificationCode,
@@ -27,7 +28,9 @@ export const authKeys = {
export const useLoginMutation = () => useMutation({ mutationFn: apiLogin }) export const useLoginMutation = () => useMutation({ mutationFn: apiLogin })
export const useLoginWithCodeMutation = () => useMutation({ mutationFn: apiLoginWithCode }) export const useRequestLoginOtpMutation = () => useMutation({ mutationFn: apiRequestLoginOtp })
export const useVerifyLoginOtpMutation = () => useMutation({ mutationFn: apiVerifyLoginOtp })
export const useRegisterMutation = () => useMutation({ mutationFn: apiRegister }) export const useRegisterMutation = () => useMutation({ mutationFn: apiRegister })