refactor: Consolidate mutation options, simplify tag attachment and removal logic, and remove unused tag drop handler.

This commit is contained in:
2025-12-02 13:01:14 +01:00
parent 5ffe9e4d27
commit ebe8b163b9
2 changed files with 16 additions and 79 deletions
@@ -78,22 +78,7 @@ interface DocumentTagExtras {
input?: { value?: string } | null; input?: { value?: string } | null;
} }
interface DeleteOptions { interface MessageOptions {
showMessage?: boolean;
}
interface TagAttachArgs {
documentId?: DocumentId;
tagId?: DocumentId;
tag?: Tag | null;
}
interface TagRemoveOptions {
refreshTagList?: boolean;
showMessage?: boolean;
}
interface FolderDeleteOptions {
showMessage?: boolean; showMessage?: boolean;
} }
@@ -142,14 +127,14 @@ interface UseDocumentMutationsResult {
handleThumbnailRegeneration: (documentId: DocumentId) => Promise<void>; handleThumbnailRegeneration: (documentId: DocumentId) => Promise<void>;
handleDocumentsDelete: ( handleDocumentsDelete: (
documentIds: DocumentId[], documentIds: DocumentId[],
options?: DeleteOptions, options?: MessageOptions,
) => Promise<boolean>; ) => Promise<boolean>;
handleDocumentTagAdd: ( handleDocumentTagAdd: (
document: Document, document: Document,
label: string, label: string,
extras?: DocumentTagExtras | null, extras?: DocumentTagExtras | null,
) => Promise<void>; ) => Promise<void>;
handleDocumentTagAttach: (args: TagAttachArgs) => Promise<boolean>; handleDocumentTagAttach: (documentId: DocumentId, tagId: DocumentId) => Promise<boolean>;
handleDocumentTitleUpdate: (documentId: DocumentId, nextTitle: string) => Promise<boolean>; handleDocumentTitleUpdate: (documentId: DocumentId, nextTitle: string) => Promise<boolean>;
handleDocumentIssuedUpdate: ( handleDocumentIssuedUpdate: (
documentId: DocumentId, documentId: DocumentId,
@@ -158,9 +143,8 @@ interface UseDocumentMutationsResult {
handleTagRemove: ( handleTagRemove: (
documentId?: DocumentId, documentId?: DocumentId,
tagId?: DocumentId, tagId?: DocumentId,
options?: TagRemoveOptions,
) => Promise<boolean>; ) => Promise<boolean>;
handleFolderDelete: (folderId?: FolderId, options?: FolderDeleteOptions) => Promise<boolean>; handleFolderDelete: (folderId?: FolderId, options?: MessageOptions) => Promise<boolean>;
} }
const normalizeDocumentId = (value: unknown): DocumentId | null => { const normalizeDocumentId = (value: unknown): DocumentId | null => {
@@ -404,7 +388,7 @@ const useDocumentMutations = ({
); );
const handleDocumentsDelete = useCallback( const handleDocumentsDelete = useCallback(
async (documentIds: DocumentId[], { showMessage = true }: DeleteOptions = {}) => { async (documentIds: DocumentId[], { showMessage = true }: MessageOptions = {}) => {
if (!documentIds || documentIds.length === 0) { if (!documentIds || documentIds.length === 0) {
return false; return false;
} }
@@ -596,25 +580,24 @@ const useDocumentMutations = ({
); );
const handleDocumentTagAttach = useCallback( const handleDocumentTagAttach = useCallback(
async ({ documentId, tagId, tag: tagData = null }: TagAttachArgs) => { async (documentId: DocumentId, tagId: DocumentId) => {
if (!documentId || !tagId) { if (!documentId || !tagId) {
return false; return false;
} }
const resolveTagForCache = (): Tag | null => { const resolveTagForCache = (): Tag | null => {
const lookupTag = tagLookupById.get(tagId); const lookupTag = tagLookupById.get(tagId);
const source = lookupTag ?? tagData; if (!lookupTag || lookupTag.id == null) {
if (!source || source.id == null) {
return null; return null;
} }
const labelText = `${source.label ?? ''} `.trim(); const labelText = `${lookupTag.label ?? ''} `.trim();
if (!labelText) { if (!labelText) {
return null; return null;
} }
return { return {
id: source.id, id: lookupTag.id,
label: labelText, label: labelText,
color: Object.prototype.hasOwnProperty.call(source, 'color') ? (source as Tag).color ?? null : null, color: Object.prototype.hasOwnProperty.call(lookupTag, 'color') ? (lookupTag as Tag).color ?? null : null,
}; };
}; };
@@ -654,7 +637,6 @@ const useDocumentMutations = ({
async ( async (
documentId?: DocumentId, documentId?: DocumentId,
tagId?: DocumentId, tagId?: DocumentId,
{ refreshTagList = true, showMessage = true }: TagRemoveOptions = {},
) => { ) => {
if (!documentId || !tagId) { if (!documentId || !tagId) {
return false; return false;
@@ -663,12 +645,7 @@ const useDocumentMutations = ({
try { try {
await deleteDocumentTag(documentId, tagId); await deleteDocumentTag(documentId, tagId);
applyTagRemovalToCaches(documentId, tagId); applyTagRemovalToCaches(documentId, tagId);
if (refreshTagList) { setStatusMessage('Tag removed.', 'success');
await refreshTags();
}
if (showMessage) {
setStatusMessage('Tag removed.', 'success');
}
return true; return true;
} catch (error) { } catch (error) {
const message = (error as Record<string, any>)?.response?.data?.error || 'Failed to remove tag.'; const message = (error as Record<string, any>)?.response?.data?.error || 'Failed to remove tag.';
@@ -676,11 +653,11 @@ const useDocumentMutations = ({
return false; return false;
} }
}, },
[applyTagRemovalToCaches, notifyApiError, refreshTags, setStatusMessage], [applyTagRemovalToCaches, notifyApiError, setStatusMessage],
); );
const handleFolderDelete = useCallback( const handleFolderDelete = useCallback(
async (folderId?: FolderId, { showMessage = true }: FolderDeleteOptions = {}) => { async (folderId?: FolderId, { showMessage = true }: MessageOptions = {}) => {
if (!token) { if (!token) {
if (showMessage) { if (showMessage) {
setStatusMessage('Log in to manage folders.', 'error'); setStatusMessage('Log in to manage folders.', 'error');
@@ -936,16 +936,7 @@ const useDocumentsWorkspace = ({
[assetManager, updateDocumentCaches, notifyApiError], [assetManager, updateDocumentCaches, notifyApiError],
); );
const handleDocumentTagDrop = useCallback(
async (documentId, tagId) => {
if (!documentId || !tagId) {
return;
}
await handleDocumentTagAttach({ documentId, tagId });
},
[handleDocumentTagAttach],
);
const handlePromptCreateFolder = useCallback(async (parentId?: Identifier | null) => { const handlePromptCreateFolder = useCallback(async (parentId?: Identifier | null) => {
if (creatingFolder) { if (creatingFolder) {
@@ -1053,48 +1044,17 @@ const useDocumentsWorkspace = ({
setTagRemovalCursor(false); setTagRemovalCursor(false);
}; };
const handleTagDrop = async (event) => {
if (!isTagTransfer(event)) {
return;
}
setTagRemovalCursor(false);
if (isDocumentDropTarget(event.target) || event.defaultPrevented) {
return;
}
event.preventDefault();
event.stopPropagation();
const raw =
event.dataTransfer.getData('application/x-papercrate-tag') ||
event.dataTransfer.getData('text/papercrate-tag');
if (!raw) {
return;
}
try {
const payload = JSON.parse(raw);
if (payload?.sourceDocId && payload?.id) {
await handleTagRemove(payload.sourceDocId, payload.id, {
refreshTagList: false,
showMessage: true,
});
}
} catch (error) {
console.warn('Failed to remove tag from drop target', error);
}
};
const handleTagDragEnd = () => { const handleTagDragEnd = () => {
setTagRemovalCursor(false); setTagRemovalCursor(false);
}; };
host.addEventListener('dragover', handleTagDragOver, true); host.addEventListener('dragover', handleTagDragOver, true);
host.addEventListener('dragleave', handleTagDragLeave, true); host.addEventListener('dragleave', handleTagDragLeave, true);
host.addEventListener('drop', handleTagDrop, true);
window.addEventListener('dragend', handleTagDragEnd, true); window.addEventListener('dragend', handleTagDragEnd, true);
return () => { return () => {
host.removeEventListener('dragover', handleTagDragOver, true); host.removeEventListener('dragover', handleTagDragOver, true);
host.removeEventListener('dragleave', handleTagDragLeave, true); host.removeEventListener('dragleave', handleTagDragLeave, true);
host.removeEventListener('drop', handleTagDrop, true);
window.removeEventListener('dragend', handleTagDragEnd, true); window.removeEventListener('dragend', handleTagDragEnd, true);
setTagRemovalCursor(false); setTagRemovalCursor(false);
}; };
@@ -1204,7 +1164,7 @@ const useDocumentsWorkspace = ({
activeCorrespondentFilters, activeCorrespondentFilters,
ensureAssetUrl, ensureAssetUrl,
getDocumentAsset, getDocumentAsset,
handleDocumentTagAttach: handleDocumentTagDrop, handleDocumentTagAttach,
handleDocumentTagDetach: handleTagRemove, handleDocumentTagDetach: handleTagRemove,
documentsViewMode, documentsViewMode,
documentsSortField, documentsSortField,
@@ -1280,7 +1240,7 @@ const useDocumentsWorkspace = ({
refreshTags, refreshTags,
handleTagUpdate, handleTagUpdate,
handleTagDelete, handleTagDelete,
handleDocumentTagDrop, handleDocumentTagDrop: handleDocumentTagAttach,
correspondents, correspondents,
refreshCorrespondents, refreshCorrespondents,
handleCorrespondentUpdate, handleCorrespondentUpdate,
@@ -1330,7 +1290,7 @@ const useDocumentsWorkspace = ({
refreshTags, refreshTags,
handleTagUpdate, handleTagUpdate,
handleTagDelete, handleTagDelete,
handleDocumentTagDrop, handleDocumentTagAttach,
correspondents, correspondents,
refreshCorrespondents, refreshCorrespondents,
handleCorrespondentUpdate, handleCorrespondentUpdate,