Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
128 lines
4.5 KiB
TypeScript
128 lines
4.5 KiB
TypeScript
import type { CreateUserContactLinkDto, UpdateUserContactLinkDto, UserContactLinkResponseDto } from '@/api/generated/models'
|
|
import { getUsers } from '@/api/generated/users/users'
|
|
import {
|
|
createServiceError,
|
|
errorResult,
|
|
handleServiceError,
|
|
type ServiceCallOptions,
|
|
type ServiceResult,
|
|
shouldBubbleErrorToParent,
|
|
successResult,
|
|
} from '@/services/errorHandler'
|
|
import { unwrapApiData } from '@/services/apiResponse'
|
|
import { texts } from '@/texts'
|
|
|
|
export type ContactLink = UserContactLinkResponseDto
|
|
export type CreateContactLinkPayload = CreateUserContactLinkDto
|
|
export type UpdateContactLinkPayload = UpdateUserContactLinkDto
|
|
|
|
export const CONTACT_CHANNEL_OPTIONS = [
|
|
{ selectKey: 'instagram', name: texts.common.instagram, placeholder: texts.profile.usernamePlaceholder },
|
|
{ selectKey: 'telegram', name: texts.common.telegram, placeholder: texts.profile.usernamePlaceholder },
|
|
{ selectKey: 'twitter', name: texts.profile.channelTwitter, placeholder: texts.profile.usernamePlaceholder },
|
|
{ selectKey: 'linkedin', name: texts.profile.channelLinkedin, placeholder: texts.profile.channelLinkedinPlaceholder },
|
|
{ selectKey: 'youtube', name: texts.profile.channelYoutube, placeholder: texts.profile.channelYoutubePlaceholder },
|
|
{ selectKey: 'website', name: texts.profile.channelWebsite, placeholder: texts.profile.channelWebsitePlaceholder },
|
|
{ selectKey: 'support_phone', name: texts.profile.channelSupportPhone, placeholder: texts.profile.channelSupportPhonePlaceholder },
|
|
] as const
|
|
|
|
const usersApi = getUsers()
|
|
|
|
export const LIST_CONTACT_LINKS = async (options?: ServiceCallOptions): Promise<ServiceResult<ContactLink[]>> => {
|
|
try {
|
|
const res = await usersApi.userContactLinksControllerList()
|
|
const payload = res.data
|
|
|
|
if (!payload.success) {
|
|
throw createServiceError(payload.message || texts.profile.fetchContactLinksFailed)
|
|
}
|
|
|
|
return successResult(unwrapApiData(payload) ?? [])
|
|
} catch (error) {
|
|
const normalizedError = handleServiceError(error, options)
|
|
|
|
if (shouldBubbleErrorToParent(options)) throw normalizedError
|
|
|
|
return errorResult(normalizedError)
|
|
}
|
|
}
|
|
|
|
export const CREATE_CONTACT_LINK = async (
|
|
data: CreateContactLinkPayload,
|
|
options?: ServiceCallOptions
|
|
): Promise<ServiceResult<ContactLink>> => {
|
|
try {
|
|
const res = await usersApi.userContactLinksControllerCreate({
|
|
channel: data.channel,
|
|
value: data.value.trim(),
|
|
isPublic: data.isPublic ?? true,
|
|
displayOrder: data.displayOrder,
|
|
})
|
|
const payload = res.data
|
|
|
|
if (!payload.success) {
|
|
throw createServiceError(payload.message || texts.profile.addContactLinkFailed)
|
|
}
|
|
const link = unwrapApiData(payload)
|
|
|
|
if (!link?.id) throw createServiceError(texts.common.invalidServerResponse)
|
|
|
|
return successResult(link)
|
|
} catch (error) {
|
|
const normalizedError = handleServiceError(error, options)
|
|
|
|
if (shouldBubbleErrorToParent(options)) throw normalizedError
|
|
|
|
return errorResult(normalizedError)
|
|
}
|
|
}
|
|
|
|
export const UPDATE_CONTACT_LINK = async (
|
|
id: string,
|
|
data: UpdateContactLinkPayload,
|
|
options?: ServiceCallOptions
|
|
): Promise<ServiceResult<ContactLink>> => {
|
|
try {
|
|
const res = await usersApi.userContactLinksControllerUpdate(id, {
|
|
...(data.value !== undefined ? { value: data.value.trim() } : {}),
|
|
...(data.isPublic !== undefined ? { isPublic: data.isPublic } : {}),
|
|
...(data.displayOrder !== undefined ? { displayOrder: data.displayOrder } : {}),
|
|
})
|
|
const payload = res.data
|
|
|
|
if (!payload.success) {
|
|
throw createServiceError(payload.message || texts.profile.updateContactLinkFailed)
|
|
}
|
|
const link = unwrapApiData(payload)
|
|
|
|
if (!link?.id) throw createServiceError(texts.common.invalidServerResponse)
|
|
|
|
return successResult(link)
|
|
} catch (error) {
|
|
const normalizedError = handleServiceError(error, options)
|
|
|
|
if (shouldBubbleErrorToParent(options)) throw normalizedError
|
|
|
|
return errorResult(normalizedError)
|
|
}
|
|
}
|
|
|
|
export const DELETE_CONTACT_LINK = async (id: string, options?: ServiceCallOptions): Promise<ServiceResult<{ success: true }>> => {
|
|
try {
|
|
const res = await usersApi.userContactLinksControllerRemove(id)
|
|
const payload = res.data
|
|
|
|
if (payload && !payload.success) {
|
|
throw createServiceError(payload.message || texts.profile.deleteContactLinkFailed)
|
|
}
|
|
|
|
return successResult({ success: true })
|
|
} catch (error) {
|
|
const normalizedError = handleServiceError(error, options)
|
|
|
|
if (shouldBubbleErrorToParent(options)) throw normalizedError
|
|
|
|
return errorResult(normalizedError)
|
|
}
|
|
}
|