Skip to content

Commit f22c4ca

Browse files
committed
feat: paginated copilot requests page
1 parent 9e4b437 commit f22c4ca

File tree

5 files changed

+58
-30
lines changed

5 files changed

+58
-30
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 & 25 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,
@@ -144,19 +144,18 @@ const CopilotRequestsPage: FC = () => {
144144
[profile],
145145
)
146146

147-
const { data: requests = [], isValidating: requestsLoading }: CopilotRequestsResponse = useCopilotRequests()
147+
const {
148+
data: requests = [],
149+
isValidating: requestsLoading,
150+
hasMoreCopilotRequests,
151+
setSize,
152+
size }: CopilotRequestsResponse = useCopilotRequests()
148153
const projectIds = useMemo(() => (
149154
(new Set(requests.map(r => r.projectId))
150155
.values() as any)
151156
.toArray()
152157
), [requests])
153158

154-
const { data: projects = [], isValidating: projectsLoading }: ProjectsResponse = useProjects(undefined, {
155-
filter: { id: projectIds },
156-
isPaused: () => !projectIds?.length,
157-
})
158-
const isLoading = projectsLoading || requestsLoading
159-
160159
const viewRequestDetails = useMemo(() => (
161160
routeParams.requestId && find(requests, { id: +routeParams.requestId }) as CopilotRequest
162161
), [requests, routeParams.requestId])
@@ -165,10 +164,6 @@ const CopilotRequestsPage: FC = () => {
165164
navigate(copilotRoutesMap.CopilotRequests)
166165
}, [navigate])
167166

168-
const projectsMap = useMemo(() => projects.reduce((all, c) => (
169-
Object.assign(all, { [c.id]: c })
170-
), {} as {[key: string]: Project}), [projects])
171-
172167
const handleLinkClick = useCallback((e: React.MouseEvent<HTMLAnchorElement>) => {
173168
e.stopPropagation()
174169
}, [])
@@ -178,7 +173,6 @@ const CopilotRequestsPage: FC = () => {
178173
label: 'Project',
179174
propertyName: 'projectName',
180175
renderer: (copilotRequest: CopilotRequest) => {
181-
const projectName = projectsMap[copilotRequest.projectId]?.name
182176
const projectLink = `
183177
${EnvironmentConfig.ADMIN.WORK_MANAGER_URL}/projects/${copilotRequest.projectId}/challenges
184178
`
@@ -190,7 +184,7 @@ const CopilotRequestsPage: FC = () => {
190184
rel='noreferrer'
191185
onClick={handleLinkClick}
192186
>
193-
{projectName}
187+
{copilotRequest.project?.name}
194188
</a>
195189
)
196190
},
@@ -238,9 +232,13 @@ const CopilotRequestsPage: FC = () => {
238232

239233
const tableData = useMemo(() => requests.map(request => ({
240234
...request,
241-
projectName: projectsMap[request.projectId]?.name,
235+
projectName: request.project?.name,
242236
type: ProjectTypeLabels[request.projectType] ?? '',
243-
})), [projectsMap, requests])
237+
})), [requests])
238+
239+
function loadMore(): void {
240+
setSize(size + 1)
241+
}
244242

245243
// header button config
246244
const addNewRequestButton: ButtonProps = {
@@ -263,18 +261,17 @@ const CopilotRequestsPage: FC = () => {
263261
buttonConfig={addNewRequestButton}
264262
>
265263
<PageTitle>Copilot Requests</PageTitle>
266-
{isLoading ? (
267-
<LoadingSpinner inline />
268-
) : (
269-
<Table
270-
columns={tableColumns}
271-
data={tableData}
272-
/>
273-
)}
264+
<Table
265+
columns={tableColumns}
266+
data={tableData}
267+
moreToLoad={hasMoreCopilotRequests}
268+
onLoadMoreClick={loadMore}
269+
/>
270+
{requestsLoading && <LoadingCircles /> }
274271
{viewRequestDetails && (
275272
<CopilotRequestModal
276273
request={viewRequestDetails}
277-
project={projectsMap[viewRequestDetails.projectId]}
274+
project={viewRequestDetails.project as Project}
278275
onClose={hideRequestDetails}
279276
/>
280277
)}

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)