Skip to content

Commit 4e916ae

Browse files
committed
feat(staking): add page size selector
1 parent 275248e commit 4e916ae

File tree

2 files changed

+109
-57
lines changed

2 files changed

+109
-57
lines changed

apps/staking/src/components/OracleIntegrityStaking/index.tsx

Lines changed: 43 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ import {
3232
Form,
3333
Switch,
3434
MenuTrigger,
35-
Select,
36-
Popover,
37-
ListBox,
38-
ListBoxItem,
3935
} from "react-aria-components";
4036

4137
import { type States, StateType as ApiStateType } from "../../hooks/use-api";
@@ -50,15 +46,14 @@ import { ModalDialog } from "../ModalDialog";
5046
import { OracleIntegrityStakingGuide } from "../OracleIntegrityStakingGuide";
5147
import { ProgramSection } from "../ProgramSection";
5248
import { PublisherFaq } from "../PublisherFaq";
49+
import { Select } from "../Select";
5350
import { SparkChart } from "../SparkChart";
5451
import { StakingTimeline } from "../StakingTimeline";
5552
import { Styled } from "../Styled";
5653
import { Tokens } from "../Tokens";
5754
import { AmountType, TransferButton } from "../TransferButton";
5855
import { TruncatedKey } from "../TruncatedKey";
5956

60-
const PAGE_SIZE = 10;
61-
6257
type Props = {
6358
api: States[ApiStateType.Loaded] | States[ApiStateType.LoadedNoStakeAccount];
6459
currentEpoch: bigint;
@@ -582,6 +577,9 @@ const PublisherList = ({
582577
totalStaked,
583578
yieldRate,
584579
}: PublisherListProps) => {
580+
const [pageSize, setPageSize] = useState<(typeof PageSize)[number]>(
581+
PageSize[2],
582+
);
585583
const scrollTarget = useRef<HTMLDivElement | null>(null);
586584
const [search, setSearch] = useState("");
587585
const [yoursFirst, setYoursFirst] = useState(true);
@@ -615,10 +613,10 @@ const PublisherList = ({
615613
const paginatedPublishers = useMemo(
616614
() =>
617615
filteredSortedPublishers.slice(
618-
(currentPage - 1) * PAGE_SIZE,
619-
currentPage * PAGE_SIZE,
616+
(currentPage - 1) * pageSize,
617+
currentPage * pageSize,
620618
),
621-
[filteredSortedPublishers, currentPage],
619+
[filteredSortedPublishers, currentPage, pageSize],
622620
);
623621

624622
const updatePage = useCallback<typeof setPage>(
@@ -656,8 +654,8 @@ const PublisherList = ({
656654
);
657655

658656
const numPages = useMemo(
659-
() => Math.floor(filteredSortedPublishers.length / PAGE_SIZE),
660-
[filteredSortedPublishers],
657+
() => Math.floor(filteredSortedPublishers.length / pageSize),
658+
[filteredSortedPublishers, pageSize],
661659
);
662660

663661
return (
@@ -687,48 +685,26 @@ const PublisherList = ({
687685
</div>
688686
</SearchField>
689687
<Select
690-
className="flex flex-row items-center gap-2 2xl:hidden"
688+
className="2xl:hidden"
689+
label="Sort by"
690+
options={[
691+
SortOption.PublisherNameDescending,
692+
SortOption.PublisherNameAscending,
693+
SortOption.RemainingPoolDescending,
694+
SortOption.RemainingPoolAscending,
695+
SortOption.ApyDescending,
696+
SortOption.ApyAscending,
697+
SortOption.SelfStakeDescending,
698+
SortOption.SelfStakeAscending,
699+
SortOption.NumberOfFeedsDescending,
700+
SortOption.NumberOfFeedsAscending,
701+
SortOption.QualityRankingDescending,
702+
SortOption.QualityRankingAscending,
703+
]}
691704
selectedKey={sort}
692-
// @ts-expect-error react-aria coerces everything to Key for some reason...
693705
onSelectionChange={updateSort}
694-
>
695-
<Label className="whitespace-nowrap opacity-80">Sort by</Label>
696-
<Button
697-
className="group flex flex-row items-center gap-2 px-2 py-3 text-xs transition sm:px-4"
698-
size="nopad"
699-
>
700-
{getSortName(sort)}
701-
<ChevronDownIcon className="size-4 flex-none opacity-60 transition duration-300 group-data-[pressed]:-rotate-180" />
702-
</Button>
703-
<Popover
704-
placement="bottom end"
705-
className="data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in data-[exiting]:fade-out"
706-
>
707-
<ListBox
708-
className="flex origin-top-right flex-col border border-neutral-400 bg-pythpurple-100 py-2 text-sm text-pythpurple-950 shadow shadow-neutral-400 outline-none"
709-
items={[
710-
SortOption.PublisherNameDescending,
711-
SortOption.PublisherNameAscending,
712-
SortOption.RemainingPoolDescending,
713-
SortOption.RemainingPoolAscending,
714-
SortOption.ApyDescending,
715-
SortOption.ApyAscending,
716-
SortOption.SelfStakeDescending,
717-
SortOption.SelfStakeAscending,
718-
SortOption.NumberOfFeedsDescending,
719-
SortOption.NumberOfFeedsAscending,
720-
SortOption.QualityRankingDescending,
721-
SortOption.QualityRankingAscending,
722-
].map((id) => ({ id }))}
723-
>
724-
{({ id }) => (
725-
<ListBoxItem className="flex cursor-pointer items-center gap-2 whitespace-nowrap px-4 py-2 text-left data-[disabled]:cursor-default data-[focused]:bg-pythpurple-800/20 data-[has-submenu]:data-[open]:bg-pythpurple-800/10 data-[has-submenu]:data-[open]:data-[focused]:bg-pythpurple-800/20 focus:outline-none focus-visible:outline-none">
726-
{getSortName(id)}
727-
</ListBoxItem>
728-
)}
729-
</ListBox>
730-
</Popover>
731-
</Select>
706+
show={getSortName}
707+
/>
732708
<Switch
733709
isSelected={yoursFirst}
734710
onChange={updateYoursFirst}
@@ -841,11 +817,19 @@ const PublisherList = ({
841817
)}
842818

843819
{numPages > 1 && (
844-
<Paginator
845-
currentPage={currentPage}
846-
numPages={numPages}
847-
onPageChange={updatePage}
848-
/>
820+
<div className="flex flex-col items-center justify-between gap-4 border-t border-neutral-600/50 p-4 sm:flex-row">
821+
<Select
822+
label="Page size"
823+
options={PageSize}
824+
selectedKey={pageSize}
825+
onSelectionChange={setPageSize}
826+
/>
827+
<Paginator
828+
currentPage={currentPage}
829+
numPages={numPages}
830+
onPageChange={updatePage}
831+
/>
832+
</div>
849833
)}
850834
</div>
851835
);
@@ -864,7 +848,7 @@ const Paginator = ({ currentPage, numPages, onPageChange }: PaginatorProps) => {
864848
.map((_, i) => i + first);
865849

866850
return (
867-
<ul className="sticky inset-x-0 flex flex-row items-center justify-end gap-2 border-t border-neutral-600/50 p-4">
851+
<ul className="sticky inset-x-0 flex flex-row gap-2">
868852
{currentPage > 1 && (
869853
<li>
870854
<Button
@@ -1698,6 +1682,8 @@ const getSortName = (sortOption: SortOption) => {
16981682
}
16991683
};
17001684

1685+
const PageSize = [10, 20, 30, 40, 50] as const;
1686+
17011687
class InvalidKeyError extends Error {
17021688
constructor() {
17031689
super("Invalid public key");
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { ChevronDownIcon } from "@heroicons/react/24/outline";
2+
import clsx from "clsx";
3+
import type { ComponentProps, ReactNode } from "react";
4+
import {
5+
Label,
6+
SelectValue,
7+
Select as BaseSelect,
8+
Popover,
9+
ListBox,
10+
ListBoxItem,
11+
} from "react-aria-components";
12+
13+
import { Button } from "../Button";
14+
15+
type Props<T> = Omit<
16+
ComponentProps<typeof BaseSelect>,
17+
"selectedKey" | "onSelectionChange"
18+
> & {
19+
label: ReactNode;
20+
selectedKey: T;
21+
onSelectionChange: (newValue: T) => void;
22+
options: readonly T[];
23+
show?: (value: T) => string;
24+
};
25+
26+
export const Select = <T extends string | number>({
27+
className,
28+
options,
29+
show,
30+
selectedKey,
31+
onSelectionChange,
32+
label,
33+
...props
34+
}: Props<T>) => (
35+
<BaseSelect
36+
className={clsx("flex flex-row items-center gap-2", className)}
37+
selectedKey={selectedKey}
38+
// @ts-expect-error react-aria coerces everything to Key for some reason...
39+
onSelectionChange={onSelectionChange}
40+
{...props}
41+
>
42+
<Label className="whitespace-nowrap opacity-80">{label}</Label>
43+
<Button
44+
className="group flex flex-row items-center gap-2 px-2 py-3 text-xs transition sm:px-4"
45+
size="nopad"
46+
>
47+
<SelectValue />
48+
<ChevronDownIcon className="size-4 flex-none opacity-60 transition duration-300 group-data-[pressed]:-rotate-180" />
49+
</Button>
50+
<Popover
51+
placement="bottom end"
52+
className="min-w-[--trigger-width] data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in data-[exiting]:fade-out"
53+
>
54+
<ListBox
55+
className="flex origin-top-right flex-col border border-neutral-400 bg-pythpurple-100 py-2 text-sm text-pythpurple-950 shadow shadow-neutral-400 outline-none"
56+
items={options.map((id) => ({ id }))}
57+
>
58+
{({ id }) => (
59+
<ListBoxItem className="flex cursor-pointer items-center gap-2 whitespace-nowrap px-4 py-2 text-left data-[disabled]:cursor-default data-[focused]:bg-pythpurple-800/20 data-[has-submenu]:data-[open]:bg-pythpurple-800/10 data-[has-submenu]:data-[open]:data-[focused]:bg-pythpurple-800/20 focus:outline-none focus-visible:outline-none">
60+
{show?.(id) ?? id}
61+
</ListBoxItem>
62+
)}
63+
</ListBox>
64+
</Popover>
65+
</BaseSelect>
66+
);

0 commit comments

Comments
 (0)