diff --git a/src/features/core/utils.ts b/src/features/core/utils.ts new file mode 100644 index 0000000..4726d34 --- /dev/null +++ b/src/features/core/utils.ts @@ -0,0 +1,21 @@ +export const sortUtil = (a: unknown, b: unknown, sorting: "asc" | "desc") => { + if (typeof a !== typeof b) { + return 0; + } + + if (typeof a === "string") { + return sorting === "asc" + ? a.localeCompare(b as string) + : (b as string).localeCompare(a); + } + + if (typeof a === "number") { + if (Number.isNaN(a) || Number.isNaN(b as number)) { + return 0; + } + + return sorting === "asc" ? a - (b as number) : (b as number) - a; + } + + return 0; +}; diff --git a/src/features/staking/components/delegation-details.tsx b/src/features/staking/components/delegation-details.tsx index a15f2e7..d7bcc9d 100644 --- a/src/features/staking/components/delegation-details.tsx +++ b/src/features/staking/components/delegation-details.tsx @@ -7,6 +7,7 @@ import { HeaderTitleBase } from "@/features/core/components/table"; import { useCore } from "@/features/core/context/hooks"; import { setIsLoadingBlocking } from "@/features/core/context/reducer"; import type { CoreContextType } from "@/features/core/context/state"; +import { sortUtil } from "@/features/core/utils"; import { claimRewardsAction, @@ -253,9 +254,24 @@ const UnbondingRow = ({ disabled, staking, unbonding }: UnbondingRowProps) => { ); }; -type SortMethod = "bar" | "foo" | "none"; - -const HeaderTitle = HeaderTitleBase; +type DelegationSortMethod = + | "commission-asc" + | "commission-desc" + | "none" + | "rewards-asc" + | "rewards-desc" + | "staked-asc" + | "staked-desc"; + +type SortMethod = + | "amount-asc" + | "amount-desc" + | "completion-asc" + | "completion-desc" + | "none"; + +const DelegationHeaderTitle = HeaderTitleBase; +const UnbondingHeaderTitle = HeaderTitleBase; const headerStyle = "grid w-full items-center justify-between gap-2 p-4 uppercase"; @@ -267,7 +283,7 @@ const DelegationDetails = () => { const { client, staking } = stakingRef; const [delegationsSortMethod, setDelegationsSortMethod] = - useState("none"); + useState("none"); const [unbondingsSortMethod, setUnbondingsSortMethod] = useState("none"); @@ -285,34 +301,80 @@ const DelegationDetails = () => {
{hasDelegations && (() => { - const sortedDelegations = delegations.items.slice(); + const validatorIdToValidator = + staking.state.validators?.items.reduce( + (acc, v) => { + acc[v.operatorAddress] = v; + + return acc; + }, + { ...staking.state.extraValidators }, + ) || {}; + + const sortedDelegations = delegations.items.slice().sort((a, b) => { + switch (delegationsSortMethod) { + case "staked-asc": + case "staked-desc": + return sortUtil( + a.balance.amount, + b.balance.amount, + delegationsSortMethod === "staked-asc" ? "asc" : "desc", + ); + + case "rewards-asc": + case "rewards-desc": + return sortUtil( + a.rewards.amount, + b.rewards.amount, + delegationsSortMethod === "rewards-asc" ? "asc" : "desc", + ); + + case "commission-asc": + + case "commission-desc": { + const validatorA = validatorIdToValidator[a.validatorAddress]; + const validatorB = validatorIdToValidator[b.validatorAddress]; + + return sortUtil( + Number(validatorA?.commission.commissionRates.rate), + Number(validatorB?.commission.commissionRates.rate), + delegationsSortMethod === "commission-asc" ? "asc" : "desc", + ); + } + + default: + delegationsSortMethod satisfies "none"; + + return 0; + } + }); return (
- Delegations - Delegations +
Staked Amount
-
- +
Commission
-
- +
Rewards
-
+
{sortedDelegations.map((delegation, index) => ( { })()} {hasUnbondings && (() => { - const sortedUnbondings = unbondings.items.slice(); + const sortedUnbondings = unbondings.items.slice().sort((a, b) => { + switch (unbondingsSortMethod) { + case "amount-asc": + case "amount-desc": + return sortUtil( + Number(a.balance.amount), + Number(b.balance.amount), + unbondingsSortMethod === "amount-asc" ? "asc" : "desc", + ); + + case "completion-asc": + case "completion-desc": + return sortUtil( + a.completionTime, + b.completionTime, + unbondingsSortMethod === "completion-asc" ? "asc" : "desc", + ); + + default: + unbondingsSortMethod satisfies "none"; + + return 0; + } + }); return (
- Delegations - Unstakings +
Staked Amount
-
- + +
Status
-
- +
Completion Time
-
+
{sortedUnbondings.map((unbonding, index) => (