Skip to content
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

Tong/395 phase 2 modal #410

Merged
merged 6 commits into from
Nov 30, 2024
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
14 changes: 7 additions & 7 deletions src/app/api/getDelegationsV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,14 @@ export const getDelegationsV2 = async (
unbondingTime: apiDelegation.delegation_unbonding.unbonding_time,
unbondingTxHex: apiDelegation.delegation_unbonding.unbonding_tx,
unbondingSlashingTxHex:
apiDelegation.delegation_unbonding.slashing_tx_hex,
apiDelegation.delegation_unbonding.slashing_tx_hex,
covenantUnbondingSignatures:
apiDelegation.delegation_unbonding.covenant_unbonding_signatures?.map(
(signature) => ({
covenantBtcPkHex: signature.covenant_btc_pk_hex,
signatureHex: signature.signature_hex,
}),
),
apiDelegation.delegation_unbonding.covenant_unbonding_signatures?.map(
(signature) => ({
covenantBtcPkHex: signature.covenant_btc_pk_hex,
signatureHex: signature.signature_hex,
}),
),
slashingTxHex: apiDelegation.delegation_staking.slashing_tx_hex,
};
},
Expand Down
41 changes: 27 additions & 14 deletions src/app/components/Modals/CongratModal.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import { Button, Heading } from "@babylonlabs-io/bbn-core-ui";
import {
Button,
Dialog,
DialogBody,
DialogFooter,
Heading,
MobileDialog,
} from "@babylonlabs-io/bbn-core-ui";
import { LuPartyPopper } from "react-icons/lu";

import { GeneralModal } from "./GeneralModal";
import { useIsMobileView } from "@/app/hooks/useBreakpoint";

interface CongratModalProps {
open: boolean;
onClose: () => void;
}

export function CongratModal({ open, onClose }: CongratModalProps) {
const isMobileView = useIsMobileView();
const DialogComponent = isMobileView ? MobileDialog : Dialog;

return (
<GeneralModal
open={open}
onClose={onClose}
closeOnOverlayClick={false}
closeOnEsc={false}
>
<div className="flex flex-col gap-8 md:max-w-[34rem] text-primary-dark">
<DialogComponent open={open} onClose={onClose}>
<DialogBody className="flex flex-col pb-8 pt-4 text-primary-dark gap-4">
<div className="py-4 flex flex-col items-center gap-4">
<LuPartyPopper className="text-5xl" />
<div className="bg-primary-contrast h-20 w-20 flex items-center justify-center">
<LuPartyPopper className="text-5xl" />
</div>
<Heading variant="h4">Conratulations</Heading>
<p className="text-base text-center">
Share feedback or report issues on our{" "}
Expand All @@ -43,10 +50,16 @@ export function CongratModal({ open, onClose }: CongratModalProps) {
community!
</p>
</div>
<Button onClick={onClose}>
<span>Done</span>
</DialogBody>
<DialogFooter className="flex gap-4">
<Button
variant="contained"
className="flex-1 text-xs sm:text-base"
onClick={onClose}
>
Done
</Button>
</div>
</GeneralModal>
</DialogFooter>
</DialogComponent>
);
}
41 changes: 41 additions & 0 deletions src/app/components/Modals/TransitionModal/StageEnd.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
Button,
DialogBody,
DialogFooter,
Heading,
} from "@babylonlabs-io/bbn-core-ui";
import { IoMdCheckmark } from "react-icons/io";

interface StageEndProps {
onClose: () => void;
}

export function StageEnd({ onClose }: StageEndProps) {
return (
<>
<DialogBody className="flex flex-col pb-8 pt-4 text-primary-dark gap-4">
<div className="py-4 flex flex-col items-center gap-4">
<div className="bg-primary-contrast h-20 w-20 flex items-center justify-center">
<IoMdCheckmark className="text-5xl" />
</div>
<Heading variant="h4">Transition Submitted</Heading>
<p className="text-base text-center">
Your phase-1 staking transaction has been successfully submitted to
the Babylon blockchain and should be activated and receive voting
power in a few blocks. Please monitor the Activity tab for the
activation status.
</p>
</div>
</DialogBody>
<DialogFooter className="flex gap-4">
<Button
variant="contained"
className="flex-1 text-xs sm:text-base"
onClick={onClose}
>
Confirm
</Button>
</DialogFooter>
</>
);
}
45 changes: 45 additions & 0 deletions src/app/components/Modals/TransitionModal/StageStart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
Button,
DialogBody,
DialogFooter,
Heading,
} from "@babylonlabs-io/bbn-core-ui";
import { MdLooksTwo } from "react-icons/md";

interface StageStartProps {
onClose: () => void;
}

