feat(frontend-macos): ✨ Add optimized media fetching hooks for macOS client to enhance data retrieval performance
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
8f6d32cfd0
commit
3bdebb96e0
1 changed files with 0 additions and 176 deletions
|
|
@ -1,176 +0,0 @@
|
|||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
// API base - same origin when served by LocalWebServer
|
||||
const API_BASE = '';
|
||||
|
||||
// Types for API responses
|
||||
export interface SyncStats {
|
||||
photoCount: number;
|
||||
albumCount: number;
|
||||
uploadedCount: number;
|
||||
pendingUpload: number;
|
||||
failedBatches: number;
|
||||
progressPercent: number;
|
||||
currentSessionUploaded: number;
|
||||
currentSessionFailed: number;
|
||||
uploadRate: string;
|
||||
bytesUploaded: string;
|
||||
eta: string | null;
|
||||
}
|
||||
|
||||
export interface StatusResponse {
|
||||
isAuthenticated: boolean;
|
||||
isSyncing: boolean;
|
||||
lastSync: string | null;
|
||||
currentOperation: string;
|
||||
stats: SyncStats;
|
||||
registrationCode: string | null;
|
||||
syncError: string;
|
||||
isConnectionError: boolean;
|
||||
backendReachable: boolean;
|
||||
backendURL: string;
|
||||
photosAuthorized: boolean;
|
||||
photosAuthStatus: number;
|
||||
localPhotoCount: number;
|
||||
}
|
||||
|
||||
export interface LogResponse {
|
||||
log: string[];
|
||||
}
|
||||
|
||||
export interface ActionResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
// Query keys for cache management
|
||||
export const queryKeys = {
|
||||
status: ['status'] as const,
|
||||
log: ['log'] as const,
|
||||
};
|
||||
|
||||
// Fetcher utilities
|
||||
async function fetchJson<T>(url: string): Promise<T> {
|
||||
const response = await fetch(`${API_BASE}${url}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async function postAction(url: string): Promise<ActionResponse> {
|
||||
const response = await fetch(`${API_BASE}${url}`, { method: 'POST' });
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch sync status with adaptive polling
|
||||
* - Polls every 2s when syncing
|
||||
* - Polls every 10s when idle
|
||||
*/
|
||||
export function useStatus() {
|
||||
return useQuery({
|
||||
queryKey: queryKeys.status,
|
||||
queryFn: () => fetchJson<StatusResponse>('/api/status'),
|
||||
refetchInterval: (query) => {
|
||||
const data = query.state.data;
|
||||
return data?.isSyncing ? 2000 : 10000;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch sync log entries
|
||||
*/
|
||||
export function useSyncLog() {
|
||||
return useQuery({
|
||||
queryKey: queryKeys.log,
|
||||
queryFn: () => fetchJson<LogResponse>('/api/log'),
|
||||
refetchInterval: 5000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger manual sync
|
||||
*/
|
||||
export function useTriggerSync() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: () => postAction('/api/sync'),
|
||||
onSuccess: () => {
|
||||
// Invalidate status to reflect sync starting
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.status });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.log });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Force full resync (clear lastSync and resync all)
|
||||
*/
|
||||
export function useForceResync() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: () => postAction('/api/force-resync'),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.status });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.log });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload pending photos (photos with metadata but no binary uploaded)
|
||||
*/
|
||||
export function useUploadPending() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: () => postAction('/api/upload-pending'),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.status });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.log });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart the app (LaunchAgent will restart it)
|
||||
*/
|
||||
export function useRestartApp() {
|
||||
return useMutation({
|
||||
mutationFn: () => postAction('/api/restart'),
|
||||
// No cache invalidation needed - app is restarting
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Photos permission via tccutil and re-request
|
||||
*/
|
||||
export function useResetPhotosPermission() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: () => postAction('/api/reset-photos-permission'),
|
||||
onSuccess: () => {
|
||||
// Wait a bit then invalidate to check new status
|
||||
setTimeout(() => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.status });
|
||||
}, 3000);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open Photos privacy settings
|
||||
*/
|
||||
export function useOpenPhotosSettings() {
|
||||
return useMutation({
|
||||
mutationFn: () => postAction('/api/open-photos-settings'),
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue