Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions web/src/assets/svgs/styled/three-pnks.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 16 additions & 8 deletions web/src/components/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const FieldContainer = styled.div<FieldContainerProps>`
justify-content: flex-start;
white-space: nowrap;
width: 100%;

.value {
flex-grow: 1;
text-align: end;
Expand All @@ -28,7 +27,6 @@ const FieldContainer = styled.div<FieldContainerProps>`
cursor: pointer;
}
}

${({ isList }) =>
isList &&
css`
Expand All @@ -42,8 +40,8 @@ const FieldContainer = styled.div<FieldContainerProps>`
`
)}
`};
${({ isOverview }) =>
isOverview &&
${({ isOverview, isJurorBalance }) =>
(isOverview || isJurorBalance) &&
css`
${landscapeStyle(
() => css`
Expand All @@ -66,6 +64,7 @@ type FieldContainerProps = {
width?: string;
isList?: boolean;
isOverview?: boolean;
isJurorBalance?: boolean;
};

interface IField {
Expand All @@ -76,12 +75,22 @@ interface IField {
width?: string;
displayAsList?: boolean;
isOverview?: boolean;
isJurorBalance?: boolean;
}

const Field: React.FC<IField> = ({ icon: Icon, name, value, link, width, displayAsList, isOverview }) => {
const Field: React.FC<IField> = ({
icon: Icon,
name,
value,
link,
width,
displayAsList,
isOverview,
isJurorBalance,
}) => {
return (
<FieldContainer isList={displayAsList} isOverview={isOverview} width={width}>
{(!displayAsList || isOverview) && (
<FieldContainer isList={displayAsList} isOverview={isOverview} isJurorBalance={isJurorBalance} width={width}>
{(!displayAsList || isOverview || isJurorBalance) && (
<>
<Icon />
<label>{name}:</label>
Expand All @@ -97,5 +106,4 @@ const Field: React.FC<IField> = ({ icon: Icon, name, value, link, width, display
</FieldContainer>
);
};

export default Field;
15 changes: 15 additions & 0 deletions web/src/components/NumberInputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ const Container = styled.div`
const StyledField = styled(Field)`
width: 100%;
height: fit-content;

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
appearance: none;
}
input[type="number"] {
-moz-appearance: textfield;
}
input {
border: 1px solid ${({ theme }) => theme.stroke};
border-right: none;
height: 45px;
font-size: 16px;
}
`;

interface INumberInputField {
Expand Down
64 changes: 36 additions & 28 deletions web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { commify, uncommify } from "utils/commify";
import { EnsureChain } from "components/EnsureChain";

const StyledField = styled(NumberInputField)`
width: 100%;
height: fit-content;
`;

Expand All @@ -33,6 +32,13 @@ const InputArea = styled.div`
flex-direction: column;
align-items: center;
gap: 12px;
width: 100%;
`;

const InputFieldAndButton = styled.div`
display: flex;
flex-direction: row;
width: 100%;
`;

interface IInputDisplay {
Expand Down Expand Up @@ -87,35 +93,37 @@ const InputDisplay: React.FC<IInputDisplay> = ({
</StyledLabel>
</LabelArea>
<InputArea>
<StyledField
value={uncommify(amount)}
onChange={(e) => {
setAmount(e);
}}
placeholder={isStaking ? "Amount to stake" : "Amount to withdraw"}
message={
isStaking
? `You need to stake at least ${formatPNK(courtDetails?.court.minStake ?? 0n, 3)} PNK. ` +
"You may need two transactions, one to increase allowance, the other to stake."
: `You need to either withdraw all or keep at least ${formatPNK(
courtDetails?.court.minStake ?? 0n,
3
)} PNK.`
}
formatter={(number: string) => commify(roundNumberDown(Number(number)))}
/>
<EnsureChain>
<StakeWithdrawButton
{...{
parsedAmount,
action,
setAmount,
isSending,
setIsSending,
setIsPopupOpen,
<InputFieldAndButton>
<StyledField
value={uncommify(amount)}
onChange={(e) => {
setAmount(e);
}}
placeholder={isStaking ? "Amount to stake" : "Amount to withdraw"}
// message={
// isStaking
// ? `You need to stake at least ${formatPNK(courtDetails?.court.minStake ?? 0n, 3)} PNK. ` +
// "You may need two transactions, one to increase allowance, the other to stake."
// : `You need to either withdraw all or keep at least ${formatPNK(
// courtDetails?.court.minStake ?? 0n,
// 3
// )} PNK.`
// }
formatter={(number: string) => commify(roundNumberDown(Number(number)))}
/>
</EnsureChain>
<EnsureChain>
<StakeWithdrawButton
{...{
parsedAmount,
action,
setAmount,
isSending,
setIsSending,
setIsPopupOpen,
}}
/>
</EnsureChain>
</InputFieldAndButton>
</InputArea>
</>
);
Expand Down
16 changes: 14 additions & 2 deletions web/src/pages/Courts/CourtDetails/StakePanel/JurorStakeDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useEffect, useMemo } from "react";
import styled from "styled-components";
import styled, { css } from "styled-components";
import { landscapeStyle } from "styles/landscapeStyle";
import { useParams } from "react-router-dom";
import { formatEther } from "viem";
import { useAccount } from "wagmi";
Expand All @@ -13,10 +14,21 @@ import { useKlerosCoreGetJurorBalance } from "hooks/contracts/generated";

const Container = styled.div`
display: flex;
width: 100%;
flex-direction: column;
justify-content: space-between;
gap: 8px;
margin-top: 12px;

${landscapeStyle(
() => css`
margin-top: 32px;
gap: 32px;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
`
)}
`;

const format = (value: bigint | undefined): string => (value !== undefined ? formatEther(value) : "0");
Expand Down Expand Up @@ -104,7 +116,7 @@ const JurorBalanceDisplay = () => {
return (
<Container>
{data.map(({ icon, name, value }) => (
<Field key={name} {...{ icon, name, value }} />
<Field isJurorBalance={true} key={name} {...{ icon, name, value }} />
))}
</Container>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useMemo } from "react";
import styled from "styled-components";
import { useParams } from "react-router-dom";
import { useAccount, usePublicClient } from "wagmi";
import { Button } from "@kleros/ui-components-library";
Expand All @@ -17,6 +18,11 @@ import { wrapWithToast } from "utils/wrapWithToast";
import { isUndefined } from "utils/index";
import { EnsureChain } from "components/EnsureChain";

const StyledStakeWithdrawButton = styled(Button)`
border: 1px solid ${({ theme }) => theme.stroke};
height: 45px;
`;

export enum ActionType {
allowance = "allowance",
stake = "stake",
Expand Down Expand Up @@ -129,7 +135,7 @@ const StakeWithdrawButton: React.FC<IActionButton> = ({
const { text, checkDisabled, onClick } = buttonProps[isAllowance ? ActionType.allowance : action];
return (
<EnsureChain>
<Button
<StyledStakeWithdrawButton
text={text}
isLoading={isSending}
disabled={
Expand Down
95 changes: 69 additions & 26 deletions web/src/pages/Courts/CourtDetails/StakePanel/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { useState } from "react";
import styled from "styled-components";
import styled, { css } from "styled-components";
import { landscapeStyle } from "styles/landscapeStyle";
import { useLockOverlayScroll } from "hooks/useLockOverlayScroll";
import Tag from "components/Tag";
import JurorBalanceDisplay from "./JurorStakeDisplay";
import InputDisplay from "./InputDisplay";
import { ActionType } from "./StakeWithdrawButton";
import Popup, { PopupType } from "components/Popup/index";
import BalanceIcon from "assets/svgs/icons/balance.svg";
import ThreePnksIcon from "tsx:assets/svgs/styled/three-pnks.svg";

const Container = styled.div`
position: relative;
Expand All @@ -15,6 +17,23 @@ const Container = styled.div`
display: flex;
flex-direction: column;
gap: 28px;

${landscapeStyle(
() => css`
flex-direction: row;
`
)};
`;

const LeftArea = styled.div`
display: flex;
flex-direction: column;

${landscapeStyle(
() => css`
width: 50%;
`
)};
`;

const TagArea = styled.div`
Expand All @@ -23,13 +42,32 @@ const TagArea = styled.div`
`;

const StakeArea = styled(TagArea)`
margin-top: 28px;
flex-direction: column;
`;

const TextArea = styled.div`
margin-top: 32px;
color: ${({ theme }) => theme.primaryText};
`;

const ThreePnksIconContainer = styled.div`
display: flex;
width: 100%;
justify-content: flex-start;
align-items: center;

${landscapeStyle(
() => css`
width: 50%;
justify-content: flex-end;
align-items: flex-end;
margin-bottom: 42px;
margin-right: 52px;
`
)};
`;

const StakePanel: React.FC<{ courtName: string; id: string }> = ({ courtName = "General Court", id }) => {
const [amount, setAmount] = useState("");
const [isSending, setIsSending] = useState<boolean>(false);
Expand All @@ -47,31 +85,36 @@ const StakePanel: React.FC<{ courtName: string; id: string }> = ({ courtName = "
const isStaking = action === ActionType.stake;
return (
<Container>
<TagArea>
<Tag text="Stake" active={isActive} onClick={() => handleClick(ActionType.stake)} />
<Tag text="Withdraw" active={!isActive} onClick={() => handleClick(ActionType.withdraw)} />
</TagArea>
<TextArea>
<strong>{`${isStaking ? "Stake" : "Withdraw"} PNK`}</strong> {`${isStaking ? "to join the" : "from"}`}{" "}
{courtName} court. Depending on the staking phase, your stake might take some time to be live.
</TextArea>
<StakeArea>
<InputDisplay {...{ action, isSending, setIsSending, setIsPopupOpen, amount, setAmount }} />
<JurorBalanceDisplay />
</StakeArea>
{isPopupOpen && (
<Popup
title={isStaking ? "Stake Confirmed" : "Withdraw Confirmed"}
icon={BalanceIcon}
popupType={PopupType.STAKE_WITHDRAW}
isStake={isStaking}
pnkStaked={amount}
courtName={courtName}
courtId={id}
setIsOpen={setIsPopupOpen}
setAmount={setAmount}
/>
)}
<LeftArea>
<TagArea>
<Tag text="Stake" active={isActive} onClick={() => handleClick(ActionType.stake)} />
<Tag text="Withdraw" active={!isActive} onClick={() => handleClick(ActionType.withdraw)} />
</TagArea>
<TextArea>
<strong>{`${isStaking ? "Stake" : "Withdraw"} PNK`}</strong> {`${isStaking ? "to join the" : "from"}`}{" "}
{courtName} court
</TextArea>
<StakeArea>
<InputDisplay {...{ action, isSending, setIsSending, setIsPopupOpen, amount, setAmount }} />
<JurorBalanceDisplay />
</StakeArea>
{isPopupOpen && (
<Popup
title={isStaking ? "Stake Confirmed" : "Withdraw Confirmed"}
icon={BalanceIcon}
popupType={PopupType.STAKE_WITHDRAW}
isStake={isStaking}
pnkStaked={amount}
courtName={courtName}
courtId={id}
setIsOpen={setIsPopupOpen}
setAmount={setAmount}
/>
)}
</LeftArea>
<ThreePnksIconContainer>
<ThreePnksIcon />
</ThreePnksIconContainer>
</Container>
);
};
Expand Down