export function StageStart({ onClose }: StageStartProps) {
return (
<>
<DialogBody className="flex flex-col pb-8 pt-4 text-primary-dark gap-4">
<div className="py-4 flex flex-col items-center gap-4">
<div className="bg-primary-contrast h-20 w-20 flex items-center justify-center">
<MdLooksTwo className="text-5xl" />
</div>
<Heading variant="h4">Transition to Phase 2</Heading>
<p className="text-base text-center">
You are about to transition your phase-1 stake delegation to secure
the phase-2 Babylon PoS blockchain. The transition requires the
association of your Babylon testnet rewards account with your BTC
key as well as your consent to slashing in the case of equivocation.
</p>
</div>
</DialogBody>
<DialogFooter className="flex gap-4">
<Button
variant="outlined"
color="primary"
onClick={onClose}
className="flex-1 text-xs sm:text-base"
>
Cancel
</Button>
<Button variant="contained" className="flex-1 text-xs sm:text-base">
Proceed
</Button>
</DialogFooter>
</>
);
}
109 changes: 109 additions & 0 deletions src/app/components/Modals/TransitionModal/StageStepping.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {
Button,
DialogBody,
DialogFooter,
DialogHeader,
Loader,
Text,
} from "@babylonlabs-io/bbn-core-ui";
import { twMerge } from "tailwind-merge";

import { Tick } from "./Tick";

const stepContent = [
"Step 1: Consent to slashing",
"Step 2: Consent to slashing during unbonding ",
"Step 3: BTC-BBN address binding for receiving staking rewards",
"Step 4: Staking transaction registration",
];

interface StageSteppingProps {
onClose: () => void;
onSign: () => void;
step: number;
awaitingResponse?: boolean;
}
const Step = ({
active,
completed,
current,
content,
}: {
active: boolean;
completed: boolean;
current: number;
content: string;
}) => (
<div
className={twMerge(
"p-4 flex flex-row items-center justify-start gap-3 rounded border border-primary-dark/20 bg-secondary-contrast self-stretch",
!active && "opacity-25",
)}
>
{completed ? (
<Tick />
) : (
<div className="rounded-full bg-secondary-main flex h-10 w-10 items-center justify-center">
<Text variant="body1" className="text-secondary-contrast">
{current}
</Text>
</div>
)}
<Text variant="body1" className="text-primary-dark">
{content}
</Text>
</div>
);
export function StageStepping({
onClose,
onSign,
step,
awaitingResponse = false,
}: StageSteppingProps) {
return (
<>
<DialogHeader
title="Transition to Phase 2"
onClose={onClose}
className="text-primary-dark"
/>
<DialogBody className="flex flex-col pb-8 pt-4 text-primary-dark gap-4">
<Text variant="body1" className="text-primary-main">
Please sign the following messages
</Text>
<div className="py-4 flex flex-col items-start gap-6">
{stepContent.map((content, index) => (
<Step
key={content}
completed={step > index + 1}
active={step === index + 1}
current={index + 1}
content={content}
/>
))}
</div>
</DialogBody>
<DialogFooter className="flex gap-4">
<Button
variant="outlined"
color="primary"
onClick={onClose}
className="flex-1 text-xs sm:text-base"
>
Cancel
</Button>
<Button
variant="contained"
className="flex-1 text-xs sm:text-base"
onClick={onSign}
>
{awaitingResponse ? (
<Loader size={16} className="text-white" />
) : (
"Sign"
)}
</Button>
</DialogFooter>
</>
);
}
9 changes: 9 additions & 0 deletions src/app/components/Modals/TransitionModal/Tick.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IoCheckmarkSharp } from "react-icons/io5";

export function Tick() {
return (
<div className="rounded-full bg-primary-light flex h-10 w-10 items-center justify-center">
<IoCheckmarkSharp size={24} className="text-secondary-contrast" />
</div>
);
}
75 changes: 75 additions & 0 deletions src/app/components/Modals/TransitionModal/TransitionModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Dialog, MobileDialog } from "@babylonlabs-io/bbn-core-ui";

import { useIsMobileView } from "@/app/hooks/useBreakpoint";

import { StageEnd } from "./StageEnd";
import { StageStart } from "./StageStart";
import { StageStepping } from "./StageStepping";

interface TransitionModalProps {
open: boolean;
onClose: () => void;
onSign: () => void;
stage:
| "start"
| "step-1"
| "step-2"
| "step-3"
| "step-4"
| "pre-end"
| "end";
}
const stageUIMapping = {
start: ({ onClose }: TransitionModalProps) => (
<StageStart onClose={onClose} />
),
"step-1": ({ onClose, onSign }: TransitionModalProps) => (
<StageStepping step={1} onClose={onClose} onSign={onSign} />
),
"step-2": ({ onClose, onSign }: TransitionModalProps) => (
<StageStepping
step={2}
onClose={onClose}
onSign={onSign}
awaitingResponse={true}
/>
),
"step-3": ({ onClose, onSign }: TransitionModalProps) => (
<StageStepping
step={3}
onClose={onClose}
onSign={onSign}
awaitingResponse={true}
/>
),
"step-4": ({ onClose, onSign }: TransitionModalProps) => (
<StageStepping
step={4}
onClose={onClose}
onSign={onSign}
awaitingResponse={true}
/>
),
"pre-end": ({ onClose, onSign }: TransitionModalProps) => (
<StageStepping
step={5}
onClose={onClose}
onSign={onSign}
awaitingResponse={true}
/>
),
end: ({ onClose }: TransitionModalProps) => <StageEnd onClose={onClose} />,
} as const;
export function TransitionModal(props: TransitionModalProps) {
const { open, onClose, stage } = props;
const isMobileView = useIsMobileView();
const DialogComponent = isMobileView ? MobileDialog : Dialog;

const Content = stageUIMapping[stage];

return (
<DialogComponent open={open} onClose={onClose}>
<Content {...props} />
</DialogComponent>
);
}