Skip to content
This repository has been archived by the owner on Mar 23, 2023. It is now read-only.

refactor: update the WalletUpdate modal to use tab steps #2667

Merged
merged 3 commits into from Aug 14, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,31 +1,14 @@
import { boolean } from "@storybook/addon-knobs";
import React, { useEffect, useState } from "react";
import React from "react";

import { WalletUpdate } from "./WalletUpdate";

export default { title: "Domains / Wallet / Components / WalletUpdate" };

export const Default = () => {
const [isUpdate, setIsUpdate] = useState(false);
const [isReady, setIsReady] = useState(false);

useEffect(() => {
if (isUpdate) {
setTimeout(() => {
setIsReady(true);
setIsUpdate(false);
}, 2000);
}
}, [isUpdate]);

return (
<WalletUpdate
isOpen={boolean("Is Open", true)}
isUpdate={isUpdate}
isReady={isReady}
onClose={() => alert("closed")}
onCancel={() => alert("cancelled")}
onUpdate={() => setIsUpdate(true)}
/>
);
};
export const Default = () => (
<WalletUpdate
isOpen={boolean("Is Open", true)}
onClose={() => alert("closed")}
onCancel={() => alert("cancelled")}
/>
);
85 changes: 39 additions & 46 deletions src/domains/wallet/components/WalletUpdate/WalletUpdate.test.tsx
@@ -1,73 +1,66 @@
import { translations as COMMON } from "app/i18n/common/i18n";
/* eslint-disable @typescript-eslint/require-await */
import { act } from "@testing-library/react-hooks";
import React from "react";
import { fireEvent, render } from "testing-library";
import { fireEvent, render, RenderResult, waitFor } from "testing-library";

import { translations as WALLETS } from "../../i18n";
import { WalletUpdate } from "./WalletUpdate";
import { FirstStep, SecondStep, ThirdStep, WalletUpdate } from "./WalletUpdate";

