Skip to content

Commit

Permalink
feat(OUT-789): implement lazy client fetching using suspense
Browse files Browse the repository at this point in the history
  • Loading branch information
rrojan committed Aug 28, 2024
1 parent a02ff79 commit a666733
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 13 deletions.
4 changes: 3 additions & 1 deletion src/app/api/clients/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { z } from 'zod'
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams
const token = searchParams.get('token')
const nextToken = searchParams.get('nextToken') || undefined
const limit = searchParams.get('limit') || '100'
if (!token) {
return errorHandler('Missing token', 422)
}

const copilotClient = new CopilotAPI(z.string().parse(token))
try {
const clients = await copilotClient.getClients()
const clients = await copilotClient.getClients(+limit, nextToken)

return NextResponse.json(clients)
} catch (error: unknown) {
Expand Down
30 changes: 20 additions & 10 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,23 @@ import { IClient, ICustomField } from '@/types/interfaces'
import { z } from 'zod'
import InvalidToken from './components/InvalidToken'
import NotificationsModal from '@/components/NotificationsModal'
import { LazyClientFetcher } from '@/components/_fetchers/LazyClientFetcher'
import { Suspense } from 'react'

export const revalidate = 0

async function listClients(token: string) {
const copilotClient = new CopilotAPI(token)
const clientList = ClientsResponseSchema.parse(
await copilotClient.getClients(),
await copilotClient.getClients(1),
)

return (clientList.data?.sort((a, b) =>
a.givenName.localeCompare(b.givenName),
) || []) as IClient[]
return {
data: (clientList.data?.sort((a, b) =>
a.givenName.localeCompare(b.givenName),
) || []) as IClient[],
nextToken: clientList.nextToken,
}
}

async function getCustomFields(token: string) {
Expand Down Expand Up @@ -54,12 +59,13 @@ export default async function Page({

const copilotClient = new CopilotAPI(token)

const [clientList, settings, workspace, customFields] = await Promise.all([
listClients(token),
getSettings(token),
copilotClient.getWorkspaceInfo(),
getCustomFields(token),
])
const [{ data: clientList, nextToken }, settings, workspace, customFields] =
await Promise.all([
listClients(token),
getSettings(token),
copilotClient.getWorkspaceInfo(),
getCustomFields(token),
])

return (
<>
Expand Down Expand Up @@ -87,6 +93,10 @@ export default async function Page({
height: '100vh',
}}
>
<Suspense>
<LazyClientFetcher token={token} nextToken={nextToken} />
</Suspense>

<SideBarInterface
displayTasks={settings?.displayTasks}
clientList={clientList}
Expand Down
29 changes: 29 additions & 0 deletions src/components/_fetchers/LazyClientFetcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { apiUrl } from '@/config'
import { ClientsResponseSchema } from '@/types/common'
import { LazyClientSetter } from './LazyClientSetter'
import { IClient } from '@/types/interfaces'

interface LazyClientFetcherProps {
token: string
nextToken?: string
}

export const LazyClientFetcher = async ({
token,
nextToken,
}: LazyClientFetcherProps) => {
const MAX_FETCH_LIMIT = 5_000

if (!nextToken) {
return <></>
}
const res = await fetch(
`${apiUrl}/api/clients/?token=${token}&nextToken=${nextToken}&limit=${MAX_FETCH_LIMIT}`,
)
const newClients = ClientsResponseSchema.parse(await res.json())
const newClientsData = (newClients.data?.sort((a, b) =>
a.givenName.localeCompare(b.givenName),
) || []) as IClient[]

return <LazyClientSetter newClients={newClientsData} />
}
16 changes: 16 additions & 0 deletions src/components/_fetchers/LazyClientSetter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use client'

import { useAppState } from '@/hooks/useAppState'
import { IClient } from '@/types/interfaces'

interface LazyClientSetterProps {
newClients: IClient[]
}

export const LazyClientSetter = ({ newClients }: LazyClientSetterProps) => {
const appState = useAppState()
console.log('setting new clients list')
appState?.setClientList([...appState.appState.clientList, ...newClients])

return <></>
}
1 change: 1 addition & 0 deletions src/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export type ClientResponse = z.infer<typeof ClientResponseSchema>

export const ClientsResponseSchema = z.object({
data: z.array(ClientResponseSchema).nullable(),
nextToken: z.string().optional(),
})
export type ClientsResponse = z.infer<typeof ClientsResponseSchema>

Expand Down
6 changes: 4 additions & 2 deletions src/utils/copilotApiUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ export class CopilotAPI {
)
}

async getClients() {
return ClientsResponseSchema.parse(await this.copilot.listClients({}))
async getClients(limit: number = 100, nextToken?: string) {
return ClientsResponseSchema.parse(
await this.copilot.listClients({ limit, nextToken }),
)
}

async getCompany(companyId: string): Promise<CompanyResponse> {
Expand Down

0 comments on commit a666733

Please sign in to comment.