mirror of
https://github.com/docmost/docmost.git
synced 2026-08-29 01:37:05 +08:00
feat(bases): auto-fetch next rows when kanban scrolls to its end
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useMemo, useRef } from "react";
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
||||||
import { Badge } from "@mantine/core";
|
import { Badge } from "@mantine/core";
|
||||||
import { IconPlus } from "@tabler/icons-react";
|
import { IconPlus } from "@tabler/icons-react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -30,6 +30,9 @@ type BaseKanbanProps = {
|
|||||||
rows: IBaseRow[];
|
rows: IBaseRow[];
|
||||||
effectiveView: IBaseView | undefined;
|
effectiveView: IBaseView | undefined;
|
||||||
onCardClick: (rowId: string) => void;
|
onCardClick: (rowId: string) => void;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
isFetchingNextPage: boolean;
|
||||||
|
onFetchNextPage: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function BaseKanban({
|
export function BaseKanban({
|
||||||
@@ -37,6 +40,9 @@ export function BaseKanban({
|
|||||||
rows,
|
rows,
|
||||||
effectiveView,
|
effectiveView,
|
||||||
onCardClick,
|
onCardClick,
|
||||||
|
hasNextPage,
|
||||||
|
isFetchingNextPage,
|
||||||
|
onFetchNextPage,
|
||||||
}: BaseKanbanProps) {
|
}: BaseKanbanProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const groupByPropertyId = effectiveView?.config?.groupByPropertyId;
|
const groupByPropertyId = effectiveView?.config?.groupByPropertyId;
|
||||||
@@ -58,6 +64,7 @@ export function BaseKanban({
|
|||||||
const reorderRowMutation = useReorderRowMutation();
|
const reorderRowMutation = useReorderRowMutation();
|
||||||
const sortsActive = (effectiveView?.config?.sorts?.length ?? 0) > 0;
|
const sortsActive = (effectiveView?.config?.sorts?.length ?? 0) > 0;
|
||||||
const boardRef = useRef<HTMLDivElement>(null);
|
const boardRef = useRef<HTMLDivElement>(null);
|
||||||
|
const endRef = useRef<HTMLDivElement>(null);
|
||||||
const canScrollBoard = useCallback(
|
const canScrollBoard = useCallback(
|
||||||
({ source }: { source: { data: Record<string, unknown> } }) =>
|
({ source }: { source: { data: Record<string, unknown> } }) =>
|
||||||
source.data.type === "base-kanban-card" ||
|
source.data.type === "base-kanban-card" ||
|
||||||
@@ -66,6 +73,21 @@ export function BaseKanban({
|
|||||||
);
|
);
|
||||||
useKanbanAutoScroll(boardRef, canScrollBoard);
|
useKanbanAutoScroll(boardRef, canScrollBoard);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasNextPage || isFetchingNextPage) return;
|
||||||
|
const target = endRef.current;
|
||||||
|
const root = boardRef.current;
|
||||||
|
if (!target || !root) return;
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
if (entries.some((e) => e.isIntersecting)) onFetchNextPage();
|
||||||
|
},
|
||||||
|
{ root, threshold: 0.1 },
|
||||||
|
);
|
||||||
|
observer.observe(target);
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [hasNextPage, isFetchingNextPage, onFetchNextPage]);
|
||||||
|
|
||||||
// Rules of Hooks: call useKanbanGroups unconditionally with `undefined`
|
// Rules of Hooks: call useKanbanGroups unconditionally with `undefined`
|
||||||
// when not groupable; switch the render path on isGroupable below.
|
// when not groupable; switch the render path on isGroupable below.
|
||||||
const { columns } = useKanbanGroups(
|
const { columns } = useKanbanGroups(
|
||||||
@@ -276,6 +298,7 @@ export function BaseKanban({
|
|||||||
sortsActive={sortsActive}
|
sortsActive={sortsActive}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
<div ref={endRef} style={{ flex: "0 0 1px" }} aria-hidden />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ export function ViewRenderer(props: ViewRendererProps) {
|
|||||||
rows={props.rows}
|
rows={props.rows}
|
||||||
effectiveView={props.effectiveView}
|
effectiveView={props.effectiveView}
|
||||||
onCardClick={props.onCardClick}
|
onCardClick={props.onCardClick}
|
||||||
|
hasNextPage={props.hasNextPage}
|
||||||
|
isFetchingNextPage={props.isFetchingNextPage}
|
||||||
|
onFetchNextPage={props.onFetchNextPage}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user