Skip to content

Commit f049721

Browse files
committed
feat(suite): rework pagination
1 parent e441a1a commit f049721

File tree

1 file changed

+134
-26
lines changed

1 file changed

+134
-26
lines changed

packages/suite/src/components/wallet/Pagination.tsx

+134-26
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,18 @@ const Wrapper = styled.div`
1313
gap: ${spacingsPx.xxxs};
1414
`;
1515

16-
const PageItem = styled.div<{ $isActive?: boolean }>`
16+
const Ellipsis = styled.div`
17+
display: flex;
18+
align-items: center;
19+
justify-content: center;
20+
width: ${spacingsPx.xxl};
21+
height: ${spacingsPx.xxl};
22+
padding: ${spacingsPx.xxs} ${spacingsPx.xs};
23+
text-align: center;
24+
${typography.hint};
25+
`;
26+
27+
const PageItem = styled.div<{ $isActive?: boolean; $isDisabled?: boolean }>`
1728
display: flex;
1829
align-items: center;
1930
justify-content: center;
@@ -31,14 +42,22 @@ const PageItem = styled.div<{ $isActive?: boolean }>`
3142
${typography.hint};
3243
cursor: pointer;
3344
34-
${({ $isActive, theme }) =>
45+
${({ $isActive, $isDisabled, theme }) =>
3546
!$isActive &&
47+
!$isDisabled &&
3648
css`
3749
&:hover {
3850
background: ${theme.backgroundTertiaryDefaultOnElevation0};
3951
color: ${theme.textOnTertiary};
4052
}
4153
`};
54+
55+
${({ $isDisabled }) =>
56+
$isDisabled &&
57+
css`
58+
color: ${({ theme }) => theme.textDisabled};
59+
cursor: not-allowed;
60+
`};
4261
`;
4362

