From 4873f7b9ff3f986cb2fbe07921560bca10fe7f84 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Sat, 31 Jan 2026 23:33:25 +0000
Subject: [PATCH] prefetch history
---
.../page-history/components/history-item.tsx | 38 +++++++++++++----
.../page-history/components/history-list.tsx | 42 +++++++++++++++++--
2 files changed, 68 insertions(+), 12 deletions(-)
diff --git a/apps/client/src/features/page-history/components/history-item.tsx b/apps/client/src/features/page-history/components/history-item.tsx
index eb348bd6..bd48e501 100644
--- a/apps/client/src/features/page-history/components/history-item.tsx
+++ b/apps/client/src/features/page-history/components/history-item.tsx
@@ -3,18 +3,40 @@ import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
import { formattedDate } from "@/lib/time";
import classes from "./history.module.css";
import clsx from "clsx";
+import { IPageHistory } from "@/features/page-history/types/page.types";
+import { memo, useCallback } from "react";
interface HistoryItemProps {
- historyItem: any;
- onSelect: (id: string) => void;
+ historyItem: IPageHistory;
+ index: number;
+ onSelect: (id: string, index: number) => void;
+ onHover?: (id: string) => void;
+ onHoverEnd?: () => void;
isActive: boolean;
}
-function HistoryItem({ historyItem, onSelect, isActive }: HistoryItemProps) {
+const HistoryItem = memo(function HistoryItem({
+ historyItem,
+ index,
+ onSelect,
+ onHover,
+ onHoverEnd,
+ isActive,
+}: HistoryItemProps) {
+ const handleClick = useCallback(() => {
+ onSelect(historyItem.id, index);
+ }, [onSelect, historyItem.id, index]);
+
+ const handleMouseEnter = useCallback(() => {
+ onHover?.(historyItem.id);
+ }, [onHover, historyItem.id]);
+
return (
onSelect(historyItem.id)}
+ onClick={handleClick}
+ onMouseEnter={handleMouseEnter}
+ onMouseLeave={onHoverEnd}
className={clsx(classes.history, { [classes.active]: isActive })}
>
@@ -27,11 +49,11 @@ function HistoryItem({ historyItem, onSelect, isActive }: HistoryItemProps) {
- {historyItem.lastUpdatedBy.name}
+ {historyItem.lastUpdatedBy?.name}
@@ -39,6 +61,6 @@ function HistoryItem({ historyItem, onSelect, isActive }: HistoryItemProps) {
);
-}
+});
export default HistoryItem;
diff --git a/apps/client/src/features/page-history/components/history-list.tsx b/apps/client/src/features/page-history/components/history-list.tsx
index b4a674c3..08f7c37f 100644
--- a/apps/client/src/features/page-history/components/history-list.tsx
+++ b/apps/client/src/features/page-history/components/history-list.tsx
@@ -2,6 +2,8 @@ import {
usePageHistoryListQuery,
usePageHistoryQuery,
} from "@/features/page-history/queries/page-history-query";
+import { getPageHistoryById } from "@/features/page-history/services/page-history-service";
+import { queryClient } from "@/main";
import HistoryItem from "@/features/page-history/components/history-item";
import {
activeHistoryIdAtom,
@@ -34,6 +36,8 @@ import {
SpaceCaslSubject,
} from "@/features/space/permissions/permissions.type.ts";
+const PREFETCH_DELAY_MS = 300;
+
interface Props {
pageId: string;
}
@@ -58,6 +62,7 @@ function HistoryList({ pageId }: Props) {
);
const loadMoreRef = useRef(null);
+ const prefetchTimeoutRef = useRef | null>(null);
const [mainEditor] = useAtom(pageEditorAtom);
const [mainEditorTitle] = useAtom(titleEditorAtom);
@@ -99,6 +104,35 @@ function HistoryList({ pageId }: Props) {
}
}, [activeHistoryData]);
+ const clearPrefetchTimeout = useCallback(() => {
+ if (prefetchTimeoutRef.current) {
+ clearTimeout(prefetchTimeoutRef.current);
+ prefetchTimeoutRef.current = null;
+ }
+ }, []);
+
+ const handleHover = useCallback((historyId: string) => {
+ clearPrefetchTimeout();
+ prefetchTimeoutRef.current = setTimeout(() => {
+ queryClient.prefetchQuery({
+ queryKey: ["page-history", historyId],
+ queryFn: () => getPageHistoryById(historyId),
+ });
+ }, PREFETCH_DELAY_MS);
+ }, [clearPrefetchTimeout]);
+
+ useEffect(() => {
+ return clearPrefetchTimeout;
+ }, [clearPrefetchTimeout]);
+
+ const handleSelect = useCallback(
+ (id: string, index: number) => {
+ setActiveHistoryId(id);
+ setActiveHistoryPrevId(historyItems[index + 1]?.id ?? "");
+ },
+ [historyItems, setActiveHistoryId, setActiveHistoryPrevId],
+ );
+
useEffect(() => {
if (historyItems.length > 0 && !activeHistoryId) {
setActiveHistoryId(historyItems[0].id);
@@ -142,10 +176,10 @@ function HistoryList({ pageId }: Props) {
{
- setActiveHistoryId(id);
- setActiveHistoryPrevId(historyItems[index + 1]?.id ?? "");
- }}
+ index={index}
+ onSelect={handleSelect}
+ onHover={handleHover}
+ onHoverEnd={clearPrefetchTimeout}
isActive={historyItem.id === activeHistoryId}
/>
))}