diff --git a/apps/web/src/components/SendFlow/Delegation/ChangeDelegateNoticeModal.tsx b/apps/web/src/components/SendFlow/Delegation/ChangeDelegateNoticeModal.tsx
deleted file mode 100644
index 4b5e89fce7..0000000000
--- a/apps/web/src/components/SendFlow/Delegation/ChangeDelegateNoticeModal.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import {
- Button,
- Center,
- Heading,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalHeader,
- Text,
-} from "@chakra-ui/react";
-import { useDynamicModalContext } from "@umami/components";
-import { type Account } from "@umami/core";
-import { type TzktAlias } from "@umami/tzkt";
-
-import { FormPage } from "./FormPage";
-import { StubIcon as WarningIcon } from "../../../assets/icons";
-import { useColor } from "../../../styles/useColor";
-
-export const ChangeDelegateNoticeModal = ({
- account,
- delegate,
-}: {
- account: Account;
- delegate: TzktAlias;
-}) => {
- const { openWith } = useDynamicModalContext();
- const color = useColor();
-
- return (
-
-
-
-
-
- Important notice
-
-
-
-
-
- Changing the baker will automatically unstake all the existing staked balance. This
- balance will be finalizable after 4 cycles.
-
-
-
- openWith(
-
- )
- }
- size="lg"
- >
- I understand
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/Delegation/FormPage.test.tsx b/apps/web/src/components/SendFlow/Delegation/FormPage.test.tsx
deleted file mode 100644
index 73b993f713..0000000000
--- a/apps/web/src/components/SendFlow/Delegation/FormPage.test.tsx
+++ /dev/null
@@ -1,170 +0,0 @@
-import { estimate, makeAccountOperations, mockImplicitAccount } from "@umami/core";
-import {
- type UmamiStore,
- accountsActions,
- addTestAccount,
- assetsActions,
- makeStore,
- mockToast,
-} from "@umami/state";
-import { executeParams } from "@umami/test-utils";
-import { CustomError } from "@umami/utils";
-
-import { FormPage, type FormValues } from "./FormPage";
-import { SignPage } from "./SignPage";
-import {
- act,
- dynamicModalContextMock,
- renderInModal,
- screen,
- userEvent,
- waitFor,
-} from "../../../testUtils";
-import { type FormPageProps } from "../utils";
-
-const fixture = (props: FormPageProps) => ;
-
-jest.mock("@umami/core", () => ({
- ...jest.requireActual("@umami/core"),
- estimate: jest.fn(),
-}));
-
-let store: UmamiStore;
-
-beforeEach(() => {
- store = makeStore();
- addTestAccount(store, mockImplicitAccount(0));
- store.dispatch(accountsActions.setCurrent(mockImplicitAccount(0).address.pkh));
-});
-
-describe("", () => {
- describe("default values", () => {
- it("renders a form with default form values", async () => {
- await renderInModal(
- fixture({
- form: {
- sender: mockImplicitAccount(0).address.pkh,
- baker: mockImplicitAccount(1).address.pkh,
- },
- }),
- store
- );
-
- await waitFor(() => {
- expect(screen.getByTestId("real-address-input-sender")).toHaveValue(
- mockImplicitAccount(0).address.pkh
- );
- });
- });
-
- it("displays delegate for address who is not delegating", async () => {
- const sender = mockImplicitAccount(0);
- await renderInModal(
- fixture({
- sender,
- }),
- store
- );
-
- expect(screen.getByText("Delegate")).toBeInTheDocument();
- });
-
- it("displays change baker for address who is delegating", async () => {
- const sender = mockImplicitAccount(0);
- const baker = mockImplicitAccount(1);
- store.dispatch(
- assetsActions.updateBakers([
- { address: baker.address.pkh, name: "baker1", stakingBalance: 1 },
- ])
- );
-
- await renderInModal(
- fixture({
- sender,
- form: {
- sender: sender.address.pkh,
- baker: baker.address.pkh,
- },
- }),
- store
- );
-
- await waitFor(() => {
- expect(screen.getByText("Change baker")).toBeInTheDocument();
- });
- });
- });
-
- it("shows a toast if estimation fails", async () => {
- const user = userEvent.setup();
- await renderInModal(
- fixture({
- sender: mockImplicitAccount(0),
- form: {
- sender: mockImplicitAccount(0).address.pkh,
- baker: mockImplicitAccount(1).address.pkh,
- },
- }),
- store
- );
- const submitButton = screen.getByText("Preview");
- await waitFor(() => {
- expect(submitButton).toBeEnabled();
- });
-
- const estimateMock = jest.mocked(estimate);
- estimateMock.mockRejectedValue(new CustomError("Some error occurred"));
-
- await act(() => user.click(submitButton));
-
- expect(estimateMock).toHaveBeenCalledTimes(1);
- expect(mockToast).toHaveBeenCalledWith({
- description: "Some error occurred",
- status: "error",
- isClosable: true,
- });
- });
-
- it("opens a sign page if estimation succeeds", async () => {
- const user = userEvent.setup();
- const sender = mockImplicitAccount(0);
- await renderInModal(
- fixture({
- sender: sender,
- form: {
- sender: sender.address.pkh,
- baker: mockImplicitAccount(1).address.pkh,
- },
- }),
- store
- );
- const submitButton = screen.getByText("Preview");
- await waitFor(() => {
- expect(submitButton).toBeEnabled();
- });
- const operations = {
- ...makeAccountOperations(sender, sender, [
- {
- type: "delegation",
- sender: sender.address,
- recipient: mockImplicitAccount(1).address,
- },
- ]),
- estimates: [executeParams()],
- };
-
- jest.mocked(estimate).mockResolvedValueOnce(operations);
-
- await act(() => user.click(submitButton));
-
- expect(dynamicModalContextMock.openWith).toHaveBeenCalledWith(
-
- );
- expect(mockToast).not.toHaveBeenCalled();
- });
-});
diff --git a/apps/web/src/components/SendFlow/Delegation/FormPage.tsx b/apps/web/src/components/SendFlow/Delegation/FormPage.tsx
deleted file mode 100644
index 1ab5c8dd01..0000000000
--- a/apps/web/src/components/SendFlow/Delegation/FormPage.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import {
- FormControl,
- FormErrorMessage,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalFooter,
- ModalHeader,
- Text,
-} from "@chakra-ui/react";
-import hj from "@hotjar/browser";
-import { type Delegation } from "@umami/core";
-import { type RawPkh, parseImplicitPkh, parsePkh } from "@umami/tezos";
-import { FormProvider, useForm } from "react-hook-form";
-
-import { SignPage } from "./SignPage";
-import { BakersAutocomplete, OwnedAccountsAutocomplete } from "../../AddressAutocomplete";
-import {
- useAddToBatchFormAction,
- useHandleOnSubmitFormActions,
- useOpenSignPageFormAction,
-} from "../onSubmitFormActionHooks";
-import { type FormPageProps, FormSubmitButton, formDefaultValues } from "../utils";
-
-export type FormValues = {
- sender: RawPkh;
- baker: RawPkh;
-};
-
-export const FormPage = (props: FormPageProps) => {
- const baker = props.form?.baker;
-
- hj.stateChange("send_flow/delegation_form_page");
-
- const openSignPage = useOpenSignPageFormAction({
- SignPage,
- signPageExtraData: undefined,
- FormPage,
- defaultFormPageProps: props,
- toOperation,
- });
-
- const addToBatch = useAddToBatchFormAction(toOperation);
-
- const {
- onFormSubmitActionHandlers: [onSingleSubmit],
- isLoading,
- } = useHandleOnSubmitFormActions([openSignPage, addToBatch]);
-
- const form = useForm({
- mode: "onBlur",
- defaultValues: formDefaultValues(props),
- });
-
- const {
- formState: { errors },
- handleSubmit,
- } = form;
-
- return (
-
-
-
-
-
- );
-};
-
-const toOperation = (formValues: FormValues): Delegation => ({
- type: "delegation",
- sender: parsePkh(formValues.sender),
- recipient: parseImplicitPkh(formValues.baker),
-});
diff --git a/apps/web/src/components/SendFlow/Delegation/NewDelegateNoticeModal.tsx b/apps/web/src/components/SendFlow/Delegation/NewDelegateNoticeModal.tsx
deleted file mode 100644
index 54986aa0a4..0000000000
--- a/apps/web/src/components/SendFlow/Delegation/NewDelegateNoticeModal.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import {
- Button,
- Center,
- Heading,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalHeader,
- Text,
-} from "@chakra-ui/react";
-import { useDynamicModalContext } from "@umami/components";
-import { type Account } from "@umami/core";
-
-import { FormPage } from "./FormPage";
-import { StubIcon as NoticeIcon } from "../../../assets/icons";
-import { useColor } from "../../../styles/useColor";
-import { NoticeSteps } from "../NoticeSteps";
-
-export const NewDelegateNoticeModal = ({ account }: { account: Account }) => {
- const { openWith } = useDynamicModalContext();
- const color = useColor();
-
- return (
-
-
-
-
-
- Delegation
-
-
-
-
-
- Earn risk-free rewards by delegating to a Tezos baker. Delegated funds remain in your
- account, and you can always spend them at will.
-
-
-
-
- openWith( )} size="lg">
- Continue
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/Delegation/NoticeModal.tsx b/apps/web/src/components/SendFlow/Delegation/NoticeModal.tsx
deleted file mode 100644
index ba2d1a6fa3..0000000000
--- a/apps/web/src/components/SendFlow/Delegation/NoticeModal.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { type Account } from "@umami/core";
-import { useGetAccountDelegate } from "@umami/state";
-
-import { ChangeDelegateNoticeModal } from "./ChangeDelegateNoticeModal";
-import { NewDelegateNoticeModal } from "./NewDelegateNoticeModal";
-
-export const NoticeModal = ({ account }: { account: Account }) => {
- const delegate = useGetAccountDelegate()(account.address.pkh);
-
- if (delegate) {
- return ;
- }
- return ;
-};
diff --git a/apps/web/src/components/SendFlow/Delegation/SignPage.test.tsx b/apps/web/src/components/SendFlow/Delegation/SignPage.test.tsx
deleted file mode 100644
index 6868583e75..0000000000
--- a/apps/web/src/components/SendFlow/Delegation/SignPage.test.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import { Modal } from "@chakra-ui/react";
-import { makeAccountOperations, mockImplicitAccount, mockMnemonicAccount } from "@umami/core";
-import { type UmamiStore, addTestAccount, assetsActions, makeStore } from "@umami/state";
-import { executeParams } from "@umami/test-utils";
-import { TEZ } from "@umami/tezos";
-
-import { SignPage } from "./SignPage";
-import { render, screen, waitFor } from "../../../testUtils";
-import { type SignPageProps } from "../utils";
-
-const fixture = (props: SignPageProps) => (
- {}}>
-
-
-);
-
-let store: UmamiStore;
-
-beforeEach(() => {
- store = makeStore();
- addTestAccount(store, mockMnemonicAccount(0));
-});
-
-describe(" ", () => {
- const sender = mockImplicitAccount(0);
- const operations = {
- ...makeAccountOperations(sender, mockImplicitAccount(0), [
- {
- type: "delegation",
- sender: sender.address,
- recipient: mockImplicitAccount(1).address,
- },
- ]),
- estimates: [executeParams({ fee: 1234567 })],
- };
-
- it("displays the fee in tez", async () => {
- const props: SignPageProps = {
- operations,
- mode: "single",
- data: undefined,
- };
- render(fixture(props), { store });
-
- await waitFor(() => expect(screen.getByTestId("fee")).toHaveTextContent(`1.234567 ${TEZ}`));
- });
-
- it("displays address tile for baker", async () => {
- const baker = mockImplicitAccount(1);
-
- store.dispatch(
- assetsActions.updateBakers([
- { address: baker.address.pkh, name: "baker1", stakingBalance: 1 },
- ])
- );
-
- const props: SignPageProps = {
- operations,
- mode: "single",
- data: undefined,
- };
- render(fixture(props), { store });
-
- await waitFor(() =>
- expect(screen.getAllByTestId("address-tile")[1]).toHaveTextContent("baker1")
- );
- });
-});
diff --git a/apps/web/src/components/SendFlow/Delegation/SignPage.tsx b/apps/web/src/components/SendFlow/Delegation/SignPage.tsx
deleted file mode 100644
index d8b1432135..0000000000
--- a/apps/web/src/components/SendFlow/Delegation/SignPage.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import { Flex, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
-import { type Delegation } from "@umami/core";
-import { FormProvider } from "react-hook-form";
-
-import { AddressTile } from "../../AddressTile/AddressTile";
-import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
-import { SignButton } from "../SignButton";
-import { SignPageFee } from "../SignPageFee";
-import { SignPageHeader } from "../SignPageHeader";
-import { type SignPageProps, useSignPageHelpers } from "../utils";
-
-export const SignPage = (props: SignPageProps) => {
- const { operations: initialOperations } = props;
- const { fee, operations, estimationFailed, isLoading, form, signer, onSign } =
- useSignPageHelpers(initialOperations);
- const baker = (operations.operations[0] as Delegation).recipient;
- return (
-
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/FinalizeUnstake/SignPage.tsx b/apps/web/src/components/SendFlow/FinalizeUnstake/SignPage.tsx
deleted file mode 100644
index 5df771a4fa..0000000000
--- a/apps/web/src/components/SendFlow/FinalizeUnstake/SignPage.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import {
- Center,
- Flex,
- FormLabel,
- Heading,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalFooter,
- ModalHeader,
-} from "@chakra-ui/react";
-import { type BigNumber } from "bignumber.js";
-import { FormProvider } from "react-hook-form";
-
-import { AddressTile } from "../../AddressTile/AddressTile";
-import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
-import { TezTile } from "../../AssetTiles/TezTile";
-import { SignButton } from "../SignButton";
-import { SignPageFee } from "../SignPageFee";
-import { type SignPageProps, useSignPageHelpers } from "../utils";
-
-// TODO: test
-export const SignPage = (props: SignPageProps<{ finalizableAmount: BigNumber }>) => {
- const {
- operations,
- data: { finalizableAmount },
- } = props;
- const { isLoading, form, signer, onSign, fee } = useSignPageHelpers(operations);
-
- return (
-
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/Token/SignPage.test.tsx b/apps/web/src/components/SendFlow/LocalSignPage.test.tsx
similarity index 57%
rename from apps/web/src/components/SendFlow/Token/SignPage.test.tsx
rename to apps/web/src/components/SendFlow/LocalSignPage.test.tsx
index cf7ff64b66..305dc1ba4b 100644
--- a/apps/web/src/components/SendFlow/Token/SignPage.test.tsx
+++ b/apps/web/src/components/SendFlow/LocalSignPage.test.tsx
@@ -1,7 +1,5 @@
import { Modal } from "@chakra-ui/react";
import {
- type FA12TokenBalance,
- type FA2TokenBalance,
makeAccountOperations,
mockFA2Token,
mockImplicitAccount,
@@ -9,20 +7,20 @@ import {
} from "@umami/core";
import { type UmamiStore, addTestAccount, makeStore } from "@umami/state";
import { executeParams } from "@umami/test-utils";
-import { TEZ, parseContractPkh } from "@umami/tezos";
+import { TEZ, mockImplicitAddress, parseContractPkh } from "@umami/tezos";
-import { SignPage } from "./SignPage";
-import { render, screen, waitFor } from "../../../testUtils";
-import { type SignPageProps } from "../utils";
+import { LocalSignPage } from "./LocalSignPage";
+import { type LocalSignPageProps } from "./utils";
+import { render, screen, waitFor } from "../../testUtils";
jest.mock("@chakra-ui/react", () => ({
...jest.requireActual("@chakra-ui/react"),
useBreakpointValue: jest.fn(),
}));
-const fixture = (props: SignPageProps<{ token: FA12TokenBalance | FA2TokenBalance }>) => (
+const fixture = (props: LocalSignPageProps) => (
{}}>
-
+
);
@@ -35,7 +33,33 @@ beforeEach(() => {
const mockAccount = mockMnemonicAccount(0);
const mockFAToken = mockFA2Token(0, mockAccount);
-describe(" ", () => {
+
+describe(" ", () => {
+ describe("fee", () => {
+ it("displays the fee in tez", async () => {
+ const store = makeStore();
+ addTestAccount(store, mockMnemonicAccount(0));
+ const props: LocalSignPageProps = {
+ operations: {
+ ...makeAccountOperations(mockImplicitAccount(0), mockImplicitAccount(0), [
+ {
+ type: "tez",
+ amount: "1000000",
+ recipient: mockImplicitAddress(1),
+ },
+ ]),
+ estimates: [executeParams({ fee: 1234567 })],
+ },
+ operationType: "tez",
+ };
+ render(fixture(props), { store });
+
+ await waitFor(() => expect(screen.getByTestId("fee")).toHaveTextContent(`1.234567 ${TEZ}`));
+ });
+ });
+});
+
+describe(" ", () => {
const sender = mockImplicitAccount(0);
const operations = {
...makeAccountOperations(sender, mockImplicitAccount(0), [
@@ -56,12 +80,10 @@ describe(" ", () => {
};
describe("fee", () => {
it("displays the fee in tez", async () => {
- const props: SignPageProps<{
- token: FA12TokenBalance | FA2TokenBalance;
- }> = {
+ const props: LocalSignPageProps = {
operations,
- mode: "single",
- data: { token: mockFAToken },
+ operationType: "token",
+ token: mockFAToken,
};
render(fixture(props), { store });
@@ -71,12 +93,10 @@ describe(" ", () => {
describe("token", () => {
it("displays the correct symbol", async () => {
- const props: SignPageProps<{
- token: FA12TokenBalance | FA2TokenBalance;
- }> = {
+ const props: LocalSignPageProps = {
operations,
- mode: "single",
- data: { token: mockFAToken },
+ operationType: "token",
+ token: mockFAToken,
};
render(fixture(props), { store });
@@ -88,12 +108,10 @@ describe(" ", () => {
});
it("displays the correct amount", async () => {
- const props: SignPageProps<{
- token: FA12TokenBalance | FA2TokenBalance;
- }> = {
+ const props: LocalSignPageProps = {
operations,
- mode: "single",
- data: { token: mockFA2Token(0, mockAccount, 1, 0) },
+ operationType: "token",
+ token: mockFA2Token(0, mockAccount, 1, 0),
};
render(fixture(props), { store });
diff --git a/apps/web/src/components/SendFlow/LocalSignPage.tsx b/apps/web/src/components/SendFlow/LocalSignPage.tsx
new file mode 100644
index 0000000000..1d1e8ce41d
--- /dev/null
+++ b/apps/web/src/components/SendFlow/LocalSignPage.tsx
@@ -0,0 +1,138 @@
+import {
+ Flex,
+ FormControl,
+ FormLabel,
+ ModalBody,
+ ModalContent,
+ ModalFooter,
+ VStack,
+ useBreakpointValue,
+} from "@chakra-ui/react";
+import {
+ type FA12TokenBalance,
+ type FA2TokenBalance,
+ type TezTransfer,
+ type TokenTransfer,
+} from "@umami/core";
+import { type Address } from "@umami/tezos";
+import { CustomError } from "@umami/utils";
+import { FormProvider } from "react-hook-form";
+
+import { SignButton } from "./SignButton";
+import { SignPageFee } from "./SignPageFee";
+import { SignPageHeader } from "./SignPageHeader";
+import { type LocalSignPageProps, useSignPageHelpers } from "./utils";
+import { AddressTile } from "../AddressTile";
+import { AdvancedSettingsAccordion } from "../AdvancedSettingsAccordion";
+import { TezTile, TokenTile } from "../AssetTiles";
+
+export const LocalSignPage = (props: LocalSignPageProps) => {
+ const { operations: initialOperations, token, operationType } = props;
+ const { fee, operations, estimationFailed, isLoading, form, signer, onSign } =
+ useSignPageHelpers(initialOperations);
+ const hideBalance = useBreakpointValue({ base: true, md: false });
+
+ const operation = operations.operations[0];
+
+ const fields: Record = {};
+
+ switch (operationType) {
+ case "tez":
+ fields["mutezAmount"] = (operation as TezTransfer).amount;
+ fields["to"] = (operation as TezTransfer).recipient;
+ fields["from"] = operations.sender.address;
+ break;
+ case "token":
+ if (!token) {
+ throw new CustomError("Token is required for token operation");
+ }
+ fields["amount"] = (operation as TokenTransfer).amount;
+ fields["to"] = (operation as TokenTransfer).recipient;
+ fields["from"] = operations.sender.address;
+ fields["token"] = token;
+ break;
+ }
+
+ const AddressLabelAndTile = (heading: string, address: Address | undefined) => {
+ if (!address) {
+ return null;
+ }
+ return (
+
+ {heading}
+
+
+ );
+ };
+
+ const Fee = () => (
+
+
+
+ );
+
+ const MutezAndFee = (mutezAmount: string | undefined) => {
+ if (!mutezAmount) {
+ return null;
+ }
+ return (
+
+ Amount
+
+
+
+ );
+ };
+
+ const TokenAndFee = (token: FA12TokenBalance | FA2TokenBalance | undefined, amount: string) => {
+ if (!token) {
+ return null;
+ }
+ return (
+
+ Amount
+
+
+
+ );
+ };
+
+ const formFields = {
+ mutezAmount: MutezAndFee(fields["mutezAmount"]),
+ from: AddressLabelAndTile("From", fields["from"]),
+ to: AddressLabelAndTile("To", fields["to"]),
+ token: TokenAndFee(fields["token"], fields["amount"]),
+ };
+
+ const renderField = (key: keyof typeof formFields) => formFields[key];
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/apps/web/src/components/SendFlow/Stake/FormPage.tsx b/apps/web/src/components/SendFlow/Stake/FormPage.tsx
deleted file mode 100644
index b658095ef4..0000000000
--- a/apps/web/src/components/SendFlow/Stake/FormPage.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-import {
- Center,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Heading,
- Input,
- InputGroup,
- InputRightElement,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalFooter,
- ModalHeader,
-} from "@chakra-ui/react";
-import hj from "@hotjar/browser";
-import { type Stake } from "@umami/core";
-import { type RawPkh, TEZ, TEZ_DECIMALS, parsePkh, tezToMutez } from "@umami/tezos";
-import { FormProvider, useForm } from "react-hook-form";
-
-import { SignPage } from "./SignPage";
-import { AddressTile } from "../../AddressTile/AddressTile";
-import {
- useAddToBatchFormAction,
- useHandleOnSubmitFormActions,
- useOpenSignPageFormAction,
-} from "../onSubmitFormActionHooks";
-import {
- type FormPageProps,
- FormSubmitButton,
- formDefaultValues,
- getSmallestUnit,
- makeValidateDecimals,
-} from "../utils";
-
-type FormValues = {
- sender: RawPkh;
- prettyAmount: string;
-};
-
-// TODO: test
-export const FormPage = (props: FormPageProps) => {
- const openSignPage = useOpenSignPageFormAction({
- SignPage,
- signPageExtraData: undefined,
- FormPage,
- defaultFormPageProps: props,
- toOperation,
- });
-
- const addToBatch = useAddToBatchFormAction(toOperation);
-
- const {
- onFormSubmitActionHandlers: [onSingleSubmit],
- isLoading,
- } = useHandleOnSubmitFormActions([openSignPage, addToBatch]);
-
- const form = useForm({
- mode: "onBlur",
- defaultValues: formDefaultValues(props),
- });
- const {
- formState: { errors },
- register,
- handleSubmit,
- } = form;
-
- hj.stateChange("send_flow/stake_form_page");
-
- return (
-
-
-
-
-
- );
-};
-
-const toOperation = (formValues: FormValues): Stake => ({
- type: "stake",
- amount: tezToMutez(formValues.prettyAmount).toFixed(),
- sender: parsePkh(formValues.sender),
-});
diff --git a/apps/web/src/components/SendFlow/Stake/NoticeModal.tsx b/apps/web/src/components/SendFlow/Stake/NoticeModal.tsx
deleted file mode 100644
index 35a80c2402..0000000000
--- a/apps/web/src/components/SendFlow/Stake/NoticeModal.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import {
- Button,
- Center,
- Checkbox,
- Heading,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalHeader,
- Text,
-} from "@chakra-ui/react";
-import { useDynamicModalContext } from "@umami/components";
-import { type Account } from "@umami/core";
-import { useForm } from "react-hook-form";
-
-import { FormPage } from "./FormPage";
-import { StubIcon as WarningIcon } from "../../../assets/icons";
-import { useColor } from "../../../styles/useColor";
-
-export const NoticeModal = ({ account }: { account: Account }) => {
- const { openWith } = useDynamicModalContext();
- const { setValue, watch } = useForm<{ consent: boolean }>({
- mode: "onBlur",
- defaultValues: { consent: false },
- });
- const color = useColor();
-
- const isConsentGiven = !watch("consent");
-
- return (
-
-
-
-
-
- Disclaimer
-
-
-
-
-
- Staked balances are locked in your account until they are manually unstaked and
- finalized. You need to wait 4 cycles to finalize after an unstake.
-
-
-
- Staked funds are at risk. You might lose a portion of your stake if the chosen baker is
- slashed for not following Tezos consensus mechanism rules.
-
-
- setValue("consent", event.target.checked)}
- paddingX="50px"
- paddingY="25px"
- >
- I understand and accept the risks.
-
-
- openWith( )}
- size="lg"
- >
- Continue
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/Stake/SignPage.tsx b/apps/web/src/components/SendFlow/Stake/SignPage.tsx
deleted file mode 100644
index 422693a8f6..0000000000
--- a/apps/web/src/components/SendFlow/Stake/SignPage.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { Flex, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
-import { type Stake } from "@umami/core";
-import { FormProvider } from "react-hook-form";
-
-import { AddressTile } from "../../AddressTile/AddressTile";
-import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
-import { TezTile } from "../../AssetTiles/TezTile";
-import { SignButton } from "../SignButton";
-import { SignPageFee } from "../SignPageFee";
-import { SignPageHeader } from "../SignPageHeader";
-import { type SignPageProps, useSignPageHelpers } from "../utils";
-
-// TODO: test
-export const SignPage = (props: SignPageProps) => {
- const { operations } = props;
- const { isLoading, form, signer, onSign, fee } = useSignPageHelpers(operations);
-
- const { amount: mutezAmount } = operations.operations[0] as Stake;
-
- return (
-
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/Tez/FormPage.test.tsx b/apps/web/src/components/SendFlow/Tez/FormPage.test.tsx
index bad1e4d215..ae2941aeac 100644
--- a/apps/web/src/components/SendFlow/Tez/FormPage.test.tsx
+++ b/apps/web/src/components/SendFlow/Tez/FormPage.test.tsx
@@ -17,7 +17,6 @@ import { CustomError } from "@umami/utils";
import { BigNumber } from "bignumber.js";
import { FormPage } from "./FormPage";
-import { SignPage } from "./SignPage";
import {
act,
dynamicModalContextMock,
@@ -27,6 +26,7 @@ import {
userEvent,
waitFor,
} from "../../../testUtils";
+import { LocalSignPage } from "../LocalSignPage";
jest.mock("@umami/core", () => ({
...jest.requireActual("@umami/core"),
@@ -262,10 +262,9 @@ describe("", () => {
await act(() => user.click(submitButton));
expect(dynamicModalContextMock.openWith).toHaveBeenCalledWith(
-
);
diff --git a/apps/web/src/components/SendFlow/Tez/FormPage.tsx b/apps/web/src/components/SendFlow/Tez/FormPage.tsx
index a36dc0dd32..a29f662c78 100644
--- a/apps/web/src/components/SendFlow/Tez/FormPage.tsx
+++ b/apps/web/src/components/SendFlow/Tez/FormPage.tsx
@@ -15,7 +15,6 @@ import { useGetAccountBalanceDetails } from "@umami/state";
import { type RawPkh, TEZ, TEZ_DECIMALS, parsePkh, tezToMutez } from "@umami/tezos";
import { FormProvider, useForm } from "react-hook-form";
-import { SignPage } from "./SignPage";
import { useColor } from "../../../styles/useColor";
import { KnownAccountsAutocomplete } from "../../AddressAutocomplete";
import { TezTile } from "../../AssetTiles";
@@ -42,8 +41,7 @@ export type FormValues = {
export const FormPage = ({ ...props }: FormPageProps) => {
const color = useColor();
const openSignPage = useOpenSignPageFormAction({
- SignPage,
- signPageExtraData: undefined,
+ operationType: "tez",
FormPage,
defaultFormPageProps: props,
toOperation,
diff --git a/apps/web/src/components/SendFlow/Tez/SignPage.test.tsx b/apps/web/src/components/SendFlow/Tez/SignPage.test.tsx
deleted file mode 100644
index 04e15a667d..0000000000
--- a/apps/web/src/components/SendFlow/Tez/SignPage.test.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { Modal } from "@chakra-ui/react";
-import { makeAccountOperations, mockImplicitAccount, mockMnemonicAccount } from "@umami/core";
-import { addTestAccount, makeStore } from "@umami/state";
-import { executeParams } from "@umami/test-utils";
-import { TEZ, mockImplicitAddress } from "@umami/tezos";
-
-import { SignPage } from "./SignPage";
-import { render, screen, waitFor } from "../../../testUtils";
-import { type SignPageProps } from "../utils";
-
-jest.mock("@chakra-ui/react", () => ({
- ...jest.requireActual("@chakra-ui/react"),
- useBreakpointValue: jest.fn(),
-}));
-
-const fixture = (props: SignPageProps) => (
- {}}>
-
-
-);
-
-describe(" ", () => {
- describe("fee", () => {
- it("displays the fee in tez", async () => {
- const store = makeStore();
- addTestAccount(store, mockMnemonicAccount(0));
- const props: SignPageProps = {
- operations: {
- ...makeAccountOperations(mockImplicitAccount(0), mockImplicitAccount(0), [
- {
- type: "tez",
- amount: "1000000",
- recipient: mockImplicitAddress(1),
- },
- ]),
- estimates: [executeParams({ fee: 1234567 })],
- },
- mode: "single",
- data: undefined,
- };
- render(fixture(props), { store });
-
- await waitFor(() => expect(screen.getByTestId("fee")).toHaveTextContent(`1.234567 ${TEZ}`));
- });
- });
-});
diff --git a/apps/web/src/components/SendFlow/Tez/SignPage.tsx b/apps/web/src/components/SendFlow/Tez/SignPage.tsx
deleted file mode 100644
index 444dc7e666..0000000000
--- a/apps/web/src/components/SendFlow/Tez/SignPage.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import {
- Flex,
- FormControl,
- FormLabel,
- ModalBody,
- ModalContent,
- ModalFooter,
- useBreakpointValue,
-} from "@chakra-ui/react";
-import { type TezTransfer } from "@umami/core";
-import { FormProvider } from "react-hook-form";
-
-import { AddressTile } from "../../AddressTile/AddressTile";
-import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
-import { TezTile } from "../../AssetTiles/TezTile";
-import { SignButton } from "../SignButton";
-import { SignPageFee } from "../SignPageFee";
-import { SignPageHeader } from "../SignPageHeader";
-import { type SignPageProps, useSignPageHelpers } from "../utils";
-
-export const SignPage = (props: SignPageProps) => {
- const { operations: initialOperations } = props;
- const { fee, operations, estimationFailed, isLoading, form, signer, onSign } =
- useSignPageHelpers(initialOperations);
- const hideBalance = useBreakpointValue({ base: true, md: false });
-
- const { amount: mutezAmount, recipient } = operations.operations[0] as TezTransfer;
-
- return (
-
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/Token/FormPage.test.tsx b/apps/web/src/components/SendFlow/Token/FormPage.test.tsx
index 11eba0205f..6fce4fd51b 100644
--- a/apps/web/src/components/SendFlow/Token/FormPage.test.tsx
+++ b/apps/web/src/components/SendFlow/Token/FormPage.test.tsx
@@ -13,7 +13,6 @@ import { executeParams } from "@umami/test-utils";
import { parseContractPkh } from "@umami/tezos";
import { FormPage, type FormValues } from "./FormPage";
-import { SignPage } from "./SignPage";
import {
act,
dynamicModalContextMock,
@@ -23,6 +22,7 @@ import {
userEvent,
waitFor,
} from "../../../testUtils";
+import { LocalSignPage } from "../LocalSignPage";
import { type FormPagePropsWithSender } from "../utils";
jest.mock("@umami/core", () => ({
@@ -241,11 +241,11 @@ describe(" ", () => {
await act(() => user.click(submitButton));
expect(dynamicModalContextMock.openWith).toHaveBeenCalledWith(
-
);
expect(mockToast).not.toHaveBeenCalled();
diff --git a/apps/web/src/components/SendFlow/Token/FormPage.tsx b/apps/web/src/components/SendFlow/Token/FormPage.tsx
index 7439c3a95b..4d27d10d82 100644
--- a/apps/web/src/components/SendFlow/Token/FormPage.tsx
+++ b/apps/web/src/components/SendFlow/Token/FormPage.tsx
@@ -23,7 +23,6 @@ import {
import { type RawPkh, parseContractPkh, parsePkh } from "@umami/tezos";
import { FormProvider, useForm } from "react-hook-form";
-import { SignPage } from "./SignPage";
import { KnownAccountsAutocomplete } from "../../AddressAutocomplete";
import { TokenTile } from "../../AssetTiles";
import { FormPageHeader } from "../FormPageHeader";
@@ -51,8 +50,8 @@ export const FormPage = (
) => {
const { token } = props;
const openSignPage = useOpenSignPageFormAction({
- SignPage,
- signPageExtraData: { token },
+ operationType: "token",
+ token,
FormPage,
defaultFormPageProps: props,
toOperation: toOperation(token),
diff --git a/apps/web/src/components/SendFlow/Token/SignPage.tsx b/apps/web/src/components/SendFlow/Token/SignPage.tsx
deleted file mode 100644
index cae07bbcb6..0000000000
--- a/apps/web/src/components/SendFlow/Token/SignPage.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import {
- Flex,
- FormControl,
- FormLabel,
- ModalBody,
- ModalContent,
- ModalFooter,
- useBreakpointValue,
-} from "@chakra-ui/react";
-import { type FA12TokenBalance, type FA2TokenBalance, type TokenTransfer } from "@umami/core";
-import { FormProvider } from "react-hook-form";
-
-import { AddressTile } from "../../AddressTile/AddressTile";
-import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
-import { TokenTile } from "../../AssetTiles";
-import { SignButton } from "../SignButton";
-import { SignPageFee } from "../SignPageFee";
-import { SignPageHeader } from "../SignPageHeader";
-import { type SignPageProps, useSignPageHelpers } from "../utils";
-
-export const SignPage = (props: SignPageProps<{ token: FA12TokenBalance | FA2TokenBalance }>) => {
- const {
- operations: initialOperations,
- data: { token },
- } = props;
- const { fee, operations, estimationFailed, isLoading, form, signer, onSign } =
- useSignPageHelpers(initialOperations);
- const hideBalance = useBreakpointValue({ base: true, md: false });
- const { amount, recipient } = operations.operations[0] as TokenTransfer;
-
- return (
-
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/Undelegation/FormPage.test.tsx b/apps/web/src/components/SendFlow/Undelegation/FormPage.test.tsx
deleted file mode 100644
index d71e2b16a4..0000000000
--- a/apps/web/src/components/SendFlow/Undelegation/FormPage.test.tsx
+++ /dev/null
@@ -1,152 +0,0 @@
-import {
- estimate,
- makeAccountOperations,
- mockImplicitAccount,
- mockMnemonicAccount,
- mockMultisigAccount,
-} from "@umami/core";
-import {
- type UmamiStore,
- addTestAccounts,
- assetsActions,
- makeStore,
- mockToast,
-} from "@umami/state";
-import { executeParams } from "@umami/test-utils";
-import { mockImplicitAddress } from "@umami/tezos";
-import { CustomError } from "@umami/utils";
-
-import { FormPage, type FormValues } from "./FormPage";
-import { SignPage } from "./SignPage";
-import {
- act,
- dynamicModalContextMock,
- renderInModal,
- screen,
- userEvent,
- waitFor,
-} from "../../../testUtils";
-import { type FormPagePropsWithSender } from "../utils";
-
-const fixture = (props: FormPagePropsWithSender) => ;
-
-let store: UmamiStore;
-
-beforeEach(() => {
- store = makeStore();
-});
-
-jest.mock("@umami/core", () => ({
- ...jest.requireActual("@umami/core"),
- estimate: jest.fn(),
-}));
-
-describe("", () => {
- describe("default values", () => {
- it("renders a form with a prefilled sender", async () => {
- await renderInModal(fixture({ sender: mockImplicitAccount(0) }), store);
-
- expect(screen.getAllByTestId("address-tile")[0]).toHaveTextContent(
- mockImplicitAccount(0).address.pkh
- );
- });
-
- it("shows address tile for baker", async () => {
- const sender = mockImplicitAccount(0);
- const baker = mockImplicitAccount(1);
- store.dispatch(
- assetsActions.updateBakers([
- { address: baker.address.pkh, name: "baker1", stakingBalance: 1 },
- ])
- );
-
- await renderInModal(
- fixture({
- sender: sender,
- form: {
- sender: sender.address.pkh,
- baker: baker.address.pkh,
- },
- }),
- store
- );
-
- expect(screen.getAllByTestId("address-tile")[1]).toHaveTextContent("baker1");
- });
- });
-
- describe("single transaction", () => {
- beforeEach(() => {
- addTestAccounts(store, [mockMnemonicAccount(0), mockMultisigAccount(0)]);
- });
-
- it("shows a toast if estimation fails", async () => {
- const user = userEvent.setup();
- await renderInModal(
- fixture({
- sender: mockImplicitAccount(0),
- form: {
- sender: mockImplicitAccount(0).address.pkh,
- baker: mockImplicitAccount(1).address.pkh,
- },
- }),
- store
- );
-
- const estimateMock = jest.mocked(estimate);
- estimateMock.mockRejectedValue(new CustomError("Some error occurred"));
-
- const submitButton = screen.getByText("Preview");
- await waitFor(() => expect(submitButton).toBeEnabled());
- await act(() => user.click(submitButton));
-
- expect(estimateMock).toHaveBeenCalledTimes(1);
- expect(mockToast).toHaveBeenCalledWith({
- description: "Some error occurred",
- status: "error",
- isClosable: true,
- });
- });
-
- it("opens a sign page if estimation succeeds", async () => {
- const user = userEvent.setup();
- const sender = mockImplicitAccount(0);
- await renderInModal(
- fixture({
- sender: sender,
- form: {
- sender: sender.address.pkh,
- baker: mockImplicitAddress(2).pkh,
- },
- }),
- store
- );
- const submitButton = screen.getByText("Preview");
- await waitFor(() => expect(submitButton).toBeEnabled());
-
- const operations = {
- ...makeAccountOperations(sender, sender, [
- {
- type: "undelegation",
- sender: sender.address,
- },
- ]),
- estimates: [executeParams()],
- };
-
- jest.mocked(estimate).mockResolvedValueOnce(operations);
-
- await act(() => user.click(submitButton));
-
- expect(dynamicModalContextMock.openWith).toHaveBeenCalledWith(
-
- );
- expect(mockToast).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/apps/web/src/components/SendFlow/Undelegation/FormPage.tsx b/apps/web/src/components/SendFlow/Undelegation/FormPage.tsx
deleted file mode 100644
index bef9d2c1c1..0000000000
--- a/apps/web/src/components/SendFlow/Undelegation/FormPage.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import { FormControl, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
-import hj from "@hotjar/browser";
-import { type Undelegation } from "@umami/core";
-import { type RawPkh, parsePkh } from "@umami/tezos";
-import { FormProvider, useForm } from "react-hook-form";
-
-import { SignPage } from "./SignPage";
-import { OwnedAccountsAutocomplete } from "../../AddressAutocomplete";
-import { AddressTile } from "../../AddressTile/AddressTile";
-import { FormPageHeader } from "../FormPageHeader";
-import {
- useAddToBatchFormAction,
- useHandleOnSubmitFormActions,
- useOpenSignPageFormAction,
-} from "../onSubmitFormActionHooks";
-import { type FormPagePropsWithSender, FormSubmitButton, formDefaultValues } from "../utils";
-
-export type FormValues = {
- sender: RawPkh;
- baker: RawPkh;
-};
-
-export const FormPage = (props: FormPagePropsWithSender) => {
- const { sender } = props;
- // it must always be passed in from the parent component
- const baker = props.form?.baker;
-
- const openSignPage = useOpenSignPageFormAction({
- SignPage,
- signPageExtraData: undefined,
- FormPage,
- defaultFormPageProps: { sender },
- toOperation,
- });
-
- const addToBatch = useAddToBatchFormAction(toOperation);
-
- const {
- onFormSubmitActionHandlers: [onSingleSubmit],
- isLoading,
- } = useHandleOnSubmitFormActions([openSignPage, addToBatch]);
-
- const form = useForm({
- mode: "onBlur",
- defaultValues: formDefaultValues({ sender }),
- });
-
- const { handleSubmit } = form;
-
- hj.stateChange("send_flow/undelegation_form_page");
-
- return (
-
-
-
-
-
- );
-};
-
-const toOperation = (formValues: FormValues): Undelegation => ({
- type: "undelegation",
- sender: parsePkh(formValues.sender),
-});
diff --git a/apps/web/src/components/SendFlow/Undelegation/SignPage.test.tsx b/apps/web/src/components/SendFlow/Undelegation/SignPage.test.tsx
deleted file mode 100644
index d48227cbd1..0000000000
--- a/apps/web/src/components/SendFlow/Undelegation/SignPage.test.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import { Modal } from "@chakra-ui/react";
-import { makeAccountOperations, mockImplicitAccount, mockMnemonicAccount } from "@umami/core";
-import { type UmamiStore, addTestAccount, makeStore } from "@umami/state";
-import { executeParams } from "@umami/test-utils";
-import { TEZ } from "@umami/tezos";
-
-import { SignPage } from "./SignPage";
-import { render, screen, waitFor } from "../../../testUtils";
-import { type SignPageProps } from "../utils";
-
-const fixture = (props: SignPageProps) => (
- {}}>
-
-
-);
-
-let store: UmamiStore;
-
-beforeEach(() => {
- store = makeStore();
- addTestAccount(store, mockMnemonicAccount(0));
-});
-
-describe(" ", () => {
- const sender = mockImplicitAccount(0);
- const operations = {
- ...makeAccountOperations(sender, mockImplicitAccount(0), [
- {
- type: "undelegation",
- sender: sender.address,
- },
- ]),
- estimates: [
- executeParams({
- fee: 1234567,
- }),
- ],
- };
-
- describe("fee", () => {
- it("displays the fee in tez", async () => {
- const props: SignPageProps = {
- operations,
- mode: "single",
- data: undefined,
- };
- render(fixture(props), { store });
-
- await waitFor(() => expect(screen.getByTestId("fee")).toHaveTextContent(`1.234567 ${TEZ}`));
- });
- });
-});
diff --git a/apps/web/src/components/SendFlow/Undelegation/SignPage.tsx b/apps/web/src/components/SendFlow/Undelegation/SignPage.tsx
deleted file mode 100644
index b4a4689c4e..0000000000
--- a/apps/web/src/components/SendFlow/Undelegation/SignPage.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Flex, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
-import { FormProvider } from "react-hook-form";
-
-import { AddressTile } from "../../AddressTile/AddressTile";
-import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
-import { SignButton } from "../SignButton";
-import { SignPageFee } from "../SignPageFee";
-import { SignPageHeader } from "../SignPageHeader";
-import { type SignPageProps, useSignPageHelpers } from "../utils";
-
-export const SignPage = (props: SignPageProps) => {
- const { operations: initialOperations } = props;
-
- const { fee, estimationFailed, isLoading, form, signer, onSign } =
- useSignPageHelpers(initialOperations);
- return (
-
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/Unstake/FormPage.tsx b/apps/web/src/components/SendFlow/Unstake/FormPage.tsx
deleted file mode 100644
index 8c4e049e62..0000000000
--- a/apps/web/src/components/SendFlow/Unstake/FormPage.tsx
+++ /dev/null
@@ -1,127 +0,0 @@
-import {
- Center,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Heading,
- Input,
- InputGroup,
- InputRightElement,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalFooter,
- ModalHeader,
-} from "@chakra-ui/react";
-import hj from "@hotjar/browser";
-import { type Unstake } from "@umami/core";
-import { type RawPkh, TEZ, TEZ_DECIMALS, parsePkh, tezToMutez } from "@umami/tezos";
-import { BigNumber } from "bignumber.js";
-import { FormProvider, useForm } from "react-hook-form";
-
-import { SignPage } from "./SignPage";
-import { TezTile } from "../../AssetTiles/TezTile";
-import {
- useAddToBatchFormAction,
- useHandleOnSubmitFormActions,
- useOpenSignPageFormAction,
-} from "../onSubmitFormActionHooks";
-import {
- type FormPageProps,
- FormSubmitButton,
- formDefaultValues,
- getSmallestUnit,
- makeValidateDecimals,
-} from "../utils";
-
-type FormValues = {
- sender: RawPkh;
- prettyAmount: string;
-};
-
-// TODO: test
-export const FormPage = (props: FormPageProps & { stakedBalance: number }) => {
- const stakedBalance = props.stakedBalance;
-
- const openSignPage = useOpenSignPageFormAction({
- SignPage,
- signPageExtraData: { stakedBalance },
- FormPage,
- defaultFormPageProps: props,
- toOperation,
- });
-
- const addToBatch = useAddToBatchFormAction(toOperation);
-
- const {
- onFormSubmitActionHandlers: [onSingleSubmit],
- isLoading,
- } = useHandleOnSubmitFormActions([openSignPage, addToBatch]);
-
- const form = useForm({
- mode: "onBlur",
- defaultValues: formDefaultValues(props),
- });
- const {
- formState: { errors },
- register,
- handleSubmit,
- } = form;
-
- hj.stateChange("send_flow/unstake_form_page");
-
- return (
-
-
-
-
-
- );
-};
-
-const toOperation = (formValues: FormValues): Unstake => ({
- type: "unstake",
- amount: tezToMutez(formValues.prettyAmount).toFixed(),
- sender: parsePkh(formValues.sender),
-});
diff --git a/apps/web/src/components/SendFlow/Unstake/NoticeModal.tsx b/apps/web/src/components/SendFlow/Unstake/NoticeModal.tsx
deleted file mode 100644
index fb62667f81..0000000000
--- a/apps/web/src/components/SendFlow/Unstake/NoticeModal.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import {
- Button,
- Center,
- Heading,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalHeader,
- Text,
-} from "@chakra-ui/react";
-import { useDynamicModalContext } from "@umami/components";
-import { type Account } from "@umami/core";
-import { useGetAccountStakedBalance } from "@umami/state";
-
-import { FormPage } from "./FormPage";
-import { StubIcon as WarningIcon } from "../../../assets/icons";
-import { useColor } from "../../../styles/useColor";
-import { NoticeSteps } from "../NoticeSteps";
-// TODO: test
-export const NoticeModal = ({ account }: { account: Account }) => {
- const color = useColor();
- const { openWith } = useDynamicModalContext();
- const stakedBalance = useGetAccountStakedBalance(account.address.pkh);
-
- return (
-
-
-
-
-
- Important notice
-
-
-
-
-
- After submitting an unstake, the chosen amount will become finalizable after 4 cycles
- (~10 days). Then, you will need to finalize unstaked balances in order to make them
- spendable.
-
-
-
-
- openWith( )}
- size="lg"
- >
- I understand
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/Unstake/SignPage.tsx b/apps/web/src/components/SendFlow/Unstake/SignPage.tsx
deleted file mode 100644
index dc23a36692..0000000000
--- a/apps/web/src/components/SendFlow/Unstake/SignPage.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import { Flex, FormLabel, ModalBody, ModalContent, ModalFooter } from "@chakra-ui/react";
-import { type Unstake } from "@umami/core";
-import { FormProvider } from "react-hook-form";
-
-import { AddressTile } from "../../AddressTile/AddressTile";
-import { AdvancedSettingsAccordion } from "../../AdvancedSettingsAccordion";
-import { TezTile } from "../../AssetTiles/TezTile";
-import { SignButton } from "../SignButton";
-import { SignPageFee } from "../SignPageFee";
-import { SignPageHeader } from "../SignPageHeader";
-import { type SignPageProps, useSignPageHelpers } from "../utils";
-// TODO: test
-export const SignPage = (props: SignPageProps<{ stakedBalance: number }>) => {
- const {
- operations,
- data: { stakedBalance },
- } = props;
- const { isLoading, form, signer, onSign, fee } = useSignPageHelpers(operations);
- const { amount: mutezAmount } = operations.operations[0] as Unstake;
-
- return (
-
-
-
-
-
- );
-};
diff --git a/apps/web/src/components/SendFlow/common/RequestSignPage.test.tsx b/apps/web/src/components/SendFlow/common/RequestSignPage.test.tsx
index 89f3c63d0d..cb3be67327 100644
--- a/apps/web/src/components/SendFlow/common/RequestSignPage.test.tsx
+++ b/apps/web/src/components/SendFlow/common/RequestSignPage.test.tsx
@@ -39,7 +39,7 @@ import {
} from "../../../testUtils";
import { SuccessStep } from "../SuccessStep";
import { type SdkSignPageProps, type SignHeaderProps } from "../utils";
-import { SingleSignPage } from "./RequestSignPage";
+import { RequestSignPage } from "./RequestSignPage";
jest.mock("@umami/core", () => ({
...jest.requireActual("@umami/core"),
@@ -89,7 +89,7 @@ const operation: EstimatedAccountOperations = {
estimates: [executeParams({ fee: 123 })],
};
-describe(" ", () => {
+describe(" ", () => {
const store = makeStore();
const user = userEvent.setup();
@@ -125,7 +125,7 @@ describe(" ", () => {
jest.mocked(executeOperations).mockResolvedValue({ opHash: "ophash" } as BatchWalletOperation);
- await renderInModal( , store);
+ await renderInModal( , store);
expect(screen.getByText("Ghostnet")).toBeInTheDocument();
expect(screen.queryByText("Mainnet")).not.toBeInTheDocument();
@@ -244,7 +244,7 @@ describe("batch handling", () => {
jest.mocked(executeOperations).mockResolvedValue({ opHash: "ophash" } as BatchWalletOperation);
jest.spyOn(WalletClient, "respond").mockResolvedValue();
- await renderInModal( , store);
+ await renderInModal( , store);
expect(screen.getByText("Ghostnet")).toBeInTheDocument();
expect(screen.queryByText("Mainnet")).not.toBeInTheDocument();
diff --git a/apps/web/src/components/SendFlow/common/RequestSignPage.tsx b/apps/web/src/components/SendFlow/common/RequestSignPage.tsx
index e76ded8e1e..1344fc2eed 100644
--- a/apps/web/src/components/SendFlow/common/RequestSignPage.tsx
+++ b/apps/web/src/components/SendFlow/common/RequestSignPage.tsx
@@ -40,7 +40,7 @@ import { SignPageFee } from "../SignPageFee";
import { type SdkSignPageProps } from "../utils";
import { useSignWithWalletConnect } from "../WalletConnect/useSignWithWalletConnect";
-export const SingleSignPage = (signProps: SdkSignPageProps) => {
+export const RequestSignPage = (signProps: SdkSignPageProps) => {
const color = useColor();
const totalFinalizableAmount = useAccountTotalFinalizableUnstakeAmount(
diff --git a/apps/web/src/components/SendFlow/onSubmitFormActionHooks.tsx b/apps/web/src/components/SendFlow/onSubmitFormActionHooks.tsx
index 7d290ac354..3d65a716c8 100644
--- a/apps/web/src/components/SendFlow/onSubmitFormActionHooks.tsx
+++ b/apps/web/src/components/SendFlow/onSubmitFormActionHooks.tsx
@@ -1,6 +1,12 @@
import { useToast } from "@chakra-ui/react";
import { useDynamicModalContext } from "@umami/components";
-import { type EstimatedAccountOperations, type Operation, estimate } from "@umami/core";
+import {
+ type EstimatedAccountOperations,
+ type FA12TokenBalance,
+ type FA2TokenBalance,
+ type Operation,
+ estimate,
+} from "@umami/core";
import {
estimateAndUpdateBatch,
useAppDispatch,
@@ -9,12 +15,8 @@ import {
} from "@umami/state";
import { type FunctionComponent } from "react";
-import {
- type BaseFormValues,
- type FormPageProps,
- type SignPageProps,
- useMakeFormOperations,
-} from "./utils";
+import { LocalSignPage } from "./LocalSignPage";
+import { type BaseFormValues, type FormPageProps, useMakeFormOperations } from "./utils";
// This file defines hooks to create actions when form is submitted.
@@ -23,14 +25,11 @@ type OnSubmitFormAction = (
) => Promise;
type UseOpenSignPageArgs<
- ExtraData,
FormValues extends BaseFormValues,
FormProps extends FormPageProps,
> = {
- // Sign page component to render.
- SignPage: FunctionComponent>;
- // Extra data to pass to the Sign page component (e.g. NFT or Token)
- signPageExtraData: ExtraData;
+ operationType: "token" | "tez";
+ token?: FA12TokenBalance | FA2TokenBalance;
// Form page component to render when the user goes back from the sign page.
FormPage: FunctionComponent;
// Form page props, used to render the form page again when the user goes back from the sign page
@@ -42,16 +41,15 @@ type UseOpenSignPageArgs<
// Hook to open the sign page that knows how to get back to the form page.
export const useOpenSignPageFormAction = <
- SignPageData,
FormValues extends BaseFormValues,
FormProps extends FormPageProps,
>({
- SignPage,
- signPageExtraData,
+ operationType,
+ token,
FormPage,
defaultFormPageProps,
toOperation,
-}: UseOpenSignPageArgs): OnSubmitFormAction => {
+}: UseOpenSignPageArgs): OnSubmitFormAction => {
const { openWith } = useDynamicModalContext();
const makeFormOperations = useMakeFormOperations(toOperation);
const network = useSelectedNetwork();
@@ -61,8 +59,7 @@ export const useOpenSignPageFormAction = <
const estimatedOperations = await estimate(operations, network);
return openWith(
-
openWith(
)
}
- mode="single"
+ operationType={operationType}
operations={estimatedOperations}
+ token={token}
/>
);
};
diff --git a/apps/web/src/components/SendFlow/utils.tsx b/apps/web/src/components/SendFlow/utils.tsx
index 6c5961a1f3..13be353432 100644
--- a/apps/web/src/components/SendFlow/utils.tsx
+++ b/apps/web/src/components/SendFlow/utils.tsx
@@ -6,6 +6,8 @@ import {
type Account,
type AccountOperations,
type EstimatedAccountOperations,
+ type FA12TokenBalance,
+ type FA2TokenBalance,
type ImplicitAccount,
type Operation,
estimate,
@@ -45,6 +47,13 @@ export type BaseFormValues = { sender: RawPkh };
export type SignPageMode = "single" | "batch";
+export type LocalSignPageProps = {
+ goBack?: () => void;
+ operationType: "token" | "tez";
+ token?: FA12TokenBalance | FA2TokenBalance;
+ operations: EstimatedAccountOperations;
+};
+
export type SignPageProps = {
goBack?: () => void;
operations: EstimatedAccountOperations;
diff --git a/apps/web/src/components/WalletConnect/useHandleWcRequest.tsx b/apps/web/src/components/WalletConnect/useHandleWcRequest.tsx
index e1dbe80d63..b0199b7e3d 100644
--- a/apps/web/src/components/WalletConnect/useHandleWcRequest.tsx
+++ b/apps/web/src/components/WalletConnect/useHandleWcRequest.tsx
@@ -21,7 +21,7 @@ import { formatJsonRpcError, formatJsonRpcResult } from "@walletconnect/jsonrpc-
import { type SessionTypes, type SignClientTypes, type Verify } from "@walletconnect/types";
import { SignPayloadRequestModal } from "../common/SignPayloadRequestModal";
-import { SingleSignPage } from "../SendFlow/common/RequestSignPage";
+import { RequestSignPage } from "../SendFlow/common/RequestSignPage";
import {
type SdkSignPageProps,
type SignHeaderProps,
@@ -184,7 +184,7 @@ export const useHandleWcRequest = () => {
operation: estimatedOperations,
};
- modal = ;
+ modal = ;
onClose = () => {
handleUserRejected();
diff --git a/apps/web/src/components/beacon/useHandleBeaconMessage.test.tsx b/apps/web/src/components/beacon/useHandleBeaconMessage.test.tsx
index 148e709e31..49fc37c055 100644
--- a/apps/web/src/components/beacon/useHandleBeaconMessage.test.tsx
+++ b/apps/web/src/components/beacon/useHandleBeaconMessage.test.tsx
@@ -21,7 +21,7 @@ import { CustomError } from "@umami/utils";
import { useHandleBeaconMessage } from "./useHandleBeaconMessage";
import { act, dynamicModalContextMock, renderHook, screen, waitFor } from "../../testUtils";
-import { SingleSignPage } from "../SendFlow/common/RequestSignPage";
+import { RequestSignPage } from "../SendFlow/common/RequestSignPage";
import { type SdkSignPageProps, type SignHeaderProps } from "../SendFlow/utils";
jest.mock("@umami/core", () => ({
@@ -352,7 +352,7 @@ describe(" ", () => {
});
describe("single operation", () => {
- it("opens a modal with the SingleSignPage for 1 operation", async () => {
+ it("opens a modal with the RequestSignPage for 1 operation", async () => {
jest.mocked(estimate).mockResolvedValueOnce({
...makeAccountOperations(account, account, [
{ type: "tez", amount: "1", recipient: mockImplicitAddress(2) },
@@ -400,7 +400,7 @@ describe(" ", () => {
await waitFor(() =>
expect(dynamicModalContextMock.openWith).toHaveBeenCalledWith(
- ,
+ ,
{ onClose: expect.any(Function) }
)
);
@@ -510,7 +510,7 @@ describe(" ", () => {
await waitFor(() =>
expect(dynamicModalContextMock.openWith).toHaveBeenCalledWith(
- ,
+ ,
{ onClose: expect.any(Function) }
)
);
diff --git a/apps/web/src/components/beacon/useHandleBeaconMessage.tsx b/apps/web/src/components/beacon/useHandleBeaconMessage.tsx
index 53871e4c53..fc3cd216d1 100644
--- a/apps/web/src/components/beacon/useHandleBeaconMessage.tsx
+++ b/apps/web/src/components/beacon/useHandleBeaconMessage.tsx
@@ -19,7 +19,7 @@ import { BeaconError, CustomError, getErrorContext } from "@umami/utils";
import { PermissionRequestModal } from "./PermissionRequestModal";
import { SignPayloadRequestModal } from "../common/SignPayloadRequestModal";
-import { SingleSignPage } from "../SendFlow/common/RequestSignPage";
+import { RequestSignPage } from "../SendFlow/common/RequestSignPage";
import {
type SdkSignPageProps,
type SignHeaderProps,
@@ -30,7 +30,7 @@ import {
* @returns a function that handles a beacon message and opens a modal with the appropriate content
*
* For operation requests it will also try to convert the operation(s) to our {@link Operation} format,
- * estimate the fee and open the SingleSignPage only if it succeeds
+ * estimate the fee and open the RequestSignPage only if it succeeds
*/
export const useHandleBeaconMessage = () => {
const { openWith, isOpen, canBeOverridden } = useDynamicModalContext();
@@ -147,7 +147,7 @@ export const useHandleBeaconMessage = () => {
operation: estimatedOperations,
};
- modal = ;
+ modal = ;
onClose = () => respondWithError(message.id, BeaconErrorType.ABORTED_ERROR);