fix: fix the scroll infinite in this version
This commit is contained in:
parent
585e66570d
commit
31fa601ab2
|
|
@ -230,7 +230,7 @@ export function DashboardHome() {
|
||||||
style={{ height: `${Math.random() * 80 + 20}%` }}
|
style={{ height: `${Math.random() * 80 + 20}%` }}
|
||||||
></div>
|
></div>
|
||||||
<div
|
<div
|
||||||
className="w-full bg-green-400/30 rounded-t-sm"
|
className="w-full bg-pr-green rounded-t-sm"
|
||||||
style={{ height: `${Math.random() * 80 + 20}%` }}
|
style={{ height: `${Math.random() * 80 + 20}%` }}
|
||||||
></div>
|
></div>
|
||||||
<div
|
<div
|
||||||
|
|
@ -378,7 +378,7 @@ export function DashboardHome() {
|
||||||
gridType="circle"
|
gridType="circle"
|
||||||
radialLines={false}
|
radialLines={false}
|
||||||
stroke="none"
|
stroke="none"
|
||||||
className="first:fill-red-400 last:fill-[#24273A]"
|
className="first:fill-pr-red last:fill-[#24273A]"
|
||||||
polarRadius={[38, 31]}
|
polarRadius={[38, 31]}
|
||||||
/>
|
/>
|
||||||
<RadialBar
|
<RadialBar
|
||||||
|
|
@ -506,7 +506,7 @@ export function DashboardHome() {
|
||||||
gridType="circle"
|
gridType="circle"
|
||||||
radialLines={false}
|
radialLines={false}
|
||||||
stroke="none"
|
stroke="none"
|
||||||
className="first:fill-red-400 last:fill-[#24273A]"
|
className="first:fill-pr-red last:fill-[#24273A]"
|
||||||
polarRadius={[38, 31]}
|
polarRadius={[38, 31]}
|
||||||
/>
|
/>
|
||||||
<RadialBar
|
<RadialBar
|
||||||
|
|
@ -734,7 +734,7 @@ export function DashboardHome() {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-center gap-4">
|
<div className="flex items-center justify-center gap-4">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Book className="w-4 h-4 text-green-400" />
|
<Book className="w-4 h-4 text-pr-green" />
|
||||||
<span className="text-sm">مقاله:</span>
|
<span className="text-sm">مقاله:</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-base font-bold ">
|
<span className="text-base font-bold ">
|
||||||
|
|
@ -791,7 +791,7 @@ export function DashboardHome() {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-center gap-4">
|
<div className="flex items-center justify-center gap-4">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Book className="w-4 h-4 text-green-400" />
|
<Book className="w-4 h-4 text-pr-green" />
|
||||||
<span className="text-sm">برگزاری رویداد:</span>
|
<span className="text-sm">برگزاری رویداد:</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-base font-bold ">
|
<span className="text-base font-bold ">
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,8 @@ export function DigitalInnovationPage() {
|
||||||
// const [avarage, setAvarage] = useState<number>(0);
|
// const [avarage, setAvarage] = useState<number>(0);
|
||||||
const observerRef = useRef<HTMLDivElement>(null);
|
const observerRef = useRef<HTMLDivElement>(null);
|
||||||
const fetchingRef = useRef(false);
|
const fetchingRef = useRef(false);
|
||||||
|
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// Selection handlers
|
// Selection handlers
|
||||||
const handleSelectAll = () => {
|
const handleSelectAll = () => {
|
||||||
|
|
@ -346,10 +348,10 @@ export function DigitalInnovationPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadMore = useCallback(() => {
|
const loadMore = useCallback(() => {
|
||||||
if (hasMore && !loading) {
|
if (hasMore && !loading && !loadingMore && !fetchingRef.current) {
|
||||||
setCurrentPage((prev) => prev + 1);
|
setCurrentPage((prev) => prev + 1);
|
||||||
}
|
}
|
||||||
}, [hasMore, loading]);
|
}, [hasMore, loading, loadingMore]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchTable(true);
|
fetchTable(true);
|
||||||
|
|
@ -363,28 +365,41 @@ export function DigitalInnovationPage() {
|
||||||
}
|
}
|
||||||
}, [currentPage]);
|
}, [currentPage]);
|
||||||
|
|
||||||
|
// Infinite scroll observer with debouncing
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const scrollContainer = document.querySelector(".overflow-auto");
|
const scrollContainer = scrollContainerRef.current;
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
if (!scrollContainer || !hasMore) return;
|
if (!scrollContainer || !hasMore || loadingMore || fetchingRef.current) return;
|
||||||
|
|
||||||
const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
|
// Clear previous timeout
|
||||||
const scrollPercentage = (scrollTop + clientHeight) / scrollHeight;
|
if (scrollTimeoutRef.current) {
|
||||||
|
clearTimeout(scrollTimeoutRef.current);
|
||||||
if (scrollPercentage == 1) {
|
|
||||||
loadMore();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debounce scroll events
|
||||||
|
scrollTimeoutRef.current = setTimeout(() => {
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
|
||||||
|
const scrollPercentage = (scrollTop + clientHeight) / scrollHeight;
|
||||||
|
|
||||||
|
// Trigger load more when scrolled to 95% of the container
|
||||||
|
if (scrollPercentage >= 0.95) {
|
||||||
|
loadMore();
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
scrollContainer.addEventListener("scroll", handleScroll);
|
scrollContainer.addEventListener("scroll", handleScroll, { passive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
scrollContainer.removeEventListener("scroll", handleScroll);
|
scrollContainer.removeEventListener("scroll", handleScroll);
|
||||||
}
|
}
|
||||||
|
if (scrollTimeoutRef.current) {
|
||||||
|
clearTimeout(scrollTimeoutRef.current);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [loadMore, hasMore, loadingMore]);
|
}, [loadMore, hasMore, loadingMore]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,8 @@ export function ManageIdeasTechPage() {
|
||||||
});
|
});
|
||||||
const observerRef = useRef<HTMLDivElement>(null);
|
const observerRef = useRef<HTMLDivElement>(null);
|
||||||
const fetchingRef = useRef(false);
|
const fetchingRef = useRef(false);
|
||||||
|
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const fetchProjects = async (reset = false) => {
|
const fetchProjects = async (reset = false) => {
|
||||||
// Prevent concurrent API calls
|
// Prevent concurrent API calls
|
||||||
|
|
@ -341,10 +343,10 @@ export function ManageIdeasTechPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadMore = useCallback(() => {
|
const loadMore = useCallback(() => {
|
||||||
if (hasMore && !loading) {
|
if (hasMore && !loading && !loadingMore && !fetchingRef.current) {
|
||||||
setCurrentPage((prev) => prev + 1);
|
setCurrentPage((prev) => prev + 1);
|
||||||
}
|
}
|
||||||
}, [hasMore, loading]);
|
}, [hasMore, loading, loadingMore]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchProjects(true);
|
fetchProjects(true);
|
||||||
|
|
@ -357,30 +359,41 @@ export function ManageIdeasTechPage() {
|
||||||
}
|
}
|
||||||
}, [currentPage]);
|
}, [currentPage]);
|
||||||
|
|
||||||
// Infinite scroll observer
|
// Infinite scroll observer with debouncing
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const scrollContainer = document.querySelector(".overflow-auto");
|
const scrollContainer = scrollContainerRef.current;
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
if (!scrollContainer || !hasMore) return;
|
if (!scrollContainer || !hasMore || loadingMore || fetchingRef.current) return;
|
||||||
|
|
||||||
const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
|
// Clear previous timeout
|
||||||
const scrollPercentage = (scrollTop + clientHeight) / scrollHeight;
|
if (scrollTimeoutRef.current) {
|
||||||
|
clearTimeout(scrollTimeoutRef.current);
|
||||||
// Trigger load more when scrolled to 90% of the container
|
|
||||||
if (scrollPercentage == 1) {
|
|
||||||
loadMore();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debounce scroll events
|
||||||
|
scrollTimeoutRef.current = setTimeout(() => {
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
|
||||||
|
const scrollPercentage = (scrollTop + clientHeight) / scrollHeight;
|
||||||
|
|
||||||
|
// Trigger load more when scrolled to 95% of the container
|
||||||
|
if (scrollPercentage >= 0.95) {
|
||||||
|
loadMore();
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
scrollContainer.addEventListener("scroll", handleScroll);
|
scrollContainer.addEventListener("scroll", handleScroll, { passive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
scrollContainer.removeEventListener("scroll", handleScroll);
|
scrollContainer.removeEventListener("scroll", handleScroll);
|
||||||
}
|
}
|
||||||
|
if (scrollTimeoutRef.current) {
|
||||||
|
clearTimeout(scrollTimeoutRef.current);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [loadMore, hasMore, loadingMore]);
|
}, [loadMore, hasMore, loadingMore]);
|
||||||
|
|
||||||
|
|
@ -656,7 +669,7 @@ export function ManageIdeasTechPage() {
|
||||||
<Card className="bg-transparent backdrop-blur-sm rounded-2xl overflow-hidden">
|
<Card className="bg-transparent backdrop-blur-sm rounded-2xl overflow-hidden">
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Table containerClassName="overflow-auto custom-scrollbar max-h-[calc(100vh-200px)]">
|
<Table containerRef={scrollContainerRef} containerClassName="overflow-auto custom-scrollbar max-h-[calc(100vh-200px)]">
|
||||||
<TableHeader className="sticky top-0 z-50 bg-muted">
|
<TableHeader className="sticky top-0 z-50 bg-muted">
|
||||||
<TableRow className="bg-muted">
|
<TableRow className="bg-muted">
|
||||||
{columns.map((column) => (
|
{columns.map((column) => (
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,8 @@ export function ProjectManagementPage() {
|
||||||
});
|
});
|
||||||
const observerRef = useRef<HTMLDivElement>(null);
|
const observerRef = useRef<HTMLDivElement>(null);
|
||||||
const fetchingRef = useRef(false);
|
const fetchingRef = useRef(false);
|
||||||
|
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const fetchProjects = async (reset = false) => {
|
const fetchProjects = async (reset = false) => {
|
||||||
// Prevent concurrent API calls
|
// Prevent concurrent API calls
|
||||||
|
|
@ -264,10 +266,10 @@ export function ProjectManagementPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadMore = useCallback(() => {
|
const loadMore = useCallback(() => {
|
||||||
if (hasMore && !loading) {
|
if (hasMore && !loading && !loadingMore && !fetchingRef.current) {
|
||||||
setCurrentPage((prev) => prev + 1);
|
setCurrentPage((prev) => prev + 1);
|
||||||
}
|
}
|
||||||
}, [hasMore, loading]);
|
}, [hasMore, loading, loadingMore]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchProjects(true);
|
fetchProjects(true);
|
||||||
|
|
@ -280,29 +282,43 @@ export function ProjectManagementPage() {
|
||||||
}
|
}
|
||||||
}, [currentPage]);
|
}, [currentPage]);
|
||||||
|
|
||||||
// Infinite scroll observer
|
// Infinite scroll observer with debouncing
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const scrollContainer = document.querySelector(".overflow-auto");
|
const scrollContainer = scrollContainerRef.current;
|
||||||
const handleScroll = () => {
|
|
||||||
if (!scrollContainer || !hasMore) return;
|
|
||||||
|
|
||||||
const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
|
const handleScroll = () => {
|
||||||
const scrollPercentage = (scrollTop + clientHeight) / scrollHeight;
|
if (!scrollContainer || !hasMore || loadingMore || fetchingRef.current) return;
|
||||||
// Trigger load more when scrolled to 90% of the container
|
|
||||||
if (scrollPercentage == 1 || scrollPercentage == .9) {
|
// Clear previous timeout
|
||||||
loadMore();
|
if (scrollTimeoutRef.current) {
|
||||||
|
clearTimeout(scrollTimeoutRef.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debounce scroll events
|
||||||
|
scrollTimeoutRef.current = setTimeout(() => {
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
|
||||||
|
const scrollPercentage = (scrollTop + clientHeight) / scrollHeight;
|
||||||
|
|
||||||
|
// Trigger load more when scrolled to 95% of the container
|
||||||
|
if (scrollPercentage >= 0.95) {
|
||||||
|
loadMore();
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
scrollContainer.addEventListener("scroll", handleScroll);
|
scrollContainer.addEventListener("scroll", handleScroll, { passive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
scrollContainer.removeEventListener("scroll", handleScroll);
|
scrollContainer.removeEventListener("scroll", handleScroll);
|
||||||
}
|
}
|
||||||
|
if (scrollTimeoutRef.current) {
|
||||||
|
clearTimeout(scrollTimeoutRef.current);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [loadMore, hasMore]);
|
}, [loadMore, hasMore, loadingMore]);
|
||||||
|
|
||||||
const handleSort = (field: string) => {
|
const handleSort = (field: string) => {
|
||||||
fetchingRef.current = false; // Reset fetching state on sort
|
fetchingRef.current = false; // Reset fetching state on sort
|
||||||
|
|
@ -754,7 +770,7 @@ export function ProjectManagementPage() {
|
||||||
<Card className="bg-transparent backdrop-blur-sm rounded-2xl overflow-hidden">
|
<Card className="bg-transparent backdrop-blur-sm rounded-2xl overflow-hidden">
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="relative overflow-auto custom-scrollbar max-h-[calc(100vh-120px)]">
|
<div ref={scrollContainerRef} className="relative overflow-auto custom-scrollbar max-h-[calc(100vh-120px)]">
|
||||||
<Table className="table-fixed">
|
<Table className="table-fixed">
|
||||||
<TableHeader className="sticky top-0 z-50 bg-[#3F415A]">
|
<TableHeader className="sticky top-0 z-50 bg-[#3F415A]">
|
||||||
<TableRow className="bg-[#3F415A]">
|
<TableRow className="bg-[#3F415A]">
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,11 @@ const Progress = React.forwardRef<
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<span className="left-0 text-sm absolute z-10 px-2 text-[#5F6284]">۰%</span>
|
<span className="left-0 text-sm absolute z-10 px-2 text-[#5F6284]">۰%</span>
|
||||||
<span className="w-full text-sm absolute z-10 px-2 text-[#5F6284]"
|
<span className="w-full right-0 text-sm absolute z-10 px-2 text-[#5F6284]"
|
||||||
style={{ transform: `translateX(-${10 - (value || 0)}%)` }}
|
|
||||||
>{formatNumber(Math.ceil(value || 0 * 10) / 10)}%</span>
|
>{formatNumber(Math.ceil(value || 0 * 10) / 10)}%</span>
|
||||||
<span className="right-0 text-sm absolute z-10 px-2 text-[#5F6284]">{formatNumber(.2)}%</span>
|
|
||||||
<ProgressPrimitive.Indicator
|
<ProgressPrimitive.Indicator
|
||||||
className="h-full w-full flex-1 bg-primary transition-all"
|
className="h-full w-full flex-1 bg-primary transition-all"
|
||||||
style={{ transform: `translateX(-${20 - (value || 0)}%)` }}
|
style={{ transform: `translateX(-${15 - (value || 0)}%)` }}
|
||||||
/>
|
/>
|
||||||
</ProgressPrimitive.Root>
|
</ProgressPrimitive.Root>
|
||||||
))
|
))
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ import { cn } from "~/lib/utils"
|
||||||
|
|
||||||
interface TableProps extends React.HTMLAttributes<HTMLTableElement> {
|
interface TableProps extends React.HTMLAttributes<HTMLTableElement> {
|
||||||
containerClassName?: string
|
containerClassName?: string
|
||||||
|
containerRef?: React.RefObject<HTMLDivElement>
|
||||||
}
|
}
|
||||||
|
|
||||||
const Table = React.forwardRef<HTMLTableElement, TableProps>(
|
const Table = React.forwardRef<HTMLTableElement, TableProps>(
|
||||||
({ className, containerClassName, ...props }, ref) => (
|
({ className, containerClassName, containerRef, ...props }, ref) => (
|
||||||
<div className={cn("relative w-full", containerClassName)}>
|
<div ref={containerRef} className={cn("relative w-full", containerClassName)}>
|
||||||
<table
|
<table
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("w-full caption-bottom text-sm h-full", className)}
|
className={cn("w-full caption-bottom text-sm h-full", className)}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user