From b9490a53acc23c18255f0c7b145139490fb3a969 Mon Sep 17 00:00:00 2001
From: Richard R
Date: Thu, 28 May 2026 09:15:18 -0600
Subject: [PATCH] refactor(doclist): remove loading state and unify navigation
prefetch behavior
Eliminate unused loading state and related effects from document tile and list
row components. Standardize navigation by disabling prefetch on all document
open links in doclist views for consistent client-side routing. Cache
document list state on load to improve state restoration and initialization.
---
src/components/doclist/DocumentList.tsx | 38 ++++++++++++++-----
src/components/doclist/views/ColumnsView.tsx | 6 ++-
src/components/doclist/views/DocumentTile.tsx | 17 ++-------
src/components/doclist/views/GalleryView.tsx | 4 +-
src/components/doclist/views/ListView.tsx | 16 ++------
5 files changed, 42 insertions(+), 39 deletions(-)
diff --git a/src/components/doclist/DocumentList.tsx b/src/components/doclist/DocumentList.tsx
index 5d9118a..2233e90 100644
--- a/src/components/doclist/DocumentList.tsx
+++ b/src/components/doclist/DocumentList.tsx
@@ -36,6 +36,8 @@ import { ListView } from './views/ListView';
import { ColumnsView } from './views/ColumnsView';
import { GalleryView } from './views/GalleryView';
+let cachedDocumentListState: DocumentListState | null = null;
+
type DocumentToDelete = {
id: string;
name: string;
@@ -116,22 +118,25 @@ interface DocumentListInnerProps {
}
function DocumentListInner({ brand, appActions }: DocumentListInnerProps) {
- const [sortBy, setSortBy] = useState(DEFAULT_STATE.sortBy);
+ const cachedState = cachedDocumentListState;
+ const [sortBy, setSortBy] = useState(cachedState?.sortBy ?? DEFAULT_STATE.sortBy);
const [sortDirection, setSortDirection] = useState(
- DEFAULT_STATE.sortDirection,
+ cachedState?.sortDirection ?? DEFAULT_STATE.sortDirection,
);
- const [viewMode, setViewMode] = useState(DEFAULT_STATE.viewMode);
- const [iconSize, setIconSize] = useState(DEFAULT_STATE.iconSize);
- const [folders, setFolders] = useState(DEFAULT_STATE.folders);
- const [showHint, setShowHint] = useState(true);
- const [sidebarWidth, setSidebarWidth] = useState(DEFAULT_STATE.sidebarWidth);
- const [sidebarFilter, setSidebarFilter] = useState('all');
- const [sidebarOpen, setSidebarOpen] = useState(true);
+ const [viewMode, setViewMode] = useState(
+ normalizeViewMode(cachedState?.viewMode ?? DEFAULT_STATE.viewMode),
+ );
+ const [iconSize, setIconSize] = useState(cachedState?.iconSize ?? DEFAULT_STATE.iconSize);
+ const [folders, setFolders] = useState(cachedState?.folders ?? DEFAULT_STATE.folders);
+ const [showHint, setShowHint] = useState(cachedState?.showHint ?? true);
+ const [sidebarWidth, setSidebarWidth] = useState(cachedState?.sidebarWidth ?? DEFAULT_STATE.sidebarWidth);
+ const [sidebarFilter, setSidebarFilter] = useState(cachedState?.sidebarFilter ?? 'all');
+ const [sidebarOpen, setSidebarOpen] = useState(!(cachedState?.sidebarCollapsed ?? false));
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
const [query, setQuery] = useState('');
const [recentlyOpenedById, setRecentlyOpenedById] = useState>({});
- const [isInitialized, setIsInitialized] = useState(false);
+ const [isInitialized, setIsInitialized] = useState(cachedState !== null);
const [documentToDelete, setDocumentToDelete] = useState(null);
const [pendingMerge, setPendingMerge] = useState<
@@ -164,6 +169,7 @@ function DocumentListInner({ brand, appActions }: DocumentListInnerProps) {
const saved = await getDocumentListState();
if (cancelled) return;
if (saved) {
+ cachedDocumentListState = saved;
setSortBy(saved.sortBy);
setSortDirection(saved.sortDirection);
setFolders(saved.folders ?? []);
@@ -173,6 +179,17 @@ function DocumentListInner({ brand, appActions }: DocumentListInnerProps) {
setSidebarWidth(saved.sidebarWidth ?? DEFAULT_STATE.sidebarWidth);
setSidebarFilter(saved.sidebarFilter ?? 'all');
setSidebarOpen(!(saved.sidebarCollapsed ?? false));
+ } else {
+ cachedDocumentListState = null;
+ setSortBy(DEFAULT_STATE.sortBy);
+ setSortDirection(DEFAULT_STATE.sortDirection);
+ setFolders(DEFAULT_STATE.folders);
+ setShowHint(DEFAULT_STATE.showHint);
+ setViewMode(DEFAULT_STATE.viewMode);
+ setIconSize(DEFAULT_STATE.iconSize);
+ setSidebarWidth(DEFAULT_STATE.sidebarWidth);
+ setSidebarFilter(DEFAULT_STATE.sidebarFilter);
+ setSidebarOpen(!DEFAULT_STATE.sidebarCollapsed);
}
setIsInitialized(true);
})();
@@ -196,6 +213,7 @@ function DocumentListInner({ brand, appActions }: DocumentListInnerProps) {
sidebarFilter,
sidebarCollapsed: !sidebarOpen,
};
+ cachedDocumentListState = state;
void saveDocumentListState(state);
}, [
sortBy,
diff --git a/src/components/doclist/views/ColumnsView.tsx b/src/components/doclist/views/ColumnsView.tsx
index 4c1ba9c..922c07a 100644
--- a/src/components/doclist/views/ColumnsView.tsx
+++ b/src/components/doclist/views/ColumnsView.tsx
@@ -102,6 +102,9 @@ export function ColumnsView({
}: ColumnsViewProps) {
const { setVisibleOrder } = useDocumentSelection();
const [selectedDoc, setSelectedDoc] = useState(null);
+ const openHref = selectedDoc
+ ? `/${selectedDoc.type}/${encodeURIComponent(selectedDoc.id)}`
+ : null;
useEffect(() => {
setVisibleOrder(documents);
@@ -154,7 +157,8 @@ export function ColumnsView({
Open
diff --git a/src/components/doclist/views/DocumentTile.tsx b/src/components/doclist/views/DocumentTile.tsx
index 4263a86..832612d 100644
--- a/src/components/doclist/views/DocumentTile.tsx
+++ b/src/components/doclist/views/DocumentTile.tsx
@@ -1,7 +1,6 @@
'use client';
import Link from 'next/link';
-import { useEffect, useState } from 'react';
import { useDrag, useDrop, type DragSourceMonitor } from 'react-dnd';
import { Button } from '@headlessui/react';
import { PDFIcon, EPUBIcon, FileIcon } from '@/components/icons/Icons';
@@ -70,7 +69,6 @@ export function DocumentTile({
onDelete,
onMergeIntoFolder,
}: DocumentTileProps) {
- const [loading, setLoading] = useState(false);
const { authEnabled } = useAuthConfig();
const { data: session } = useAuthSession();
const href = `/${doc.type}/${encodeURIComponent(doc.id)}`;
@@ -136,19 +134,9 @@ export function DocumentTile({
if (e.shiftKey || e.metaKey || e.ctrlKey) {
e.preventDefault();
selection.select(doc, { shift: e.shiftKey, meta: e.metaKey || e.ctrlKey });
- return;
}
- selection.replace([doc]);
- setLoading(true);
};
- // Cap any stuck loading flag if the user navigates back.
- useEffect(() => {
- if (!loading) return;
- const t = setTimeout(() => setLoading(false), 2500);
- return () => clearTimeout(t);
- }, [loading]);
-
return (
(null);
const [activeIdx, setActiveIdx] = useState(0);
const activeDoc = useMemo(() => documents[activeIdx], [documents, activeIdx]);
+ const openHref = activeDoc ? `/${activeDoc.type}/${encodeURIComponent(activeDoc.id)}` : null;
useEffect(() => {
setVisibleOrder(documents);
@@ -163,7 +164,8 @@ export function GalleryView({
Open
diff --git a/src/components/doclist/views/ListView.tsx b/src/components/doclist/views/ListView.tsx
index 89870d2..3b08d2c 100644
--- a/src/components/doclist/views/ListView.tsx
+++ b/src/components/doclist/views/ListView.tsx
@@ -1,7 +1,7 @@
'use client';
import Link from 'next/link';
-import { useEffect, useState } from 'react';
+import { useEffect } from 'react';
import { useDrag, useDrop } from 'react-dnd';
import { Button } from '@headlessui/react';
import type {
@@ -87,7 +87,6 @@ function DocRow({
const selection = useDocumentSelection();
const isSelected = selection.isSelected(doc);
const isInFolder = Boolean(doc.folderId);
- const [loading, setLoading] = useState(false);
const href = `/${doc.type}/${encodeURIComponent(doc.id)}`;
const [{ isDragging }, dragRef] = useDrag(() => ({
@@ -117,22 +116,13 @@ function DocRow({
dropRef(node);
};
- useEffect(() => {
- if (!loading) return;
- const t = setTimeout(() => setLoading(false), 2500);
- return () => clearTimeout(t);
- }, [loading]);
-
const isTarget = isOver && canDrop;
const handleClick: React.MouseEventHandler = (e) => {
if (e.shiftKey || e.metaKey || e.ctrlKey) {
e.preventDefault();
selection.select(doc, { shift: e.shiftKey, meta: e.metaKey || e.ctrlKey });
- return;
}
- selection.replace([doc]);
- setLoading(true);
};
return (
@@ -146,12 +136,12 @@ function DocRow({
? 'bg-offbase text-accent'
: 'text-foreground hover:bg-offbase') +
(isTarget ? ' ring-1 ring-accent ring-inset' : '') +
- (isDragging ? ' opacity-50' : '') +
- (loading ? ' prism-outline' : '')
+ (isDragging ? ' opacity-50' : '')
}
>