From 6bac49a3d11ece5ea70dbec4607de752fd52d920 Mon Sep 17 00:00:00 2001 From: Tomin Date: Tue, 29 Oct 2024 17:11:58 -0500 Subject: [PATCH 1/2] Lazy load --- components/Users.jsx | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/components/Users.jsx b/components/Users.jsx index 91c9a5c..8f048f4 100644 --- a/components/Users.jsx +++ b/components/Users.jsx @@ -12,7 +12,10 @@ import { where, addDoc, arrayUnion, -} from 'firebase/firestore' + startAfter, + limit, +} +from 'firebase/firestore' import { db, auth } from '../config/firebase' import { Tooltip } from 'react-tooltip' import { IoTrash } from 'react-icons/io5' @@ -102,11 +105,15 @@ const Users = () => { setIsLoading(true); try { + const lastDoc = loadedMobileUsers[loadedMobileUsers.length - 1]; + const lastDocRef = doc(db, 'mobileUsers', lastDoc.mobileUserId); + const lastDocSnap = await getDoc(lastDocRef); + const mobileUsersQuerySnapshot = await getDocs( query( collection(db, 'mobileUsers'), - limit(pageSize), - startAfter(page * pageSize) + startAfter(lastDocSnap), + limit(pageSize) ) ); @@ -125,7 +132,7 @@ const Users = () => { } setLoadedMobileUsers((prevUsers) => [...prevUsers, ...newUsers]); - setPage((prevPage) => prevPage + 1); + setEndIndex((prevEndIndex) => prevEndIndex + newUsers.length); } catch (error) { console.error('Failed to fetch more user data:', error); } finally { @@ -170,6 +177,9 @@ const Users = () => { const [newUserEmail, setNewUserEmail] = useState('') const [errors, setErrors] = useState({}) + + + /** * Fetches all agency documents from the Firestore 'agency' collection * and stores them in an array with their ID and name. @@ -885,7 +895,7 @@ const Users = () => {
Date: Tue, 12 Nov 2024 15:41:46 -0600 Subject: [PATCH 2/2] Added lazy load for user list. Does not work for list > 500 --- components/Users.jsx | 146 ++++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 58 deletions(-) diff --git a/components/Users.jsx b/components/Users.jsx index 8f048f4..b3511c8 100644 --- a/components/Users.jsx +++ b/components/Users.jsx @@ -12,10 +12,9 @@ import { where, addDoc, arrayUnion, + limit, startAfter, - limit, -} -from 'firebase/firestore' +} from 'firebase/firestore' import { db, auth } from '../config/firebase' import { Tooltip } from 'react-tooltip' import { IoTrash } from 'react-icons/io5' @@ -96,49 +95,6 @@ const sortByJoinedDate = (users) => { const Users = () => { // Initialize authentication context - const [hasMore, setHasMore] = useState(true); - const [page, setPage] = useState(0); - const pageSize = 10; - - const fetchMoreData = async () => { - if (isLoading) return; - - setIsLoading(true); - try { - const lastDoc = loadedMobileUsers[loadedMobileUsers.length - 1]; - const lastDocRef = doc(db, 'mobileUsers', lastDoc.mobileUserId); - const lastDocSnap = await getDoc(lastDocRef); - - const mobileUsersQuerySnapshot = await getDocs( - query( - collection(db, 'mobileUsers'), - startAfter(lastDocSnap), - limit(pageSize) - ) - ); - - const newUsers = await Promise.all( - mobileUsersQuerySnapshot.docs.map(async (doc) => { - const userData = doc.data(); - userData.mobileUserId = doc.id; - userData.disabled = await fetchUserDetails(doc.id); - userData.joined = getJoinedDate(userData, null); - return userData; - }) - ); - - if (newUsers.length < pageSize) { - setHasMore(false); - } - - setLoadedMobileUsers((prevUsers) => [...prevUsers, ...newUsers]); - setEndIndex((prevEndIndex) => prevEndIndex + newUsers.length); - } catch (error) { - console.error('Failed to fetch more user data:', error); - } finally { - setIsLoading(false); - } - }; const { user, addAdminRole, @@ -176,9 +132,8 @@ const Users = () => { }) const [newUserEmail, setNewUserEmail] = useState('') const [errors, setErrors] = useState({}) - - - + const [lastVisible, setLastVisible] = useState(null); // the last document fetched + const [hasMore, setHasMore] = useState(true); // to track if more users are available to load /** * Fetches all agency documents from the Firestore 'agency' collection @@ -368,6 +323,81 @@ const Users = () => { } } + const USERS_PER_PAGE = 10; // Number of users to fetch per page + +const getInitialUsers = async () => { + setIsLoading(true); + const userQuery = query( + collection(db, 'mobileUsers'), + limit(USERS_PER_PAGE) + ); + + try { + const querySnapshot = await getDocs(userQuery); + const users = querySnapshot.docs.map(doc => ({ + mobileUserId: doc.id, + ...doc.data(), + })); + + setLoadedMobileUsers(users); + + // Set the last visible document for pagination + const lastVisibleDoc = querySnapshot.docs[querySnapshot.docs.length - 1]; + setLastVisible(lastVisibleDoc); + + // If less than USERS_PER_PAGE were fetched, no more users are available + if (querySnapshot.docs.length < USERS_PER_PAGE) { + setHasMore(false); + } + + setIsLoading(false); + } catch (error) { + console.error("Error fetching users:", error); + setIsLoading(false); + } +}; + +useEffect(() => { + getInitialUsers(); // Fetch users when the component mounts +}, []); + +const fetchMoreUsers = async () => { + if (!lastVisible || !hasMore || isLoading) return; // Prevent fetching if already loading or no more users + + setIsLoading(true); + + const nextUserQuery = query( + collection(db, 'mobileUsers'), + startAfter(lastVisible), // Start after the last loaded document + limit(USERS_PER_PAGE) + ); + + try { + const querySnapshot = await getDocs(nextUserQuery); + const users = querySnapshot.docs.map(doc => ({ + mobileUserId: doc.id, + ...doc.data(), + })); + + // Append newly loaded users to the existing list + setLoadedMobileUsers((prevUsers) => [...prevUsers, ...users]); + + // Update the last visible document for the next batch + const lastVisibleDoc = querySnapshot.docs[querySnapshot.docs.length - 1]; + setLastVisible(lastVisibleDoc); + + // If less than USERS_PER_PAGE were fetched, no more users are available + if (querySnapshot.docs.length < USERS_PER_PAGE) { + setHasMore(false); + } + + setIsLoading(false); + } catch (error) { + console.error("Error fetching more users:", error); + setIsLoading(false); + } +}; + /** * Handles the event when the "Add New User" button is clicked, opening the modal to add a new user. * @@ -893,16 +923,16 @@ const Users = () => { )}
- +Loading more users...} // Loader for when more users are being fetched + scrollableTarget="scrollableDiv" // The target div that is scrollable +> - + @@ -1090,4 +1120,4 @@ const Users = () => { ) } -export default Users +export default Users \ No newline at end of file
Name