describe("WalletUpdate", () => {
it("should not render if not open", () => {
const { asFragment, getByTestId } = render(<WalletUpdate isOpen={false} onUpdate={() => void 0} />);
const { asFragment, getByTestId } = render(<WalletUpdate isOpen={false} />);

expect(() => getByTestId("modal__inner")).toThrow(/Unable to find an element by/);
expect(asFragment()).toMatchSnapshot();
});

it("should render a modal", () => {
const { asFragment, getByTestId } = render(<WalletUpdate isOpen={true} onUpdate={() => void 0} />);
it("should render 1st step", () => {
const { asFragment, getByTestId } = render(<FirstStep />);

expect(getByTestId("modal__inner")).toHaveTextContent(WALLETS.MODAL_WALLET_UPDATE.DESCRIPTION_1);
expect(getByTestId("WalletUpdate__first-step")).toBeTruthy();
expect(asFragment()).toMatchSnapshot();
});

it("should handle update action", () => {
const handleUpdate = jest.fn();
it("should render 2st step", () => {
const { asFragment, getByTestId } = render(<SecondStep />);

const { getByTestId } = render(<WalletUpdate isOpen={true} onUpdate={handleUpdate} />);

fireEvent.click(getByTestId("wallet-update__update-button"));
expect(handleUpdate).toHaveBeenCalled();
expect(getByTestId("WalletUpdate__second-step")).toBeTruthy();
expect(asFragment()).toMatchSnapshot();
});

it("should handle cancel action", () => {
const handleCancel = jest.fn();

const { getByTestId } = render(<WalletUpdate isOpen={true} onUpdate={() => void 0} onCancel={handleCancel} />);
it("should render 3st step", () => {
const { asFragment, getByTestId } = render(<ThirdStep />);

fireEvent.click(getByTestId("wallet-update__cancel-button"));
expect(handleCancel).toHaveBeenCalled();
expect(getByTestId("WalletUpdate__third-step")).toBeTruthy();
expect(asFragment()).toMatchSnapshot();
});

it("should render download step", () => {
const { getByTestId } = render(<WalletUpdate isOpen={true} isUpdate={true} onUpdate={() => void 0} />);
it("should render", async () => {
let rendered: RenderResult;

expect(getByTestId("modal__inner")).toHaveTextContent(COMMON.DOWNLOADED);
});
await act(async () => {
rendered = render(<WalletUpdate isOpen={true} />);
await waitFor(() => expect(rendered.getByTestId("WalletUpdate__first-step")).toBeTruthy());
});

it("should handle install action", () => {
const handleInstall = jest.fn();

const { getByTestId } = render(
<WalletUpdate
isOpen={true}
isUpdate={false}
isReady={true}
onUpdate={() => void 0}
onInstall={handleInstall}
/>,
);

fireEvent.click(getByTestId("wallet-update__install-button"));
expect(getByTestId("modal__inner")).toHaveTextContent(WALLETS.MODAL_WALLET_UPDATE.DESCRIPTION_2);
expect(handleInstall).toHaveBeenCalled();
});
const { asFragment, getByTestId } = rendered!;

expect(asFragment()).toMatchSnapshot();

await act(async () => {
// Navigation between steps
await fireEvent.click(getByTestId("WalletUpdate__update-button"));
expect(getByTestId("WalletUpdate__second-step")).toBeTruthy();

it("should handle close action", () => {
const handleClose = jest.fn();
// Back
await fireEvent.click(getByTestId("WalletUpdate__back-button"));
expect(getByTestId("WalletUpdate__first-step")).toBeTruthy();

const { getByTestId } = render(<WalletUpdate isOpen={true} onUpdate={() => void 0} onClose={handleClose} />);
// Navigation between steps
await fireEvent.click(getByTestId("WalletUpdate__update-button"));
expect(getByTestId("WalletUpdate__second-step")).toBeTruthy();

fireEvent.click(getByTestId("modal__close-btn"));
expect(handleClose).toHaveBeenCalled();
await fireEvent.click(getByTestId("WalletUpdate__continue-button"));
expect(getByTestId("WalletUpdate__third-step")).toBeTruthy();
});
});
});
165 changes: 101 additions & 64 deletions src/domains/wallet/components/WalletUpdate/WalletUpdate.tsx
Expand Up @@ -2,100 +2,137 @@ import { images } from "app/assets/images";
import { Button } from "app/components/Button";
import { CircularProgressBar } from "app/components/CircularProgressBar";
import { Modal } from "app/components/Modal";
import React from "react";
import { TabPanel, Tabs } from "app/components/Tabs";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";

type WalletUpdateProps = {
isOpen: boolean;
isUpdate: boolean;
isReady: boolean;
onClose?: any;
onCancel?: any;
onUpdate: any;
onInstall?: any;
};

const { WalletUpdateBanner, WalletUpdateReadyBanner } = images.wallet.components.walletUpdate;

export const WalletUpdate = ({
isOpen,
isUpdate,
isReady,
onClose,
onCancel,
onUpdate,
onInstall,
}: WalletUpdateProps) => {
export const FirstStep = () => {
const { t } = useTranslation();

return (
<section data-testid="WalletUpdate__first-step">
<div className="mb-8 text-center">
<p className="text-sm text-theme-neutral-dark md:text-base">
{t("WALLETS.MODAL_WALLET_UPDATE.DESCRIPTION_1")}
</p>
</div>
</section>
);
};

export const SecondStep = () => {
const { t } = useTranslation();

return (
<section data-testid="WalletUpdate__second-step">
{/* TODO: Remove the class name `mb-8` in the functional code */}
<div className="flex w-2/5 mx-auto mb-8">
<div className="flex-1">
<p className="text-sm font-semibold text-theme-neutral-light">{t("COMMON.DOWNLOADED")}</p>
<p className="text-sm font-bold text-theme-neutral-dark">154 KB / 154 KB</p>
</div>
<div className="flex-1">
<div className="flex justify-center">
<CircularProgressBar value={78} size={50} strokeWidth={5} fontSize={0.8} />
</div>
</div>
</div>
</section>
);
};

export const ThirdStep = () => {
const { t } = useTranslation();

return (
<section data-testid="WalletUpdate__third-step">
<div className="mb-6 text-center">
<p className="text-sm text-theme-neutral-dark md:text-base">
{t("WALLETS.MODAL_WALLET_UPDATE.DESCRIPTION_2")}
</p>
</div>
</section>
);
};

export const WalletUpdate = ({ isOpen, onClose, onCancel }: WalletUpdateProps) => {
const { t } = useTranslation();
const [activeStep, setActiveStep] = useState(1);

const handleBack = () => {
setActiveStep(activeStep - 1);
};

const handleNext = () => {
setActiveStep(activeStep + 1);
};

return (
<Modal
title={t("WALLETS.MODAL_WALLET_UPDATE.TITLE", { version: "3.0.7" })}
image={isReady ? <WalletUpdateReadyBanner className="my-8" /> : <WalletUpdateBanner className="my-8" />}
image={
activeStep < 3 ? <WalletUpdateBanner className="my-8" /> : <WalletUpdateReadyBanner className="my-8" />
}
isOpen={isOpen}
onClose={onClose}
>
<div className="container">
{!isUpdate && !isReady ? (
<>
<div className="mb-8 text-center">
<p className="text-sm text-theme-neutral-dark md:text-base">
{t("WALLETS.MODAL_WALLET_UPDATE.DESCRIPTION_1")}
</p>
</div>
<div className="flex flex-col justify-center space-x-0 sm:flex-row sm:space-x-3">
<Button onClick={onUpdate} data-testid="wallet-update__update-button">
{t("COMMON.UPDATE_NOW")}
</Button>
<Tabs activeId={activeStep}>
<TabPanel tabId={1}>
<FirstStep />
</TabPanel>
<TabPanel tabId={2}>
<SecondStep />
</TabPanel>
<TabPanel tabId={3}>
<ThirdStep />
</TabPanel>

<div className="flex flex-col justify-center space-x-0 sm:flex-row sm:space-x-3">
{activeStep === 1 && (
<>
<Button
variant="plain"
className="mt-2 sm:mt-0"
onClick={onCancel}
data-testid="wallet-update__cancel-button"
data-testid="WalletUpdate__cancel-button"
>
{t("COMMON.UPDATE_LATER")}
</Button>
</div>
</>
) : (
!isReady && (
<div className="flex w-2/5 mx-auto">
<div className="flex-1">
<p className="text-sm font-semibold text-theme-neutral-light">
{t("COMMON.DOWNLOADED")}
</p>
<p className="text-sm font-bold text-theme-neutral-dark">154 KB / 154 KB</p>
</div>
<div className="flex-1">
<div className="flex justify-center">
<CircularProgressBar value={78} size={50} strokeWidth={5} fontSize={0.8} />
</div>
</div>
</div>
)
)}

{isReady && (
<>
<div className="mb-6 text-center">
<p className="text-sm text-theme-neutral-dark md:text-base">
{t("WALLETS.MODAL_WALLET_UPDATE.DESCRIPTION_2")}
</p>
</div>
<div className="flex justify-center">
<Button onClick={onInstall} data-testid="wallet-update__install-button">
{t("COMMON.INSTALL")}
<Button onClick={handleNext} data-testid="WalletUpdate__update-button">
{t("COMMON.UPDATE_NOW")}
</Button>
</div>
</>
)}
</div>
</>
)}

{/* TODO: Remove these buttons from the second step in the functional code */}
{activeStep === 2 && (
<>
<Button variant="plain" onClick={handleBack} data-testid="WalletUpdate__back-button">
{t("COMMON.BACK")}
</Button>
<Button onClick={handleNext} data-testid="WalletUpdate__continue-button">
{t("COMMON.CONTINUE")}
</Button>
</>
)}

{activeStep === 3 && (
<Button data-testid="WalletUpdate__install-button">{t("COMMON.INSTALL")}</Button>
)}
</div>
</Tabs>
</Modal>
);
};

WalletUpdate.defaultProps = {
isOpen: false,
isUpdate: false,
isReady: false,
};