mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-23 18:17:44 +02:00
Phase 1: Monorepo infrastructure - Add Turborepo with turbo.json pipeline (build, dev, typecheck, test) - Update pnpm-workspace.yaml to include packages/* - Create shared TypeScript config (packages/tsconfig) Phase 2: Extract packages/core (zero react-dom, all-platform reuse) - Move domain types, API client, logger, utils → packages/core/ - Move TanStack Query modules (issues, inbox, workspace, runtimes) - Move Zustand stores (auth, workspace, issues, navigation, modals) - Move realtime sync (WSProvider, hooks, ws-updaters) - Refactor auth/workspace stores to factory pattern for DI - Refactor ApiClient with onUnauthorized callback - Refactor useWorkspaceId to React Context (WorkspaceIdProvider) - Refactor WSProvider to accept wsUrl + store props - Create apps/web/platform/ bridge layer (api singleton, store instances) - Update 91 import paths across apps/web/ - Fix 3 test files for new import paths Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
59 lines
1.4 KiB
TypeScript
59 lines
1.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useCallback } from "react";
|
|
import type { ApiClient } from "../api/client";
|
|
import type { Attachment } from "../types";
|
|
import { MAX_FILE_SIZE } from "../constants/upload";
|
|
|
|
export interface UploadResult {
|
|
id: string;
|
|
filename: string;
|
|
link: string;
|
|
}
|
|
|
|
export interface UploadContext {
|
|
issueId?: string;
|
|
commentId?: string;
|
|
}
|
|
|
|
export function useFileUpload(
|
|
api: ApiClient,
|
|
onError?: (error: Error) => void,
|
|
) {
|
|
const [uploading, setUploading] = useState(false);
|
|
|
|
const upload = useCallback(
|
|
async (file: File, ctx?: UploadContext): Promise<UploadResult | null> => {
|
|
if (file.size > MAX_FILE_SIZE) {
|
|
throw new Error("File exceeds 100 MB limit");
|
|
}
|
|
|
|
setUploading(true);
|
|
try {
|
|
const att: Attachment = await api.uploadFile(file, {
|
|
issueId: ctx?.issueId,
|
|
commentId: ctx?.commentId,
|
|
});
|
|
return { id: att.id, filename: att.filename, link: att.url };
|
|
} finally {
|
|
setUploading(false);
|
|
}
|
|
},
|
|
[api],
|
|
);
|
|
|
|
const uploadWithToast = useCallback(
|
|
async (file: File, ctx?: UploadContext): Promise<UploadResult | null> => {
|
|
try {
|
|
return await upload(file, ctx);
|
|
} catch (err) {
|
|
onError?.(err instanceof Error ? err : new Error("Upload failed"));
|
|
return null;
|
|
}
|
|
},
|
|
[upload, onError],
|
|
);
|
|
|
|
return { upload, uploadWithToast, uploading };
|
|
}
|