From 36b861266f7c43927e4a99557aeb23bb94db578e Mon Sep 17 00:00:00 2001 From: Tiago Ribeiro Date: Thu, 18 Apr 2024 16:03:09 +0100 Subject: [PATCH] ENCOA-18: Improve the loading of the company names on the Group and Users lists --- src/pages/(admin)/Lists/GroupList.tsx | 26 ++++++++++++------ src/pages/(admin)/Lists/UserList.tsx | 24 ++++++++++------- src/pages/api/users/[id].ts | 29 ++++++++++++++++++++ src/utils/groups.ts | 39 +++++++++++++++++++-------- 4 files changed, 90 insertions(+), 28 deletions(-) create mode 100644 src/pages/api/users/[id].ts diff --git a/src/pages/(admin)/Lists/GroupList.tsx b/src/pages/(admin)/Lists/GroupList.tsx index 855e68ad..5e28543d 100644 --- a/src/pages/(admin)/Lists/GroupList.tsx +++ b/src/pages/(admin)/Lists/GroupList.tsx @@ -14,20 +14,30 @@ import {toast} from "react-toastify"; import readXlsxFile from "read-excel-file"; import {useFilePicker} from "use-file-picker"; import {getUserCorporate} from "@/utils/groups"; +import { isAgentUser, isCorporateUser } from "@/resources/user"; const columnHelper = createColumnHelper(); const EMAIL_REGEX = new RegExp(/^[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*@[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*$/); -const LinkedCorporate = ({userId}: {userId: string}) => { +const LinkedCorporate = ({userId, users, groups}: {userId: string, users: User[], groups: Group[]}) => { const [companyName, setCompanyName] = useState(""); const [isLoading, setIsLoading] = useState(false); - useEffect(() => { - setIsLoading(true); - getUserCorporate(userId) - .then((result) => setCompanyName(result?.corporateInformation?.companyInformation?.name || "")) - .finally(() => setIsLoading(false)); - }, [userId]); + useEffect(() => { + const user = users.find((u) => u.id === userId) + if (!user) return setCompanyName("") + + if (isCorporateUser(user)) return setCompanyName(user.corporateInformation?.companyInformation?.name || user.name) + if (isAgentUser(user)) return setCompanyName(user.agentInformation?.companyName || user.name) + + const belongingGroups = groups.filter((x) => x.participants.includes(userId)) + const belongingGroupsAdmins = belongingGroups.map((x) => users.find((u) => u.id === x.admin)).filter((x) => !!x && isCorporateUser(x)) + + if (belongingGroupsAdmins.length === 0) return setCompanyName("") + + const admin = (belongingGroupsAdmins[0] as CorporateUser) + setCompanyName(admin.corporateInformation?.companyInformation.name || admin.name) + }, [userId, users, groups]); return isLoading ? Loading... : <>{companyName}; }; @@ -224,7 +234,7 @@ export default function GroupList({user}: {user: User}) { }), columnHelper.accessor("admin", { header: "Linked Corporate", - cell: (info) => , + cell: (info) => , }), columnHelper.accessor("participants", { header: "Participants", diff --git a/src/pages/(admin)/Lists/UserList.tsx b/src/pages/(admin)/Lists/UserList.tsx index ee8e6bb4..c163187d 100644 --- a/src/pages/(admin)/Lists/UserList.tsx +++ b/src/pages/(admin)/Lists/UserList.tsx @@ -2,7 +2,7 @@ import Button from "@/components/Low/Button"; import {PERMISSIONS} from "@/constants/userPermissions"; import useGroups from "@/hooks/useGroups"; import useUsers from "@/hooks/useUsers"; -import {Type, User, userTypes, CorporateUser} from "@/interfaces/user"; +import {Type, User, userTypes, CorporateUser, Group} from "@/interfaces/user"; import {Popover, Transition} from "@headlessui/react"; import {createColumnHelper, flexRender, getCoreRowModel, useReactTable} from "@tanstack/react-table"; import axios from "axios"; @@ -44,16 +44,22 @@ const getCompanyName = async (user: User) => { return ""; }; -const CompanyNameCell = (user: User) => { +const CompanyNameCell = ({users, user, groups}: {user: User, users: User[], groups: Group[]}) => { const [companyName, setCompanyName] = useState(""); const [isLoading, setIsLoading] = useState(false); - useEffect(() => { - setIsLoading(true); - getCompanyName(user) - .then((result) => setCompanyName(result)) - .finally(() => setIsLoading(false)); - }, [user]); + useEffect(() => { + if (isCorporateUser(user)) return setCompanyName(user.corporateInformation?.companyInformation?.name || user.name) + if (isAgentUser(user)) return setCompanyName(user.agentInformation?.companyName || user.name) + + const belongingGroups = groups.filter((x) => x.participants.includes(user.id)) + const belongingGroupsAdmins = belongingGroups.map((x) => users.find((u) => u.id === x.admin)).filter((x) => !!x && isCorporateUser(x)) + + if (belongingGroupsAdmins.length === 0) return setCompanyName("") + + const admin = (belongingGroupsAdmins[0] as CorporateUser) + setCompanyName(admin.corporateInformation?.companyInformation.name || admin.name) + }, [user, users, groups]); return isLoading ? Loading... : <>{companyName}; }; @@ -372,7 +378,7 @@ export default function UserList({user, filters = []}: {user: User; filters?: (( ) as any, - cell: (info) => , + cell: (info) => , }), columnHelper.accessor("subscriptionExpirationDate", { header: ( diff --git a/src/pages/api/users/[id].ts b/src/pages/api/users/[id].ts new file mode 100644 index 00000000..5b663616 --- /dev/null +++ b/src/pages/api/users/[id].ts @@ -0,0 +1,29 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from "next"; +import { app } from "@/firebase"; +import { + getFirestore, + collection, + getDocs, + getDoc, + doc, +} from "firebase/firestore"; +import { withIronSessionApiRoute } from "iron-session/next"; +import { sessionOptions } from "@/lib/session"; + +const db = getFirestore(app); + +export default withIronSessionApiRoute(handler, sessionOptions); + +async function handler(req: NextApiRequest, res: NextApiResponse) { + if (!req.session.user) { + res.status(401).json({ ok: false }); + return; + } + + const { id } = req.query as { id: string }; + const snapshot = await getDoc(doc(db, "users", id)); + if (!snapshot.exists()) return res.status(404).json({ ok: false }); + + res.status(200).json({ ...snapshot.data(), id: snapshot.id }); +} diff --git a/src/utils/groups.ts b/src/utils/groups.ts index 6b96380c..0c2ca04b 100644 --- a/src/utils/groups.ts +++ b/src/utils/groups.ts @@ -1,20 +1,37 @@ -import {CorporateUser, Group, User} from "@/interfaces/user"; +import { CorporateUser, Group, User } from "@/interfaces/user"; import axios from "axios"; export const isUserFromCorporate = async (userID: string) => { - const groups = (await axios.get(`/api/groups?participant=${userID}`)).data; - const users = (await axios.get("/api/users/list")).data; + const groups = (await axios.get(`/api/groups?participant=${userID}`)) + .data; + const users = (await axios.get("/api/users/list")).data; - const adminTypes = groups.map((g) => users.find((u) => u.id === g.admin)?.type); - return adminTypes.includes("corporate"); + const adminTypes = groups.map( + (g) => users.find((u) => u.id === g.admin)?.type, + ); + return adminTypes.includes("corporate"); }; -export const getUserCorporate = async (userID: string) => { - const users = (await axios.get("/api/users/list")).data; - if (users.find((u) => u.id === userID)?.type === "corporate") return users.find((u) => u.id === userID) as CorporateUser; +export const getUserCorporate = async ( + userID: string, +): Promise => { + const userRequest = await axios.get(`/api/users/${userID}`); + if (userRequest.status === 200) { + const user = userRequest.data; + if (user.type === "corporate") return user; + } - const groups = (await axios.get(`/api/groups?participant=${userID}`)).data; + const groups = (await axios.get(`/api/groups?participant=${userID}`)) + .data; - const admins = groups.map((g) => users.find((u) => u.id === g.admin)).filter((x) => x?.type === "corporate"); - return admins.length > 0 ? (admins[0] as CorporateUser) : undefined; + const adminRequests = await Promise.all( + groups.map(async (g) => { + const userRequest = await axios.get(`/api/users/${g.admin}`); + if (userRequest.status === 200) return userRequest.data; + return undefined; + }), + ); + + const admins = adminRequests.filter((x) => x?.type === "corporate"); + return admins.length > 0 ? (admins[0] as CorporateUser) : undefined; };