From d9daf9f58396b8bfe51970ee70ffe16c1ebaeab5 Mon Sep 17 00:00:00 2001 From: John Huang Date: Wed, 21 Feb 2024 12:52:11 -0800 Subject: [PATCH] Feature/mob 193 install app dlg (#308) * getOS and get meta from header * Clean up * Update localization * Comments * Rename URL variable * MOB-193 PR * PR --- src/constants/dialogs.ts | 1 + src/layout/DialogManager.tsx | 2 + src/views/dialogs/MobileDownloadDialog.tsx | 140 +++++++++++++++++++++ src/views/menus/AccountMenu.tsx | 13 ++ 4 files changed, 156 insertions(+) create mode 100644 src/views/dialogs/MobileDownloadDialog.tsx diff --git a/src/constants/dialogs.ts b/src/constants/dialogs.ts index 6ed34ec..c624182 100644 --- a/src/constants/dialogs.ts +++ b/src/constants/dialogs.ts @@ -11,6 +11,7 @@ export enum DialogTypes { ExternalNavKeplr = 'ExternalNavKeplr', MnemonicExport = 'MnemonicExport', MobileSignIn = 'MobileSignIn', + MobileDownload = 'MobileDownload', Onboarding = 'Onboarding', OrderDetails = 'OrderDetails', Preferences = 'Preferences', diff --git a/src/layout/DialogManager.tsx b/src/layout/DialogManager.tsx index 4c5ec7e..cef213e 100644 --- a/src/layout/DialogManager.tsx +++ b/src/layout/DialogManager.tsx @@ -31,6 +31,7 @@ import { FillDetailsDialog } from '@/views/dialogs/DetailsDialog/FillDetailsDial import { NewMarketMessageDetailsDialog } from '@/views/dialogs/NewMarketMessageDetailsDialog'; import { NewMarketAgreementDialog } from '@/views/dialogs/NewMarketAgreementDialog'; import { ExternalNavStrideDialog } from '@/views/dialogs/ExternalNavStrideDialog'; +import { MobileDownloadDialog } from '@/views/dialogs/MobileDownloadDialog'; export const DialogManager = () => { const dispatch = useDispatch(); @@ -63,6 +64,7 @@ export const DialogManager = () => { [DialogTypes.ExternalNavStride]: , [DialogTypes.MnemonicExport]: , [DialogTypes.MobileSignIn]: , + [DialogTypes.MobileDownload]: , [DialogTypes.Onboarding]: , [DialogTypes.OrderDetails]: , [DialogTypes.Preferences]: , diff --git a/src/views/dialogs/MobileDownloadDialog.tsx b/src/views/dialogs/MobileDownloadDialog.tsx new file mode 100644 index 0000000..6a4aff1 --- /dev/null +++ b/src/views/dialogs/MobileDownloadDialog.tsx @@ -0,0 +1,140 @@ +import styled, { AnyStyledComponent, css } from 'styled-components'; + +import { layoutMixins } from '@/styles/layoutMixins'; + +import { Dialog } from '@/components/Dialog'; +import { QrCode } from '@/components/QrCode'; +import { useStringGetter } from '@/hooks'; +import { STRING_KEYS } from '@/constants/localization'; + +type ElementProps = { + setIsOpen: (open: boolean) => void; +}; + +/* + When/if deployer deploys the web app with smartbanner, "smartbanner:button-url-apple" and/or + "smartbanner:button-url-google" are set. + This implementation assumes "smartbanner:button-url-apple" and "smartbanner:button-url-google" + are set to the same value with onelink or other redirect URL. + Since there is no way for the desktop web app to know what mobile device the user is using, + we should give a onelink URL which redirects to either iOS or Android app store depending on + the mobile device used to scan the link. +*/ + +// for testing only +// export const mobileAppUrl = "http://example.com"; + +let mobileAppUrl: string | undefined | null = undefined; + +export const getMobileAppUrl = () => { + if (!mobileAppUrl) { + mobileAppUrl = + // for testing to verify is retrieved by name, QR code should show "@dYdX" as value + // document.querySelector('meta[name="twitter:creator"]')?.getAttribute('content') ?? + document.querySelector('meta[name="smartbanner:button-url-apple"]')?.getAttribute('content') ?? + document.querySelector('meta[name="smartbanner:button-url-google"]')?.getAttribute('content'); + } + return mobileAppUrl; +} + +const MobileQrCode = ({ + url, +}: { + url: string; +}) => { + return ( + + + + ); +}; + +/* +MobileDownloadDialog should only been shown on desktop when mobileAppUrl has value. That's controlled by AccountMenu.tsx. +*/ + +export const MobileDownloadDialog = ({ setIsOpen }: ElementProps) => { + const stringGetter = useStringGetter(); + const content = ( + + ); + + return ( + + {content} + + ); +}; + +const Styled: Record = {}; + +Styled.Content = styled.div` + ${layoutMixins.column} + gap: 1rem; + + strong { + font-weight: 900; + color: var(--color-text-2); + } + + footer { + ${layoutMixins.row} + justify-content: space-between; + + svg { + width: auto; + } + } +`; + +Styled.WaitingSpan = styled.span` + strong { + color: var(--color-warning); + } +`; + +Styled.QrCodeContainer = styled.figure<{ isShowing: boolean }>` + ${layoutMixins.stack} + + overflow: hidden; + border-radius: 0.75em; + + cursor: pointer; + + transition: 0.2s; + + &:hover { + filter: brightness(var(--hover-filter-base)); + } + + > * { + position: relative; + transition: 0.16s; + } + + > :first-child { + pointer-events: none; + + ${({ isShowing }) => + !isShowing && + css` + filter: blur(1rem) brightness(1.4); + will-change: filter; + `} + } + + > span { + place-self: center; + + font-size: 1.4em; + color: var(--color-text-2); + + ${({ isShowing }) => + isShowing && + css` + opacity: 0; + `} + } +`; diff --git a/src/views/menus/AccountMenu.tsx b/src/views/menus/AccountMenu.tsx index f40b2b4..5dd5732 100644 --- a/src/views/menus/AccountMenu.tsx +++ b/src/views/menus/AccountMenu.tsx @@ -40,6 +40,7 @@ import { getAppTheme } from '@/state/configsSelectors'; import { isTruthy } from '@/lib/isTruthy'; import { truncateAddress } from '@/lib/wallet'; import { MustBigNumber } from '@/lib/numbers'; +import { getMobileAppUrl } from '../dialogs/MobileDownloadDialog'; export const AccountMenu = () => { const stringGetter = useStringGetter(); @@ -189,6 +190,18 @@ export const AccountMenu = () => { label: stringGetter({ key: STRING_KEYS.DISPLAY_SETTINGS }), onSelect: () => dispatch(openDialog({ type: DialogTypes.DisplaySettings })), }, + ...(getMobileAppUrl() + ? [ + { + value: 'MobileDownload', + icon: , + label: stringGetter({ key: STRING_KEYS.DOWNLOAD_MOBILE_APP }), + onSelect: () => { + dispatch(openDialog({ type: DialogTypes.MobileDownload })); + }, + }, + ] + : []), ...(onboardingState === OnboardingState.AccountConnected && hdKey ? [ {