Skip to content

Commit

Permalink
feat: start with search and review modals
Browse files Browse the repository at this point in the history
  • Loading branch information
icfor committed Mar 6, 2024
1 parent 9d2b71b commit 61a36fd
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 114 deletions.
13 changes: 13 additions & 0 deletions src/features/core/components/base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,16 @@ export const FloatingDropdown = ({
</div>
);
};

type SearchInputProps = React.DetailedHTMLProps<
React.InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>;

export const SearchInput = (props: SearchInputProps) => (
<input
{...props}
className="border-none bg-transparent text-white outline-none"
style={{ borderBottom: "1px solid white" }}
/>
);
1 change: 0 additions & 1 deletion src/features/staking/components/main-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ function StakingPage() {
</div>
<StakingOverview />
{isShowingDetails && canShowDetail && <DelegationDetails />}
<Title>Validators</Title>
<ValidatorsTable />
</div>
<StakingModals />
Expand Down
90 changes: 63 additions & 27 deletions src/features/staking/components/modals/staking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,68 @@ const StakingModal = () => {
);
}

if (step === "review") {
return (
<>
<div className="text-center">
<div className="mb-[16px]">
<HeroText>REVIEW</HeroText>
</div>
<div>
Get ready to stake your XION token with{" "}
{validator.description.moniker}. Press 'Confirm' to proceed.
</div>
</div>
<div className="mb-[32px] mt-[32px] flex w-full flex-col items-center justify-center gap-[12px]">
<Heading8>Staked Amount</Heading8>
<Heading2>{amountXION}</Heading2>
<Heading8>$24N</Heading8>
</div>
{!!memo && (
<div className="mb-[32px] text-center italic">
<div>{memo}</div>
</div>
)}
<Button
disabled={isLoading}
onClick={() => {
if (!client) return;

setIsLoading(true);

const addresses: StakeAddresses = {
delegator: account.bech32Address,
validator: validator.operatorAddress,
};

stakeValidatorAction(
addresses,
getXionCoin(amountXIONParsed),
memo,
client,
staking,
)
.then((fetchDataFn) => {
setStep("completed");

return fetchDataFn();
})
.catch(() => {
toast("Staking error", {
type: "error",
});
})
.finally(() => {
setIsLoading(false);
});
}}
>
CONFIRM
</Button>
</>
);
}

const getHasAmountError = () =>
!amountUSD ||
!availableTokens ||
Expand All @@ -135,33 +197,7 @@ const StakingModal = () => {
)
return;

setIsLoading(true);

const addresses: StakeAddresses = {
delegator: account.bech32Address,
validator: validator.operatorAddress,
};

stakeValidatorAction(
addresses,
getXionCoin(amountXIONParsed),
memo,
client,
staking,
)
.then((fetchDataFn) => {
setStep("completed");

return fetchDataFn();
})
.catch(() => {
toast("Staking error", {
type: "error",
});
})
.finally(() => {
setIsLoading(false);
});
setStep("review");
};

