diff --git a/src/data/Model/Organisation.ts b/src/data/Model/Organisation.ts index ac90ca1..706d96c 100644 --- a/src/data/Model/Organisation.ts +++ b/src/data/Model/Organisation.ts @@ -8,12 +8,14 @@ import { SnapshotOptions, QuerySnapshot, where, - Query, query, QueryConstraint, getDoc, doc, limit, + startAfter, + DocumentSnapshot, + getCountFromServer, } from "firebase/firestore"; import { Collections } from "../../services/Firebase/Names"; import { db } from "../../services/Firebase/FirebaseConfig"; @@ -119,16 +121,17 @@ export type OrganisationListingQueryFilters = { export async function getOrganisationsForListingsPage( filters?: OrganisationListingQueryFilters, skipOrgName?: string, - limitNum: number = 0 -): Promise { - console.log( - `Getting organisation with filters: ${JSON.stringify(filters, null, 2)}` - ); - + limitNum: number = 0, + lastVisible?: DocumentSnapshot +): Promise<{ + organisations: Organisation[]; + lastVisible: DocumentSnapshot | null; + totalCount: number; +}> { const queryConstraints: QueryConstraint[] = []; let onlyServicesFilter = false; - if (filters !== undefined) { + if (filters) { if ((filters.specialisations?.length ?? 0) > 10) { return Promise.reject( new RangeError( @@ -170,10 +173,6 @@ export async function getOrganisationsForListingsPage( } if (filters.services !== undefined && !queryConstraints.length) { - // must perform this condition at the end - // current limitation in firestore does not allow the use of - // 'array-contains-any' and 'in' clause in the same query - onlyServicesFilter = true; queryConstraints.push( where("services", "array-contains-any", filters.services) @@ -181,34 +180,46 @@ export async function getOrganisationsForListingsPage( } } - if (limitNum > 0) { - queryConstraints.push(limit(limitNum)); + if (skipOrgName) { + queryConstraints.push(where("name", "!=", skipOrgName)); } - if (skipOrgName !== undefined) { - queryConstraints.push(where("name", "!=", skipOrgName)); + if (lastVisible) { + queryConstraints.push(startAfter(lastVisible)); } - // define the organisation collection reference - const orgsRef: Query = collection( - db, - Collections.organisations - ).withConverter(organisationConverter); - // get organisations with the supplied filters + const orgsRef = collection(db, Collections.organisations).withConverter( + organisationConverter + ); + + // Get total count + const totalCountSnapshot = await getCountFromServer( + query(orgsRef, ...queryConstraints) + ); + const totalCount = totalCountSnapshot.data().count; + + if (limitNum > 0) { + queryConstraints.push(limit(limitNum)); + } + + // Get paginated organisations const querySnapshot: QuerySnapshot = await getDocs( query(orgsRef, ...queryConstraints) ); const orgs: Organisation[] = []; - querySnapshot.forEach((doc) => orgs.push(doc.data())); - - if (filters?.services !== undefined && !onlyServicesFilter) { - return orgs.filter((org) => - org.services.some((s) => filters?.services?.includes(s)) - ); - } + querySnapshot.forEach((doc) => { + orgs.push(doc.data()); + }); - return orgs; + return { + organisations: orgs, + lastVisible: + querySnapshot.docs.length > 0 + ? querySnapshot.docs[querySnapshot.docs.length - 1] + : null, + totalCount: totalCount, + }; } // get an organisation for profile page