diff --git a/src/apps/copilots/src/pages/copilot-requests/CopilotRequestsPage.module.scss b/src/apps/copilots/src/pages/copilot-requests/CopilotRequestsPage.module.scss index 8c5108caa..43f1e21e2 100644 --- a/src/apps/copilots/src/pages/copilot-requests/CopilotRequestsPage.module.scss +++ b/src/apps/copilots/src/pages/copilot-requests/CopilotRequestsPage.module.scss @@ -7,6 +7,10 @@ padding: $sp-2 0; } +.title { + max-width: 200px; +} + @media (max-width: 767px) { .title { min-width: 200px; diff --git a/src/apps/copilots/src/pages/copilot-requests/index.tsx b/src/apps/copilots/src/pages/copilot-requests/index.tsx index 1f4cc6f64..2bc53f485 100644 --- a/src/apps/copilots/src/pages/copilot-requests/index.tsx +++ b/src/apps/copilots/src/pages/copilot-requests/index.tsx @@ -1,4 +1,4 @@ -import { FC, useCallback, useContext, useMemo } from 'react' +import { FC, useCallback, useContext, useMemo, useState } from 'react' import { find } from 'lodash' import { NavigateFunction, Params, useNavigate, useParams } from 'react-router-dom' import classNames from 'classnames' @@ -18,6 +18,7 @@ import { } from '~/libs/ui' import { profileContext, ProfileContextData, UserRole } from '~/libs/core' import { EnvironmentConfig } from '~/config' +import { Sort } from '~/apps/admin/src/platform/gamification-admin/src/game-lib' import { ProjectTypeLabels } from '../../constants' import { approveCopilotRequest, CopilotRequestsResponse, useCopilotRequests } from '../../services/copilot-requests' @@ -136,6 +137,10 @@ const CopilotTableActions: FC<{request: CopilotRequest}> = props => { const CopilotRequestsPage: FC = () => { const navigate: NavigateFunction = useNavigate() const routeParams: Params = useParams() + const [sort, setSort] = useState({ + direction: 'desc', + fieldName: 'createdAt', + }) const { profile }: ProfileContextData = useContext(profileContext) const isAdminOrPM: boolean = useMemo( @@ -148,7 +153,7 @@ const CopilotRequestsPage: FC = () => { isValidating: requestsLoading, hasMoreCopilotRequests, setSize, - size }: CopilotRequestsResponse = useCopilotRequests() + size }: CopilotRequestsResponse = useCopilotRequests(sort) const viewRequestDetails = useMemo(() => ( routeParams.requestId && find(requests, { id: +routeParams.requestId }) as CopilotRequest @@ -195,7 +200,7 @@ const CopilotRequestsPage: FC = () => { }, { label: 'Type', - propertyName: 'type', + propertyName: 'projectType', type: 'text', }, { @@ -227,13 +232,17 @@ const CopilotRequestsPage: FC = () => { const tableData = useMemo(() => requests.map(request => ({ ...request, projectName: request.project?.name, - type: ProjectTypeLabels[request.projectType] ?? '', + projectType: ProjectTypeLabels[request.projectType] ?? '', })), [requests]) function loadMore(): void { setSize(size + 1) } + function onToggleSort(s: Sort): void { + setSort(s) + } + // header button config const addNewRequestButton: ButtonProps = { label: 'New Copilot Request', @@ -260,6 +269,7 @@ const CopilotRequestsPage: FC = () => { data={tableData} moreToLoad={hasMoreCopilotRequests} onLoadMoreClick={loadMore} + onToggleSort={onToggleSort} /> {requestsLoading && } {viewRequestDetails && ( diff --git a/src/apps/copilots/src/services/copilot-requests.ts b/src/apps/copilots/src/services/copilot-requests.ts index 56af61630..a1b725b9d 100644 --- a/src/apps/copilots/src/services/copilot-requests.ts +++ b/src/apps/copilots/src/services/copilot-requests.ts @@ -4,6 +4,8 @@ import useSWRInfinite, { SWRInfiniteResponse } from 'swr/infinite' import { EnvironmentConfig } from '~/config' import { xhrGetAsync, xhrPatchAsync, xhrPostAsync } from '~/libs/core' import { buildUrl } from '~/libs/shared/lib/utils/url' +import { Sort } from '~/apps/admin/src/platform/gamification-admin/src/game-lib' +import { getPaginatedAsync, PaginatedResponse } from '~/libs/core/lib/xhr/xhr-functions/xhr.functions' import { CopilotRequest } from '../models/CopilotRequest' @@ -43,32 +45,37 @@ export type CopilotRequestsResponse = { * @param {string} [projectId] - Optional project ID to fetch copilot requests for a specific project. * @returns {CopilotRequestsResponse} - The response containing copilot requests. */ -export const useCopilotRequests = (projectId?: string): CopilotRequestsResponse => { +export const useCopilotRequests = (sort: Sort, projectId?: string): CopilotRequestsResponse => { + const getKey = (pageIndex: number, previousPageData: CopilotRequest[]): string | undefined => { if (previousPageData && previousPageData.length < PAGE_SIZE) return undefined const url = buildUrl(`${baseUrl}${projectId ? `/${projectId}` : ''}/copilots/requests`) return ` - ${url}?page=${pageIndex + 1}&pageSize=${PAGE_SIZE}&sort=createdAt desc + ${url}?page=${pageIndex + 1}&pageSize=${PAGE_SIZE}&sort=${sort.fieldName} ${sort.direction} ` } - const fetcher = (url: string): Promise => xhrGetAsync(url) - .then((data: any) => data.map(copilotRequestFactory)) + const fetcher = ( + url: string, + ): Promise> => getPaginatedAsync(url) + .then((data: any) => ( + { + ...data, + data: data.data.map(copilotRequestFactory), + } + )) const { isValidating, data = [], size, setSize, - }: SWRInfiniteResponse = useSWRInfinite(getKey, fetcher, { + }: SWRInfiniteResponse> = useSWRInfinite(getKey, fetcher, { revalidateOnFocus: false, }) - - // Flatten data array - const copilotRequests = data ? data.flat() : [] - - const lastPage = data[data.length - 1] || [] - const hasMoreCopilotRequests = lastPage.length === PAGE_SIZE + const latestPage = data[data.length - 1] || {} + const copilotRequests = data.flatMap(page => page.data) + const hasMoreCopilotRequests = latestPage.page + 1 < latestPage.totalPages return { data: copilotRequests, hasMoreCopilotRequests, isValidating, setSize: (s: number) => { setSize(s) }, size } }