return (
Expand Down
200 changes: 114 additions & 86 deletions src/features/staking/components/validators-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
import BigNumber from "bignumber.js";
import { memo, useState } from "react";

import { ButtonPill, NavLink } from "@/features/core/components/base";
import {
ButtonPill,
NavLink,
SearchInput,
Title,
} from "@/features/core/components/base";
import { HeaderTitleBase } from "@/features/core/components/table";

import { useStaking } from "../context/hooks";
Expand Down Expand Up @@ -128,112 +133,135 @@ const HeaderTitle = HeaderTitleBase<SortMethod>;
const ValidatorsTable = () => {
const { isConnected, staking } = useStaking();
const [sortMethod, setSortMethod] = useState<SortMethod>("none");
const [searchValue, setSearchValue] = useState<string>("");

const { validators } = staking.state;

if (!validators?.items.length) return null;

const sortedItems = validators.items.slice().sort((a, b) => {
if (sortMethod === "none") return 0;
const sortedItems = validators.items
.slice()
.sort((a, b) => {
if (sortMethod === "none") return 0;

if (["voting-power-asc", "voting-power-desc"].includes(sortMethod)) {
const votingPowerA = getVotingPowerPerc(a.tokens, staking.state);
const votingPowerB = getVotingPowerPerc(b.tokens, staking.state);

if (["voting-power-asc", "voting-power-desc"].includes(sortMethod)) {
const votingPowerA = getVotingPowerPerc(a.tokens, staking.state);
const votingPowerB = getVotingPowerPerc(b.tokens, staking.state);
if (!votingPowerA || !votingPowerB) return 0;

if (!votingPowerA || !votingPowerB) return 0;
return sortMethod === "voting-power-asc"
? votingPowerA - votingPowerB
: votingPowerB - votingPowerA;
}

return sortMethod === "voting-power-asc"
? votingPowerA - votingPowerB
: votingPowerB - votingPowerA;
}
if (["commission-asc", "commission-desc"].includes(sortMethod)) {
const commissionA = parseFloat(a.commission.commissionRates.rate);
const commissionB = parseFloat(b.commission.commissionRates.rate);

if (["commission-asc", "commission-desc"].includes(sortMethod)) {
const commissionA = parseFloat(a.commission.commissionRates.rate);
const commissionB = parseFloat(b.commission.commissionRates.rate);
if (!commissionA || !commissionB) return 0;

if (!commissionA || !commissionB) return 0;
return sortMethod === "commission-asc"
? commissionA - commissionB
: commissionB - commissionA;
}

return sortMethod === "commission-asc"
? commissionA - commissionB
: commissionB - commissionA;
}
if (["name-asc", "name-desc"].includes(sortMethod)) {
const nameA = a.description.moniker.toLowerCase();
const nameB = b.description.moniker.toLowerCase();

if (["name-asc", "name-desc"].includes(sortMethod)) {
const nameA = a.description.moniker.toLowerCase();
const nameB = b.description.moniker.toLowerCase();
if (!nameA || !nameB) return 0;

if (!nameA || !nameB) return 0;
return sortMethod === "name-asc"
? nameA.localeCompare(nameB)
: nameB.localeCompare(nameA);
}

return sortMethod === "name-asc"
? nameA.localeCompare(nameB)
: nameB.localeCompare(nameA);
}
if (["staked-asc", "staked-desc"].includes(sortMethod)) {
const aTokens = new BigNumber(a.tokens);
const bTokens = new BigNumber(b.tokens);

if (["staked-asc", "staked-desc"].includes(sortMethod)) {
const aTokens = new BigNumber(a.tokens);
const bTokens = new BigNumber(b.tokens);
return sortMethod === "staked-asc"
? aTokens.minus(bTokens).toNumber()
: bTokens.minus(aTokens).toNumber();
}

return sortMethod === "staked-asc"
? aTokens.minus(bTokens).toNumber()
: bTokens.minus(aTokens).toNumber();
}
return 0;
})
.filter((validator) => {
if (!searchValue) return true;

return 0;
});
const moniker = validator.description.moniker.toLowerCase();
const operatorAddress = validator.operatorAddress.toLowerCase();

return (
moniker.includes(searchValue.toLowerCase()) ||
operatorAddress.includes(searchValue.toLowerCase())
);
});

return (
<div className="overflow-hidden rounded-[24px] bg-bg-600 pb-4 text-typo-100">
<div
className="grid w-full items-center justify-between gap-2 bg-bg-500 p-4 uppercase"
style={gridStyle}
>
<div />
<HeaderTitle
onSort={setSortMethod}
sort={sortMethod}
sorting={["name-asc", "name-desc"]}
>
Validator
</HeaderTitle>
<HeaderTitle
onSort={setSortMethod}
sort={sortMethod}
sorting={["staked-asc", "staked-desc"]}
>
<div className="text-right">Staked Amount</div>
</HeaderTitle>
<HeaderTitle
onSort={setSortMethod}
sort={sortMethod}
sorting={["commission-asc", "commission-desc"]}
>
<div className="text-right">Commission</div>
</HeaderTitle>
<HeaderTitle
onSort={setSortMethod}
sort={sortMethod}
sorting={["voting-power-asc", "voting-power-desc"]}
<>
<div className="flex w-full flex-row justify-start gap-[16px]">
<Title>Validators</Title>
<SearchInput
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
/>
</div>
<div className="overflow-hidden rounded-[24px] bg-bg-600 pb-4 text-typo-100">
<div
className="grid w-full items-center justify-between gap-2 bg-bg-500 p-4 uppercase"
style={gridStyle}
>
<div className="text-right">Voting Power</div>
</HeaderTitle>
<div />
<HeaderTitle
onSort={setSortMethod}
sort={sortMethod}
sorting={["name-asc", "name-desc"]}
>
Validator
</HeaderTitle>
<HeaderTitle
onSort={setSortMethod}
sort={sortMethod}
sorting={["staked-asc", "staked-desc"]}
>
<div className="text-right">Staked Amount</div>
</HeaderTitle>
<HeaderTitle
onSort={setSortMethod}
sort={sortMethod}
sorting={["commission-asc", "commission-desc"]}
>
<div className="text-right">Commission</div>
</HeaderTitle>
<HeaderTitle
onSort={setSortMethod}
sort={sortMethod}
sorting={["voting-power-asc", "voting-power-desc"]}
>
<div className="text-right">Voting Power</div>
</HeaderTitle>
</div>
{sortedItems.map((validator) => (
<ValidatorRow
disabled={!isConnected}
key={validator.operatorAddress}
onStake={() => {
staking.dispatch(
setModalOpened({
content: { validator },
type: "delegate",
}),
);
}}
staking={staking}
validator={validator}
/>
))}
</div>
{sortedItems.map((validator) => (
<ValidatorRow
disabled={!isConnected}
key={validator.operatorAddress}
onStake={() => {
staking.dispatch(
setModalOpened({
content: { validator },
type: "delegate",
}),
);
}}
staking={staking}
validator={validator}
/>
))}
</div>
</>
);
};

Expand Down

0 comments on commit 61a36fd

Please sign in to comment.