From 710fe641e2a5864125bf8875c17e351d15da5000 Mon Sep 17 00:00:00 2001 From: bu3alwa <3469062+bu3alwa@users.noreply.github.com> Date: Tue, 20 Aug 2024 20:52:53 -0400 Subject: [PATCH] refactor activity page to use react query requests Co-authored-by: Bill Thornton --- CONTRIBUTORS.md | 1 + src/apps/dashboard/routes/activity.tsx | 96 +++++++++----------------- src/hooks/useLogEntries.tsx | 33 +++++++++ src/hooks/useUsers.tsx | 31 +++++++++ 4 files changed, 98 insertions(+), 63 deletions(-) create mode 100644 src/hooks/useLogEntries.tsx create mode 100644 src/hooks/useUsers.tsx diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ca76b38eab..4e5e14b873 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -92,6 +92,7 @@ - [Venkat Karasani](https://github.com/venkat-karasani) - [Connor Smith](https://github.com/ConnorS1110) - [iFraan](https://github.com/iFraan) +- [Ali](https://github.com/bu3alwa) ## Emby Contributors diff --git a/src/apps/dashboard/routes/activity.tsx b/src/apps/dashboard/routes/activity.tsx index 36ceee215d..ec2cbe47a0 100644 --- a/src/apps/dashboard/routes/activity.tsx +++ b/src/apps/dashboard/routes/activity.tsx @@ -1,6 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react'; -import { getActivityLogApi } from '@jellyfin/sdk/lib/utils/api/activity-log-api'; -import { getUserApi } from '@jellyfin/sdk/lib/utils/api/user-api'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import type { ActivityLogEntry } from '@jellyfin/sdk/lib/generated-client/models/activity-log-entry'; import type { UserDto } from '@jellyfin/sdk/lib/generated-client/models/user-dto'; import PermMedia from '@mui/icons-material/PermMedia'; @@ -14,7 +12,8 @@ import { Link, useSearchParams } from 'react-router-dom'; import Page from 'components/Page'; import UserAvatar from 'components/UserAvatar'; -import { useApi } from 'hooks/useApi'; +import { useLogEntires } from 'hooks/useLogEntries'; +import { useUsers } from 'hooks/useUsers'; import { parseISO8601Date, toLocaleDateString, toLocaleTimeString } from 'scripts/datetime'; import globalize from 'lib/globalize'; import { toBoolean } from 'utils/string'; @@ -41,19 +40,42 @@ const getActivityView = (param: string | null) => { const getRowId = (row: ActivityLogEntry) => row.Id ?? -1; const Activity = () => { - const { api } = useApi(); const [ searchParams, setSearchParams ] = useSearchParams(); const [ activityView, setActivityView ] = useState( getActivityView(searchParams.get(VIEW_PARAM))); - const [ isLoading, setIsLoading ] = useState(true); + const [ paginationModel, setPaginationModel ] = useState({ page: 0, pageSize: DEFAULT_PAGE_SIZE }); - const [ rowCount, setRowCount ] = useState(0); - const [ rows, setRows ] = useState([]); - const [ users, setUsers ] = useState>({}); + + const { data: usersData, isLoading: isUsersLoading } = useUsers(); + + type UsersRecords = Record; + const users: UsersRecords = useMemo(() => { + if (!usersData) return {}; + + return usersData.reduce((acc, user) => { + const userId = user.Id; + if (!userId) return acc; + + return { + ...acc, + [userId]: user + }; + }, {}); + }, [usersData]); + + const activityParams = useMemo(() => ({ + startIndex: paginationModel.page * paginationModel.pageSize, + limit: paginationModel.pageSize, + hasUserId: activityView !== ActivityView.All ? activityView === ActivityView.User : undefined + }), [activityView, paginationModel.page, paginationModel.pageSize]); + + const { data: logEntries, isLoading: isLogEntriesLoading } = useLogEntires(activityParams); + + const isLoading = isUsersLoading || isLogEntriesLoading; const userColDef: GridColDef[] = activityView !== ActivityView.System ? [ { @@ -153,58 +175,6 @@ const Activity = () => { } }, []); - useEffect(() => { - if (api) { - const fetchUsers = async () => { - const { data } = await getUserApi(api).getUsers(); - const usersById: Record = {}; - data.forEach(user => { - if (user.Id) { - usersById[user.Id] = user; - } - }); - - setUsers(usersById); - }; - - fetchUsers() - .catch(err => { - console.error('[activity] failed to fetch users', err); - }); - } - }, [ api ]); - - useEffect(() => { - if (api) { - const fetchActivity = async () => { - const params: { - startIndex: number, - limit: number, - hasUserId?: boolean - } = { - startIndex: paginationModel.page * paginationModel.pageSize, - limit: paginationModel.pageSize - }; - if (activityView !== ActivityView.All) { - params.hasUserId = activityView === ActivityView.User; - } - - const { data } = await getActivityLogApi(api) - .getLogEntries(params); - - setRowCount(data.TotalRecordCount ?? 0); - setRows(data.Items ?? []); - setIsLoading(false); - }; - - setIsLoading(true); - fetchActivity() - .catch(err => { - console.error('[activity] failed to fetch activity log entries', err); - }); - } - }, [ activityView, api, paginationModel ]); - useEffect(() => { const currentViewParam = getActivityView(searchParams.get(VIEW_PARAM)); if (currentViewParam !== activityView) { @@ -254,12 +224,12 @@ const Activity = () => { { + const { api } = currentApi; + + if (!api) return; + + const response = await getActivityLogApi(api).getLogEntries(requestParams, { + signal: options?.signal + }); + + return response.data; +}; + +export const useLogEntires = ( + requestParams: ActivityLogApiGetLogEntriesRequest +) => { + const currentApi = useApi(); + return useQuery({ + queryKey: ['LogEntries', requestParams], + queryFn: ({ signal }) => + fetchGetLogEntries(currentApi, requestParams, { signal }) + }); +}; diff --git a/src/hooks/useUsers.tsx b/src/hooks/useUsers.tsx new file mode 100644 index 0000000000..0a49c76d71 --- /dev/null +++ b/src/hooks/useUsers.tsx @@ -0,0 +1,31 @@ +import type { AxiosRequestConfig } from 'axios'; +import type { UserApiGetUsersRequest } from '@jellyfin/sdk/lib/generated-client'; +import { getUserApi } from '@jellyfin/sdk/lib/utils/api/user-api'; +import { useQuery } from '@tanstack/react-query'; + +import { type JellyfinApiContext, useApi } from './useApi'; + +export const fetchGetUsers = async ( + currentApi: JellyfinApiContext, + requestParams?: UserApiGetUsersRequest, + options?: AxiosRequestConfig +) => { + const { api } = currentApi; + + if (!api) return; + + const response = await getUserApi(api).getUsers(requestParams, { + signal: options?.signal + }); + + return response.data; +}; + +export const useUsers = (requestParams?: UserApiGetUsersRequest) => { + const currentApi = useApi(); + return useQuery({ + queryKey: ['Users'], + queryFn: ({ signal }) => + fetchGetUsers(currentApi, requestParams, { signal }) + }); +};