diff --git a/src/api.graphql b/src/api.graphql index 9fe0406b5..fbf7dffb2 100644 --- a/src/api.graphql +++ b/src/api.graphql @@ -56,6 +56,7 @@ query TransactionResult($txId: TxId!) { blockHash blockIndex txStatus + outputState } } } diff --git a/src/renderer/components/core/Layout/UserInfo/MigrateButton.tsx b/src/renderer/components/core/Layout/UserInfo/MigrateButton.tsx new file mode 100644 index 000000000..a2e295cd9 --- /dev/null +++ b/src/renderer/components/core/Layout/UserInfo/MigrateButton.tsx @@ -0,0 +1,42 @@ +import { motion } from "framer-motion"; +import React, { MouseEvent, useCallback } from "react"; +import { T } from "src/renderer/i18n"; +import { styled } from "src/renderer/stitches.config"; + +export const Button = styled(motion.button, { + appearance: "none", + backgroundColor: "#dc9c2d", + border: "none", + padding: "5px 1rem", + "&:disabled": { + backgroundColor: "$gray", + color: "white", + }, +}); + +const transifexTags = "v2/MigrateButton"; + +interface MigrateButtonProps { + onClick: () => void; + loading: boolean; +} + +export function MigrateButton({ loading, onClick }: MigrateButtonProps) { + const eventListener = useCallback<(e: MouseEvent) => void>( + (e) => { + e.stopPropagation(); + onClick(); + }, + [onClick], + ); + + return ( + + ); +} diff --git a/src/renderer/components/core/Layout/UserInfo/index.tsx b/src/renderer/components/core/Layout/UserInfo/index.tsx index b1bb699bc..a3e1e7d79 100644 --- a/src/renderer/components/core/Layout/UserInfo/index.tsx +++ b/src/renderer/components/core/Layout/UserInfo/index.tsx @@ -13,16 +13,17 @@ import { useClaimStakeRewardLazyQuery, useTransactionResultLazyQuery, useCheckPatchTableSubscription, + useStakeLazyQuery, } from "src/generated/graphql"; import AccountBoxIcon from "@material-ui/icons/AccountBox"; -import LaunchIcon from "@material-ui/icons/Launch"; import FileCopyIcon from "@material-ui/icons/FileCopy"; import goldIconUrl from "src/renderer/resources/ui-main-icon-gold.png"; import monsterIconUrl from "src/renderer/resources/monster.png"; import { getRemain } from "src/utils/monsterCollection/utils"; import ClaimCollectionRewardsOverlay from "src/renderer/views/ClaimCollectionRewardsOverlay"; +import MigrateCollectionRewardsOverlay from "src/renderer/views/MigrateCollectionRewardsOverlay"; import { Button, ClaimButton } from "./ClaimButton"; import { clipboard } from "electron"; import { toast } from "react-hot-toast"; @@ -37,6 +38,7 @@ import deepEqual from "deep-equal"; import { StakeStatusButton } from "./StakeStatus"; import { useStore } from "src/utils/useStore"; import Decimal from "decimal.js"; +import { MigrateButton } from "./MigrateButton"; const UserInfoStyled = styled(motion.ul, { position: "fixed", @@ -93,29 +95,47 @@ export default function UserInfo() { const isCollecting = !!startedBlockIndex && startedBlockIndex > 0; const [claimLoading, setClaimLoading] = useState(false); const [isMigratable, setIsMigratable] = useState( - isCollecting && + !!deposit && + new Decimal(deposit).gt(0) && + tip !== 0 && + isCollecting && !deepEqual(stakeRewards, latestSheet?.stateQuery.latestStakeRewards, { strict: true, }), ); + useEffect(() => { const txStatus = result?.transaction.transactionResult.txStatus; if (!txStatus || txStatus === TxStatus.Staging) return; stopPolling?.(); setClaimLoading(false); - if (txStatus === TxStatus.Success) { - toast.success( - t("Successfully sent rewards to {name} #{address}", { - _tags: "v2/monster-collection", - name: claimedAvatar.current!.name, - address: claimedAvatar.current!.address.slice(2), - }), - ); - refetch(); + if (canClaim) { + if (txStatus === TxStatus.Success) { + toast.success( + t("Successfully sent rewards to {name} #{address}", { + _tags: "v2/monster-collection", + name: claimedAvatar.current!.name, + address: claimedAvatar.current!.address.slice(2), + }), + ); + refetch(); + } else { + toast.error(t("Failed to claim your reward.")); + console.error("Claim transaction failed: ", result); + } } else { - toast.error(t("Failed to claim your reward.")); - console.error("Claim transaction failed: ", result); + if (txStatus === TxStatus.Success) { + toast.success( + t("Successfully migrated your staking.", { + _tags: "v2/monster-collection", + }), + ); + refetch(); + } else { + toast.error(t("Failed to migrate your staking.")); + console.error("Migration transaction failed: ", result); + } } }, [result]); @@ -148,9 +168,22 @@ export default function UserInfo() { }); }, }); + + const [requestMigrationTx] = useStakeLazyQuery({ + fetchPolicy: "network-only", + onCompleted: ({ actionTxQuery: { stake } }) => { + tx(stake).then((txId) => { + if (txId!.data) + fetchResult({ + variables: { txId: txId!.data.stageTransaction }, + }); + }); + }, + }); const tx = useTx(); const [openDialog, setOpenDialog] = useState(false); + const [openMigration, setOpenMigration] = useState(false); const gold = useBalance(); @@ -199,7 +232,6 @@ export default function UserInfo() { const t = useT(); - const [isCollectionOpen, setCollectionOpen] = useState(false); const [isExportKeyOpen, setExportKeyOpen] = useState(false); if (!loginSession) return null; @@ -220,13 +252,12 @@ export default function UserInfo() { gold {Number(gold)} - setCollectionOpen(true)}> + monster collection icon {deposit?.replace(/\.0+$/, "") || "0"} {isCollecting && !canClaim && tip !== 0 ? ` - Remaining: ${remainingText}` : " (-)"} - {canClaim && ( )} {isCollecting && !canClaim && tip !== 0 && isMigratable && ( - + { + setOpenMigration(true); + }} + /> )} {isCollecting && ( stakingStastics()} /> @@ -260,6 +296,24 @@ export default function UserInfo() { setOpenDialog(false); }} /> + setOpenMigration(false)} + tip={tip} + onConfirm={() => { + setClaimLoading(true); + if (loginSession.publicKey) { + requestMigrationTx({ + variables: { + publicKey: loginSession.publicKey.toHex("uncompressed"), + amount: new Decimal(deposit!).toNumber(), + }, + }); + } + + setOpenMigration(false); + }} + /> + { + onClose(); + }} + /> +

+ +

+ + If you migrate, +
+ + the reward claim cycle gets{" "} + reset +
+ and you need to wait 7 days to claim. +
+
+
+ Also, deposits cannot be withdrawn within 28 days. +
+ + + + + + + + ); +} + +export default observer(ClaimContent); diff --git a/src/renderer/views/MigrateCollectionRewardsOverlay/index.tsx b/src/renderer/views/MigrateCollectionRewardsOverlay/index.tsx new file mode 100644 index 000000000..8f052b639 --- /dev/null +++ b/src/renderer/views/MigrateCollectionRewardsOverlay/index.tsx @@ -0,0 +1,23 @@ +import { observer } from "mobx-react"; +import React from "react"; +import { OverlayProps } from "src/utils/types"; +import MigrateContent from "./MigrateContent"; + +export interface MigrateCollectionRewardsOverlayProps extends OverlayProps { + tip: number; + onConfirm(): void; +} + +const transifexTags = "v2/views/MigrateCollectionRewardsOverlay"; + +function MigrateCollectionRewardsOverlay({ + isOpen, + onClose, + ...collectionData +}: MigrateCollectionRewardsOverlayProps) { + return ( + + ); +} + +export default observer(MigrateCollectionRewardsOverlay);