151 lines
5.4 KiB
TypeScript
151 lines
5.4 KiB
TypeScript
import client from './client'
|
|
import type { AssignmentDetail, Dispute, DisputeComment, ReturnedAssignment, BonusAssignment } from '@/types'
|
|
|
|
export interface BonusCompleteResult {
|
|
bonus_assignment_id: number
|
|
points_earned: number
|
|
total_bonus_points: number
|
|
}
|
|
|
|
export const assignmentsApi = {
|
|
// Get detailed assignment info with proofs and dispute
|
|
getDetail: async (assignmentId: number): Promise<AssignmentDetail> => {
|
|
const response = await client.get<AssignmentDetail>(`/assignments/${assignmentId}`)
|
|
return response.data
|
|
},
|
|
|
|
// Create a dispute against an assignment
|
|
createDispute: async (assignmentId: number, reason: string): Promise<Dispute> => {
|
|
const response = await client.post<Dispute>(`/assignments/${assignmentId}/dispute`, { reason })
|
|
return response.data
|
|
},
|
|
|
|
// Create a dispute against a bonus assignment
|
|
createBonusDispute: async (bonusId: number, reason: string): Promise<Dispute> => {
|
|
const response = await client.post<Dispute>(`/bonus-assignments/${bonusId}/dispute`, { reason })
|
|
return response.data
|
|
},
|
|
|
|
// Add a comment to a dispute
|
|
addComment: async (disputeId: number, text: string): Promise<DisputeComment> => {
|
|
const response = await client.post<DisputeComment>(`/disputes/${disputeId}/comments`, { text })
|
|
return response.data
|
|
},
|
|
|
|
// Vote on a dispute (true = valid/proof is OK, false = invalid/proof is not OK)
|
|
vote: async (disputeId: number, vote: boolean): Promise<{ message: string }> => {
|
|
const response = await client.post<{ message: string }>(`/disputes/${disputeId}/vote`, { vote })
|
|
return response.data
|
|
},
|
|
|
|
// Get current user's returned assignments
|
|
getReturnedAssignments: async (marathonId: number): Promise<ReturnedAssignment[]> => {
|
|
const response = await client.get<ReturnedAssignment[]>(`/marathons/${marathonId}/returned-assignments`)
|
|
return response.data
|
|
},
|
|
|
|
// Get proof media as blob URL (supports both images and videos)
|
|
getProofMediaUrl: async (assignmentId: number): Promise<{ url: string; type: 'image' | 'video' }> => {
|
|
const response = await client.get(`/assignments/${assignmentId}/proof-media`, {
|
|
responseType: 'blob',
|
|
})
|
|
const contentType = response.headers['content-type'] || ''
|
|
const isVideo = contentType.startsWith('video/')
|
|
return {
|
|
url: URL.createObjectURL(response.data),
|
|
type: isVideo ? 'video' : 'image',
|
|
}
|
|
},
|
|
|
|
// Get bonus assignments for a playthrough assignment
|
|
getBonusAssignments: async (assignmentId: number): Promise<BonusAssignment[]> => {
|
|
const response = await client.get<BonusAssignment[]>(`/assignments/${assignmentId}/bonus`)
|
|
return response.data
|
|
},
|
|
|
|
// Complete a bonus challenge
|
|
completeBonusAssignment: async (
|
|
assignmentId: number,
|
|
bonusId: number,
|
|
data: { proof_file?: File; proof_files?: File[]; proof_url?: string; comment?: string }
|
|
): Promise<BonusCompleteResult> => {
|
|
const formData = new FormData()
|
|
|
|
// Support both single file (legacy) and multiple files
|
|
if (data.proof_file) {
|
|
formData.append('proof_file', data.proof_file)
|
|
}
|
|
if (data.proof_files && data.proof_files.length > 0) {
|
|
data.proof_files.forEach(file => {
|
|
formData.append('proof_files', file)
|
|
})
|
|
}
|
|
|
|
if (data.proof_url) {
|
|
formData.append('proof_url', data.proof_url)
|
|
}
|
|
if (data.comment) {
|
|
formData.append('comment', data.comment)
|
|
}
|
|
|
|
const response = await client.post<BonusCompleteResult>(
|
|
`/assignments/${assignmentId}/bonus/${bonusId}/complete`,
|
|
formData,
|
|
{ headers: { 'Content-Type': 'multipart/form-data' } }
|
|
)
|
|
return response.data
|
|
},
|
|
|
|
// Get bonus proof media as blob URL (supports both images and videos)
|
|
getBonusProofMediaUrl: async (
|
|
assignmentId: number,
|
|
bonusId: number
|
|
): Promise<{ url: string; type: 'image' | 'video' }> => {
|
|
const response = await client.get(
|
|
`/assignments/${assignmentId}/bonus/${bonusId}/proof-media`,
|
|
{ responseType: 'blob' }
|
|
)
|
|
const contentType = response.headers['content-type'] || ''
|
|
const isVideo = contentType.startsWith('video/')
|
|
return {
|
|
url: URL.createObjectURL(response.data),
|
|
type: isVideo ? 'video' : 'image',
|
|
}
|
|
},
|
|
|
|
// Get individual proof file media as blob URL (for multiple proofs support)
|
|
getProofFileMediaUrl: async (
|
|
assignmentId: number,
|
|
proofFileId: number
|
|
): Promise<{ url: string; type: 'image' | 'video' }> => {
|
|
const response = await client.get(
|
|
`/assignments/${assignmentId}/proof-files/${proofFileId}/media`,
|
|
{ responseType: 'blob' }
|
|
)
|
|
const contentType = response.headers['content-type'] || ''
|
|
const isVideo = contentType.startsWith('video/')
|
|
return {
|
|
url: URL.createObjectURL(response.data),
|
|
type: isVideo ? 'video' : 'image',
|
|
}
|
|
},
|
|
|
|
// Get individual bonus proof file media as blob URL (for multiple proofs support)
|
|
getBonusProofFileMediaUrl: async (
|
|
assignmentId: number,
|
|
bonusId: number,
|
|
proofFileId: number
|
|
): Promise<{ url: string; type: 'image' | 'video' }> => {
|
|
const response = await client.get(
|
|
`/assignments/${assignmentId}/bonus/${bonusId}/proof-files/${proofFileId}/media`,
|
|
{ responseType: 'blob' }
|
|
)
|
|
const contentType = response.headers['content-type'] || ''
|
|
const isVideo = contentType.startsWith('video/')
|
|
return {
|
|
url: URL.createObjectURL(response.data),
|
|
type: isVideo ? 'video' : 'image',
|
|
}
|
|
},
|
|
}
|