Skip to content

Commit 40f65ca

Browse files
committed
Spawn pagination machine - buggy filter
1 parent 74666ee commit 40f65ca

File tree

6 files changed

+173
-315
lines changed

6 files changed

+173
-315
lines changed

site/src/components/PaginationWidget/PaginationWidget.tsx

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,47 @@ import { makeStyles, useTheme } from "@material-ui/core/styles"
33
import useMediaQuery from "@material-ui/core/useMediaQuery"
44
import KeyboardArrowLeft from "@material-ui/icons/KeyboardArrowLeft"
55
import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight"
6+
import { useActor } from "@xstate/react"
67
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne"
78
import { Maybe } from "components/Conditionals/Maybe"
89
import { CSSProperties } from "react"
910
import { useSearchParams } from "react-router-dom"
11+
import { PaginationMachineRef } from "xServices/pagination/paginationXService"
1012
import { PageButton } from "./PageButton"
11-
import { buildPagedList, DEFAULT_RECORDS_PER_PAGE } from "./utils"
13+
import {
14+
buildPagedList,
15+
getInitialPage,
16+
} from "./utils"
1217

1318
export type PaginationWidgetProps = {
1419
prevLabel: string
1520
nextLabel: string
16-
onPageChange: (offset: number, limit: number) => void
17-
numRecordsPerPage?: number
1821
numRecords?: number
1922
containerStyle?: CSSProperties
23+
paginationRef: PaginationMachineRef
2024
}
2125

