From 2156ca5751d04ffa1763ebc6954f86adb447abf9 Mon Sep 17 00:00:00 2001 From: yosuva Rajendran Date: Thu, 28 Nov 2024 15:33:21 +0530 Subject: [PATCH] fix/performance-issues: home page api changes --- app/actions/members.actions.ts | 46 +++++++ app/actions/teams.actions.ts | 3 +- app/members/page.tsx | 10 +- app/page.tsx | 1 + .../page/members/member-infinite-list.tsx | 9 +- .../page/members/member-list-wrapper.tsx | 47 ------- components/page/members/members-list.tsx | 118 ------------------ components/page/teams/team-list.tsx | 6 +- services/home.service.ts | 6 +- services/members.service.ts | 44 +------ services/projects.service.ts | 2 +- services/teams.service.ts | 4 +- utils/constants.ts | 2 +- 13 files changed, 69 insertions(+), 229 deletions(-) delete mode 100644 components/page/members/member-list-wrapper.tsx delete mode 100644 components/page/members/members-list.tsx diff --git a/app/actions/members.actions.ts b/app/actions/members.actions.ts index e69de29b..d9f0d463 100644 --- a/app/actions/members.actions.ts +++ b/app/actions/members.actions.ts @@ -0,0 +1,46 @@ +'use server' + +import { IMemberListOptions } from "@/types/members.types"; +import { getHeader } from "@/utils/common.utils"; + +export const getMemberListForQuery = async (options: IMemberListOptions, currentPage: number, limit: number, authToken?: string) => { + const response = await fetch(`${process.env.DIRECTORY_API_URL}/v1/members?page=${currentPage}&limit=${limit}${options ? '&' + new URLSearchParams(options as any) : ''}`, { + cache: 'force-cache', + method: 'GET', + next: { tags: ['member-list'] }, + headers: getHeader(authToken?? ''), + }); + + if(!response.ok){ + return { isError: true, error: { status: response.status, statusText: response.statusText } }; + } + const result = await response.json(); + const formattedMembers: any = result?.members?.map((member: any) => { + const teams = member?.teamMemberRoles?.map((teamMemberRole: any) => ({ + id: teamMemberRole.team?.uid || '', + name: teamMemberRole.team?.name || '', + role: teamMemberRole.role || 'Contributor', + teamLead: !!teamMemberRole.teamLead, + mainTeam: !!teamMemberRole.mainTeam, + })) || []; + const mainTeam = teams.find((team: any) => team.mainTeam); + const teamLead = teams.some((team: any) => team.teamLead); + return { + id: member.uid, + name: member.name, + profile: member.image?.url || null, + officeHours: member.officeHours || null, + skills: member.skills || [], + teams, + location: member?.location, + mainTeam, + teamLead, + openToWork: member.openToWork || false, + } + }) + return { + total: result?.count, + items: formattedMembers, + }; + } + \ No newline at end of file diff --git a/app/actions/teams.actions.ts b/app/actions/teams.actions.ts index b8f72d49..729c09d6 100644 --- a/app/actions/teams.actions.ts +++ b/app/actions/teams.actions.ts @@ -2,10 +2,11 @@ import { ITeamResponse } from "@/types/teams.types"; import { getHeader } from "@/utils/common.utils"; +import { ITEMS_PER_PAGE } from "@/utils/constants"; const teamsAPI = `${process.env.DIRECTORY_API_URL}/v1/teams`; -export const getTeamList = async (queryParams: any, currentPage = 1, limit = 50) => { +export const getTeamList = async (queryParams: any, currentPage = 1, limit = ITEMS_PER_PAGE) => { const requestOptions: RequestInit = { method: 'GET', headers: getHeader(''), cache: 'force-cache', next: { tags: ['team-list'] } }; const response = await fetch(`${teamsAPI}?page=${currentPage}&limit=${limit}&${new URLSearchParams(queryParams)}`, requestOptions); const result = await response.json(); diff --git a/app/members/page.tsx b/app/members/page.tsx index 0ca858d0..b05e4dd9 100644 --- a/app/members/page.tsx +++ b/app/members/page.tsx @@ -2,16 +2,16 @@ import { getCookiesFromHeaders } from '@/utils/next-helpers'; import styles from './page.module.css'; import { IMember, IMembersSearchParams } from '@/types/members.types'; import { IUserInfo } from '@/types/shared.types'; -import { getFormattedFilters, getMembersListOptions, getMembersOptionsFromQuery, getRoleTagsFromValues, parseMemberFilters } from '@/utils/member.utils'; -import { getFilterValuesForQuery, getMemberListForQuery, getMemberRoles, getMembersFilters } from '@/services/members.service'; +import { getFormattedFilters, getMembersListOptions, getMembersOptionsFromQuery, getRoleTagsFromValues } from '@/utils/member.utils'; +import { getFilterValuesForQuery, getMemberRoles, } from '@/services/members.service'; import Error from '@/components/core/error'; import MembersToolbar from '@/components/page/members/members-toolbar'; import FilterWrapper from '@/components/page/members/filter-wrapper'; import EmptyResult from '@/components/core/empty-result'; -import MemberListWrapper from '@/components/page/members/member-list-wrapper'; import { Metadata } from 'next'; -import { SOCIAL_IMAGE_URL } from '@/utils/constants'; +import { ITEMS_PER_PAGE, SOCIAL_IMAGE_URL } from '@/utils/constants'; import MemberInfiniteList from '@/components/page/members/member-infinite-list'; +import { getMemberListForQuery } from '../actions/members.actions'; async function Page({ searchParams }: { searchParams: IMembersSearchParams }) { const { userInfo } = getCookiesFromHeaders(); @@ -59,7 +59,7 @@ const getPageData = async (searchParams: IMembersSearchParams) => { const [rawFilterValues, availableFilters, memberList, memberRoles] = await Promise.all([ getFilterValuesForQuery(null, authToken), getFilterValuesForQuery(filtersFromQueryParams, authToken), - getMemberListForQuery(memberFilterQuery, 1, 6, authToken), + getMemberListForQuery(memberFilterQuery, 1, ITEMS_PER_PAGE, authToken), getMemberRoles(filtersFromQueryParams) ]); diff --git a/app/page.tsx b/app/page.tsx index 9affa6dc..85a3cd26 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -87,6 +87,7 @@ const getPageData = async () => { discoverData } } catch (error) { + console.log(error) isError = true; return { isError, diff --git a/components/page/members/member-infinite-list.tsx b/components/page/members/member-infinite-list.tsx index 050f73de..87b69e23 100644 --- a/components/page/members/member-infinite-list.tsx +++ b/components/page/members/member-infinite-list.tsx @@ -1,7 +1,6 @@ 'use client'; -import { PAGE_ROUTES, TOAST_MESSAGES, VIEW_TYPE_OPTIONS } from '@/utils/constants'; -import MembersList from './members-list'; +import { ITEMS_PER_PAGE, PAGE_ROUTES, TOAST_MESSAGES, VIEW_TYPE_OPTIONS } from '@/utils/constants'; import MemberGridView from './member-grid-view'; import MemberListView from './member-list-view'; import { IMember, IMemberListOptions } from '@/types/members.types'; @@ -10,10 +9,10 @@ import { useMemberAnalytics } from '@/analytics/members.analytics'; import Link from 'next/link'; import usePagination from '@/hooks/irl/use-pagination'; import { useEffect, useRef, useState } from 'react'; -import { getMemberListForQuery } from '@/services/members.service'; import { getMembersListOptions, getMembersOptionsFromQuery } from '@/utils/member.utils'; import cookies from 'js-cookie'; import TableLoader from '@/components/core/table-loader'; +import { getMemberListForQuery } from '@/app/actions/members.actions'; const MemberInfiniteList = (props: any) => { const members = props?.members ?? []; @@ -47,7 +46,7 @@ const MemberInfiniteList = (props: any) => { const authToken = cookies.get('authToken'); const optionsFromQuery = getMembersOptionsFromQuery(searchParams); const listOptions: IMemberListOptions = getMembersListOptions(optionsFromQuery); - const teamsRes = await getMemberListForQuery(listOptions, currentPage, 6, authToken); + const teamsRes = await getMemberListForQuery(listOptions, currentPage, ITEMS_PER_PAGE, authToken); if (teamsRes.isError) { setIsLoading(false); toast.error(TOAST_MESSAGES.SOMETHING_WENT_WRONG); @@ -75,7 +74,7 @@ const MemberInfiniteList = (props: any) => { // Sync team list useEffect(() => { - setPagination({ page: 1, limit: 6 }); + setPagination({ page: 1, limit: ITEMS_PER_PAGE}); setUserList({ users: members, totalItems: totalItems }); }, [members]); diff --git a/components/page/members/member-list-wrapper.tsx b/components/page/members/member-list-wrapper.tsx deleted file mode 100644 index acf21cc4..00000000 --- a/components/page/members/member-list-wrapper.tsx +++ /dev/null @@ -1,47 +0,0 @@ -'use client'; - -import { PAGE_ROUTES, VIEW_TYPE_OPTIONS } from '@/utils/constants'; -import MembersList from './members-list'; -import MemberGridView from './member-grid-view'; -import MemberListView from './member-list-view'; -import { IMember } from '@/types/members.types'; -import { getAnalyticsMemberInfo, getAnalyticsUserInfo, triggerLoader } from '@/utils/common.utils'; -import { useMemberAnalytics } from '@/analytics/members.analytics'; -import Link from 'next/link'; - -const MemberListWrapper = (props: any) => { - const isUserLoggedIn = props?.isUserLoggedIn; - const searchParams = props?.searchParams; - const viewType = searchParams['viewType'] || VIEW_TYPE_OPTIONS.GRID; - const members = props?.members ?? []; - const userInfo = props?.userInfo; - - const analytics = useMemberAnalytics(); - - const onMemberOnClickHandler = (e: any, member: IMember) => { - if (!e.ctrlKey) { - triggerLoader(true); - } - analytics.onMemberCardClicked(getAnalyticsUserInfo(userInfo), getAnalyticsMemberInfo(member), viewType); - // router.push(`${PAGE_ROUTES.MEMBERS}/${id}`, {scroll: false}) - }; - - return ( - - {members?.map((member: any, index: number) => ( - onMemberOnClickHandler(e, member)} - // scroll={false} - > - {VIEW_TYPE_OPTIONS.GRID === viewType && } - {VIEW_TYPE_OPTIONS.LIST === viewType && } - - ))} - - ); -}; - -export default MemberListWrapper; diff --git a/components/page/members/members-list.tsx b/components/page/members/members-list.tsx deleted file mode 100644 index 6d60b0fb..00000000 --- a/components/page/members/members-list.tsx +++ /dev/null @@ -1,118 +0,0 @@ -'use client'; - -import { IMember, IMembersSearchParams } from '@/types/members.types'; -import { IUserInfo } from '@/types/shared.types'; -import { useRef } from 'react'; -import usePagination from '@/hooks/usePagination'; -import { VIEW_TYPE_OPTIONS } from '@/utils/constants'; - -interface IMembersList { - members: IMember[]; - totalMembers: number; - searchParams: IMembersSearchParams; - isUserLoggedIn: boolean | undefined; - userInfo: IUserInfo | undefined; - children: any; -} -const MembersList = (props: IMembersList) => { - const searchParams = props?.searchParams; - const viewType = searchParams['viewType'] || VIEW_TYPE_OPTIONS.GRID; - const observerTarget = useRef(null); - const children = props?.children; - const totalItems = children?.length; - - const [visibleItems] = usePagination({ - items: children, - observerTarget, - }); - - return ( -
-
-

Members

({totalItems})
-
-
- {visibleItems} -
-
- -
- ); -}; - -export default MembersList; diff --git a/components/page/teams/team-list.tsx b/components/page/teams/team-list.tsx index b5686475..46a5ba53 100644 --- a/components/page/teams/team-list.tsx +++ b/components/page/teams/team-list.tsx @@ -1,7 +1,7 @@ 'use client'; import { ITeam, ITeamListOptions, ITeamsSearchParams } from '@/types/teams.types'; -import { PAGE_ROUTES, TOAST_MESSAGES, VIEW_TYPE_OPTIONS } from '@/utils/constants'; +import { ITEMS_PER_PAGE, PAGE_ROUTES, TOAST_MESSAGES, VIEW_TYPE_OPTIONS } from '@/utils/constants'; import { useEffect, useRef, useState } from 'react'; import { getAnalyticsTeamInfo, getAnalyticsUserInfo, triggerLoader } from '@/utils/common.utils'; import TeamGridView from './team-grid-view'; @@ -43,7 +43,7 @@ const TeamList = (props: any) => { setIsLoading(true); const optionsFromQuery = getTeamsOptionsFromQuery(searchParams); const listOptions: ITeamListOptions = getTeamsListOptions(optionsFromQuery); - const teamsRes = await getTeamList(listOptions, currentPage, 50); + const teamsRes = await getTeamList(listOptions, currentPage); if (teamsRes.isError) { setIsLoading(false); toast.error(TOAST_MESSAGES.SOMETHING_WENT_WRONG); @@ -77,7 +77,7 @@ const TeamList = (props: any) => { // Sync team list useEffect(() => { - setPagination({ page: 1, limit: 50 }); + setPagination({ page: 1, limit: ITEMS_PER_PAGE }); setTeamList({ teams: allTeams, totalTeams: totalTeams }); }, [allTeams]); diff --git a/services/home.service.ts b/services/home.service.ts index b9984f98..5880e473 100644 --- a/services/home.service.ts +++ b/services/home.service.ts @@ -13,10 +13,10 @@ export const getFeaturedData = async () => { const result = await response.json(); - const formattedMembers = getformattedMembers(result?.members || []); - const formattedTeams = getFormattedTeams(result?.teams || []); + const formattedMembers = getformattedMembers(result?.members?.members || []); + const formattedTeams = getFormattedTeams(result?.teams?.teams || []); const formattedEvents = getFormattedEvents(result?.events || []); - const formattedProjects = getFormattedProjects(result.projects || []); + const formattedProjects = getFormattedProjects(result.projects?.projects || []); const maxLength = Math.max(formattedMembers.length, formattedTeams.length, formattedEvents.length, formattedProjects.length); diff --git a/services/members.service.ts b/services/members.service.ts index 5b545f24..3eb2832d 100644 --- a/services/members.service.ts +++ b/services/members.service.ts @@ -8,7 +8,7 @@ export const getFilterValuesForQuery = async (options?: IMemberListOptions | nul const response = await fetch(`${process.env.DIRECTORY_API_URL}/v1/members/filters${options? '?': ''}${options ? new URLSearchParams(options as any) : ''}`, { cache: 'force-cache', method: 'GET', - next: { tags: ['members-filters'] }, + next: { tags: ['member-filters'] }, headers: getHeader(authToken?? ''), }); @@ -19,48 +19,6 @@ export const getFilterValuesForQuery = async (options?: IMemberListOptions | nul return result; } -export const getMemberListForQuery = async (options: IMemberListOptions, currentPage: number, limit: number, authToken?: string) => { - const response = await fetch(`${process.env.DIRECTORY_API_URL}/v1/members?page=${currentPage}&limit=${limit}${options ? '&' + new URLSearchParams(options as any) : ''}`, { - cache: 'force-cache', - method: 'GET', - next: { tags: ['members-list'] }, - headers: getHeader(authToken?? ''), - }); - - if(!response.ok){ - return { isError: true, error: { status: response.status, statusText: response.statusText } }; - } - const result = await response.json(); - const formattedMembers: any = result?.members?.map((member: any) => { - const teams = member?.teamMemberRoles?.map((teamMemberRole: any) => ({ - id: teamMemberRole.team?.uid || '', - name: teamMemberRole.team?.name || '', - role: teamMemberRole.role || 'Contributor', - teamLead: !!teamMemberRole.teamLead, - mainTeam: !!teamMemberRole.mainTeam, - })) || []; - const mainTeam = teams.find((team: any) => team.mainTeam); - const teamLead = teams.some((team: any) => team.teamLead); - return { - id: member.uid, - name: member.name, - profile: member.image?.url || null, - officeHours: member.officeHours || null, - skills: member.skills || [], - teams, - location: member?.location, - mainTeam, - teamLead, - openToWork: member.openToWork || false, - } - }) - return { - total: result?.count, - items: formattedMembers, - }; -} - - export const getMembers = async (options: IMemberListOptions, teamId: string, currentPage: number, limit: number, isLoggedIn: boolean) => { const response = await fetch(`${process.env.DIRECTORY_API_URL}/v1/members?page=${currentPage}&limit=${limit}&${new URLSearchParams(options as any)}`, { cache: 'no-store', diff --git a/services/projects.service.ts b/services/projects.service.ts index afc14668..303efb86 100644 --- a/services/projects.service.ts +++ b/services/projects.service.ts @@ -1,4 +1,4 @@ -import { getHeader, getSortFromQuery, stringifyQueryValues } from "@/utils/common.utils" +import { getHeader} from "@/utils/common.utils" export const getProject = async (id: string, options: any) => { diff --git a/services/teams.service.ts b/services/teams.service.ts index 4e8ef3f2..8b5fdba4 100644 --- a/services/teams.service.ts +++ b/services/teams.service.ts @@ -14,7 +14,7 @@ export const getTeamListFilters = async (options: any) => { headers: getHeader(''), cache: 'force-cache', next: { - tags: ['teams-filters'], + tags: ['team-filters'], }, }; @@ -29,7 +29,7 @@ export const getTeamListFilters = async (options: any) => { }; export const getAllTeams = async (authToken: string, queryParams: any, currentPage: number, limit: number) => { - const requestOPtions: RequestInit = { method: 'GET', headers: getHeader(authToken), cache: 'force-cache', next: { tags: ['teams-list'] } }; + const requestOPtions: RequestInit = { method: 'GET', headers: getHeader(authToken), cache: 'no-cache' }; const response = await fetch(`${teamsAPI}?page=${currentPage}&limit=${limit}&${new URLSearchParams(queryParams)}`, requestOPtions); const result = await response.json(); if (!response?.ok) { diff --git a/utils/constants.ts b/utils/constants.ts index d6497f20..12e4319a 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -371,7 +371,7 @@ export const FOCUS_AREAS_FILTER_KEYS = { teams: 'teamAncestorFocusAreas', }; -export const ITEMS_PER_PAGE = 50; +export const ITEMS_PER_PAGE = 25; export const ENROLLMENT_TYPE = { MEMBER: 'MEMBER',