91 lines
2.2 KiB
TypeScript
91 lines
2.2 KiB
TypeScript
import { ApiResponse } from '@goodgo/types';
|
|
|
|
import { apiClient } from './client';
|
|
|
|
/**
|
|
* EN: Raw upload response from storage service.
|
|
* VI: Response upload thô từ storage service.
|
|
*/
|
|
interface UploadFileResult {
|
|
success: boolean;
|
|
fileId?: string;
|
|
objectKey?: string;
|
|
error?: string;
|
|
}
|
|
|
|
/**
|
|
* EN: CDN URL response payload.
|
|
* VI: Payload response URL CDN.
|
|
*/
|
|
interface CdnUrlResult {
|
|
url: string;
|
|
isCDN: boolean;
|
|
description: string;
|
|
}
|
|
|
|
/**
|
|
* EN: Normalized avatar upload response.
|
|
* VI: Response upload avatar đã chuẩn hóa.
|
|
*/
|
|
export interface UploadAvatarResult {
|
|
fileId: string;
|
|
objectKey?: string;
|
|
url: string;
|
|
}
|
|
|
|
/**
|
|
* EN: Storage API for avatar upload flow.
|
|
* VI: Storage API cho luồng upload avatar.
|
|
*/
|
|
export const storageApi = {
|
|
/**
|
|
* EN: Upload avatar as a public file and resolve CDN/fallback URL.
|
|
* VI: Upload avatar ở chế độ public và lấy URL CDN/fallback.
|
|
*/
|
|
uploadAvatar: async (file: File): Promise<ApiResponse<UploadAvatarResult>> => {
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
const uploadResponse = await apiClient.post<UploadFileResult>(
|
|
'/files/upload?accessLevel=public',
|
|
formData,
|
|
{
|
|
headers: {
|
|
'Content-Type': 'multipart/form-data',
|
|
},
|
|
}
|
|
);
|
|
|
|
const uploadedFileId = uploadResponse.data?.fileId;
|
|
if (!uploadResponse.success || !uploadResponse.data?.success || !uploadedFileId) {
|
|
throw new Error(
|
|
uploadResponse.data?.error ||
|
|
uploadResponse.error?.message ||
|
|
'Failed to upload avatar'
|
|
);
|
|
}
|
|
|
|
let resolvedUrl = '';
|
|
try {
|
|
const cdnUrlResponse = await apiClient.get<CdnUrlResult>(
|
|
`/files/${uploadedFileId}/cdn-url`
|
|
);
|
|
resolvedUrl = cdnUrlResponse.data?.url ?? '';
|
|
} catch {
|
|
// EN: Fallback keeps profile update possible even if CDN URL fetch fails.
|
|
// VI: Fallback vẫn cho phép cập nhật profile nếu lấy CDN URL thất bại.
|
|
resolvedUrl = '';
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
fileId: uploadedFileId,
|
|
objectKey: uploadResponse.data.objectKey,
|
|
url: resolvedUrl,
|
|
},
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
},
|
|
};
|