2226
export const PaginationWidget = ({
2327
prevLabel,
2428
nextLabel,
25-
onPageChange,
2629
numRecords,
27-
numRecordsPerPage = DEFAULT_RECORDS_PER_PAGE,
2830
containerStyle,
31+
paginationRef,
2932
}: PaginationWidgetProps): JSX.Element | null => {
3033
const theme = useTheme()
3134
const isMobile = useMediaQuery(theme.breakpoints.down("sm"))
3235
const styles = useStyles()
36+
const [paginationState, send] = useActor(paginationRef)
37+
console.log(paginationState.context, paginationState.event)
3338

34-
const [searchParams, setSearchParams] = useSearchParams()
35-
const currentPage = searchParams.get("page")
36-
? Number(searchParams.get("page"))
37-
: 1
39+
const [searchParams, _] = useSearchParams()
40+
const currentPage = getInitialPage(searchParams.get("page"))
41+
const numRecordsPerPage = paginationState.context.limit
3842

3943
const numPages = numRecords ? Math.ceil(numRecords / numRecordsPerPage) : 0
4044
const firstPageActive = currentPage === 1 && numPages !== 0
4145
const lastPageActive = currentPage === numPages && numPages !== 0
4246

43-
const changePage = (newPage: number) => {
44-
// change the page in the url
45-
setSearchParams({ page: newPage.toString() })
46-
// fetch new page of records
47-
const offset = (newPage - 1) * numRecordsPerPage
48-
onPageChange(offset, numRecordsPerPage)
49-
}
50-
5147
// No need to display any pagination if we know the number of pages is 1
5248
if (numPages === 1 || numRecords === 0) {
5349
return null
@@ -59,7 +55,7 @@ export const PaginationWidget = ({
5955
className={styles.prevLabelStyles}
6056
aria-label="Previous page"
6157
disabled={firstPageActive}
62-
onClick={() => changePage(currentPage - 1)}
58+
onClick={() => send({ type: "PREVIOUS_PAGE" })}
6359
>
6460
<KeyboardArrowLeft />
6561
<div>{prevLabel}</div>
@@ -83,7 +79,7 @@ export const PaginationWidget = ({
8379
activePage={currentPage}
8480
page={page}
8581
numPages={numPages}
86-
onPageClick={() => changePage(page)}
82+
onPageClick={() => send({ type: "GO_TO_PAGE", page })}
8783
/>
8884
),
8985
)}
@@ -93,7 +89,7 @@ export const PaginationWidget = ({
9389
<Button
9490
aria-label="Next page"
9591
disabled={lastPageActive}
96-
onClick={() => changePage(currentPage + 1)}
92+
onClick={() => send({ type: "NEXT_PAGE" })}
9793
>
9894
<div>{nextLabel}</div>
9995
<KeyboardArrowRight />

site/src/components/PaginationWidget/utils.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { PaginationContext, PaginationMachineRef } from "xServices/pagination/paginationXService"
2+
13
/**
24
* Generates a ranged array with an option to step over values.
35
* Shamelessly stolen from:
@@ -55,3 +57,33 @@ export const buildPagedList = (
5557

5658
return range(1, numPages)
5759
}
60+
61+
export const getInitialPage = (page: string | null): number =>
62+
page ? Number(page) : 1
63+
64+
export const getOffset = (page: number, limit: number): number =>
65+
(page - 1) * limit
66+
67+
interface PaginationData {
68+
offset: number
69+
limit: number
70+
}
71+
72+
export const getPaginationData = (
73+
ref: PaginationMachineRef,
74+
): PaginationData => {
75+
const snapshot = ref.getSnapshot()
76+
if (snapshot) {
77+
const { page, limit } = snapshot.context
78+
const offset = getOffset(page, limit)
79+
return { offset, limit }
80+
} else {
81+
throw new Error("No pagination data")
82+
}
83+
}
84+
85+
export const getPaginationContext = (searchParams: URLSearchParams, setSearchParams: ({ page }: { page: string }) => void, limit=DEFAULT_RECORDS_PER_PAGE): PaginationContext => ({
86+
page: getInitialPage(searchParams.get("page")),
87+
limit,
88+
updateURL: (page) => setSearchParams({ page: page.toString() })
89+
})

site/src/pages/WorkspacesPage/WorkspacesPage.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
import { useMachine } from "@xstate/react"
2+
import { getPaginationContext } from "components/PaginationWidget/utils"
23
import { FC } from "react"
34
import { Helmet } from "react-helmet-async"
45
import { useSearchParams } from "react-router-dom"
56
import { workspaceFilterQuery } from "util/filters"
67
import { pageTitle } from "util/page"
7-
import { workspacesMachine2 } from "xServices/workspaces/workspacesXService"
8+
import { PaginationMachineRef } from "xServices/pagination/paginationXService"
9+
import {
10+
workspacesMachine,
11+
} from "xServices/workspaces/workspacesXService"
812
import { WorkspacesPageView } from "./WorkspacesPageView"
913

1014
const WorkspacesPage: FC = () => {
1115
const [searchParams, setSearchParams] = useSearchParams()
1216
const filter = searchParams.get("filter") ?? workspaceFilterQuery.me
13-
const [workspacesState, send] = useMachine(workspacesMachine2, {
14-
context: { filter },
17+
const [workspacesState, send] = useMachine(workspacesMachine, {
18+
context: {
19+
filter,
20+
paginationContext: getPaginationContext(searchParams, setSearchParams)
21+
},
1522
})
1623

1724
const { workspaceRefs, count, getWorkspacesError, getCountError } =
1825
workspacesState.context
26+
const paginationRef = workspacesState.context.paginationRef as PaginationMachineRef
27+
28+
console.log(workspacesState.value, workspacesState.event)
1929

2030
return (
2131
<>
@@ -37,9 +47,7 @@ const WorkspacesPage: FC = () => {
3747
query,
3848
})
3949
}}
40-
onPageChange={(offset: number, limit: number) =>
41-
send({ type: "GET_WORKSPACES", offset, limit })
42-
}
50+
paginationRef={paginationRef}
4351
/>
4452
</>
4553
)

site/src/pages/WorkspacesPage/WorkspacesPageView.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Maybe } from "components/Conditionals/Maybe"
44
import { PaginationWidget } from "components/PaginationWidget/PaginationWidget"
55
import { FC } from "react"
66
import { Link as RouterLink } from "react-router-dom"
7+
import { PaginationMachineRef } from "xServices/pagination/paginationXService"
78
import { Margins } from "../../components/Margins/Margins"
89
import {
910
PageHeader,
@@ -34,7 +35,7 @@ export interface WorkspacesPageViewProps {
3435
getCountError: Error | unknown
3536
filter?: string
3637
onFilter: (query: string) => void
37-
onPageChange: (offset: number, limit: number) => void
38+
paginationRef: PaginationMachineRef
3839
}
3940

4041
export const WorkspacesPageView: FC<
@@ -47,7 +48,7 @@ export const WorkspacesPageView: FC<
4748
getCountError,
4849
filter,
4950
onFilter,
50-
onPageChange,
51+
paginationRef,
5152
}) => {
5253
const presetFilters = [
5354
{ query: workspaceFilterQuery.me, name: Language.yourWorkspacesButton },
@@ -110,7 +111,7 @@ export const WorkspacesPageView: FC<
110111
prevLabel=""
111112
nextLabel=""
112113
numRecords={count}
113-
onPageChange={onPageChange}
114+
paginationRef={paginationRef}
114115
/>
115116
</Margins>
116117
)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { ActorRefFrom, createMachine, sendParent, assign } from "xstate"
2+
3+
export interface PaginationContext {
4+
page: number
5+
limit: number
6+
updateURL: (page: number) => void
7+
}
8+
9+
export type PaginationEvent =
10+
| { type: "NEXT_PAGE" }
11+
| { type: "PREVIOUS_PAGE" }
12+
| { type: "GO_TO_PAGE"; page: number }
13+
| { type: "RESET_PAGE" }
14+
15+
export type PaginationMachineRef = ActorRefFrom<typeof paginationMachine>
16+
17+
export const paginationMachine = createMachine(
18+
{
19+
id: "paginationMachine",
20+
predictableActionArguments: true,
21+
tsTypes: {} as import("./paginationXService.typegen").Typegen0,
22+
schema: {
23+
context: {} as PaginationContext,
24+
events: {} as PaginationEvent,
25+
},
26+
initial: "idle",
27+
on: {
28+
NEXT_PAGE: {
29+
actions: ["assignNextPage", "updateURL", "sendRefreshData"],
30+
},
31+
PREVIOUS_PAGE: {
32+
actions: ["assignPreviousPage", "updateURL", "sendRefreshData"],
33+
},
34+
GO_TO_PAGE: {
35+
actions: ["assignPage", "updateURL", "sendRefreshData"],
36+
},
37+
RESET_PAGE: {
38+
actions: ["resetPage", "updateURL", "sendRefreshData"],
39+
},
40+
},
41+
states: {
42+
idle: {},
43+
},
44+
},
45+
{
46+
actions: {
47+
sendRefreshData: (_) => sendParent("REFRESH_DATA"),
48+
assignNextPage: assign({
49+
page: (context) => context.page + 1,
50+
}),
51+
assignPreviousPage: assign({
52+
page: (context) => context.page - 1,
53+
}),
54+
assignPage: assign({
55+
page: (_, event) => event.page,
56+
}),
57+
resetPage: assign({
58+
page: (_) => 1,
59+
}),
60+
updateURL: (context) => {
61+
context.updateURL(context.page)
62+
},
63+
},
64+
},
65+
)

0 commit comments

Comments
 (0)