From 57eb6c213d1328536c2cb2c309f84b446ccde8fd Mon Sep 17 00:00:00 2001 From: Sergey Kintsel Date: Mon, 12 Aug 2024 14:05:17 +0100 Subject: [PATCH] Add welcome view --- apps/web/src/App.tsx | 25 -- apps/web/src/App/App.test.tsx | 29 +++ apps/web/src/App/App.tsx | 17 ++ apps/web/src/App/index.ts | 1 + apps/web/src/Layout.tsx | 1 + apps/web/src/assets/icons/index.ts | 11 +- apps/web/src/assets/icons/tezos-logo.svg | 6 + .../AccountSelectorModal.tsx | 4 +- .../AccountTile/AccountTileIcon.tsx | 16 +- ...nboardingModal.tsx => OnboardingModal.tsx} | 9 +- .../components/Onboarding/OnboardingStep.tsx | 2 - .../components/Onboarding/eula/Eula.test.tsx | 36 --- .../src/components/Onboarding/eula/Eula.tsx | 57 ----- apps/web/src/styles/theme.ts | 6 +- apps/web/src/views/Welcome/Welcome.tsx | 230 ++++++++++++++++++ apps/web/src/views/Welcome/index.ts | 1 + 16 files changed, 312 insertions(+), 139 deletions(-) delete mode 100644 apps/web/src/App.tsx create mode 100644 apps/web/src/App/App.test.tsx create mode 100644 apps/web/src/App/App.tsx create mode 100644 apps/web/src/App/index.ts create mode 100644 apps/web/src/assets/icons/tezos-logo.svg rename apps/web/src/components/Onboarding/{useOnboardingModal.tsx => OnboardingModal.tsx} (92%) delete mode 100644 apps/web/src/components/Onboarding/eula/Eula.test.tsx delete mode 100644 apps/web/src/components/Onboarding/eula/Eula.tsx create mode 100644 apps/web/src/views/Welcome/Welcome.tsx create mode 100644 apps/web/src/views/Welcome/index.ts diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx deleted file mode 100644 index 928f5ef255..0000000000 --- a/apps/web/src/App.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useCurrentAccount } from "@umami/state"; -import { useEffect } from "react"; - -import { BeaconProvider } from "./components/beacon"; -import { useOnboardingModal } from "./components/Onboarding/useOnboardingModal"; -import { Layout } from "./Layout"; - -export const App = () => { - const currentAccount = useCurrentAccount(); - const { onOpen: openOnboardingModal, modalElement } = useOnboardingModal(); - - useEffect(() => { - if (!currentAccount) { - openOnboardingModal(); - } - }, [currentAccount, openOnboardingModal]); - - return currentAccount ? ( - - - - ) : ( - modalElement - ); -}; diff --git a/apps/web/src/App/App.test.tsx b/apps/web/src/App/App.test.tsx new file mode 100644 index 0000000000..bf5a9e7b67 --- /dev/null +++ b/apps/web/src/App/App.test.tsx @@ -0,0 +1,29 @@ +import { mockImplicitAccount } from "@umami/core"; +import { addTestAccount, makeStore } from "@umami/state"; + +import { App } from "./App"; +import { render, screen } from "../testUtils"; + +jest.mock("@chakra-ui/react", () => ({ + ...jest.requireActual("@chakra-ui/react"), + useBreakpointValue: jest.fn(map => map["lg"]), +})); + +describe("", () => { + it("renders welcome screen for a new user", () => { + render(); + + expect(screen.getByTestId("welcome-view")).toBeVisible(); + expect(screen.queryByTestId("signed-in-layout")).not.toBeInTheDocument(); + }); + + it("renders signed-in layout for an existing user", () => { + const store = makeStore(); + addTestAccount(store, mockImplicitAccount(0)); + + render(, { store }); + + expect(screen.getByTestId("signed-in-layout")).toBeVisible(); + expect(screen.queryByTestId("welcome-view")).not.toBeInTheDocument(); + }); +}); diff --git a/apps/web/src/App/App.tsx b/apps/web/src/App/App.tsx new file mode 100644 index 0000000000..b1c9109e5c --- /dev/null +++ b/apps/web/src/App/App.tsx @@ -0,0 +1,17 @@ +import { useCurrentAccount } from "@umami/state"; + +import { BeaconProvider } from "../components/beacon"; +import { Layout } from "../Layout"; +import { Welcome } from "../views/Welcome"; + +export const App = () => { + const currentAccount = useCurrentAccount(); + + return currentAccount ? ( + + + + ) : ( + + ); +}; diff --git a/apps/web/src/App/index.ts b/apps/web/src/App/index.ts new file mode 100644 index 0000000000..c854302665 --- /dev/null +++ b/apps/web/src/App/index.ts @@ -0,0 +1 @@ +export * from "./App"; diff --git a/apps/web/src/Layout.tsx b/apps/web/src/Layout.tsx index 96166fddd8..2892324237 100644 --- a/apps/web/src/Layout.tsx +++ b/apps/web/src/Layout.tsx @@ -22,6 +22,7 @@ export const Layout = () => { }} height={{ lg: "100vh", base: "100dvh" }} padding={{ lg: "20px 46px 0", base: "54px 0 0" }} + data-testid="signed-in-layout" > + + diff --git a/apps/web/src/components/AccountSelectorModal/AccountSelectorModal.tsx b/apps/web/src/components/AccountSelectorModal/AccountSelectorModal.tsx index cdd1af631e..8f85eb2749 100644 --- a/apps/web/src/components/AccountSelectorModal/AccountSelectorModal.tsx +++ b/apps/web/src/components/AccountSelectorModal/AccountSelectorModal.tsx @@ -22,13 +22,13 @@ import { ThreeDotsIcon } from "../../assets/icons"; import { useColor } from "../../styles/useColor"; import { AccountTile } from "../AccountTile"; import { ModalCloseButton } from "../CloseButton"; -import { useOnboardingModal } from "../Onboarding/useOnboardingModal"; export const AccountSelectorModal = () => { const accounts = useImplicitAccounts(); const color = useColor(); const getBalance = useGetAccountBalance(); - const { onOpen: openOnboardingModal, modalElement } = useOnboardingModal(); + // TODO: add ConnectOptions onboarding modal + const { onOpen: openOnboardingModal, modalElement } = { modalElement: null, onOpen: () => {} }; const { onClose } = useDynamicModalContext(); const dispatch = useDispatch(); diff --git a/apps/web/src/components/AccountTile/AccountTileIcon.tsx b/apps/web/src/components/AccountTile/AccountTileIcon.tsx index 375ec9b084..f2eab1c5a3 100644 --- a/apps/web/src/components/AccountTile/AccountTileIcon.tsx +++ b/apps/web/src/components/AccountTile/AccountTileIcon.tsx @@ -28,15 +28,15 @@ export const AccountTileIcon = ({ account }: { account: ImplicitAccount }) => { case "social": { switch (account.idp) { case "facebook": - return ; + return ; case "google": - return ; + return ; case "twitter": - return ; + return ; case "email": return ; case "reddit": - return ; + return ; } } // eslint-disable-next-line no-fallthrough @@ -44,3 +44,11 @@ export const AccountTileIcon = ({ account }: { account: ImplicitAccount }) => { return ; } }; + +export const FacebookAccountIcon = () => ; + +export const GoogleAccountIcon = () => ; + +export const TwitterAccountIcon = () => ; + +export const RedditAccountIcon = () => ; diff --git a/apps/web/src/components/Onboarding/useOnboardingModal.tsx b/apps/web/src/components/Onboarding/OnboardingModal.tsx similarity index 92% rename from apps/web/src/components/Onboarding/useOnboardingModal.tsx rename to apps/web/src/components/Onboarding/OnboardingModal.tsx index d8463449af..e03f1b2b63 100644 --- a/apps/web/src/components/Onboarding/useOnboardingModal.tsx +++ b/apps/web/src/components/Onboarding/OnboardingModal.tsx @@ -11,7 +11,6 @@ import { useImplicitAccounts } from "@umami/state"; import { ConnectOptions } from "./connectOptions/ConnectOptions"; import { ConnectOrCreate } from "./connectOrCreate/ConnectOrCreate"; import { DerivationPath } from "./derivationPath/DerivationPath"; -import { Eula } from "./eula/Eula"; import { FakeAccount } from "./FakeAccount"; import { MasterPassword } from "./masterPassword/MasterPassword"; import { ModalBackButton } from "./ModalBackButton"; @@ -26,12 +25,10 @@ import { ShowSeedphrase } from "./showSeedphrase/ShowSeedphrase"; import { VerifySeedphrase } from "./verifySeedphrase/VerifySeedphrase"; // TODO: rebuild it for the web. -export const useOnboardingModal = (onModalClose?: () => void) => { +export const OnboardingModal = (onModalClose?: () => void) => { const { isOpen, onOpen, onClose } = useDisclosure(); const hasAccounts = useImplicitAccounts().length !== 0; - const history = useStepHistory({ - type: hasAccounts ? "connectOrCreate" : "eula", - }); + const history = useStepHistory({ type: "connectOrCreate" }); const { currentStep, goToStep } = history; const closeModal = () => { @@ -42,8 +39,6 @@ export const useOnboardingModal = (onModalClose?: () => void) => { const getStepPage = () => { switch (currentStep.type) { - case "eula": - return ; case "connectOrCreate": return ; case "connectOptions": diff --git a/apps/web/src/components/Onboarding/OnboardingStep.tsx b/apps/web/src/components/Onboarding/OnboardingStep.tsx index b6f4392d5c..f0e90d9029 100644 --- a/apps/web/src/components/Onboarding/OnboardingStep.tsx +++ b/apps/web/src/components/Onboarding/OnboardingStep.tsx @@ -1,5 +1,4 @@ export type OnboardingStep = - | EulaStep | ConnectOrCreateStep | NoticeStep | ConnectOptionsStep @@ -14,7 +13,6 @@ export type OnboardingStep = | MasterPasswordStep | FakeAccountStep; -type EulaStep = { type: "eula" }; type ConnectOrCreateStep = { type: "connectOrCreate" }; type NoticeStep = { type: "notice" }; type ConnectOptionsStep = { type: "connectOptions" }; diff --git a/apps/web/src/components/Onboarding/eula/Eula.test.tsx b/apps/web/src/components/Onboarding/eula/Eula.test.tsx deleted file mode 100644 index 44195d4a28..0000000000 --- a/apps/web/src/components/Onboarding/eula/Eula.test.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Eula } from "./Eula"; -import { act, render, screen, userEvent } from "../../../testUtils"; - -const setStepMock = jest.fn(); - -const fixture = () => ; - -describe("", () => { - describe("When not accepted", () => { - test("button is disabled", () => { - render(fixture()); - - expect(screen.getByRole("checkbox")).not.toBeChecked(); - expect(screen.getByRole("button", { name: "Continue" })).toBeDisabled(); - }); - }); - - describe("When accepted", () => { - test("button is enabled", async () => { - const user = userEvent.setup(); - render(fixture()); - - const checkbox = screen.getByRole("checkbox"); - expect(checkbox).not.toBeChecked(); - await act(() => user.click(checkbox)); - - expect(checkbox).toBeChecked(); - - const confirmBtn = screen.getByRole("button", { name: "Continue" }); - expect(confirmBtn).toBeEnabled(); - - await act(() => user.click(confirmBtn)); - expect(setStepMock).toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/apps/web/src/components/Onboarding/eula/Eula.tsx b/apps/web/src/components/Onboarding/eula/Eula.tsx deleted file mode 100644 index b1533122cf..0000000000 --- a/apps/web/src/components/Onboarding/eula/Eula.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { Box, Button, Checkbox, Link } from "@chakra-ui/react"; -import { useState } from "react"; - -import { StubIcon as DocumentIcon } from "../../../assets/icons"; -import { useColor } from "../../../styles/useColor"; -import { ModalContentWrapper } from "../ModalContentWrapper"; -import { type OnboardingStep } from "../OnboardingStep"; - -export const Eula = ({ goToStep }: { goToStep: (step: OnboardingStep) => void }) => { - const color = useColor(); - const [isChecked, setIsChecked] = useState(false); - return ( - } title="Accept to Continue"> - <> - setIsChecked(e.target.checked)} - > - - I confirm that I have read and agreed with the{" "} - - Terms of Service - {" "} - and the{" "} - - Privacy Policy - - - - - - - ); -}; diff --git a/apps/web/src/styles/theme.ts b/apps/web/src/styles/theme.ts index 9238191b80..94567aff67 100644 --- a/apps/web/src/styles/theme.ts +++ b/apps/web/src/styles/theme.ts @@ -4,7 +4,7 @@ import { type StyleFunctionProps, mode } from "@chakra-ui/theme-tools"; import { dark, light } from "./colors"; const config = { - initialColorMode: "light", + initialColorMode: "dark", useSystemColorMode: false, }; @@ -93,6 +93,10 @@ const theme = extendTheme({ fontSize: "24px", lineHeight: "32px", }, + "3xl": { + fontSize: "30px", + lineHeight: "36px", + }, }, }, Card: { diff --git a/apps/web/src/views/Welcome/Welcome.tsx b/apps/web/src/views/Welcome/Welcome.tsx new file mode 100644 index 0000000000..cb3b628d10 --- /dev/null +++ b/apps/web/src/views/Welcome/Welcome.tsx @@ -0,0 +1,230 @@ +import { + Button, + Center, + Divider, + Flex, + type FlexProps, + Grid, + GridItem, + Heading, + Icon, + IconButton, + type IconButtonProps, + Link, + type LinkProps, + Text, + type TextProps, + useBreakpointValue, +} from "@chakra-ui/react"; + +import { LogoLightIcon, TezosLogoIcon } from "../../assets/icons"; +import { + FacebookAccountIcon, + GoogleAccountIcon, + RedditAccountIcon, + TwitterAccountIcon, +} from "../../components/AccountTile/AccountTileIcon"; +import { useColor } from "../../styles/useColor"; + +export const Welcome = () => { + const color = useColor(); + const isMobile = useBreakpointValue({ base: true, lg: false }); + + return ( + +
+ + + Welcome to Umami + + + A powerful Tezos wallet + +
+ +
+
+ + Continue with: + + +
+ + } /> + } /> + } /> + } /> + + +
+ + + or + + +
+ + + + + + + + By proceeding, you agree to Umami's{" "} + + Terms of Use + + + + {isMobile && ( + <> + + + + + + + + + + + + + + + + )} +
+
+
+ + {!isMobile && ( + <> + + + + + + + + + + + + + + + + + + + )} +
+ ); +}; + +const SocialLoginButton = (props: IconButtonProps) => { + const color = useColor(); + + return ( + + ); +}; + +const TermsLink = (props: LinkProps) => ( + + Terms + +); + +const PrivacyLink = (props: LinkProps) => ( + + Privacy + +); + +const SupportLink = (props: LinkProps) => ( + + Support + +); + +const CommunityLink = (props: LinkProps) => ( + + Community + +); + +const ArticlesLink = (props: LinkProps) => ( + + Articles + +); + +const Logo = (props: FlexProps) => ( +
+ + Powered by + + +
+); + +const Copyright = (props: TextProps) => © 2024 Umami; diff --git a/apps/web/src/views/Welcome/index.ts b/apps/web/src/views/Welcome/index.ts new file mode 100644 index 0000000000..340faae601 --- /dev/null +++ b/apps/web/src/views/Welcome/index.ts @@ -0,0 +1 @@ +export * from "./Welcome";