mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-03 18:22:57 +00:00
138 lines
3.5 KiB
TypeScript
138 lines
3.5 KiB
TypeScript
import api from './api';
|
|
|
|
// Use shared API_URL which already resolves to '/api/v1' under current origin
|
|
|
|
export interface FileInfo {
|
|
id: number;
|
|
filename: string;
|
|
file_path: string;
|
|
file_url: string;
|
|
url: string;
|
|
file_size: number;
|
|
size: number;
|
|
mime_type: string;
|
|
uploaded_by?: {
|
|
id: number;
|
|
email: string;
|
|
first_name: string;
|
|
last_name: string;
|
|
};
|
|
created_at: string;
|
|
usages?: FileUsage[];
|
|
usage_count: number;
|
|
md5_hash?: string;
|
|
}
|
|
|
|
export interface FileUsage {
|
|
id: number;
|
|
file_id: number;
|
|
entity_type: string;
|
|
entity_id: number;
|
|
field_name: string;
|
|
entity_info?: {
|
|
type: string;
|
|
id: number;
|
|
title?: string;
|
|
name?: string;
|
|
slug?: string;
|
|
url?: string;
|
|
position?: string;
|
|
};
|
|
}
|
|
|
|
export interface DuplicateFiles {
|
|
[hash: string]: FileInfo[];
|
|
}
|
|
|
|
export interface StorageUsage {
|
|
used_bytes: number;
|
|
used_count: number;
|
|
quota_mb: number;
|
|
quota_bytes: number;
|
|
percent: number;
|
|
warn_percent: number;
|
|
critical_percent: number;
|
|
status: 'ok' | 'warn' | 'critical';
|
|
}
|
|
|
|
export const getAllFiles = async (params?: {
|
|
search?: string;
|
|
mime_type?: string;
|
|
sort_by?: string;
|
|
sort_order?: string;
|
|
}): Promise<FileInfo[]> => {
|
|
const response = await api.get(`/admin/files`, { params });
|
|
return response.data;
|
|
};
|
|
|
|
export const getUnusedFiles = async (): Promise<FileInfo[]> => {
|
|
const response = await api.get(`/admin/files/unused`);
|
|
return response.data;
|
|
};
|
|
|
|
export const getDuplicateFiles = async (): Promise<DuplicateFiles> => {
|
|
const response = await api.get(`/admin/files/duplicates`);
|
|
return response.data;
|
|
};
|
|
|
|
export const getStorageUsage = async (): Promise<StorageUsage> => {
|
|
const response = await api.get(`/admin/files/usage`);
|
|
return response.data;
|
|
};
|
|
|
|
export const getFileUsages = async (fileId: number): Promise<any[]> => {
|
|
const response = await api.get(`/admin/files/${fileId}/usages`);
|
|
return response.data;
|
|
};
|
|
|
|
export const deleteFile = async (fileId: number, force: boolean = false): Promise<void> => {
|
|
await api.delete(`/admin/files/${fileId}`, { params: { force } });
|
|
};
|
|
|
|
export const scanAndSyncFiles = async (): Promise<{
|
|
message: string;
|
|
found_files: number;
|
|
new_files: number;
|
|
orphaned_files: number;
|
|
skipped_files?: number;
|
|
new_files_list?: string[];
|
|
orphaned_list?: string[];
|
|
}> => {
|
|
const response = await api.post(`/admin/files/scan`, {});
|
|
return response.data;
|
|
};
|
|
|
|
export const refreshFileTracking = async (entityType?: string): Promise<{
|
|
message: string;
|
|
stats: {
|
|
articles_scanned: number;
|
|
events_scanned: number;
|
|
players_scanned: number;
|
|
sponsors_scanned: number;
|
|
contacts_scanned: number;
|
|
teams_scanned: number;
|
|
settings_scanned: number;
|
|
};
|
|
}> => {
|
|
const response = await api.post(`/admin/files/refresh-tracking`, {}, { params: entityType ? { entity_type: entityType } : {} });
|
|
return response.data;
|
|
};
|
|
|
|
export const formatFileSize = (bytes: number): string => {
|
|
if (bytes === 0) return '0 B';
|
|
const k = 1024;
|
|
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
|
|
};
|
|
|
|
import { IconType } from 'react-icons';
|
|
import { FiImage, FiFileText, FiVideo, FiFile } from 'react-icons/fi';
|
|
|
|
export const getFileIcon = (mimeType: string): IconType => {
|
|
if (mimeType.startsWith('image/')) return FiImage;
|
|
if (mimeType === 'application/pdf') return FiFileText;
|
|
if (mimeType.startsWith('video/')) return FiVideo;
|
|
return FiFile;
|
|
};
|