prefetch history

This commit is contained in:
Philipinho
2026-01-31 23:33:25 +00:00
parent 718ca2b674
commit 4873f7b9ff
2 changed files with 68 additions and 12 deletions
@@ -3,18 +3,40 @@ import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
import { formattedDate } from "@/lib/time"; import { formattedDate } from "@/lib/time";
import classes from "./history.module.css"; import classes from "./history.module.css";
import clsx from "clsx"; import clsx from "clsx";
import { IPageHistory } from "@/features/page-history/types/page.types";
import { memo, useCallback } from "react";
interface HistoryItemProps { interface HistoryItemProps {
historyItem: any; historyItem: IPageHistory;
onSelect: (id: string) => void; index: number;
onSelect: (id: string, index: number) => void;
onHover?: (id: string) => void;
onHoverEnd?: () => void;
isActive: boolean; 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 ( return (
<UnstyledButton <UnstyledButton
p="xs" p="xs"
onClick={() => onSelect(historyItem.id)} onClick={handleClick}
onMouseEnter={handleMouseEnter}
onMouseLeave={onHoverEnd}
className={clsx(classes.history, { [classes.active]: isActive })} className={clsx(classes.history, { [classes.active]: isActive })}
> >
<Group wrap="nowrap"> <Group wrap="nowrap">
@@ -27,11 +49,11 @@ function HistoryItem({ historyItem, onSelect, isActive }: HistoryItemProps) {
<Group gap={4} wrap="nowrap"> <Group gap={4} wrap="nowrap">
<CustomAvatar <CustomAvatar
size="sm" size="sm"
avatarUrl={historyItem.lastUpdatedBy.avatarUrl} avatarUrl={historyItem.lastUpdatedBy?.avatarUrl}
name={historyItem.lastUpdatedBy.name} name={historyItem.lastUpdatedBy?.name}
/> />
<Text size="sm" c="dimmed" lineClamp={1}> <Text size="sm" c="dimmed" lineClamp={1}>
{historyItem.lastUpdatedBy.name} {historyItem.lastUpdatedBy?.name}
</Text> </Text>
</Group> </Group>
</div> </div>
@@ -39,6 +61,6 @@ function HistoryItem({ historyItem, onSelect, isActive }: HistoryItemProps) {
</Group> </Group>
</UnstyledButton> </UnstyledButton>
); );
} });
export default HistoryItem; export default HistoryItem;
@@ -2,6 +2,8 @@ import {
usePageHistoryListQuery, usePageHistoryListQuery,
usePageHistoryQuery, usePageHistoryQuery,
} from "@/features/page-history/queries/page-history-query"; } 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 HistoryItem from "@/features/page-history/components/history-item";
import { import {
activeHistoryIdAtom, activeHistoryIdAtom,
@@ -34,6 +36,8 @@ import {
SpaceCaslSubject, SpaceCaslSubject,
} from "@/features/space/permissions/permissions.type.ts"; } from "@/features/space/permissions/permissions.type.ts";
const PREFETCH_DELAY_MS = 300;
interface Props { interface Props {
pageId: string; pageId: string;
} }
@@ -58,6 +62,7 @@ function HistoryList({ pageId }: Props) {
); );
const loadMoreRef = useRef<HTMLDivElement>(null); const loadMoreRef = useRef<HTMLDivElement>(null);
const prefetchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const [mainEditor] = useAtom(pageEditorAtom); const [mainEditor] = useAtom(pageEditorAtom);
const [mainEditorTitle] = useAtom(titleEditorAtom); const [mainEditorTitle] = useAtom(titleEditorAtom);
@@ -99,6 +104,35 @@ function HistoryList({ pageId }: Props) {
} }
}, [activeHistoryData]); }, [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(() => { useEffect(() => {
if (historyItems.length > 0 && !activeHistoryId) { if (historyItems.length > 0 && !activeHistoryId) {
setActiveHistoryId(historyItems[0].id); setActiveHistoryId(historyItems[0].id);
@@ -142,10 +176,10 @@ function HistoryList({ pageId }: Props) {
<HistoryItem <HistoryItem
key={historyItem.id} key={historyItem.id}
historyItem={historyItem} historyItem={historyItem}
onSelect={(id) => { index={index}
setActiveHistoryId(id); onSelect={handleSelect}
setActiveHistoryPrevId(historyItems[index + 1]?.id ?? ""); onHover={handleHover}
}} onHoverEnd={clearPrefetchTimeout}
isActive={historyItem.id === activeHistoryId} isActive={historyItem.id === activeHistoryId}
/> />
))} ))}