Skip to content

Commit 56c237d

Browse files
authored
Merge pull request #1188 from topcoder-platform/pm-1650
feat(PM-1650): paginated copilot requests page
2 parents b42bdc6 + 7d9056a commit 56c237d

File tree

5 files changed

+58
-36
lines changed

5 files changed

+58
-36
lines changed

src/apps/copilots/src/models/CopilotRequest.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@ export interface CopilotRequest {
2323
tzRestrictions: 'yes' | 'no',
2424
createdAt: Date,
2525
opportunity?: CopilotOpportunity,
26+
project?: {
27+
name: string,
28+
},
2629
}

src/apps/copilots/src/pages/copilot-requests/index.tsx

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
ContentLayout,
1010
IconCheck,
1111
IconSolid,
12-
LoadingSpinner,
12+
LoadingCircles,
1313
PageTitle,
1414
Table,
1515
TableColumn,
@@ -22,7 +22,6 @@ import { EnvironmentConfig } from '~/config'
2222
import { ProjectTypeLabels } from '../../constants'
2323
import { approveCopilotRequest, CopilotRequestsResponse, useCopilotRequests } from '../../services/copilot-requests'
2424
import { CopilotRequest } from '../../models/CopilotRequest'
25-
import { ProjectsResponse, useProjects } from '../../services/projects'
2625
import { copilotRoutesMap } from '../../copilots.routes'
2726
import { Project } from '../../models/Project'
2827

@@ -144,18 +143,12 @@ const CopilotRequestsPage: FC = () => {
144143
[profile],
145144
)
146145

147-
const { data: requests = [], isValidating: requestsLoading }: CopilotRequestsResponse = useCopilotRequests()
148-
const projectIds = useMemo(() => (
149-
(new Set(requests.map(r => r.projectId))
150-
.values() as any)
151-
.toArray()
152-
), [requests])
153-
154-
const { data: projects = [], isValidating: projectsLoading }: ProjectsResponse = useProjects(undefined, {
155-
filter: { id: projectIds },
156-
isPaused: () => !projectIds?.length,
157-
})
158-
const isLoading = projectsLoading || requestsLoading
146+
const {
147+
data: requests = [],
148+
isValidating: requestsLoading,
149+
hasMoreCopilotRequests,
150+
setSize,
151+
size }: CopilotRequestsResponse = useCopilotRequests()
159152

160153
const viewRequestDetails = useMemo(() => (
161154
routeParams.requestId && find(requests, { id: +routeParams.requestId }) as CopilotRequest
@@ -165,10 +158,6 @@ const CopilotRequestsPage: FC = () => {
165158
navigate(copilotRoutesMap.CopilotRequests)
166159
}, [navigate])
167160

168-
const projectsMap = useMemo(() => projects.reduce((all, c) => (
169-
Object.assign(all, { [c.id]: c })
170-
), {} as {[key: string]: Project}), [projects])
171-
172161
const handleLinkClick = useCallback((e: React.MouseEvent<HTMLAnchorElement>) => {
173162
e.stopPropagation()
174163
}, [])
@@ -178,7 +167,6 @@ const CopilotRequestsPage: FC = () => {
178167
label: 'Project',
179168
propertyName: 'projectName',
180169
renderer: (copilotRequest: CopilotRequest) => {
181-
const projectName = projectsMap[copilotRequest.projectId]?.name
182170
const projectLink = `
183171
${EnvironmentConfig.ADMIN.WORK_MANAGER_URL}/projects/${copilotRequest.projectId}/challenges
184172
`
@@ -190,7 +178,7 @@ const CopilotRequestsPage: FC = () => {
190178
rel='noreferrer'
191179
onClick={handleLinkClick}
192180
>
193-
{projectName}
181+
{copilotRequest.project?.name}
194182
</a>
195183
)
196184
},
@@ -238,9 +226,13 @@ const CopilotRequestsPage: FC = () => {
238226

239227
const tableData = useMemo(() => requests.map(request => ({
240228
...request,
241-
projectName: projectsMap[request.projectId]?.name,
229+
projectName: request.project?.name,
242230
type: ProjectTypeLabels[request.projectType] ?? '',
243-
})), [projectsMap, requests])
231+
})), [requests])
232+
233+
function loadMore(): void {
234+
setSize(size + 1)
235+
}
244236

