Files
erahn-v2-fe/src/modules/feedback/services/feedback.service.ts
T
ismailmasseran c88709a32b Feature/phone register (#11)
Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local>
Co-authored-by: ISMAIL MASSERAN <topaz@Mac.dlinkrouter.local>
Reviewed-on: KoPKB/My-KOPKB#11
2026-07-14 12:03:22 +08:00

171 lines
4.8 KiB
TypeScript

import { api } from '@/core/services/api'
import type { PaginatedApiResponse } from '@/core/types/api'
import type {
Feedback,
FeedbackApiResponse,
FeedbackListItem,
FeedbackStatistics,
ListFeedbackParams,
SubmitFeedbackPayload,
UpdateFeedbackPayload,
} from '../types/feedback.types'
function appendIfPresent(formData: FormData, key: string, value: string | undefined | null) {
if (value !== null && value !== undefined && value !== '') {
formData.append(key, value)
}
}
export function buildFeedbackFormData(payload: SubmitFeedbackPayload): FormData {
const formData = new FormData()
formData.append('type', payload.type)
formData.append('title', payload.title)
formData.append('description', payload.description)
formData.append('priority', payload.priority)
appendIfPresent(formData, 'page_url', payload.page_url)
appendIfPresent(formData, 'steps_to_reproduce', payload.steps_to_reproduce)
appendIfPresent(formData, 'expected_behavior', payload.expected_behavior)
appendIfPresent(formData, 'actual_behavior', payload.actual_behavior)
appendIfPresent(formData, 'additional_notes', payload.additional_notes)
appendIfPresent(formData, 'screen_resolution', payload.screen_resolution)
appendIfPresent(formData, 'viewport_size', payload.viewport_size)
appendIfPresent(formData, 'timezone', payload.timezone)
payload.images?.forEach((file, index) => {
formData.append(`images[${index}]`, file)
})
payload.videos?.forEach((file, index) => {
formData.append(`videos[${index}]`, file)
})
return formData
}
/** Public + authenticated: POST /v1/feedback (auth cookie attaches user when present). */
export async function submitFeedback(payload: SubmitFeedbackPayload): Promise<FeedbackApiResponse> {
const formData = buildFeedbackFormData(payload)
const { data } = await api.post<FeedbackApiResponse>('/v1/feedback', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
if (!data.success) {
throw new Error(data.message ?? 'Gagal menghantar maklum balas.')
}
return data
}
export async function listFeedback(
params: ListFeedbackParams = {},
): Promise<PaginatedApiResponse<FeedbackListItem>> {
const { data } = await api.get<PaginatedApiResponse<FeedbackListItem>>('/v1/feedback', {
params,
})
if (!data.success) {
throw new Error(data.message ?? 'Gagal memuatkan senarai maklum balas.')
}
return data
}
export async function getFeedback(id: string): Promise<Feedback> {
const { data } = await api.get<FeedbackApiResponse>(`/v1/feedback/${id}`)
if (!data.success) {
throw new Error(data.message ?? 'Gagal memuatkan maklum balas.')
}
return data.data
}
export async function updateFeedback(
id: string,
payload: UpdateFeedbackPayload,
): Promise<FeedbackApiResponse> {
const { data } = await api.patch<FeedbackApiResponse>(`/v1/feedback/${id}`, payload)
if (!data.success) {
throw new Error(data.message ?? 'Gagal mengemas kini maklum balas.')
}
return data
}
export async function deleteFeedback(id: string): Promise<void> {
const { data } = await api.delete<{ success: boolean; message?: string }>(`/v1/feedback/${id}`)
if (!data.success) {
throw new Error(data.message ?? 'Gagal memadam maklum balas.')
}
}
export async function getMyFeedback(
params: ListFeedbackParams = {},
): Promise<PaginatedApiResponse<FeedbackListItem>> {
const { data } = await api.get<{
success: boolean
data: FeedbackListItem[]
meta: {
current_page: number
last_page: number
per_page: number
total: number
}
message?: string
}>('/v1/my-feedback', { params })
if (!data.success) {
throw new Error(data.message ?? 'Gagal memuatkan maklum balas anda.')
}
return {
success: true,
data: data.data,
pagination: {
current_page: data.meta.current_page,
per_page: data.meta.per_page,
total: data.meta.total,
last_page: data.meta.last_page,
from: null,
to: null,
has_more_pages: data.meta.current_page < data.meta.last_page,
},
}
}
export async function getFeedbackStatistics(): Promise<FeedbackStatistics> {
const { data } = await api.get<{ success: boolean; data: FeedbackStatistics; message?: string }>(
'/v1/feedback-statistics',
)
if (!data.success) {
throw new Error(data.message ?? 'Gagal memuatkan statistik maklum balas.')
}
return data.data
}
export async function fetchFeedbackDocument(
feedbackId: string,
documentId: string,
mimeType?: string | null,
): Promise<Blob> {
const response = await api.get(`/v1/feedback/${feedbackId}/documents/${documentId}/download`, {
responseType: 'blob',
})
const contentType =
mimeType ||
(typeof response.headers['content-type'] === 'string' ? response.headers['content-type'] : null) ||
'application/octet-stream'
return new Blob([response.data], { type: contentType })
}