Skip to content

Commit

Permalink
feat: hints in modals for Beacon and WC
Browse files Browse the repository at this point in the history
  • Loading branch information
dianasavvatina committed Jan 24, 2025
1 parent e5b5a6c commit df12b46
Show file tree
Hide file tree
Showing 16 changed files with 134 additions and 32 deletions.
43 changes: 43 additions & 0 deletions apps/web/src/components/HintsAccordion/HintsAccordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Heading,
} from "@chakra-ui/react";
import { Hints, type SignPage } from "@umami/core";

import { useColor } from "../../styles/useColor";

type HintsProps = {
signPage: SignPage;
};

export const HintsAccordion = ({ signPage }: HintsProps) => {
const color = useColor();

return (
<Accordion
width="full"
marginTop="16px"
marginBottom="16px"
allowToggle
data-testid="hints-accordion"
>
<AccordionItem border="none" borderRadius="8px" backgroundColor={color("100")}>
<h2>
<AccordionButton padding="12px" borderRadius="8px">
<Heading flex="1" textAlign="left" size="md">
{Hints[signPage].header || "No header available"}
</Heading>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel padding="16px">
{Hints[signPage].description || "No description available."}
</AccordionPanel>
</AccordionItem>
</Accordion>
);
};
1 change: 1 addition & 0 deletions apps/web/src/components/HintsAccordion/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./HintsAccordion";
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ import {
ModalContent,
ModalFooter,
} from "@chakra-ui/react";
import { type ContractCall } from "@umami/core";
import { type ContractCall, Titles } from "@umami/core";
import { FormProvider, useForm } from "react-hook-form";

