-
Notifications
You must be signed in to change notification settings - Fork 28
MAS UI integration v2 #189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0bce397
0bc9be4
11151f0
bfea1a2
c703438
3574ad0
e87c3b1
9bb6120
86c4141
794edce
dd148e7
2f9458f
6c9d8bc
27617ab
f15a7eb
c8ca9a4
d37dbd2
55a954b
1fac196
a431ed4
311fab8
bd465ca
303b6ab
da5ad3e
9e4e044
fec8758
d1ea737
f82d8d7
3ed47b0
1c939e8
0ca4fe5
37a06fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,121 @@ | ||||||||||||||||||||||||||||||||||||||
import { FC } from "react" | ||||||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||||||
BodyLg, | ||||||||||||||||||||||||||||||||||||||
Button, | ||||||||||||||||||||||||||||||||||||||
Card, | ||||||||||||||||||||||||||||||||||||||
H5, | ||||||||||||||||||||||||||||||||||||||
ModalBody, | ||||||||||||||||||||||||||||||||||||||
ModalCloseButton, | ||||||||||||||||||||||||||||||||||||||
ModalFooter, | ||||||||||||||||||||||||||||||||||||||
ModalHeader, | ||||||||||||||||||||||||||||||||||||||
LabelSm, | ||||||||||||||||||||||||||||||||||||||
BodyMd, | ||||||||||||||||||||||||||||||||||||||
List, | ||||||||||||||||||||||||||||||||||||||
ListItem, | ||||||||||||||||||||||||||||||||||||||
} from "@threshold-network/components" | ||||||||||||||||||||||||||||||||||||||
import { CheckCircleIcon } from "@chakra-ui/icons" | ||||||||||||||||||||||||||||||||||||||
import InfoBox from "../../InfoBox" | ||||||||||||||||||||||||||||||||||||||
import TokenBalance from "../../TokenBalance" | ||||||||||||||||||||||||||||||||||||||
import StakeAddressInfo from "../../../pages/Staking/StakeCard/StakeAddressInfo" | ||||||||||||||||||||||||||||||||||||||
import withBaseModal from "../withBaseModal" | ||||||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||||||
calculatePercenteage, | ||||||||||||||||||||||||||||||||||||||
formatPercentage, | ||||||||||||||||||||||||||||||||||||||
} from "../../../utils/percentage" | ||||||||||||||||||||||||||||||||||||||
import { BaseModalProps } from "../../../types" | ||||||||||||||||||||||||||||||||||||||
import { useAuthorizeMultipleAppsTransaction } from "../../../hooks/staking-applications" | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
export type AuthorizeAppsProps = BaseModalProps & { | ||||||||||||||||||||||||||||||||||||||
stakingProvider: string | ||||||||||||||||||||||||||||||||||||||
totalInTStake: string | ||||||||||||||||||||||||||||||||||||||
applications: { | ||||||||||||||||||||||||||||||||||||||
appName: string | ||||||||||||||||||||||||||||||||||||||
address: string | ||||||||||||||||||||||||||||||||||||||
authorizationAmount: string | ||||||||||||||||||||||||||||||||||||||
}[] | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
const AuthorizeStakingAppsBase: FC<AuthorizeAppsProps> = ({ | ||||||||||||||||||||||||||||||||||||||
stakingProvider, | ||||||||||||||||||||||||||||||||||||||
totalInTStake, | ||||||||||||||||||||||||||||||||||||||
applications, | ||||||||||||||||||||||||||||||||||||||
closeModal, | ||||||||||||||||||||||||||||||||||||||
}) => { | ||||||||||||||||||||||||||||||||||||||
const { authorizeMultipleApps } = useAuthorizeMultipleAppsTransaction() | ||||||||||||||||||||||||||||||||||||||
const onAuthorize = async () => { | ||||||||||||||||||||||||||||||||||||||
await authorizeMultipleApps( | ||||||||||||||||||||||||||||||||||||||
applications.map((_) => ({ | ||||||||||||||||||||||||||||||||||||||
address: _.address, | ||||||||||||||||||||||||||||||||||||||
amount: _.authorizationAmount, | ||||||||||||||||||||||||||||||||||||||
})), | ||||||||||||||||||||||||||||||||||||||
stakingProvider | ||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
Comment on lines
+45
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It won't memoize the submit function because the const [increment, setIncrement] = useState(1) // run `setIncrement((i) => i+1)` on button click
console.log("increment", increment)
const onAuthorize = useCallback(async () => {
await authorizeMultipleApps(
applications.map((_) => ({
address: _.address,
amount: _.authorizationAmount,
})),
stakingProvider
)
}, [authorizeMultipleApps, applications, stakingProvider])
useEffect(() => {
console.log("updated")
}, [onAuthorize]) Also I noticed that we use |
||||||||||||||||||||||||||||||||||||||
const numberOfApps = applications.length | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||
<> | ||||||||||||||||||||||||||||||||||||||
<ModalHeader>Authorize Apps</ModalHeader> | ||||||||||||||||||||||||||||||||||||||
<ModalCloseButton /> | ||||||||||||||||||||||||||||||||||||||
<ModalBody> | ||||||||||||||||||||||||||||||||||||||
<InfoBox variant="modal" mb="6" mt="0"> | ||||||||||||||||||||||||||||||||||||||
<H5> | ||||||||||||||||||||||||||||||||||||||
You are authorizing your stake for Threshold application | ||||||||||||||||||||||||||||||||||||||
{numberOfApps > 1 ? "s" : ""}. | ||||||||||||||||||||||||||||||||||||||
</H5> | ||||||||||||||||||||||||||||||||||||||
<BodyLg mt="4"> | ||||||||||||||||||||||||||||||||||||||
This will require {numberOfApps} transaction | ||||||||||||||||||||||||||||||||||||||
{numberOfApps > 1 ? "s" : ""}. You can adjust the authorization | ||||||||||||||||||||||||||||||||||||||
amount at any time. | ||||||||||||||||||||||||||||||||||||||
</BodyLg> | ||||||||||||||||||||||||||||||||||||||
</InfoBox> | ||||||||||||||||||||||||||||||||||||||
<List spacing="2.5"> | ||||||||||||||||||||||||||||||||||||||
{applications.map((app) => ( | ||||||||||||||||||||||||||||||||||||||
<ListItem key={app.appName}> | ||||||||||||||||||||||||||||||||||||||
<StakingApplicationToAuth | ||||||||||||||||||||||||||||||||||||||
{...app} | ||||||||||||||||||||||||||||||||||||||
stakingProvider={stakingProvider} | ||||||||||||||||||||||||||||||||||||||
totalInTStake={totalInTStake} | ||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||
</ListItem> | ||||||||||||||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||||||||||||||
</List> | ||||||||||||||||||||||||||||||||||||||
</ModalBody> | ||||||||||||||||||||||||||||||||||||||
Comment on lines
+72
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you gonna add the alerts that are in Figma designs? Link: https://www.figma.com/file/Tx1lZc7us4SqCeAgbt1hBV/Threshold-Dapp?node-id=6028%3A178394 And also: Link: https://www.figma.com/file/Tx1lZc7us4SqCeAgbt1hBV/Threshold-Dapp?node-id=6028%3A178369 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And also this one in stake Card: Link: https://www.figma.com/file/Tx1lZc7us4SqCeAgbt1hBV/Threshold-Dapp?node-id=6028%3A178187 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I'm going to add alerts in a separate PR- there are too many files to review now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gonna keep this convo as unresolved to not lost the track of it |
||||||||||||||||||||||||||||||||||||||
<ModalFooter> | ||||||||||||||||||||||||||||||||||||||
<Button onClick={closeModal} variant="outline" mr={2}> | ||||||||||||||||||||||||||||||||||||||
Dismiss | ||||||||||||||||||||||||||||||||||||||
</Button> | ||||||||||||||||||||||||||||||||||||||
<Button mr={2} onClick={onAuthorize}> | ||||||||||||||||||||||||||||||||||||||
Authorize | ||||||||||||||||||||||||||||||||||||||
</Button> | ||||||||||||||||||||||||||||||||||||||
</ModalFooter> | ||||||||||||||||||||||||||||||||||||||
</> | ||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
const StakingApplicationToAuth: FC<{ | ||||||||||||||||||||||||||||||||||||||
appName: string | ||||||||||||||||||||||||||||||||||||||
authorizationAmount: string | ||||||||||||||||||||||||||||||||||||||
stakingProvider: string | ||||||||||||||||||||||||||||||||||||||
totalInTStake: string | ||||||||||||||||||||||||||||||||||||||
}> = ({ appName, authorizationAmount, stakingProvider, totalInTStake }) => { | ||||||||||||||||||||||||||||||||||||||
const percentage = formatPercentage( | ||||||||||||||||||||||||||||||||||||||
calculatePercenteage(authorizationAmount, totalInTStake), | ||||||||||||||||||||||||||||||||||||||
undefined, | ||||||||||||||||||||||||||||||||||||||
true | ||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||
<Card> | ||||||||||||||||||||||||||||||||||||||
<LabelSm mb="4"> | ||||||||||||||||||||||||||||||||||||||
<CheckCircleIcon color="green.500" verticalAlign="top" mr="2" /> | ||||||||||||||||||||||||||||||||||||||
{appName} - {percentage} | ||||||||||||||||||||||||||||||||||||||
</LabelSm> | ||||||||||||||||||||||||||||||||||||||
<BodyMd mb="3">Authorization Amount</BodyMd> | ||||||||||||||||||||||||||||||||||||||
<TokenBalance tokenAmount={authorizationAmount} isLarge /> | ||||||||||||||||||||||||||||||||||||||
<StakeAddressInfo stakingProvider={stakingProvider} mb="0" /> | ||||||||||||||||||||||||||||||||||||||
</Card> | ||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
export const AuthorizeStakingApps = withBaseModal(AuthorizeStakingAppsBase) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import { FC, Fragment } from "react" | ||
import { Link as RouterLink, useNavigate } from "react-router-dom" | ||
import { | ||
HStack, | ||
BodyLg, | ||
Button, | ||
H5, | ||
ModalBody, | ||
ModalCloseButton, | ||
ModalFooter, | ||
ModalHeader, | ||
List, | ||
ListItem, | ||
Alert, | ||
AlertIcon, | ||
BodySm, | ||
Divider, | ||
Link, | ||
FlowStepStatus, | ||
} from "@threshold-network/components" | ||
import InfoBox from "../../InfoBox" | ||
import ExternalLink from "../../ExternalLink" | ||
import ViewInBlockExplorer from "../../ViewInBlockExplorer" | ||
import withBaseModal from "../withBaseModal" | ||
import { useAppSelector } from "../../../hooks/store" | ||
import { selectStakeByStakingProvider } from "../../../store/staking" | ||
import { | ||
calculatePercenteage, | ||
formatPercentage, | ||
} from "../../../utils/percentage" | ||
import shortenAddress from "../../../utils/shortenAddress" | ||
import { formatTokenAmount } from "../../../utils/formatAmount" | ||
import { ExplorerDataType } from "../../../utils/createEtherscanLink" | ||
import { ExternalHref } from "../../../enums" | ||
import { BaseModalProps } from "../../../types" | ||
import { getStakingAppNameFromAddress } from "../../../utils/getStakingAppNameFromAddress" | ||
import StakingTimeline from "../../StakingTimeline" | ||
|
||
export type StakingApplicationsAuthorizeProps = BaseModalProps & { | ||
stakingProvider: string | ||
authorizedStakingApplications: { | ||
address: string | ||
amount: string | ||
txHash: string | ||
}[] | ||
} | ||
|
||
const StakingApplicationsAuthorizedBase: FC< | ||
StakingApplicationsAuthorizeProps | ||
> = ({ stakingProvider, authorizedStakingApplications, closeModal }) => { | ||
const stake = useAppSelector((state) => | ||
selectStakeByStakingProvider(state, stakingProvider) | ||
) | ||
const navigate = useNavigate() | ||
const onAuthorizeOtherApps = () => { | ||
closeModal() | ||
navigate(`/staking/${stakingProvider}/authorize`) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is OK for now because I am doing the same in many modals, and I don't have a good solution to implement before the launch. But it's going to throw a warning, see: https://dev.to/jexperton/how-to-fix-the-react-memory-leak-warning-d4i also nit: why async method here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah we need to get rid of the warning some day. Reagrding async- it is unnecessary. I'll remove. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
|
||
return ( | ||
<> | ||
<ModalHeader>Step 2 Completed</ModalHeader> | ||
<ModalCloseButton /> | ||
<ModalBody> | ||
<Alert status="success" mb={4}> | ||
<AlertIcon /> | ||
Your authorization was successful! | ||
</Alert> | ||
<List spacing="2" mb="6"> | ||
<ListItem> | ||
<HStack justifyContent="space-between"> | ||
<BodySm>Provider Address</BodySm> | ||
<BodySm>{shortenAddress(stakingProvider)}</BodySm> | ||
</HStack> | ||
</ListItem> | ||
{authorizedStakingApplications.map((_) => ( | ||
<ListItem key={_.address}> | ||
<HStack justifyContent="space-between"> | ||
<BodySm>{`${getStakingAppNameFromAddress( | ||
_.address | ||
)} Authorization Amount`}</BodySm> | ||
<BodySm>{`${formatTokenAmount(_.amount)} T (${formatPercentage( | ||
calculatePercenteage(_.amount, stake?.totalInTStake) | ||
)})`}</BodySm> | ||
</HStack> | ||
</ListItem> | ||
))} | ||
</List> | ||
<InfoBox variant="modal"> | ||
<H5> | ||
You can authorize more apps, or continue to Step 3 to set up nodes. | ||
</H5> | ||
<BodyLg mt="4"> | ||
You can adjust the authorization amount at any time from the{" "} | ||
<Link as={RouterLink} to="/staking" color="brand.500"> | ||
Staking page | ||
</Link> | ||
. | ||
</BodyLg> | ||
</InfoBox> | ||
<StakingTimeline | ||
mt="9" | ||
statuses={[ | ||
FlowStepStatus.complete, | ||
FlowStepStatus.complete, | ||
FlowStepStatus.active, | ||
]} | ||
/> | ||
<BodySm align="center" mt="12"> | ||
{authorizedStakingApplications.length === 1 ? ( | ||
<> | ||
<ViewInBlockExplorer | ||
text="View" | ||
id={authorizedStakingApplications[0].txHash} | ||
type={ExplorerDataType.TRANSACTION} | ||
/>{" "} | ||
transaction on Etherscan | ||
</> | ||
) : ( | ||
<> | ||
View{" "} | ||
{authorizedStakingApplications.map((_, index) => ( | ||
<Fragment key={_.address}> | ||
<ViewInBlockExplorer | ||
text={`transaction ${index + 1}`} | ||
id={_.txHash} | ||
type={ExplorerDataType.TRANSACTION} | ||
/> | ||
{index + 1 === authorizedStakingApplications.length | ||
? " " | ||
: " and "} | ||
</Fragment> | ||
))} | ||
on Etherscan | ||
</> | ||
)} | ||
Comment on lines
+119
to
+136
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we could specify here which transaction is which by displaying the name of the app? For example:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implemented based on Figma views https://www.figma.com/file/Tx1lZc7us4SqCeAgbt1hBV/Threshold-Dapp?node-id=6098%3A141093 but I'll ping @sashatanase and @liz-shinn as well 😆. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we do that? We might need to make some changes in the copy, so we do not have a wall of text, though. Making the changes now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @michalsmiarowski let's update that once we get the final copy, ok? |
||
</BodySm> | ||
<Divider mt="4" /> | ||
</ModalBody> | ||
<ModalFooter> | ||
<Button | ||
variant="outline" | ||
as={ExternalLink} | ||
mr={2} | ||
href={ExternalHref.setupNodes} | ||
text="Node Setup Doc" | ||
withArrow | ||
/> | ||
<Button onClick={onAuthorizeOtherApps} mr={2}> | ||
Authorize Other Apps | ||
</Button> | ||
</ModalFooter> | ||
</> | ||
) | ||
} | ||
|
||
export const StakingApplicationsAuthorized = withBaseModal( | ||
StakingApplicationsAuthorizedBase | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { AuthorizeStakingApps } from "./AuthorizeStakingApps" | ||
export { StakingApplicationsAuthorized } from "./StakingApplicationsAuthorized" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this just a code cleanup change because the Icon inherits the final color?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes exactly. The previous impl won't work in a case like that:
This will render the arrow in default color even if we pass
color
prop- the icon won't inherit color from parent.