diff --git a/package-lock.json b/package-lock.json index d073e83cd4..4b7758cdd6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "ambire-wallet", - "version": "0.7.7", + "version": "0.7.8", "hasInstallScript": true, "dependencies": { "@0x/subproviders": "^6.6.5", @@ -31,7 +31,7 @@ "@web3-react/abstract-connector": "^6.0.7", "@web3-react/types": "^6.0.7", "adex-protocol-eth": "git+https://git@github.com/AmbireTech/adex-protocol-eth.git#2606263234a7e01ece1af9826e6084fd800dae8f", - "ambire-common": "npm:@ambire/common@1.0.17", + "ambire-common": "npm:@ambire/common@1.0.19", "bip44-constants": "^128.0.0", "blockies-ts": "^1.0.0", "chart.js": "^3.9.1", @@ -13586,9 +13586,9 @@ }, "node_modules/ambire-common": { "name": "@ambire/common", - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/@ambire/common/-/common-1.0.17.tgz", - "integrity": "sha512-3gZylNEx6oZmFfCLB7KfnYmnLtaKlpXVO63VklBwg0jiJTmF7n0L9T4ZaATcXnofjV1NTCeIVEMCMUL9NtXNaQ==", + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/@ambire/common/-/common-1.0.19.tgz", + "integrity": "sha512-jqcRtzS3VqaLS+Vdd8yywHd8cbDZ3pTWvn+m+QQh6NjU+GZwDOfuseEY5/iz4k3MbXgJw2Reos/z6jW9hMv/EA==", "peerDependencies": { "@ambire/signature-validator": "^1.0.3", "@ensdomains/eth-ens-namehash": "^2.0.15", @@ -67849,9 +67849,9 @@ "integrity": "sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==" }, "ambire-common": { - "version": "npm:@ambire/common@1.0.17", - "resolved": "https://registry.npmjs.org/@ambire/common/-/common-1.0.17.tgz", - "integrity": "sha512-3gZylNEx6oZmFfCLB7KfnYmnLtaKlpXVO63VklBwg0jiJTmF7n0L9T4ZaATcXnofjV1NTCeIVEMCMUL9NtXNaQ==", + "version": "npm:@ambire/common@1.0.19", + "resolved": "https://registry.npmjs.org/@ambire/common/-/common-1.0.19.tgz", + "integrity": "sha512-jqcRtzS3VqaLS+Vdd8yywHd8cbDZ3pTWvn+m+QQh6NjU+GZwDOfuseEY5/iz4k3MbXgJw2Reos/z6jW9hMv/EA==", "requires": {} }, "amdefine": { diff --git a/package.json b/package.json index 5acbd1e5f7..a659df43db 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "@web3-react/abstract-connector": "^6.0.7", "@web3-react/types": "^6.0.7", "adex-protocol-eth": "git+https://git@github.com/AmbireTech/adex-protocol-eth.git#2606263234a7e01ece1af9826e6084fd800dae8f", - "ambire-common": "npm:@ambire/common@1.0.17", + "ambire-common": "npm:@ambire/common@1.0.19", "bip44-constants": "^128.0.0", "blockies-ts": "^1.0.0", "chart.js": "^3.9.1", diff --git a/src/components/Modals/ExtensionInviteCodeModal/ExtensionInviteCodeModal.js b/src/components/Modals/ExtensionInviteCodeModal/ExtensionInviteCodeModal.js new file mode 100644 index 0000000000..8e05f558e6 --- /dev/null +++ b/src/components/Modals/ExtensionInviteCodeModal/ExtensionInviteCodeModal.js @@ -0,0 +1,114 @@ +import { useCallback, useEffect, useState } from 'react' +import cn from 'classnames' + +import { useModals } from 'hooks' + +import { ReactComponent as AmbireLogo } from 'resources/logo-new.svg' +import { ReactComponent as CopyIcon } from 'resources/icons/copy-new.svg' +import { ReactComponent as CloseIcon } from 'resources/icons/close.svg' +import { ReactComponent as ChromeWebStore } from 'resources/chrome-web-store.svg' + +import { useToasts } from 'hooks/toasts' +import styles from './ExtensionInviteCodeModal.module.scss' + +const CAN_CLOSE_AFTER_MS = 5400 + +const ExtensionInviteCodeModal = ({ inviteCode, waitForClose = true }) => { + const { hideModal } = useModals() + const { addToast } = useToasts() + const [remainingTime, setRemainingTime] = useState(CAN_CLOSE_AFTER_MS) + const [canClose, setCanClose] = useState(!waitForClose) + + const handleCloseModal = useCallback(() => { + if (!canClose) return + + hideModal() + }, [canClose, hideModal]) + + useEffect(() => { + const startingTime = Date.now() + + const interval = setInterval(() => { + const elapsedTime = Date.now() - startingTime + const newRemainingTime = CAN_CLOSE_AFTER_MS - elapsedTime + setRemainingTime(newRemainingTime) + + if (newRemainingTime <= 0) { + setCanClose(true) + clearInterval(interval) + } + }, 500) + + return () => { + clearInterval(interval) + } + }, []) + + const handleCopy = useCallback(async () => { + try { + await navigator.clipboard.writeText(inviteCode) + addToast('Invite code copied to clipboard') + } catch { + addToast('Failed to copy invite code to clipboard', { error: true }) + } + }, [addToast, inviteCode]) + + return ( +
+
+
+
+ +
+ {!canClose ? ( + + {remainingTime > 500 ? Math.round(remainingTime / 1000) : 1} + + ) : ( + + )} +
+
+
+
+

Hey!

+

+ We are onboarding the existing Ambire community first to our newest product - the Ambire + browser extension. +

+

+ Claim this exclusive invitation code to get early access and start collecting XP for our + launch campaign before everyone else 🤫 +

+
+
+ Invitation code + {inviteCode} + +
+
+

+ Go to Chrome Web Store, install the extension and use the invitation code to log in. +

+ + + +
+
+
+ ) +} + +export default ExtensionInviteCodeModal diff --git a/src/components/Modals/ExtensionInviteCodeModal/ExtensionInviteCodeModal.module.scss b/src/components/Modals/ExtensionInviteCodeModal/ExtensionInviteCodeModal.module.scss new file mode 100644 index 0000000000..d4e1fc44ae --- /dev/null +++ b/src/components/Modals/ExtensionInviteCodeModal/ExtensionInviteCodeModal.module.scss @@ -0,0 +1,268 @@ +@import 'variables.scss'; + +$max-modal-height: 55.375rem; +$min-modal-height: 34.375rem; + +.wrapper { + z-index: 52; + position: relative; + max-height: $max-modal-height; + min-height: $min-modal-height; + max-width: 37.75rem; + width: 100%; + border-radius: 1.125rem; + border: 1px $c-fiord; + background: $c-ebony-clay; +} + +// Reset +.wrapper p, +.wrapper span { + margin: 0; +} + +.header { + overflow: hidden; + position: relative; + display: flex; + justify-content: center; + padding: 2rem; + background: linear-gradient(82deg, $c-electric-violet, #353d6e); + border-radius: 0.75rem 0.75rem 0 0; + + .headerPrimaryGradient { + position: absolute; + left: -20%; + top: -35%; + z-index: 2; + width: 20rem; + height: 13.75rem; + background-color: #8b3dff; + opacity: 0.66; + filter: blur(4.375rem); + } + + .headerSecondaryGradient { + position: absolute; + left: 60%; + bottom: 30%; + z-index: 2; + width: 26.25rem; + height: 18.5rem; + background-color: #56f6c1; + opacity: 0.48; + filter: blur(6.25rem); + } + + .closeWrapper { + position: absolute; + right: 1rem; + top: 1rem; + z-index: 4; + display: flex; + align-items: center; + justify-content: center; + width: 2.5rem; + height: 2.5rem; + + .remainingTime { + color: #fff; + font-size: 0.875rem; + opacity: 0.6; + user-select: none; + } + .closeIcon { + cursor: pointer; + + :global(#background) { + display: none; + } + } + + &:not(.closeIconEnabled) { + .closeIcon { + opacity: 0.4; + cursor: not-allowed; + } + } + } + + .headerLogo { + position: relative; + z-index: 3; + } +} + +.content { + display: flex; + flex-direction: column; + padding: 2rem; + gap: 2.5rem; +} + +.textWrapper { + .text { + font-size: 1.125rem; + line-height: 1.7; + margin-bottom: 1rem; + } + .text:last-child { + margin-bottom: 0; + } +} + +.codeWrapper { + display: flex; + flex-direction: column; + align-items: center; + .codeTitle { + display: block; + color: #bbbde4; + font-size: 1rem; + margin-bottom: 1rem; + } + .code { + display: block; + margin-bottom: 2rem; + border: none; + width: 18ch; + background: repeating-linear-gradient( + 90deg, + $c-scampi 0, + $c-scampi 1ch, + transparent 0, + transparent 1.5ch + ) + 0 100%/98% 1px no-repeat; + color: $c-turquoise; // font: 36px monospace; + font-size: 2.5rem; + font-family: monospace; + letter-spacing: 0.5ch; + } + .copyButton { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1.5rem; + background: rgba(235, 236, 255, 0.08); + border-radius: 1.5rem; + cursor: pointer; + + svg, + span { + color: #bbbde4; + transition: $basic-transition; + } + + svg { + width: 1.125rem; + height: 1.125rem; + } + + &:hover { + background: rgba(235, 236, 255, 0.15); + + svg, + span { + color: #fff; + } + } + } +} + +.storeWrapper { + .storeText { + font-size: 1.125rem; + margin-bottom: 2rem; + } + .storeLink { + display: flex; + justify-content: center; + align-items: center; + width: fit-content; + gap: 0.5rem; + padding: 1rem 3rem; + margin: 0 auto; + border-radius: 4rem; + border: 1px solid $c-scampi; + background: rgba(0, 0, 0, 0.3); + cursor: pointer; + + svg { + width: 9.25rem; + height: 2rem; + } + + &:hover { + background-color: #0e0e0e; + } + } +} + +@mixin SmallScreen { + .header { + padding: 1.5rem; + } + .content { + gap: 1.5rem; + } + .storeWrapper .storeText, + .textWrapper .text { + font-size: 0.875rem; + } + .storeWrapper .storeText { + margin-bottom: 1rem; + } + .codeWrapper { + .codeTitle { + font-size: 0.875rem; + margin-bottom: 0.5rem; + } + .code { + margin-bottom: 1.5rem; + } + } +} + +@media screen and (max-height: calc(#{$max-modal-height} + 100px)) { + @include SmallScreen; +} + +@include sm-breakpoint { + @include SmallScreen; + .header, + .content { + padding: 1.5rem; + } + + .codeWrapper { + .code { + font-size: 2rem; + } + } +} + +@include xs-breakpoint { + .header, + .content { + padding: 1rem; + } + + .header { + .headerLogo { + width: 3.75rem; + width: 4rem; + height: auto; + } + .closeWrapper { + top: 0.25rem; + right: 0.25rem; + } + } +} + +@media screen and (max-width: 350px) { + .codeWrapper .code { + font-size: 1.5rem; + } +} diff --git a/src/components/Modals/WalletTokenModal/WalletTokenModal.js b/src/components/Modals/WalletTokenModal/WalletTokenModal.js index c1fcdcd040..2a9b33eb81 100644 --- a/src/components/Modals/WalletTokenModal/WalletTokenModal.js +++ b/src/components/Modals/WalletTokenModal/WalletTokenModal.js @@ -77,8 +77,8 @@ const WalletTokenModal = ({ accountId, claimableWalletToken, rewards, network }) our browser extension - . Following a recent governance vote, early users $WALLET rewards are no longer available - in the Web and Mobile versions of Ambire Wallet. + . Following a recent governance vote, early users $WALLET rewards are no longer awarded in + the Web and Mobile versions of Ambire Wallet.

- ambire-logo + )}
diff --git a/src/components/Wallet/TopBar/Accounts/Accounts.js b/src/components/Wallet/TopBar/Accounts/Accounts.js index e9b5ee1efa..3468db7395 100644 --- a/src/components/Wallet/TopBar/Accounts/Accounts.js +++ b/src/components/Wallet/TopBar/Accounts/Accounts.js @@ -173,7 +173,10 @@ const Accounts = ({ )}
-
{id}
+
+
{id}
+
Ambire v1
+
{ - Twitter + X diff --git a/src/components/Wallet/TopBar/Links/Links.module.scss b/src/components/Wallet/TopBar/Links/Links.module.scss index 1cad46d354..756218a539 100644 --- a/src/components/Wallet/TopBar/Links/Links.module.scss +++ b/src/components/Wallet/TopBar/Links/Links.module.scss @@ -6,12 +6,20 @@ height: 2rem; } .item { + display: flex; + align-items: stretch; height: 3.125rem; - padding-left: 1rem; - padding-right: 1.375rem; background-color: $c-mirage; + padding: 0; + + button { + outline: none; + border: none; + padding: 0; + cursor: pointer; + } - a { + a, button { display: flex; align-items: center; gap: 0.625rem; @@ -20,6 +28,9 @@ color: $c-titan-white; white-space: nowrap; font-weight: 400; + padding-left: 1rem; + padding-right: 1.375rem; + width: 100%; .itemIcon { width: 1.875rem; diff --git a/src/components/Wallet/TopBar/Links/images/extension-invite-code.svg b/src/components/Wallet/TopBar/Links/images/extension-invite-code.svg new file mode 100644 index 0000000000..4ce9b89240 --- /dev/null +++ b/src/components/Wallet/TopBar/Links/images/extension-invite-code.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/src/components/Wallet/TopBar/Links/images/help-center.svg b/src/components/Wallet/TopBar/Links/images/help-center.svg index 9540489556..2d4534e40b 100644 --- a/src/components/Wallet/TopBar/Links/images/help-center.svg +++ b/src/components/Wallet/TopBar/Links/images/help-center.svg @@ -1,11 +1,14 @@ - - - - - - - - - - - + + + + + + \ No newline at end of file diff --git a/src/components/Wallet/TopBar/Links/images/help-with-notification.svg b/src/components/Wallet/TopBar/Links/images/help-with-notification.svg new file mode 100644 index 0000000000..8b34eb47ae --- /dev/null +++ b/src/components/Wallet/TopBar/Links/images/help-with-notification.svg @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/src/components/Wallet/TopBar/Links/images/help.svg b/src/components/Wallet/TopBar/Links/images/help.svg index bf4f72e6d6..02c20f4174 100644 --- a/src/components/Wallet/TopBar/Links/images/help.svg +++ b/src/components/Wallet/TopBar/Links/images/help.svg @@ -1,8 +1,8 @@ - - - - - - - - + + + + \ No newline at end of file diff --git a/src/components/Wallet/TopBar/Links/images/twitter.svg b/src/components/Wallet/TopBar/Links/images/twitter.svg index 3993d58293..ab44b80483 100644 --- a/src/components/Wallet/TopBar/Links/images/twitter.svg +++ b/src/components/Wallet/TopBar/Links/images/twitter.svg @@ -1,6 +1,5 @@ - - - - - - + + + \ No newline at end of file diff --git a/src/components/Wallet/TopBar/TopBar.js b/src/components/Wallet/TopBar/TopBar.js index c2724a3dd6..397a5ac5c6 100644 --- a/src/components/Wallet/TopBar/TopBar.js +++ b/src/components/Wallet/TopBar/TopBar.js @@ -165,7 +165,10 @@ const TopBar = ({ dappsCatalog={dappsCatalog} dapModeTopBar={dappModeTopBar} /> - +
diff --git a/src/components/Wallet/Transfer/Transfer.test.jsx b/src/components/Wallet/Transfer/Transfer.test.jsx index 8365a40b7f..c69c1493c3 100644 --- a/src/components/Wallet/Transfer/Transfer.test.jsx +++ b/src/components/Wallet/Transfer/Transfer.test.jsx @@ -97,7 +97,8 @@ test('can send token', async () => { addressBook={addressBook} selectedAcc={userAddress} addRequest={addRequest} - />) + /> + ) const selectAnAsset = screen.getByText('Select an asset') await user.click(selectAnAsset) const selectMatic = screen.getByText('MATIC') diff --git a/src/components/Wallet/Wallet.js b/src/components/Wallet/Wallet.js index 913c691db6..77526defc7 100644 --- a/src/components/Wallet/Wallet.js +++ b/src/components/Wallet/Wallet.js @@ -10,6 +10,7 @@ import unsupportedDApps from 'ambire-common/src/constants/unsupportedDApps' import PermissionsModal from 'components/Modals/PermissionsModal/PermissionsModal' import UnsupportedDAppsModal from 'components/Modals/UnsupportedDAppsModal/UnsupportedDAppsModal' import { Loading } from 'components/common' +import ExtensionInviteCodeModal from 'components/Modals/ExtensionInviteCodeModal/ExtensionInviteCodeModal' import SideBar from './SideBar/SideBar' import TopBar from './TopBar/TopBar' import DappsCatalog from './DappsCatalog/DappsCatalog' @@ -42,6 +43,10 @@ export default function Wallet(props) { key: 'dAppsAdvancedMode', defaultValue: [] }) + const [extensionInviteCodeModalSeenBy, setExtensionInviteCodeModalSeenBy] = useLocalStorage({ + key: 'extensionInviteCodeModalSeenBy', + defaultValue: [] + }) const routes = [ { @@ -220,9 +225,9 @@ export default function Wallet(props) { const LoggedInGuard = () => (!isLoggedIn ? : null) - const handlePermissionsModal = useCallback(async () => { + const handleDisplayInitialModal = useCallback(async () => { const account = props.accounts.find(({ id }) => id === props.selectedAcc) - if (!account) return + if (!account || !arePermissionsLoaded) return const relayerIdentityURL = `${props.relayerURL}/identity/${account.id}` @@ -243,23 +248,47 @@ export default function Wallet(props) { /> ) - const isMobile = navigator.platform.includes('Android') || navigator.platform.includes('iOS') - if ((showCauseOfEmail || showCauseOfPermissions || showCauseOfBackupOptout) && !isMobile) + if (showCauseOfEmail || showCauseOfPermissions || showCauseOfBackupOptout) { + const isMobile = navigator.platform.includes('Android') || navigator.platform.includes('iOS') + if (isMobile) return + showModal(permissionsModal, { disableClose: true }) + return + } + const key = props.rewardsData?.rewards.extensionKey?.key + const used = props.rewardsData?.rewards.extensionKey?.used + const rewardsAccountAddr = props.rewardsData?.rewards.accountAddr + + if (!key || used || rewardsAccountAddr !== account.id) return + + const isSeen = extensionInviteCodeModalSeenBy.includes(account.id) + + if (!isSeen) { + setExtensionInviteCodeModalSeenBy((prev) => [...prev, account.id]) + } + + showModal(, { + disableClose: !isSeen + }) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ props.accounts, props.relayerURL, props.onAddAccount, props.showThankYouPage, + props.rewardsData?.rewards.extensionKey?.key, + props.rewardsData?.rewards.extensionKey?.used, + props.rewardsData?.rewards.accountAddr, props.selectedAcc, arePermissionsLoaded, isClipboardGranted, isNoticationsGranted, modalHidden, - showModal + showModal, + setExtensionInviteCodeModalSeenBy ]) - useEffect(() => handlePermissionsModal(), [handlePermissionsModal]) + useEffect(() => handleDisplayInitialModal(), [handleDisplayInitialModal]) // On pathname change (i.e. navigating to different page), always scroll to top useEffect(() => { diff --git a/src/resources/chrome-web-store.svg b/src/resources/chrome-web-store.svg new file mode 100644 index 0000000000..b21f08cad9 --- /dev/null +++ b/src/resources/chrome-web-store.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/resources/icons/copy-new.svg b/src/resources/icons/copy-new.svg new file mode 100644 index 0000000000..d38fd6e698 --- /dev/null +++ b/src/resources/icons/copy-new.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/src/resources/logo-new.svg b/src/resources/logo-new.svg new file mode 100644 index 0000000000..8e43297111 --- /dev/null +++ b/src/resources/logo-new.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/resources/logo-v1.svg b/src/resources/logo-v1.svg new file mode 100644 index 0000000000..4e0db2cd24 --- /dev/null +++ b/src/resources/logo-v1.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file