typescript
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
type ApiClient = {
|
||||
post: (path: string, body?: unknown) => Promise<{ data: unknown }>;
|
||||
delete: (path: string) => Promise<{ data: unknown }>;
|
||||
};
|
||||
|
||||
interface CorrespondentOption {
|
||||
id?: string | number;
|
||||
name?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface UseDocumentCorrespondentActionsArgs {
|
||||
apiClient: ApiClient;
|
||||
correspondents: CorrespondentOption[];
|
||||
handleCorrespondentCreate: (payload: { name: string }) => Promise<CorrespondentOption | null | undefined>;
|
||||
refreshCurrentFolder: () => Promise<void>;
|
||||
notifyApiError: (error: unknown, fallback: string) => void;
|
||||
setStatusMessage: (message: string, variant?: string) => void;
|
||||
}
|
||||
|
||||
const useDocumentCorrespondentActions = ({
|
||||
apiClient,
|
||||
correspondents,
|
||||
handleCorrespondentCreate,
|
||||
refreshCurrentFolder,
|
||||
notifyApiError,
|
||||
setStatusMessage,
|
||||
}: UseDocumentCorrespondentActionsArgs) => {
|
||||
const correspondentLookupByName = useMemo(() => {
|
||||
const map = new Map<string, CorrespondentOption>();
|
||||
correspondents.forEach((correspondent) => {
|
||||
if (correspondent?.name) {
|
||||
map.set(correspondent.name.toLowerCase(), correspondent);
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}, [correspondents]);
|
||||
|
||||
const handleDocumentCorrespondentAttach = useCallback(
|
||||
async (
|
||||
{ documentId, correspondentId }: { documentId?: string | number | null; correspondentId?: string | number | null },
|
||||
{ notify = true, refresh = true }: { notify?: boolean; refresh?: boolean } = {},
|
||||
) => {
|
||||
if (!documentId || !correspondentId) {
|
||||
throw new Error('Missing document or correspondent.');
|
||||
}
|
||||
try {
|
||||
await apiClient.post(`/documents/${documentId}/correspondents`, {
|
||||
assignments: [{ correspondent_id: correspondentId }],
|
||||
replace: false,
|
||||
});
|
||||
if (refresh) {
|
||||
await refreshCurrentFolder();
|
||||
}
|
||||
if (notify) {
|
||||
setStatusMessage('Correspondent assigned.', 'success');
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
const message = error.response?.data?.error || 'Failed to assign correspondent.';
|
||||
notifyApiError(error, message);
|
||||
throw new Error(message);
|
||||
}
|
||||
},
|
||||
[apiClient, refreshCurrentFolder, notifyApiError, setStatusMessage],
|
||||
);
|
||||
|
||||
const handleCorrespondentRemove = useCallback(
|
||||
async (
|
||||
{ documentId, correspondentId }: { documentId?: string | number | null; correspondentId?: string | number | null },
|
||||
{ notify = true, refresh = true }: { notify?: boolean; refresh?: boolean } = {},
|
||||
) => {
|
||||
if (!documentId || !correspondentId) {
|
||||
throw new Error('Missing document or correspondent.');
|
||||
}
|
||||
try {
|
||||
await apiClient.delete(`/documents/${documentId}/correspondents/${correspondentId}`);
|
||||
if (refresh) {
|
||||
await refreshCurrentFolder();
|
||||
}
|
||||
if (notify) {
|
||||
setStatusMessage('Correspondent removed.', 'success');
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
const message = error.response?.data?.error || 'Failed to remove correspondent.';
|
||||
notifyApiError(error, message);
|
||||
throw new Error(message);
|
||||
}
|
||||
},
|
||||
[apiClient, refreshCurrentFolder, notifyApiError, setStatusMessage],
|
||||
);
|
||||
|
||||
const handleCorrespondentAdd = useCallback(
|
||||
async ({ document, name, input = null, option = null }: { document?: { id?: string | number }; name?: string; input?: HTMLInputElement | null; option?: CorrespondentOption | string | null }) => {
|
||||
if (!document?.id) {
|
||||
throw new Error('Missing document for correspondent assignment.');
|
||||
}
|
||||
const trimmed = name?.trim?.() || '';
|
||||
if (!trimmed) {
|
||||
setStatusMessage('Correspondent name is required.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
let target = null;
|
||||
if (option && option.id) {
|
||||
target = correspondentLookupByName.get(trimmed.toLowerCase()) || option;
|
||||
} else {
|
||||
target = correspondentLookupByName.get(trimmed.toLowerCase()) || null;
|
||||
}
|
||||
if (!target) {
|
||||
try {
|
||||
target = await handleCorrespondentCreate({ name: trimmed });
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!target?.id) {
|
||||
setStatusMessage('Unable to resolve correspondent.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await handleDocumentCorrespondentAttach({
|
||||
documentId: document.id,
|
||||
correspondentId: target.id,
|
||||
});
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
} catch (error) {
|
||||
setStatusMessage('Failed to assign correspondent.', 'error');
|
||||
console.error('[documents] assign correspondent failed', error);
|
||||
}
|
||||
},
|
||||
[
|
||||
correspondentLookupByName,
|
||||
handleCorrespondentCreate,
|
||||
handleDocumentCorrespondentAttach,
|
||||
setStatusMessage,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
correspondentLookupByName,
|
||||
handleDocumentCorrespondentAttach,
|
||||
handleCorrespondentRemove,
|
||||
handleCorrespondentAdd,
|
||||
};
|
||||
};
|
||||
|
||||
export default useDocumentCorrespondentActions;
|
||||
Reference in New Issue
Block a user