Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
122 lines
3.7 KiB
TypeScript
122 lines
3.7 KiB
TypeScript
import type { CompleteProfileDto, UpdateUserProfileDto, UserProfileResponseDto } from '@/api/generated/models'
|
|
import {
|
|
createServiceError,
|
|
errorResult,
|
|
handleServiceError,
|
|
type ServiceCallOptions,
|
|
type ServiceResult,
|
|
shouldBubbleErrorToParent,
|
|
successResult,
|
|
} from '@/services/errorHandler'
|
|
import { unwrapApiData } from '@/services/apiResponse'
|
|
import { ANALYTICS_EVENTS, trackAnalyticsEventOnce } from '@/lib/analytics'
|
|
import { getUsers } from '@/api/generated/users/users'
|
|
import { texts } from '@/texts'
|
|
|
|
export type UserProfile = UserProfileResponseDto
|
|
export type CompleteProfilePayload = CompleteProfileDto
|
|
export type UpdateProfilePayload = UpdateUserProfileDto
|
|
|
|
const usersApi = getUsers()
|
|
|
|
export const GET_ME = async (options?: ServiceCallOptions): Promise<ServiceResult<UserProfile>> => {
|
|
try {
|
|
const res = await usersApi.usersControllerGetMe()
|
|
const payload = res.data
|
|
|
|
if (!payload.success) {
|
|
throw createServiceError(payload.message || texts.profile.fetchProfileFailed)
|
|
}
|
|
|
|
const profile = unwrapApiData(payload)
|
|
|
|
if (!profile?.id) {
|
|
throw createServiceError(texts.common.invalidServerResponse)
|
|
}
|
|
|
|
return successResult(profile)
|
|
} catch (error) {
|
|
const normalizedError = handleServiceError(error, options)
|
|
|
|
if (shouldBubbleErrorToParent(options)) {
|
|
throw normalizedError
|
|
}
|
|
|
|
return errorResult(normalizedError)
|
|
}
|
|
}
|
|
|
|
export const PATCH_ME = async (data: UpdateProfilePayload, options?: ServiceCallOptions): Promise<ServiceResult<UserProfile>> => {
|
|
try {
|
|
const body: UpdateProfilePayload = {}
|
|
|
|
if (data.firstName !== undefined) body.firstName = data.firstName.trim()
|
|
if (data.lastName !== undefined) body.lastName = data.lastName.trim()
|
|
if (data.gender !== undefined) body.gender = data.gender
|
|
if (data.cityId !== undefined) body.cityId = data.cityId
|
|
if (data.bio !== undefined) body.bio = data.bio.trim()
|
|
if (data.avatarUrl !== undefined) body.avatarUrl = data.avatarUrl
|
|
if (data.defaultAddress !== undefined) {
|
|
body.defaultAddress = data.defaultAddress === null ? null : data.defaultAddress.trim()
|
|
}
|
|
|
|
const res = await usersApi.usersControllerUpdateMe(body)
|
|
const payload = res.data
|
|
|
|
if (!payload.success) {
|
|
throw createServiceError(payload.message || texts.profile.updateProfileFailed)
|
|
}
|
|
|
|
const profile = unwrapApiData(payload)
|
|
|
|
if (!profile?.id) {
|
|
throw createServiceError(texts.common.invalidServerResponse)
|
|
}
|
|
|
|
return successResult(profile)
|
|
} catch (error) {
|
|
const normalizedError = handleServiceError(error, options)
|
|
|
|
if (shouldBubbleErrorToParent(options)) {
|
|
throw normalizedError
|
|
}
|
|
|
|
return errorResult(normalizedError)
|
|
}
|
|
}
|
|
|
|
export const COMPLETE_PROFILE = async (data: CompleteProfilePayload, options?: ServiceCallOptions): Promise<ServiceResult<UserProfile>> => {
|
|
try {
|
|
const res = await usersApi.usersControllerCompleteProfile({
|
|
firstName: data.firstName.trim(),
|
|
lastName: data.lastName.trim(),
|
|
gender: data.gender,
|
|
dateOfBirth: data.dateOfBirth,
|
|
cityId: data.cityId,
|
|
})
|
|
const payload = res.data
|
|
|
|
if (!payload.success) {
|
|
throw createServiceError(payload.message || texts.profile.completeProfileFailed)
|
|
}
|
|
|
|
const profile = unwrapApiData(payload)
|
|
|
|
if (!profile?.id) {
|
|
throw createServiceError(texts.common.invalidServerResponse)
|
|
}
|
|
|
|
trackAnalyticsEventOnce(ANALYTICS_EVENTS.SIGN_UP, profile.id, { method: 'otp_profile_completion' })
|
|
|
|
return successResult(profile)
|
|
} catch (error) {
|
|
const normalizedError = handleServiceError(error, options)
|
|
|
|
if (shouldBubbleErrorToParent(options)) {
|
|
throw normalizedError
|
|
}
|
|
|
|
return errorResult(normalizedError)
|
|
}
|
|
}
|