245237
// header button config
246238
const addNewRequestButton: ButtonProps = {
@@ -263,18 +255,17 @@ const CopilotRequestsPage: FC = () => {
263255
buttonConfig={addNewRequestButton}
264256
>
265257
<PageTitle>Copilot Requests</PageTitle>
266-
{isLoading ? (
267-
<LoadingSpinner inline />
268-
) : (
269-
<Table
270-
columns={tableColumns}
271-
data={tableData}
272-
/>
273-
)}
258+
<Table
259+
columns={tableColumns}
260+
data={tableData}
261+
moreToLoad={hasMoreCopilotRequests}
262+
onLoadMoreClick={loadMore}
263+
/>
264+
{requestsLoading && <LoadingCircles /> }
274265
{viewRequestDetails && (
275266
<CopilotRequestModal
276267
request={viewRequestDetails}
277-
project={projectsMap[viewRequestDetails.projectId]}
268+
project={viewRequestDetails.project as Project}
278269
onClose={hideRequestDetails}
279270
/>
280271
)}

src/apps/copilots/src/services/copilot-requests.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import useSWR, { SWRResponse } from 'swr'
2+
import useSWRInfinite, { SWRInfiniteResponse } from 'swr/infinite'
23

34
import { EnvironmentConfig } from '~/config'
45
import { xhrGetAsync, xhrPatchAsync, xhrPostAsync } from '~/libs/core'
@@ -7,6 +8,7 @@ import { buildUrl } from '~/libs/shared/lib/utils/url'
78
import { CopilotRequest } from '../models/CopilotRequest'
89

910
const baseUrl = `${EnvironmentConfig.API.V5}/projects`
11+
const PAGE_SIZE = 20
1012

1113
/**
1214
* Creates a CopilotRequest object by merging the provided data and its nested data,
@@ -27,7 +29,13 @@ function copilotRequestFactory(data: any): CopilotRequest {
2729
}
2830
}
2931

30-
export type CopilotRequestsResponse = SWRResponse<CopilotRequest[], CopilotRequest[]>
32+
export type CopilotRequestsResponse = {
33+
data: CopilotRequest[];
34+
hasMoreCopilotRequests: boolean;
35+
isValidating: boolean;
36+
size: number;
37+
setSize: (size: number) => void;
38+
}
3139

3240
/**
3341
* Custom hook to fetch copilot requests for a given project.
@@ -36,15 +44,33 @@ export type CopilotRequestsResponse = SWRResponse<CopilotRequest[], CopilotReque
3644
* @returns {CopilotRequestsResponse} - The response containing copilot requests.
3745
*/
3846
export const useCopilotRequests = (projectId?: string): CopilotRequestsResponse => {
39-
const url = buildUrl(`${baseUrl}${projectId ? `/${projectId}` : ''}/copilots/requests`)
47+
const getKey = (pageIndex: number, previousPageData: CopilotRequest[]): string | undefined => {
48+
if (previousPageData && previousPageData.length < PAGE_SIZE) return undefined
49+
const url = buildUrl(`${baseUrl}${projectId ? `/${projectId}` : ''}/copilots/requests`)
50+
return `
51+
${url}?page=${pageIndex + 1}&pageSize=${PAGE_SIZE}&sort=createdAt desc
52+
`
53+
}
4054

41-
const fetcher = (urlp: string): Promise<CopilotRequest[]> => xhrGetAsync<CopilotRequest[]>(urlp)
55+
const fetcher = (url: string): Promise<CopilotRequest[]> => xhrGetAsync<CopilotRequest[]>(url)
4256
.then((data: any) => data.map(copilotRequestFactory))
4357

44-
return useSWR(url, fetcher, {
45-
refreshInterval: 0,
58+
const {
59+
isValidating,
60+
data = [],
61+
size,
62+
setSize,
63+
}: SWRInfiniteResponse<CopilotRequest[]> = useSWRInfinite(getKey, fetcher, {
4664
revalidateOnFocus: false,
4765
})
66+
67+
// Flatten data array
68+
const copilotRequests = data ? data.flat() : []
69+
70+
const lastPage = data[data.length - 1] || []
71+
const hasMoreCopilotRequests = lastPage.length === PAGE_SIZE
72+
73+
return { data: copilotRequests, hasMoreCopilotRequests, isValidating, setSize: (s: number) => { setSize(s) }, size }
4874
}
4975

5076
export type CopilotRequestResponse = SWRResponse<CopilotRequest, CopilotRequest>

src/apps/wallet-admin/src/lib/components/payment-method-table/PaymentMethodTable.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const PaymentProviderTable: React.FC<PaymentMethodTableProps> = (props: PaymentM
2929
<th className='body-ultra-small-bold'>CONNECTED PROVIDER</th>
3030
<th className='body-ultra-small-bold'>PROVIDER ID</th>
3131
<th className='body-ultra-small-bold'>STATUS</th>
32+
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
3233
<th className='body-ultra-small'> </th>
3334
</tr>
3435
</thead>

src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const TaxFormTable: React.FC<TaxFormTableProps> = (props: TaxFormTableProps) =>
3030
<th className='body-ultra-small-bold'>FORM</th>
3131
<th className='body-ultra-small-bold'>DATE FILED</th>
3232
<th className='body-ultra-small-bold'>STATUS</th>
33+
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
3334
<th className='body-ultra-small'> </th>
3435
</tr>
3536
</thead>

0 commit comments

Comments
 (0)