Skip to content

Commit

Permalink
add: extension invite code modal and top bar invite code option
Browse files Browse the repository at this point in the history
  • Loading branch information
PetromirDev committed Aug 7, 2024
1 parent b4eae1a commit 89219b7
Show file tree
Hide file tree
Showing 13 changed files with 742 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
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 = 5000

const ExtensionInviteCodeModal = ({
inviteCode,
setExtensionInviteCodeModalSeenBy,
accountId,
waitForClose = true
}) => {
const { onHideModal } = useModals()
const { addToast } = useToasts()
const [canClose, setCanClose] = useState(!waitForClose)

const onCloseModal = useCallback(() => {
onHideModal()
setExtensionInviteCodeModalSeenBy((prev) => [...prev, accountId])
}, [accountId, onHideModal, setExtensionInviteCodeModalSeenBy])

useEffect(() => {
const startingTime = Date.now()

const timeout = setTimeout(() => {
if (Date.now() - startingTime < CAN_CLOSE_AFTER_MS) return

setCanClose(true)
}, CAN_CLOSE_AFTER_MS)

return () => {
clearTimeout(timeout)
}
})

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 (
<div className={styles.wrapper}>
<div className={styles.header}>
<div className={styles.headerPrimaryGradient} />
<div className={styles.headerSecondaryGradient} />
<AmbireLogo className={styles.headerLogo} width={92} height={96} />
<p className={styles.headerText}>Easy and secure self-custody for the Ethereum ecosystem</p>
<CloseIcon
className={cn(styles.closeIcon, {
[styles.closeIconEnabled]: canClose
})}
onClick={onCloseModal}
/>
</div>
<div className={styles.content}>
<div className={styles.textWrapper}>
<p className={styles.text}>Hey!</p>
<p className={styles.text}>
We are onboarding only selected Ambire Wallet users to our newest product - the Ambire
browser extension.
</p>
<p className={styles.text}>
Claim this exclusive invitation code to get early access and start collecting XP for our
launch campaign before everyone else 🤫
</p>
</div>
<div className={styles.codeWrapper}>
<span className={styles.codeTitle}>Invitation code</span>
<span className={styles.code}>{inviteCode}</span>
<button className={styles.copyButton} type="button" onClick={handleCopy}>
<CopyIcon />
<span>Copy</span>
</button>
</div>
<div className={styles.storeWrapper}>
<p className={styles.storeText}>
Go to Chrome Web Store, install the extension and use the invitation code to log in.
</p>
<a
className={styles.storeLink}
href="https://chromewebstore.google.com/detail/ambire-wallet/ehgjhhccekdedpbkifaojjaefeohnoea"
target="_blank"
rel="noreferrer"
>
<ChromeWebStore />
</a>
</div>
</div>
</div>
)
}

export default ExtensionInviteCodeModal
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
@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 #3e436b;
background: #24263d;
}

// Reset
.wrapper p,
.wrapper span {
margin: 0;
}

.header {
overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
padding: 2rem;
background: linear-gradient(82deg, #6000ff, #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);
}

.closeIcon {
position: absolute;
right: 1rem;
top: 1rem;
z-index: 4;
cursor: pointer;

:global(#background) {
display: none;
}

&:not(.closeIconEnabled) {
opacity: .4;
cursor: not-allowed;
}
}

.headerLogo {
position: relative;
z-index: 3;
margin-bottom: 1.5rem;
}
.headerText {
position: relative;
z-index: 3;
font-size: 1rem;
color: rgba(255, 255, 255, 0.6);
text-align: center;
}
}

.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,
#6770b3 0,
#6770b3 1ch,
transparent 0,
transparent 1.5ch
)
0 100%/98% 1px no-repeat;
color: #27e8a7; // 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 #6770b3;
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;

.headerLogo {
margin-bottom: 1rem;
}

.headerText {
font-size: .75rem;
}
}
.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: .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;
}
}
}
Loading

0 comments on commit 89219b7

Please sign in to comment.