import type { CreateUserReportDto, ReportReasonResponseDto, UserReportResponseDto } from '@/api/generated/models' import { createServiceError, errorResult, handleServiceError, type ServiceCallOptions, type ServiceResult, shouldBubbleErrorToParent, successResult, } from '@/services/errorHandler' import { unwrapApiData } from '@/services/apiResponse' import { getUserReports } from '@/api/generated/user-reports/user-reports' import { texts } from '@/texts' // docs/workflows/fa/user-blocking-reporting.md, Flow B — purely // informational: creating a report never blocks, hides, or notifies // anyone by itself. It only creates a `pending` row an admin reviews later. export type ReportReason = ReportReasonResponseDto export type UserReport = UserReportResponseDto const userReportsApi = getUserReports() /** * Public, unauthenticated — safe to fetch ahead of time (e.g. when the * report menu item is rendered) so the reason list is ready by the time * the user opens the report form. */ export const LIST_REPORT_REASONS = async (options?: ServiceCallOptions): Promise> => { try { const res = await userReportsApi.userReportsControllerListReportReasons() const payload = res.data if (!payload.success) { throw createServiceError(payload.message || texts.chats.listReportReasonsFailed) } return successResult(unwrapApiData(payload) ?? []) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) { throw normalizedError } return errorResult(normalizedError) } } /** * At least one of `reasonId` / `description` is required — mirrors the * backend's `CreateUserReportDto` cross-field rule * (`user_reports_content_chk`). */ export const REPORT_USER = async ( reportedId: string, payload: { reasonId?: number; description?: string }, options?: ServiceCallOptions ): Promise> => { try { const res = await userReportsApi.userReportsControllerCreate({ reportedId, ...payload, }) const responsePayload = res.data if (!responsePayload.success) { throw createServiceError(responsePayload.message || texts.chats.submitReportFailed, responsePayload.code) } const report = unwrapApiData(responsePayload) if (!report?.id) { throw createServiceError(texts.common.invalidServerResponse) } return successResult(report) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) { throw normalizedError } return errorResult(normalizedError) } } /** * Reports one specific chat message. The server derives and persists the * conversation, sender, and immutable message snapshot; the client cannot * forge those moderation fields. */ export const REPORT_MESSAGE = async ( reportedId: string, messageId: string, payload: { reasonId?: number; description?: string }, options?: ServiceCallOptions ): Promise> => { try { const request: CreateUserReportDto = { reportedId, messageId, ...payload, } const res = await userReportsApi.userReportsControllerCreate(request) const responsePayload = res.data if (!responsePayload.success) { throw createServiceError(responsePayload.message || texts.chats.submitReportFailed, responsePayload.code) } const report = unwrapApiData(responsePayload) if (!report?.id) { throw createServiceError(texts.common.invalidServerResponse) } return successResult(report) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) { throw normalizedError } return errorResult(normalizedError) } }