4463
const Actions = styled.div<{ $isActive: boolean }>`
@@ -56,27 +75,90 @@ interface PaginationProps {
5675
onPageSelected: (page: number) => void;
5776
}
5877

78+
const SLIDING_WINDOW_SIZE = 7; // should be an even number, so that the active page can be centered
79+
const calculatePages = ({
80+
currentPage,
81+
totalPages,
82+
}: {
83+
currentPage: number;
84+
totalPages: number;
85+
}) => {
86+
const calculatedPages: (number | null)[] = [];
87+
88+
// center the current page
89+
let windowBeginning = currentPage - Math.floor((SLIDING_WINDOW_SIZE - 1) / 2);
90+
91+
// prevent window overflow on the right
92+
if (windowBeginning + SLIDING_WINDOW_SIZE > totalPages)
93+
windowBeginning = totalPages - (SLIDING_WINDOW_SIZE - 1);
94+
95+
// prevent window overflow on the left
96+
if (windowBeginning < 1) windowBeginning = 1;
97+
98+
for (
99+
let page = windowBeginning;
100+
page < windowBeginning + SLIDING_WINDOW_SIZE && page <= totalPages;
101+
page++
102+
) {
103+
const indexInWindow = calculatedPages.length;
104+
105+
// first button override
106+
if (indexInWindow === 0) {
107+
calculatedPages.push(1);
108+
continue;
109+
}
110+
111+
// second button override
112+
if (indexInWindow === 1 && page !== 2) {
113+
calculatedPages.push(null);
114+
continue;
115+
}
116+
117+
// second to last button override
118+
if (
119+
indexInWindow === SLIDING_WINDOW_SIZE - 2 &&
120+
page !== totalPages - 1 &&
121+
totalPages > SLIDING_WINDOW_SIZE
122+
) {
123+
calculatedPages.push(null);
124+
continue;
125+
}
126+
127+
// last button override
128+
if (indexInWindow === SLIDING_WINDOW_SIZE - 1 && page !== totalPages) {
129+
calculatedPages.push(totalPages);
130+
continue;
131+
}
132+
133+
calculatedPages.push(page);
134+
}
135+
136+
return calculatedPages;
137+
};
138+
59139
export const Pagination = ({
60140
currentPage,
61141
onPageSelected,
62142
hasPages = true,
63-
isLastPage,
143+
isLastPage: _isLastPage,
64144
perPage,
65145
totalItems,
66146
...rest
67147
}: PaginationProps) => {
68148
const totalPages = Math.ceil(totalItems / perPage);
69-
const showPrevious = currentPage > 1;
70-
// array of int used for creating all page buttons
149+
const isFirstPage = currentPage === 1;
150+
const isLastPage = hasPages ? currentPage === totalPages : _isLastPage;
151+
152+
// array of pages to be rendered as buttons
71153
const calculatedPages = useMemo(
72-
() => [...Array(totalPages)].map((_p, i) => i + 1),
73-
[totalPages],
154+
() => calculatePages({ currentPage, totalPages }),
155+
[currentPage, totalPages],
74156
);
75157

76158
if (!hasPages) {
77159
return (
78160
<Wrapper {...rest}>
79-
<Actions $isActive={showPrevious}>
161+
<Actions $isActive={!isFirstPage}>
80162
<PageItem onClick={() => onPageSelected(currentPage - 1)}>
81163
<Translation id="TR_PAGINATION_NEWER" />
82164
</PageItem>
@@ -92,23 +174,39 @@ export const Pagination = ({
92174

93175
return (
94176
<Wrapper {...rest}>
95-
<Actions $isActive={showPrevious}>
96-
{currentPage > 2 && <PageItem onClick={() => onPageSelected(1)}>«</PageItem>}
97-
<PageItem onClick={() => onPageSelected(currentPage - 1)}></PageItem>
177+
<Actions $isActive={true}>
178+
<PageItem
179+
$isDisabled={isFirstPage}
180+
onClick={!isFirstPage ? () => onPageSelected(1) : undefined}
181+
>
182+
«
183+
</PageItem>
184+
<PageItem
185+
$isDisabled={isFirstPage}
186+
onClick={!isFirstPage ? () => onPageSelected(currentPage - 1) : undefined}
187+
>
188+
189+
</PageItem>
98190
</Actions>
99191

100192
{totalPages ? (
101-
calculatedPages.map(i => (
102-
<PageItem
103-
key={i}
104-
data-testid={`@wallet/accounts/pagination/${i}`}
105-
data-test-activated={i === currentPage}
106-
onClick={() => onPageSelected(i)}
107-
$isActive={i === currentPage}
108-
>
109-
{i}
110-
</PageItem>
111-
))
193+
<>
194+
{calculatedPages.map((page, i) =>
195+
page === null ? (
196+
<Ellipsis key={i}></Ellipsis>
197+
) : (
198+
<PageItem
199+
key={i}
200+
data-testid={`@wallet/accounts/pagination/${page}`}
201+
data-test-activated={page === currentPage}
202+
onClick={() => onPageSelected(page)}
203+
$isActive={page === currentPage}
204+
>
205+
{page}
206+
</PageItem>
207+
),
208+
)}
209+
</>
112210
) : (
113211
<>
114212
{[...Array(currentPage - 1)].map((_p, i) => (
@@ -129,10 +227,20 @@ export const Pagination = ({
129227
</>
130228
)}
131229

132-
<Actions $isActive={currentPage < (totalPages || 1)}>
133-
<PageItem onClick={() => onPageSelected(currentPage + 1)}></PageItem>
134-
{totalPages && totalPages > 2 && (
135-
<PageItem onClick={() => onPageSelected(totalPages)}>»</PageItem>
230+
<Actions $isActive={true}>
231+
<PageItem
232+
$isDisabled={isLastPage}
233+
onClick={!isLastPage ? () => onPageSelected(currentPage + 1) : undefined}
234+
>
235+
236+
</PageItem>
237+
{totalPages > 0 && (
238+
<PageItem
239+
$isDisabled={isLastPage}
240+
onClick={!isLastPage ? () => onPageSelected(totalPages) : undefined}
241+
>
242+
»
243+
</PageItem>
136244
)}
137245
</Actions>
138246
</Wrapper>

0 commit comments

Comments
 (0)