60 lines
1.7 KiB
TypeScript
60 lines
1.7 KiB
TypeScript
import { apiFetch } from '@/lib/api';
|
|
|
|
export type PresignedUploadResponse = {
|
|
key: string;
|
|
url: string;
|
|
expires_at: string;
|
|
};
|
|
|
|
export async function getPresignedUploadUrl(
|
|
filename: string,
|
|
mimeType: string,
|
|
): Promise<PresignedUploadResponse> {
|
|
return apiFetch<PresignedUploadResponse>('/admin/media/presign', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ filename, mime_type: mimeType }),
|
|
});
|
|
}
|
|
|
|
export async function uploadFileToS3(
|
|
presignedUrl: string,
|
|
file: File,
|
|
onProgress?: (percent: number) => void,
|
|
): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
const xhr = new XMLHttpRequest();
|
|
|
|
xhr.upload.addEventListener('progress', (event) => {
|
|
if (event.lengthComputable && onProgress) {
|
|
onProgress(Math.round((event.loaded / event.total) * 100));
|
|
}
|
|
});
|
|
|
|
xhr.addEventListener('load', () => {
|
|
if (xhr.status >= 200 && xhr.status < 300) {
|
|
resolve();
|
|
} else {
|
|
reject(new Error(`Upload gagal (HTTP ${xhr.status})`));
|
|
}
|
|
});
|
|
|
|
xhr.addEventListener('error', () => reject(new Error('Upload gagal. Periksa koneksi internet Anda.')));
|
|
xhr.addEventListener('abort', () => reject(new Error('Upload dibatalkan.')));
|
|
|
|
xhr.open('PUT', presignedUrl);
|
|
xhr.setRequestHeader('Content-Type', file.type);
|
|
xhr.send(file);
|
|
});
|
|
}
|
|
|
|
export async function uploadFileAndGetKey(
|
|
file: File,
|
|
onProgress?: (percent: number) => void,
|
|
): Promise<string> {
|
|
const { key, url } = await getPresignedUploadUrl(file.name, file.type);
|
|
|
|
await uploadFileToS3(url, file, onProgress);
|
|
|
|
return key;
|
|
}
|