refactor: Decouple frontend API calls from a shared client instance
This commit is contained in:
@@ -2,7 +2,7 @@ import { useCallback, useRef, useState } from 'react';
|
||||
import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
||||
import useFileDrop from './useFileDrop';
|
||||
import { DEFAULT_FOLDER_NAME, hasFiles } from '../../app/workspaceUtils';
|
||||
import { fetchDocument } from '../../lib/apiClient';
|
||||
import { fetchDocument, uploadDocument, resolveFolderPath } from '../../lib/apiClient';
|
||||
import type { Identifier } from '../../types/identifiers';
|
||||
|
||||
type FolderId = Identifier | 'root' | null;
|
||||
@@ -26,17 +26,6 @@ type UploadQueueItem = {
|
||||
conflictDocumentId: Identifier | null;
|
||||
};
|
||||
|
||||
interface UploadResponse {
|
||||
reused?: boolean;
|
||||
document?: unknown;
|
||||
folder?: { id?: FolderId };
|
||||
}
|
||||
|
||||
interface ApiClient {
|
||||
post<T = UploadResponse>(url: string, payload: unknown): Promise<{ data: T; status?: number }>;
|
||||
get<T = { document?: unknown }>(url: string): Promise<{ data: T }>;
|
||||
}
|
||||
|
||||
type StatusLevel = 'success' | 'info' | 'warning' | 'error' | string;
|
||||
type NotifyApiError = (error: unknown, fallbackMessage?: string) => void;
|
||||
type SetStatusMessage = (message: string, level?: StatusLevel) => void;
|
||||
@@ -59,7 +48,7 @@ interface FileSystemDirectoryReaderLike {
|
||||
) => void;
|
||||
}
|
||||
|
||||
interface FileSystemFileEntryLike {
|
||||
interface FileSystemFileEntryLike extends FileSystemEntry {
|
||||
isFile: true;
|
||||
isDirectory: false;
|
||||
name: string;
|
||||
@@ -69,12 +58,19 @@ interface FileSystemFileEntryLike {
|
||||
) => void;
|
||||
}
|
||||
|
||||
interface FileSystemDirectoryEntryLike {
|
||||
interface FileSystemDirectoryEntryLike extends FileSystemEntry {
|
||||
isFile: false;
|
||||
isDirectory: true;
|
||||
name: string;
|
||||
createReader: () => FileSystemDirectoryReaderLike;
|
||||
}
|
||||
const isFileEntry = (entry: FileSystemEntryLike): entry is FileSystemFileEntryLike => {
|
||||
return entry.isFile && !entry.isDirectory;
|
||||
};
|
||||
|
||||
const isDirectoryEntry = (entry: FileSystemEntryLike): entry is FileSystemDirectoryEntryLike => {
|
||||
return entry.isDirectory && !entry.isFile && 'createReader' in entry;
|
||||
};
|
||||
|
||||
const mapFilesToEntries = (filesInput?: FileList | File[] | null): FileEntry[] => {
|
||||
if (!filesInput) {
|
||||
@@ -96,7 +92,6 @@ const mapFilesToEntries = (filesInput?: FileList | File[] | null): FileEntry[] =
|
||||
};
|
||||
|
||||
interface UseDocumentUploadsArgs {
|
||||
apiClient: ApiClient;
|
||||
token?: string | null;
|
||||
selectedFolder?: FolderId;
|
||||
currentFolderName?: string | null;
|
||||
@@ -126,7 +121,6 @@ interface UseDocumentUploadsResult {
|
||||
}
|
||||
|
||||
const useDocumentUploads = ({
|
||||
apiClient,
|
||||
token,
|
||||
selectedFolder,
|
||||
currentFolderName,
|
||||
@@ -158,11 +152,10 @@ const useDocumentUploads = ({
|
||||
}
|
||||
|
||||
try {
|
||||
const { data, status } = await apiClient.post('/documents', formData);
|
||||
const duplicate = data?.reused || status === 200;
|
||||
const document = data?.document ?? data ?? null;
|
||||
const { reused, document, status } = await uploadDocument(formData);
|
||||
const duplicate = reused || status === 200;
|
||||
return {
|
||||
document,
|
||||
document: document ?? null,
|
||||
duplicate,
|
||||
statusCode: status ?? (duplicate ? 200 : 201),
|
||||
conflictDocumentId: null,
|
||||
@@ -192,7 +185,7 @@ const useDocumentUploads = ({
|
||||
throw wrapped;
|
||||
}
|
||||
},
|
||||
[apiClient, notifyApiError, setStatusMessage],
|
||||
[notifyApiError, setStatusMessage],
|
||||
);
|
||||
|
||||
const appendQueueItems = useCallback((entries: FileEntry[], targetFolderId?: FolderId) => {
|
||||
@@ -244,15 +237,12 @@ const useDocumentUploads = ({
|
||||
segments: trimmedSegments,
|
||||
};
|
||||
|
||||
const { data } = await apiClient.post<{ folder?: { id?: FolderId | null } }>(
|
||||
'/folders/path',
|
||||
payload,
|
||||
);
|
||||
const resolvedId = (data?.folder?.id ?? null) as FolderId;
|
||||
const { folder } = await resolveFolderPath(payload);
|
||||
const resolvedId = (folder?.id ?? null) as FolderId;
|
||||
cache.set(cacheKey, resolvedId);
|
||||
return resolvedId;
|
||||
},
|
||||
[apiClient],
|
||||
[],
|
||||
);
|
||||
|
||||
const extractFilesFromDataTransfer = useCallback(async (dataTransfer: DataTransfer) => {
|
||||
@@ -294,10 +284,10 @@ const useDocumentUploads = ({
|
||||
|
||||
const walkEntry = async (entry: FileSystemEntryLike | null, ancestors: string[] = []) => {
|
||||
if (!entry) return;
|
||||
if (entry.isFile) {
|
||||
if (isFileEntry(entry)) {
|
||||
const file = await new Promise<File>((resolve, reject) => {
|
||||
try {
|
||||
(entry as unknown as FileSystemFileEntryLike).file(resolve, reject);
|
||||
entry.file(resolve, reject);
|
||||
} catch (error) {
|
||||
console.warn('[Uploads] entry.file failed', error);
|
||||
reject(error as Error);
|
||||
@@ -306,9 +296,9 @@ const useDocumentUploads = ({
|
||||
pushFile(file, ancestors);
|
||||
return;
|
||||
}
|
||||
if (entry.isDirectory) {
|
||||
if (isDirectoryEntry(entry)) {
|
||||
const nextAncestors = entry.name ? [...ancestors, entry.name] : [...ancestors];
|
||||
const reader = (entry as unknown as FileSystemDirectoryEntryLike).createReader();
|
||||
const reader = entry.createReader();
|
||||
const entries = await readAllEntries(reader);
|
||||
for (const child of entries) {
|
||||
await walkEntry(child, nextAncestors);
|
||||
|
||||
Reference in New Issue
Block a user