feat: Refactor frontend authentication and tenant switching to use global state

This commit is contained in:
2025-12-08 01:19:52 +01:00
parent 5840c9d1d0
commit 608239e412
9 changed files with 82 additions and 194 deletions
+2 -2
View File
@@ -1,6 +1,7 @@
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import type { Dispatch, SetStateAction } from 'react'; import type { Dispatch, SetStateAction } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useAppState } from '../lib/store/appState';
import { TAG_FILTER_UNTAGGED } from './workspaceUtils'; import { TAG_FILTER_UNTAGGED } from './workspaceUtils';
import { listDocuments } from '../lib/api/apiClient'; import { listDocuments } from '../lib/api/apiClient';
import type { Identifier } from '../types/identifiers'; import type { Identifier } from '../types/identifiers';
@@ -15,7 +16,6 @@ import useNotifyApiError from '../hooks/useNotifyApiError';
interface UseDocumentsSearchArgs { interface UseDocumentsSearchArgs {
api: ApiClient; api: ApiClient;
token?: string | null;
selectedFolder?: Identifier | 'root' | null; selectedFolder?: Identifier | 'root' | null;
locationPathname?: string; locationPathname?: string;
isDocumentsRoute?: boolean; isDocumentsRoute?: boolean;
@@ -65,7 +65,6 @@ interface UseDocumentsSearchResult {
const useDocumentsSearch = ({ const useDocumentsSearch = ({
api, api,
token,
selectedFolder, selectedFolder,
locationPathname, locationPathname,
isDocumentsRoute, isDocumentsRoute,
@@ -75,6 +74,7 @@ const useDocumentsSearch = ({
setSearchIncludeDescendants, setSearchIncludeDescendants,
documentsManager, documentsManager,
}: UseDocumentsSearchArgs): UseDocumentsSearchResult => { }: UseDocumentsSearchArgs): UseDocumentsSearchResult => {
const { token } = useAppState();
const [searchQuery, setSearchQuery] = useState<string>(''); const [searchQuery, setSearchQuery] = useState<string>('');
const [activeTagFilters, setActiveTagFilters] = useState<Identifier[]>([]); const [activeTagFilters, setActiveTagFilters] = useState<Identifier[]>([]);
const [activeCorrespondentFilters, setActiveCorrespondentFilters] = useState<Identifier[]>([]); const [activeCorrespondentFilters, setActiveCorrespondentFilters] = useState<Identifier[]>([]);
+5 -13
View File
@@ -3,15 +3,9 @@ import type { MutableRefObject } from 'react';
import { clearAuthToken, logoutSession, refreshSession, setAuthToken } from '../../lib/api/apiClient'; import { clearAuthToken, logoutSession, refreshSession, setAuthToken } from '../../lib/api/apiClient';
import { useStatusToast } from '../../lib/context/StatusToastContext'; import { useStatusToast } from '../../lib/context/StatusToastContext';
type AppStatus = string; import { useAppDispatch, useAppState } from '../../lib/store/appState';
type AppDispatch = (action: { type: string;[key: string]: unknown }) => void; interface UseAuthManagerArgs { }
interface UseAuthManagerArgs {
token?: string | null;
appStatus: AppStatus;
appDispatch: AppDispatch;
}
interface UseAuthManagerResult { interface UseAuthManagerResult {
tokenRef: MutableRefObject<string | null>; tokenRef: MutableRefObject<string | null>;
@@ -19,11 +13,9 @@ interface UseAuthManagerResult {
handleLogout: () => Promise<void>; handleLogout: () => Promise<void>;
} }
const useAuthManager = ({ const useAuthManager = (_: UseAuthManagerArgs = {}): UseAuthManagerResult => {
token, const { token, status: appStatus } = useAppState();
appStatus, const appDispatch = useAppDispatch();
appDispatch,
}: UseAuthManagerArgs): UseAuthManagerResult => {
const tokenRef = useRef<string | null>(token); const tokenRef = useRef<string | null>(token);
const initialRefreshAttemptedRef = useRef(Boolean(token)); const initialRefreshAttemptedRef = useRef(Boolean(token));
const { showToast } = useStatusToast(); const { showToast } = useStatusToast();
@@ -1,6 +1,7 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import type { Dispatch, MutableRefObject, SetStateAction } from 'react'; import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
import { useStatusToast } from '../../lib/context/StatusToastContext'; import { useStatusToast } from '../../lib/context/StatusToastContext';
import { DEFAULT_FOLDER_NAME } from '../../app/workspaceUtils'; import { DEFAULT_FOLDER_NAME } from '../../app/workspaceUtils';
import { getEntryId, isDocumentEntry } from '../../app/entryKey'; import { getEntryId, isDocumentEntry } from '../../app/entryKey';
import { import {
@@ -74,7 +75,6 @@ interface DocumentTagExtras {
import useNotifyApiError from '../../hooks/useNotifyApiError'; import useNotifyApiError from '../../hooks/useNotifyApiError';
interface UseDocumentMutationsArgs { interface UseDocumentMutationsArgs {
token?: string | null;
documentLookup: Map<DocumentId, Document>; documentLookup: Map<DocumentId, Document>;
folderLabelMap: Map<FolderId, string>; folderLabelMap: Map<FolderId, string>;
ensureFolderData: EnsureFolderData; ensureFolderData: EnsureFolderData;
@@ -143,7 +143,6 @@ const normalizeDocumentId = (value: unknown): DocumentId | null => {
}; };
const useDocumentMutations = ({ const useDocumentMutations = ({
token,
documentLookup, documentLookup,
folderLabelMap, folderLabelMap,
ensureFolderData, ensureFolderData,
@@ -338,10 +337,6 @@ const useDocumentMutations = ({
const handleThumbnailRegeneration = useCallback( const handleThumbnailRegeneration = useCallback(
async (documentId: DocumentId) => { async (documentId: DocumentId) => {
if (!token) {
showToast('Log in to manage assets.', 'error');
return;
}
try { try {
await queueDocumentReanalysis(documentId, { force: true }); await queueDocumentReanalysis(documentId, { force: true });
showToast('Document re-analysis queued.', 'info'); showToast('Document re-analysis queued.', 'info');
@@ -351,7 +346,7 @@ const useDocumentMutations = ({
notifyApiError(error, message); notifyApiError(error, message);
} }
}, },
[token, refreshCurrentFolder, notifyApiError, showToast], [refreshCurrentFolder, notifyApiError, showToast],
); );
const handleDocumentsDelete = useCallback( const handleDocumentsDelete = useCallback(
@@ -360,11 +355,6 @@ const useDocumentMutations = ({
return false; return false;
} }
if (!token) {
showToast('Log in to manage documents.', 'error');
return false;
}
try { try {
await Promise.all(documentIds.map((documentId) => trashDocument(documentId))); await Promise.all(documentIds.map((documentId) => trashDocument(documentId)));
@@ -386,8 +376,6 @@ const useDocumentMutations = ({
} }
}, },
[ [
token,
removeDocumentsFromCaches, removeDocumentsFromCaches,
previewDocumentId, previewDocumentId,
closeDocumentPreview, closeDocumentPreview,
@@ -625,12 +613,6 @@ const useDocumentMutations = ({
const handleFolderDelete = useCallback( const handleFolderDelete = useCallback(
async (folderId?: FolderId, { showMessage = true }: MessageOptions = {}) => { async (folderId?: FolderId, { showMessage = true }: MessageOptions = {}) => {
if (!token) {
if (showMessage) {
showToast('Log in to manage folders.', 'error');
}
return false;
}
if (!folderId || folderId === 'root') { if (!folderId || folderId === 'root') {
if (showMessage) { if (showMessage) {
showToast('The root folder cannot be removed.', 'error'); showToast('The root folder cannot be removed.', 'error');
@@ -695,7 +677,6 @@ const useDocumentMutations = ({
} }
}, },
[ [
token,
ensureFolderData, ensureFolderData,
selectedFolder, selectedFolder,
folderNodes, folderNodes,
@@ -145,15 +145,8 @@ const useDocumentsWorkspace = ({
: []; : [];
const { showToast } = useStatusToast(); const { showToast } = useStatusToast();
const notifyApiError = useNotifyApiError(); const notifyApiError = useNotifyApiError();
const [creatingFolder, setCreatingFolder] = useState(false); const [creatingFolder, setCreatingFolder] = useState(false);
const { handleLogout } = useAuthManager({});
const { tokenRef, handleLogout } = useAuthManager({
token,
appStatus,
appDispatch,
});
const tagRemovalCursorActiveRef = useRef(false); const tagRemovalCursorActiveRef = useRef(false);
const tenantIdRef = useRef(currentTenantId); const tenantIdRef = useRef(currentTenantId);
@@ -287,63 +280,59 @@ const useDocumentsWorkspace = ({
folderId: FolderNodeId, folderId: FolderNodeId,
options: { includeDocuments?: boolean } = {} options: { includeDocuments?: boolean } = {}
) => { ) => {
try {
const path = folderId === 'root' ? 'root' : folderId;
const includeDocuments = options.includeDocuments ?? true;
const params: Record<string, unknown> = {
include_documents: includeDocuments,
sort: activeSortFieldRef.current,
dir: activeSortDirectionRef.current,
};
const data = await listFolderContents(path, params); const path = folderId === 'root' ? 'root' : folderId;
const includeDocuments = options.includeDocuments ?? true;
const params: Record<string, unknown> = {
include_documents: includeDocuments,
sort: activeSortFieldRef.current,
dir: activeSortDirectionRef.current,
};
// Only update UI state if we are fetching for the currently selected folder const data = await listFolderContents(path, params);
if (folderId === selectedFolder) {
// Update documents state if included
if (includeDocuments) {
setDocuments((data.documents || []) as Document[]);
}
setCurrentSubfolders((data.subfolders || []) as any[]);
// Update selection state based on new documents // Only update UI state if we are fetching for the currently selected folder
if (includeDocuments) { if (folderId === selectedFolder) {
const docs = (data.documents || []) as Document[]; // Update documents state if included
const subfolders = (data.subfolders || []) as any[]; if (includeDocuments) {
setDocuments((data.documents || []) as Document[]);
}
setCurrentSubfolders((data.subfolders || []) as any[]);
const availableDocKeys = docs // Update selection state based on new documents
.map((doc) => createDocumentEntryKey(doc?.id as Identifier)) if (includeDocuments) {
.filter(Boolean); const docs = (data.documents || []) as Document[];
const availableDocKeySet = new Set(availableDocKeys); const subfolders = (data.subfolders || []) as any[];
const availableFolderKeys = new Set(
subfolders
.map((folder) => createFolderEntryKey(folder?.id as Identifier))
.filter(Boolean),
);
setSelectedEntries((previous) => { const availableDocKeys = docs
const previousFolderKeys = previous .map((doc) => createDocumentEntryKey(doc?.id as Identifier))
.filter(isFolderEntry) .filter(Boolean);
.filter((key) => availableFolderKeys.has(key)); const availableDocKeySet = new Set(availableDocKeys);
const previousDocKeys = previous.filter(isDocumentEntry); const availableFolderKeys = new Set(
const nextDocKeys = previousDocKeys.filter((key) => availableDocKeySet.has(key)); subfolders
const mergedSelection = [...previousFolderKeys, ...nextDocKeys]; .map((folder) => createFolderEntryKey(folder?.id as Identifier))
return mergedSelection; .filter(Boolean),
}); );
}
setSelectedEntries((previous) => {
const previousFolderKeys = previous
.filter(isFolderEntry)
.filter((key) => availableFolderKeys.has(key));
const previousDocKeys = previous.filter(isDocumentEntry);
const nextDocKeys = previousDocKeys.filter((key) => availableDocKeySet.has(key));
const mergedSelection = [...previousFolderKeys, ...nextDocKeys];
return mergedSelection;
});
} }
return data; // Return data for consumers (e.g. useDocumentMutations)
} catch (error) {
notifyApiError(error, 'Failed to fetch folder contents');
throw error;
} }
return data; // Return data for consumers (e.g. useDocumentMutations)
}, },
[ [
activeSortFieldRef, activeSortFieldRef,
activeSortDirectionRef, activeSortDirectionRef,
setDocuments, setDocuments,
setSelectedEntries, setSelectedEntries,
notifyApiError,
setCurrentSubfolders, setCurrentSubfolders,
selectedFolder, selectedFolder,
] ]
@@ -351,9 +340,11 @@ const useDocumentsWorkspace = ({
useEffect(() => { useEffect(() => {
if (selectedFolder) { if (selectedFolder) {
ensureFolderData(selectedFolder); ensureFolderData(selectedFolder).catch((error) => {
notifyApiError(error, 'Failed to fetch folder contents');
});
} }
}, [selectedFolder, documentsSortField, documentsSortDirection, ensureFolderData]); }, [selectedFolder, documentsSortField, documentsSortDirection, ensureFolderData, notifyApiError]);
const { const {
searchQuery, searchQuery,
@@ -369,7 +360,6 @@ const useDocumentsWorkspace = ({
documentsFilterValue, documentsFilterValue,
} = useDocumentsSearch({ } = useDocumentsSearch({
api: apiClient, api: apiClient,
token,
selectedFolder, selectedFolder,
locationPathname: location.pathname, locationPathname: location.pathname,
isDocumentsRoute, isDocumentsRoute,
@@ -542,9 +532,7 @@ const useDocumentsWorkspace = ({
refreshPasskeys, refreshPasskeys,
registerPasskey, registerPasskey,
revokePasskey, revokePasskey,
} = usePasskeys({ } = usePasskeys({});
token,
});
const resolveTargetDocumentIds = useCallback( const resolveTargetDocumentIds = useCallback(
(candidateIds) => { (candidateIds) => {
@@ -585,7 +573,6 @@ const useDocumentsWorkspace = ({
resetUploadsState, resetUploadsState,
handleFileSelection, handleFileSelection,
} = useDocumentUploads({ } = useDocumentUploads({
token,
selectedFolder, selectedFolder,
currentFolderName, currentFolderName,
ensureFolderData, ensureFolderData,
@@ -709,7 +696,6 @@ const useDocumentsWorkspace = ({
handleDocumentIssuedUpdate, handleDocumentIssuedUpdate,
handleTagRemove, handleTagRemove,
} = useDocumentMutations({ } = useDocumentMutations({
token,
documentLookup, documentLookup,
folderLabelMap, folderLabelMap,
ensureFolderData, ensureFolderData,
@@ -749,7 +735,6 @@ const useDocumentsWorkspace = ({
handleFolderDelete, handleFolderDelete,
folderClickHandlers, folderClickHandlers,
} = useFolderTreeActions({ } = useFolderTreeActions({
token,
folderNodes, folderNodes,
setFolderNodes, setFolderNodes,
selectedFolder, selectedFolder,
@@ -1078,13 +1063,7 @@ const useDocumentsWorkspace = ({
const { handleTenantSelect } = useTenantManager({ const { handleTenantSelect } = useTenantManager({
currentTenantId, currentTenantId,
resetWorkspaceState,
refreshTags,
refreshCorrespondents,
loadFolder,
handleDocumentsViewModeChange, handleDocumentsViewModeChange,
tokenRef,
tenantIdRef,
}); });
const sessionContext = { const sessionContext = {
+23 -42
View File
@@ -1,68 +1,65 @@
import { MutableRefObject, useCallback } from 'react'; import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import type { FolderId, TenantId } from '../../types/identifiers'; import type { TenantId } from '../../types/identifiers';
import { useStatusToast } from '../../lib/context/StatusToastContext'; import { useStatusToast } from '../../lib/context/StatusToastContext';
import { useAppDispatch } from '../../lib/store/appState'; import { useAppDispatch } from '../../lib/store/appState';
import { api, listTenants, switchTenant } from '../../lib/api/apiClient'; import { api, listTenants, switchTenant } from '../../lib/api/apiClient';
import useNotifyApiError from '../../hooks/useNotifyApiError';
interface TenantOption { interface TenantOption {
id?: TenantId; id?: TenantId;
name?: string; name?: string;
} }
import useNotifyApiError from '../../hooks/useNotifyApiError';
interface UseTenantManagerOptions { interface UseTenantManagerOptions {
currentTenantId: TenantId | null; currentTenantId: TenantId | null;
resetWorkspaceState: () => void;
refreshTags: () => Promise<void>;
refreshCorrespondents: () => Promise<void>;
loadFolder: (folderId: FolderId, options?: { preserveSearch?: boolean }) => Promise<void>;
handleDocumentsViewModeChange: (mode: string) => void; handleDocumentsViewModeChange: (mode: string) => void;
tokenRef?: MutableRefObject<string | null>;
tenantIdRef?: MutableRefObject<TenantId | null>;
} }
const useTenantManager = ({ const useTenantManager = ({
currentTenantId, currentTenantId,
resetWorkspaceState,
refreshTags,
refreshCorrespondents,
loadFolder,
handleDocumentsViewModeChange, handleDocumentsViewModeChange,
tokenRef,
tenantIdRef,
}: UseTenantManagerOptions) => { }: UseTenantManagerOptions) => {
const { showToast } = useStatusToast(); const { showToast } = useStatusToast();
const notifyApiError = useNotifyApiError(); const notifyApiError = useNotifyApiError();
const navigate = useNavigate(); const navigate = useNavigate();
const appDispatch = useAppDispatch(); const appDispatch = useAppDispatch();
const handleTenantSelect = useCallback( const handleTenantSelect = useCallback(
async (tenantOption: TenantOption | null, { refreshOnly = false }: { refreshOnly?: boolean } = {}) => { async (tenantOption: TenantOption | null, { refreshOnly = false }: { refreshOnly?: boolean } = {}) => {
const requestedTenantId = tenantOption?.id ?? null; const requestedTenantId = tenantOption?.id ?? null;
// 1. Guard Clauses
if (!refreshOnly && (!requestedTenantId || requestedTenantId === currentTenantId)) { if (!refreshOnly && (!requestedTenantId || requestedTenantId === currentTenantId)) {
return; return;
} }
try { try {
// 2. Refresh Logic
if (refreshOnly) { if (refreshOnly) {
const data = await listTenants(); const data = await listTenants();
appDispatch({ appDispatch({ type: 'SET_TENANTS', tenants: data });
type: 'SET_TENANTS',
tenants: data,
});
return; return;
} }
// 3. Switch Logic
const data = await switchTenant(requestedTenantId); const data = await switchTenant(requestedTenantId);
if (!data?.access_token) { if (!data?.access_token) {
throw new Error('Missing access token in tenant switch response.'); throw new Error('Missing access token in tenant switch response.');
} }
appDispatch({ type: 'LOGOUT' }); // 4. Reset UI to safe state BEFORE updating global auth
resetWorkspaceState(); // This prevents old components from reacting to state changes.
// 5. Update Global State IMMEDIATELY
// Don't wait for navigation. Data consistency comes first.
handleDocumentsViewModeChange('list');
api.defaults.headers.common.Authorization = `Bearer ${data.access_token}`;
appDispatch({ appDispatch({
type: 'LOGIN_SUCCESS', type: 'LOGIN_SUCCESS',
@@ -70,26 +67,16 @@ const useTenantManager = ({
tenant: data.tenant || null, tenant: data.tenant || null,
}); });
api.defaults.headers.common.Authorization = `Bearer ${data.access_token}`;
if (tokenRef) {
tokenRef.current = data.access_token;
}
if (tenantIdRef) {
tenantIdRef.current = data?.tenant?.id ?? null;
}
if (Array.isArray(data?.tenants)) { if (Array.isArray(data?.tenants)) {
appDispatch({ type: 'SET_TENANTS', tenants: data.tenants }); appDispatch({ type: 'SET_TENANTS', tenants: data.tenants });
} }
handleDocumentsViewModeChange('list');
navigate('/documents', { replace: true });
await Promise.all([refreshTags(), refreshCorrespondents()]);
await loadFolder('root', { preserveSearch: false });
const tenantLabel = data?.tenant?.name || data?.tenant?.id || 'tenant'; const tenantLabel = data?.tenant?.name || data?.tenant?.id || 'tenant';
showToast(`Switched to ${tenantLabel}.`, 'info'); showToast(`Switched to ${tenantLabel}.`, 'info');
// 5. Handle UI/Navigation changes AFTER state is secure
navigate('/documents', { replace: true });
} catch (error) { } catch (error) {
notifyApiError(error, 'Failed to switch tenant.'); notifyApiError(error, 'Failed to switch tenant.');
} }
@@ -98,15 +85,9 @@ const useTenantManager = ({
appDispatch, appDispatch,
currentTenantId, currentTenantId,
handleDocumentsViewModeChange, handleDocumentsViewModeChange,
loadFolder,
navigate, navigate,
notifyApiError, notifyApiError,
refreshCorrespondents,
refreshTags,
resetWorkspaceState,
showToast, showToast,
tenantIdRef,
tokenRef,
], ],
); );
@@ -33,7 +33,6 @@ interface FolderClickHandlers {
import useNotifyApiError from '../../../hooks/useNotifyApiError'; import useNotifyApiError from '../../../hooks/useNotifyApiError';
interface UseFolderTreeActionsOptions { interface UseFolderTreeActionsOptions {
token?: string | null;
folderNodes: Map<FolderKey, FolderNode>; folderNodes: Map<FolderKey, FolderNode>;
setFolderNodes: (updater: (prev: Map<FolderKey, FolderNode>) => Map<FolderKey, FolderNode>) => void; setFolderNodes: (updater: (prev: Map<FolderKey, FolderNode>) => Map<FolderKey, FolderNode>) => void;
selectedFolder: FolderKey; selectedFolder: FolderKey;
@@ -49,7 +48,6 @@ interface UseFolderTreeActionsOptions {
} }
const useFolderTreeActions = ({ const useFolderTreeActions = ({
token,
folderNodes, folderNodes,
setFolderNodes, setFolderNodes,
selectedFolder, selectedFolder,
@@ -181,10 +179,6 @@ const useFolderTreeActions = ({
const handleFolderRename = useCallback( const handleFolderRename = useCallback(
async (folderId: FolderKey, nextName: string) => { async (folderId: FolderKey, nextName: string) => {
if (!token) {
showToast('Log in to rename folders.', 'error');
return false;
}
const trimmed = nextName?.trim?.() || ''; const trimmed = nextName?.trim?.() || '';
if (!trimmed) { if (!trimmed) {
showToast('Folder name cannot be empty.', 'error'); showToast('Folder name cannot be empty.', 'error');
@@ -214,16 +208,11 @@ const useFolderTreeActions = ({
notifyApiError, notifyApiError,
setFolderNodes, setFolderNodes,
showToast, showToast,
token,
], ],
); );
const handleFolderCreate = useCallback( const handleFolderCreate = useCallback(
async (name: string, parentId?: FolderKey | null) => { async (name: string, parentId?: FolderKey | null) => {
if (!token) {
showToast('Log in to create folders.', 'error');
return false;
}
if (!name.trim()) { if (!name.trim()) {
showToast('Folder name cannot be empty.', 'error'); showToast('Folder name cannot be empty.', 'error');
return false; return false;
@@ -291,18 +280,11 @@ const useFolderTreeActions = ({
setCreatingFolder, setCreatingFolder,
setFolderNodes, setFolderNodes,
showToast, showToast,
token,
], ],
); );
const handleFolderDelete = useCallback( const handleFolderDelete = useCallback(
async (folderId: FolderKey, { showMessage = true }: MessageOptions = {}) => { async (folderId: FolderKey, { showMessage = true }: MessageOptions = {}) => {
if (!token) {
if (showMessage) {
showToast('Log in to manage folders.', 'error');
}
return false;
}
if (!folderId || folderId === 'root') { if (!folderId || folderId === 'root') {
if (showMessage) { if (showMessage) {
showToast('The root folder cannot be removed.', 'error'); showToast('The root folder cannot be removed.', 'error');
@@ -352,7 +334,6 @@ const useFolderTreeActions = ({
} }
}, },
[ [
token,
folderNodes, folderNodes,
notifyApiError, notifyApiError,
selectedFolder, selectedFolder,
@@ -91,7 +91,6 @@ const mapFilesToEntries = (filesInput?: FileList | File[] | null): FileEntry[] =
}; };
interface UseDocumentUploadsArgs { interface UseDocumentUploadsArgs {
token?: string | null;
selectedFolder?: FolderId; selectedFolder?: FolderId;
currentFolderName?: string | null; currentFolderName?: string | null;
ensureFolderData: (folderId: FolderId, options?: { [key: string]: unknown }) => Promise<void>; ensureFolderData: (folderId: FolderId, options?: { [key: string]: unknown }) => Promise<void>;
@@ -121,7 +120,6 @@ interface UseDocumentUploadsResult {
import useNotifyApiError from '../../../hooks/useNotifyApiError'; import useNotifyApiError from '../../../hooks/useNotifyApiError';
const useDocumentUploads = ({ const useDocumentUploads = ({
token,
selectedFolder, selectedFolder,
currentFolderName, currentFolderName,
ensureFolderData, ensureFolderData,
@@ -370,19 +368,6 @@ const useDocumentUploads = ({
const queueItems = appendQueueItems(entries, targetFolderId); const queueItems = appendQueueItems(entries, targetFolderId);
if (!token) {
queueItems.forEach((item) => {
const patch = {
status: 'error',
error: 'Please log in before uploading.',
code: null,
};
updateQueueItem(item.id, patch);
Object.assign(item, patch);
});
return;
}
try { try {
folderPathCacheRef.current.clear(); folderPathCacheRef.current.clear();
@@ -461,7 +446,6 @@ const useDocumentUploads = ({
} }
}, },
[ [
token,
ensureFolderPathOnServer, ensureFolderPathOnServer,
uploadFile, uploadFile,
refreshCurrentFolder, refreshCurrentFolder,
@@ -497,7 +481,6 @@ const useDocumentUploads = ({
useFileDrop({ useFileDrop({
shellRef, shellRef,
token,
currentFolderName, currentFolderName,
selectedFolder, selectedFolder,
handleFileDrop, handleFileDrop,
@@ -9,7 +9,6 @@ interface DropOverlayState {
interface UseFileDropOptions { interface UseFileDropOptions {
shellRef: MutableRefObject<HTMLElement | null>; shellRef: MutableRefObject<HTMLElement | null>;
token?: string | null;
currentFolderName: string | null; currentFolderName: string | null;
selectedFolder: FolderId; selectedFolder: FolderId;
handleFileDrop: (dataTransfer: DataTransfer, folderId: FolderId) => Promise<void>; handleFileDrop: (dataTransfer: DataTransfer, folderId: FolderId) => Promise<void>;
@@ -21,7 +20,6 @@ interface UseFileDropOptions {
const useFileDrop = ({ const useFileDrop = ({
shellRef, shellRef,
token,
currentFolderName, currentFolderName,
selectedFolder, selectedFolder,
handleFileDrop, handleFileDrop,
@@ -32,12 +30,6 @@ const useFileDrop = ({
}: UseFileDropOptions) => { }: UseFileDropOptions) => {
useEffect(() => { useEffect(() => {
if (!token) {
setDropOverlayState((prev) => ({ ...prev, active: false }));
dragCounterRef.current = 0;
return undefined;
}
const handleDragEnter = (event: DragEvent) => { const handleDragEnter = (event: DragEvent) => {
if (!hasFiles(event)) return; if (!hasFiles(event)) return;
event.preventDefault(); event.preventDefault();
@@ -86,7 +78,6 @@ const useFileDrop = ({
setDropOverlayState((prev) => ({ ...prev, active: false })); setDropOverlayState((prev) => ({ ...prev, active: false }));
}; };
}, [ }, [
token,
handleFileDrop, handleFileDrop,
currentFolderName, currentFolderName,
defaultFolderName, defaultFolderName,
+4 -4
View File
@@ -1,4 +1,5 @@
import { useState, useCallback } from 'react'; import { useState, useCallback } from 'react';
import { useAppState } from '../lib/store/appState';
import { useStatusToast } from '../lib/context/StatusToastContext'; import { useStatusToast } from '../lib/context/StatusToastContext';
/* global PublicKeyCredentialCreationOptions, CredentialCreationOptions */ /* global PublicKeyCredentialCreationOptions, CredentialCreationOptions */
@@ -69,9 +70,7 @@ type RevokePasskeyResult =
import useNotifyApiError from '../hooks/useNotifyApiError'; import useNotifyApiError from '../hooks/useNotifyApiError';
interface UsePasskeysArgs { interface UsePasskeysArgs { }
token?: string | null;
}
interface UsePasskeysResult { interface UsePasskeysResult {
passkeys: PasskeyRecord[]; passkeys: PasskeyRecord[];
@@ -87,7 +86,8 @@ interface UsePasskeysResult {
) => Promise<RevokePasskeyResult>; ) => Promise<RevokePasskeyResult>;
} }
const usePasskeys = ({ token }: UsePasskeysArgs): UsePasskeysResult => { const usePasskeys = (_: UsePasskeysArgs = {}): UsePasskeysResult => {
const { token } = useAppState();
const [passkeys, setPasskeys] = useState<PasskeyRecord[]>([]); const [passkeys, setPasskeys] = useState<PasskeyRecord[]>([]);
const [passkeysSupported, setPasskeysSupported] = useState<boolean | null>(null); const [passkeysSupported, setPasskeysSupported] = useState<boolean | null>(null);
const [passkeysLoading, setPasskeysLoading] = useState(false); const [passkeysLoading, setPasskeysLoading] = useState(false);