Files
erahn-v2-fe/src/modules/activity/services/activity.service.ts
T

338 lines
8.5 KiB
TypeScript

import { api } from '@/core/services/api'
import type { PaginatedApiResponse } from '@/core/types/api'
import type {
ActivityDetail,
ActivityListItem,
ActivityReport,
ActivityType,
CreateActivityReportPayload,
CreateActivityPayload,
CreateActivityTypePayload,
ListActivitiesParams,
UpdateActivityFiles,
UpdateActivityPayload,
UpdateActivityReportPayload,
} from '../types/activity.types'
type ActivityApiResponse = {
success: boolean
data: ActivityDetail
message?: string
}
type ActivityReportApiResponse = {
success: boolean
data: ActivityReport
message?: string
}
function appendIfPresent(formData: FormData, key: string, value: string | null | undefined) {
if (value !== null && value !== undefined && value !== '') {
formData.append(key, value)
}
}
export function buildActivityFormData(
payload: UpdateActivityPayload,
files: UpdateActivityFiles = {},
options: { method?: 'PUT' } = {},
): FormData {
const formData = new FormData()
formData.append('activity_type_id', payload.activity_type_id)
formData.append('title', payload.title)
formData.append('is_active', payload.is_active ? '1' : '0')
appendIfPresent(formData, 'reference_number', payload.reference_number ?? undefined)
appendIfPresent(formData, 'description', payload.description ?? undefined)
appendIfPresent(formData, 'start_datetime', payload.start_datetime ?? undefined)
appendIfPresent(formData, 'end_datetime', payload.end_datetime ?? undefined)
appendIfPresent(formData, 'organizer', payload.organizer ?? undefined)
appendIfPresent(formData, 'location', payload.location ?? undefined)
files.documents?.forEach((file, index) => {
formData.append(`documents[${index}]`, file)
})
files.gallery?.forEach((file, index) => {
formData.append(`gallery[${index}]`, file)
})
if (options.method === 'PUT') {
formData.append('_method', 'PUT')
}
return formData
}
export async function listActivities(
params: ListActivitiesParams,
): Promise<PaginatedApiResponse<ActivityListItem>> {
const { data } = await api.get<PaginatedApiResponse<ActivityListItem>>('/v1/activities', {
params,
})
if (!data.success) {
throw new Error(data.message ?? 'Gagal memuatkan senarai aktiviti.')
}
return data
}
export async function listActivityTypes(): Promise<ActivityType[]> {
const { data } = await api.get<PaginatedApiResponse<ActivityType>>('/v1/activity-types', {
params: { per_page: 1000 },
})
if (!data.success) {
throw new Error(data.message ?? 'Gagal memuatkan jenis aktiviti.')
}
return data.data
}
type ActivityTypeApiResponse = {
success: boolean
data: ActivityType
message?: string
}
export async function createActivityType(
payload: CreateActivityTypePayload,
): Promise<ActivityType> {
const { data } = await api.post<ActivityTypeApiResponse>('/v1/activity-types', payload)
if (!data.success) {
throw new Error(data.message ?? 'Gagal menambah jenis aktiviti.')
}
return data.data
}
export async function getActivity(id: string): Promise<ActivityDetail> {
const { data } = await api.get<ActivityApiResponse>(`/v1/activities/${id}`)
if (!data.success) {
throw new Error(data.message ?? 'Gagal memuatkan butiran aktiviti.')
}
return data.data
}
export async function updateActivity(
id: string,
payload: UpdateActivityPayload,
files: UpdateActivityFiles = {},
): Promise<ActivityDetail> {
const formData = buildActivityFormData(payload, files, { method: 'PUT' })
const { data } = await api.post<ActivityApiResponse>(`/v1/activities/${id}`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
if (!data.success) {
throw new Error(data.message ?? 'Gagal mengemaskini aktiviti.')
}
return data.data
}
export async function createActivity(
payload: CreateActivityPayload,
files: UpdateActivityFiles = {},
): Promise<ActivityDetail> {
const formData = buildActivityFormData(payload, files)
const { data } = await api.post<ActivityApiResponse>('/v1/activities', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
if (!data.success) {
throw new Error(data.message ?? 'Gagal mendaftar aktiviti.')
}
return data.data
}
export async function uploadActivityGalleryImage(
activityId: string,
file: File,
): Promise<ActivityDetail> {
const formData = new FormData()
formData.append('file', file)
const { data } = await api.post<ActivityApiResponse>(
`/v1/activities/${activityId}/gallery`,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
},
)
if (!data.success) {
throw new Error(data.message ?? 'Gagal memuat naik imej galeri.')
}
return data.data
}
export async function uploadActivityDocument(
activityId: string,
file: File,
): Promise<ActivityDetail> {
const formData = new FormData()
formData.append('file', file)
const { data } = await api.post<ActivityApiResponse>(
`/v1/activities/${activityId}/documents`,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
},
)
if (!data.success) {
throw new Error(data.message ?? 'Gagal memuat naik dokumen.')
}
return data.data
}
export async function deleteActivityGalleryImage(
activityId: string,
imageId: string,
): Promise<ActivityDetail> {
const { data } = await api.delete<ActivityApiResponse>(
`/v1/activities/${activityId}/gallery/${imageId}`,
)
if (!data.success) {
throw new Error(data.message ?? 'Gagal memadam imej galeri.')
}
return data.data
}
export async function deleteActivityDocument(
activityId: string,
documentId: string,
): Promise<ActivityDetail> {
const { data } = await api.delete<ActivityApiResponse>(
`/v1/activities/${activityId}/documents/${documentId}`,
)
if (!data.success) {
throw new Error(data.message ?? 'Gagal memadam dokumen.')
}
return data.data
}
export async function fetchActivityGalleryImage(
activityId: string,
imageId: string,
mimeType?: string | null,
): Promise<Blob> {
const response = await api.get(`/v1/activities/${activityId}/gallery/${imageId}`, {
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 })
}
export async function fetchActivityDocument(
activityId: string,
documentId: string,
mimeType?: string | null,
): Promise<Blob> {
const response = await api.get(
`/v1/activities/${activityId}/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 })
}
export async function downloadActivityDocument(
activityId: string,
documentId: string,
fileName: string,
mimeType?: string | null,
): Promise<void> {
const blob = await fetchActivityDocument(activityId, documentId, mimeType)
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = fileName
link.click()
window.URL.revokeObjectURL(url)
}
export async function createActivityReport(
payload: CreateActivityReportPayload,
): Promise<ActivityReport> {
const { data } = await api.post<ActivityReportApiResponse>('/v1/activity-reports', payload)
if (!data.success) {
throw new Error(data.message ?? 'Gagal menambah laporan aktiviti.')
}
return data.data
}
export async function updateActivityReport(
id: string,
payload: UpdateActivityReportPayload,
): Promise<ActivityReport> {
const { data } = await api.put<ActivityReportApiResponse>(`/v1/activity-reports/${id}`, payload)
if (!data.success) {
throw new Error(data.message ?? 'Gagal mengemaskini laporan aktiviti.')
}
return data.data
}
type ActivityDeleteResponse = {
success: boolean
message?: string
}
export async function deleteActivity(id: string): Promise<void> {
const { data } = await api.delete<ActivityDeleteResponse>(`/v1/activities/${id}`)
if (!data.success) {
throw new Error(data.message ?? 'Gagal memadam aktiviti.')
}
}
type ActivityReportDeleteResponse = {
success: boolean
message?: string
}
export async function deleteActivityReport(id: string): Promise<void> {
const { data } = await api.delete<ActivityReportDeleteResponse>(`/v1/activity-reports/${id}`)
if (!data.success) {
throw new Error(data.message ?? 'Gagal memadam laporan aktiviti.')
}
}