import { Header } from "./Header";
import { useColor } from "../../../styles/useColor";
import { AddressTile } from "../../AddressTile/AddressTile";
import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
import { TezTile } from "../../AssetTiles/TezTile";
import { HintsAccordion } from "../../HintsAccordion";
import { JsValueWrap } from "../../JsValueWrap";
import { Titles } from "../../Titles/Titles";
import { SignButton } from "../SignButton";
import { SignPageFee } from "../SignPageFee";
import { type CalculatedSignProps, type SdkSignPageProps } from "../utils";
Expand All @@ -47,6 +47,7 @@ export const ContractCallSignPage = ({
<ModalContent data-testid="ContractCallSignPage">
<form>
<Header headerProps={headerProps} title={Titles.ContractCallSignPage} />
<HintsAccordion signPage="ContractCallSignPage" />
<ModalBody>
<TezTile mutezAmount={mutezAmount} />

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Flex, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
import { type Delegation } from "@umami/core";
import { type Delegation, Titles } from "@umami/core";
import { FormProvider, useForm } from "react-hook-form";

import { Header } from "./Header";
import { AddressTile } from "../../AddressTile/AddressTile";
import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
import { Titles } from "../../Titles/Titles";
import { HintsAccordion } from "../../HintsAccordion";
import { SignButton } from "../SignButton";
import { SignPageFee } from "../SignPageFee";
import { type CalculatedSignProps, type SdkSignPageProps } from "../utils";
Expand All @@ -27,6 +27,7 @@ export const DelegationSignPage = ({
<ModalContent data-testid="DelegationSignPage">
<form>
<Header headerProps={headerProps} title={Titles.DelegationSignPage} />
<HintsAccordion signPage="DelegationSignPage" />
<ModalBody>
<FormLabel>From</FormLabel>
<AddressTile address={operation.signer.address} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Flex, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
import { Titles } from "@umami/core";
import { useAccountTotalFinalizableUnstakeAmount } from "@umami/state";
import { FormProvider, useForm } from "react-hook-form";

import { Header } from "./Header";
import { AddressTile } from "../../AddressTile/AddressTile";
import { TezTile } from "../../AssetTiles/TezTile";
import { Titles } from "../../Titles/Titles";
import { HintsAccordion } from "../../HintsAccordion";
import { SignButton } from "../SignButton";
import { SignPageFee } from "../SignPageFee";
import { type CalculatedSignProps, type SdkSignPageProps } from "../utils";
Expand All @@ -27,6 +28,7 @@ export const FinalizeUnstakeSignPage = ({
<ModalContent data-testid="FinalizeUnstakeSignPage">
<form>
<Header headerProps={headerProps} title={Titles.FinalizeUnstakeSignPage} />
<HintsAccordion signPage="FinalizeUnstakeSignPage" />
<ModalBody>
<Flex alignItems="center" justifyContent="end" marginTop="12px">
<SignPageFee fee={fee} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ describe("<OriginationOperationSignPage />", () => {

expect(screen.getByTestId("sign-page-header")).toHaveTextContent("Origination Request");
expect(screen.getByTestId("app-name")).toHaveTextContent("mockDappName");
expect(screen.getByTestId("hints-accordion")).toBeInTheDocument();
});

it("passes correct payload to sign handler", async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import {
ModalContent,
ModalFooter,
} from "@chakra-ui/react";
import { type ContractOrigination } from "@umami/core";
import { type ContractOrigination, Titles } from "@umami/core";
import { FormProvider, useForm } from "react-hook-form";

import { useColor } from "../../../styles/useColor";
import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
import { HintsAccordion } from "../../HintsAccordion";
import { JsValueWrap } from "../../JsValueWrap";
import { SignButton } from "../SignButton";
import { SignPageFee } from "../SignPageFee";
import { type CalculatedSignProps, type SdkSignPageProps } from "../utils";
import { Header } from "./Header";
import { Titles } from "../../Titles/Titles";

export const OriginationOperationSignPage = ({
operation,
Expand All @@ -39,6 +39,7 @@ export const OriginationOperationSignPage = ({
<ModalContent data-testid="OriginationOperationSignPage">
<form>
<Header headerProps={headerProps} title={Titles.OriginationOperationSignPage} />
<HintsAccordion signPage="OriginationOperationSignPage" />
<ModalBody data-testid="beacon-request-body">
<Flex alignItems="center" justifyContent="end" marginTop="12px">
<SignPageFee fee={fee} />
Expand Down
26 changes: 8 additions & 18 deletions apps/web/src/components/SendFlow/common/SingleSignPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { BeaconMessageType, NetworkType, type OperationRequestOutput } from "@ai
import type { BatchWalletOperation } from "@taquito/taquito/dist/types/wallet/batch-operation";
import {
type EstimatedAccountOperations,
Hints,
type Operation,
type SignPage,
Titles,
executeOperations,
mockContractCall,
mockContractOrigination,
mockDelegationOperation,
mockFinalizeUnstakeOperation,
mockImplicitAccount,
mockStakeOperation,
mockTezOperation,
mockUndelegationOperation,
mockUnstakeOperation,
} from "@umami/core";
mockTezOperation, mockUndelegationOperation, mockUnstakeOperation } from "@umami/core";
import { WalletClient, makeStore, networksActions, useGetSecretKey } from "@umami/state";
import { executeParams } from "@umami/test-utils";
import { GHOSTNET, makeToolkit } from "@umami/tezos";
Expand All @@ -29,7 +29,6 @@ import {
import { SuccessStep } from "../SuccessStep";
import { type SdkSignPageProps, type SignHeaderProps } from "../utils";
import { SingleSignPage } from "./SingleSignPage";
import { Titles } from "../../Titles/Titles";

jest.mock("@umami/core", () => ({
...jest.requireActual("@umami/core"),
Expand Down Expand Up @@ -60,7 +59,7 @@ describe("<SingleSignPage />", () => {
} as OperationRequestOutput;

// check all types of Modals called by SingleSignOperation
const mockedOperations: Record<string, Operation> = {
const mockedOperations: Record<SignPage, Operation> = {
TezSignPage: mockTezOperation(0),
ContractCallSignPage: mockContractCall(0),
DelegationSignPage: mockDelegationOperation(0),
Expand All @@ -71,17 +70,6 @@ describe("<SingleSignPage />", () => {
FinalizeUnstakeSignPage: mockFinalizeUnstakeOperation(0),
};

const titles: Record<string, string> = {
TezSignPage: Titles.TezSignPage,
ContractCallSignPage: Titles.ContractCallSignPage,
DelegationSignPage: Titles.DelegationSignPage,
UndelegationSignPage: Titles.UndelegationSignPage,
OriginationOperationSignPage: Titles.OriginationOperationSignPage,
StakeSignPage: Titles.StakeSignPage,
UnstakeSignPage: Titles.UnstakeSignPage,
FinalizeUnstakeSignPage: Titles.FinalizeUnstakeSignPage,
};

const operation: EstimatedAccountOperations = {
type: "implicit" as const,
sender: mockImplicitAccount(0),
Expand Down Expand Up @@ -117,8 +105,10 @@ describe("<SingleSignPage />", () => {
expect(screen.queryByText("Mainnet")).not.toBeInTheDocument();
expect(screen.getByTestId(key)).toBeInTheDocument(); // e.g. TezSignPage

expect(screen.getByTestId("sign-page-header")).toHaveTextContent(titles[key]);
expect(screen.getByTestId("sign-page-header")).toHaveTextContent(Titles[key]);
expect(screen.getByTestId("app-name")).toHaveTextContent("mockDappName");
expect(screen.getByTestId("hints-accordion")).toHaveTextContent(Hints[key].header || "");
expect(screen.getByTestId("hints-accordion")).toHaveTextContent(Hints[key].description || "");

const signButton = screen.getByRole("button", {
name: "Confirm Transaction",
Expand Down
5 changes: 3 additions & 2 deletions apps/web/src/components/SendFlow/common/StakeSignPage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Flex, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
import { type Stake } from "@umami/core";
import { type Stake, Titles } from "@umami/core";
import { FormProvider, useForm } from "react-hook-form";

import { Header } from "./Header";
import { AddressTile } from "../../AddressTile/AddressTile";
import { TezTile } from "../../AssetTiles/TezTile";
import { Titles } from "../../Titles/Titles";
import { HintsAccordion } from "../../HintsAccordion";
import { SignButton } from "../SignButton";
import { SignPageFee } from "../SignPageFee";
import { type CalculatedSignProps, type SdkSignPageProps } from "../utils";
Expand All @@ -27,6 +27,7 @@ export const StakeSignPage = ({
<ModalContent data-testid="StakeSignPage">
<form>
<Header headerProps={headerProps} title={Titles.StakeSignPage} />
<HintsAccordion signPage="StakeSignPage" />
<ModalBody>
<Flex alignItems="center" justifyContent="end" marginTop="12px">
<SignPageFee fee={fee} />
Expand Down
5 changes: 3 additions & 2 deletions apps/web/src/components/SendFlow/common/TezSignPage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Flex, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
import { type TezTransfer } from "@umami/core";
import { type TezTransfer, Titles } from "@umami/core";
import { FormProvider, useForm } from "react-hook-form";

import { Header } from "./Header";
import { AddressTile } from "../../AddressTile/AddressTile";
import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
import { TezTile } from "../../AssetTiles/TezTile";
import { Titles } from "../../Titles/Titles";
import { HintsAccordion } from "../../HintsAccordion";
import { SignButton } from "../SignButton";
import { SignPageFee } from "../SignPageFee";
import { type CalculatedSignProps, type SdkSignPageProps } from "../utils";
Expand All @@ -27,6 +27,7 @@ export const TezSignPage = ({
<ModalContent data-testid="TezSignPage">
<form>
<Header headerProps={headerProps} title={Titles.TezSignPage} />
<HintsAccordion signPage="TezSignPage" />
<ModalBody>
<TezTile mutezAmount={mutezAmount} />

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Flex, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
import { Titles } from "@umami/core";
import { FormProvider, useForm } from "react-hook-form";

import { Header } from "./Header";
import { AddressTile } from "../../AddressTile/AddressTile";
import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
import { Titles } from "../../Titles/Titles";
import { HintsAccordion } from "../../HintsAccordion";
import { SignButton } from "../SignButton";
import { SignPageFee } from "../SignPageFee";
import { type CalculatedSignProps, type SdkSignPageProps } from "../utils";
Expand All @@ -24,6 +25,7 @@ export const UndelegationSignPage = ({
<ModalContent data-testid="UndelegationSignPage">
<form>
<Header headerProps={headerProps} title={Titles.UndelegationSignPage} />
<HintsAccordion signPage="UndelegationSignPage" />
<ModalBody>
<FormLabel>From</FormLabel>
<AddressTile address={operation.signer.address} />
Expand Down
5 changes: 3 additions & 2 deletions apps/web/src/components/SendFlow/common/UnstakeSignPage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Flex, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
import { type Unstake } from "@umami/core";
import { Titles, type Unstake } from "@umami/core";
import { FormProvider, useForm } from "react-hook-form";

import { Header } from "./Header";
import { AddressTile } from "../../AddressTile/AddressTile";
import { TezTile } from "../../AssetTiles/TezTile";
import { Titles } from "../../Titles/Titles";
import { HintsAccordion } from "../../HintsAccordion";
import { SignButton } from "../SignButton";
import { SignPageFee } from "../SignPageFee";
import { type CalculatedSignProps, type SdkSignPageProps } from "../utils";
Expand All @@ -27,6 +27,7 @@ export const UnstakeSignPage = ({
<ModalContent data-testid="UnstakeSignPage">
<form>
<Header headerProps={headerProps} title={Titles.UnstakeSignPage} />
<HintsAccordion signPage="UnstakeSignPage" />
<ModalBody>
<Flex alignItems="center" justifyContent="end" marginTop="12px">
<SignPageFee fee={fee} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ describe("<useHandleBeaconMessage />", () => {
);
expect(screen.getByTestId("sign-page-header")).toHaveTextContent("Send Request");
expect(screen.getByTestId("app-name")).toHaveTextContent("mockDappName");
expect(screen.getByTestId("hints-accordion")).toBeInTheDocument();

expect(mockToast).not.toHaveBeenCalled();
});
Expand Down
53 changes: 53 additions & 0 deletions packages/core/src/Hints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { type SignPage } from "./Titles";

type HintData = {
header?: string;
description?: string;
};
const basicOperationHeader =
"A confirmation takes 1 block (8 seconds). The transaction becomes final and irreversible after 2 blocks (16 seconds).";
const basicOperationDescription =
"A confirmation means that the block is confirmed by the network but the operation can still be cancelled due to chain reorganizations. Finality means that the operation is irreversible.";

export const Hints: Record<SignPage, HintData> = {
TezSignPage: {
header: basicOperationHeader,
description: basicOperationDescription,
},
OriginationOperationSignPage: {
header: basicOperationHeader,
description: basicOperationDescription,
},
ContractCallSignPage: {
header: basicOperationHeader,
description: basicOperationDescription,
},
DelegationSignPage: {
header: "It takes 4 cycles (~6 days) to start receiving delegation rewards.",
description:
"Bakers usually distribute delegation rewards every cycle (~2.8 days). Ensure that the delegation fee offered by the baker is less than 100%; otherwise, you might not receive rewards. Delegation means that all your funds are delegated to one baker. The funds are still spendable, and you can cancel or change the delegation at any time.",
},
UndelegationSignPage: {
header:
"Immediately stops delegation and initiates unstaking. Restoring delegation rewards takes 4 cycles (~10 days). After 4 cycles (~10 days), unstaked tez can be finalized and made avaialable",
description:
"Undelegation takes effect immediately, and you will stop accruing staking rewards. However, delegation rewards for the current and the next 2 cycles will still be received, as baking rights are computed 2 cycles in advance. By undelegating, you also initiate the unstaking process if you have staked. The unstaking process takes approximately 4 cycles (~10 days) to unlock your staked funds, making them finalizable. Once finalized, the funds will be returned to your balance. You will receive delegation rewards for finalizable funds.",
},
StakeSignPage: {
header:
"Your balance will be reduced by the staked amount. You will start receiving rewards within 1 cycle (~3 days) max.",
description:
"When you stake, the chosen amount is automatically deducted from your available balance. Rewards are added to your staked balance automatically every time your chosen baker produces a new block and at the end of each cycle (every ~3 days). If you decide to cancel staking, it will take approximately 4 cycles (~10 days) to unlock your staked funds, making them finalizable. Once finalized, the funds will be returned to your balance. You will receive delegation rewards for finalizable funds.",
},
UnstakeSignPage: {
header: "Unstaking takes at least 4 cycles (~10 days) to complete.",
description:
"During this time, your funds are locked, and you will not receive staking rewards. After 4 cycles, your staked funds become finalizable. Once finalized, the funds will be returned to your balance. You will receive delegation rewards for finalizable funds.",
},
FinalizeUnstakeSignPage: {
header:
"Finalizing unstake takes 1 block (8 seconds) to complete and applies to all finalizable funds in your balance.",
description:
"Once finalized, your funds are returned to your balance, allowing you to spend them or stake them again to earn rewards. Delegation rewards for these funds will stop once they are finalized.",
},
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export type SignPage = keyof typeof Titles;
export const Titles: Record<string, string> = {
TezSignPage: "Send Request",
ContractCallSignPage: "Contract Call Request",
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ export * from "./Delegate";
export * from "./estimate";
export * from "./execute";
export * from "./helpers";
export * from "./Hints";
export * from "./Operation";
export * from "./testUtils";
export * from "./Titles";
export * from "./Token";
export * from "./TokenBalance";
export * from "./beaconUtils";
Expand Down

0 comments on commit df12b46

Please sign in to comment.