Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui): airdrop login and code sharing on setup screen #1312

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion public/locales/en/airdrop.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,8 @@
"topTooltipTitle": "Testnet Rewards",
"unclaimedGems": "Unclaimed Gems",
"you-reached-your-giftinh-goal": "You reached your gifting goal!",
"your-friend-accepted-gift": "One of your friends accepted your gift!"
"your-friend-accepted-gift": "One of your friends accepted your gift!",
"setupLoginText": "Earn gems while mining to increase your airdrop reward during testnet! Connect your airdrop account to start earning.",
"setupInviteTitle": "invite friends & earn <span>{{gems}}</span> Gems",
"setupCopyButton": "Copy"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useCallback, useEffect } from 'react';
import { open } from '@tauri-apps/plugin-shell';
import { v4 as uuidv4 } from 'uuid';
import { useAirdropStore } from '@app/store/useAirdropStore';
import { useMiningStore } from '@app/store/useMiningStore';

export const useAirdropAuth = () => {
const { backendInMemoryConfig, authUuid, setAuthUuid, setAirdropTokens } = useAirdropStore();
const restartMining = useMiningStore((s) => s.restartMining);

const handleAuth = useCallback(
(code?: string) => {
const token = uuidv4();
if (backendInMemoryConfig?.airdropTwitterAuthUrl) {
setAuthUuid(token);
open(
`${backendInMemoryConfig?.airdropTwitterAuthUrl}?tauri=${token}${code ? `&universeReferral=${code}` : ''}`
);
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[backendInMemoryConfig?.airdropTwitterAuthUrl]
);

useEffect(() => {
if (authUuid && backendInMemoryConfig?.airdropApiUrl) {
const interval = setInterval(() => {
if (authUuid) {
fetch(`${backendInMemoryConfig?.airdropApiUrl}/auth/twitter/get-token/${authUuid}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => response.json())
.then((data) => {
if (!data.error) {
clearInterval(interval);
setAirdropTokens(data);
restartMining();
}
});
}
}, 1000);
const timeout = setTimeout(
() => {
clearInterval(interval);
setAuthUuid('');
},
1000 * 60 * 5
);

return () => {
clearInterval(interval);
clearTimeout(timeout);
};
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [authUuid, backendInMemoryConfig?.airdropApiUrl]);

return { handleAuth };
};
Original file line number Diff line number Diff line change
@@ -1,69 +1,17 @@
import { GIFT_GEMS, useAirdropStore } from '@app/store/useAirdropStore';
import { ClaimButton, GemPill, Image, Title, Wrapper } from './styles';
import { useCallback, useEffect, useState } from 'react';
import { open } from '@tauri-apps/plugin-shell';
import { v4 as uuidv4 } from 'uuid';
import { useState } from 'react';
import ClaimModal from '../../components/ClaimModal/ClaimModal';
import { useTranslation } from 'react-i18next';
import gemImage from '../../images/gem.png';
import { useMiningStore } from '@app/store/useMiningStore';
import { useAirdropAuth } from '../../hooks/useAirdropAuth';

export default function LoggedOut() {
const [modalIsOpen, setModalIsOpen] = useState(false);
const { t } = useTranslation(['airdrop'], { useSuspense: false });
const restartMining = useMiningStore((s) => s.restartMining);
const { referralQuestPoints, authUuid, setAuthUuid, setAirdropTokens, setUserPoints, backendInMemoryConfig } =
useAirdropStore();
const { referralQuestPoints } = useAirdropStore();

const handleAuth = useCallback(
(code?: string) => {
const token = uuidv4();
if (backendInMemoryConfig?.airdropTwitterAuthUrl) {
setAuthUuid(token);
open(
`${backendInMemoryConfig?.airdropTwitterAuthUrl}?tauri=${token}${code ? `&universeReferral=${code}` : ''}`
);
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[backendInMemoryConfig?.airdropTwitterAuthUrl]
);

useEffect(() => {
if (authUuid && backendInMemoryConfig?.airdropApiUrl) {
const interval = setInterval(() => {
if (authUuid) {
fetch(`${backendInMemoryConfig?.airdropApiUrl}/auth/twitter/get-token/${authUuid}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => response.json())
.then((data) => {
if (!data.error) {
clearInterval(interval);
setAirdropTokens(data);
restartMining();
}
});
}
}, 1000);
const timeout = setTimeout(
() => {
clearInterval(interval);
setAuthUuid('');
},
1000 * 60 * 5
);

return () => {
clearInterval(interval);
clearTimeout(timeout);
};
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [authUuid, backendInMemoryConfig?.airdropApiUrl]);
const { handleAuth } = useAirdropAuth();

const gemsValue = (referralQuestPoints?.pointsForClaimingReferral || GIFT_GEMS).toLocaleString();

Expand Down
6 changes: 4 additions & 2 deletions src/containers/phase/Setup/Setup.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import styled from 'styled-components';

export const SetupWrapper = styled.div<{ $bg?: string }>`
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 3;
width: 100%;
height: 100%;

padding: 0 40px 30px;
background-image: ${({ $bg, theme }) => `${theme.gradients.setupBg}, url("${$bg}")`};
background-blend-mode: darken;
Expand Down
3 changes: 1 addition & 2 deletions src/containers/phase/Setup/Setup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ import HeroText from './components/HeroText';
import InfoNav from './components/InfoNav/InfoNav';
import { SetupWrapper } from '@app/containers/phase/Setup/Setup.styles';
import grain from '/assets/img/grain.png';
import AppVersion from './components/AppVersion';

export default function Setup() {
useSetUp();

return (
<SetupWrapper $bg={grain}>
<HeroText />
<InfoNav />
<Footer />
<AppVersion />
</SetupWrapper>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ClaimButton, Gem1, Gem2, Gem3, GemsWrapper, Text, TextWrapper, Title, Wrapper } from './styles';
import gemLargeImage from '../../../../main/Airdrop/AirdropGiftTracker/images/gem.png';
import { useTranslation } from 'react-i18next';
import { useCallback } from 'react';
import { useAppConfigStore } from '@app/store/useAppConfigStore';
import { useAirdropAuth } from '@app/containers/main/Airdrop/AirdropGiftTracker/hooks/useAirdropAuth';

export default function AirdropLogin() {
const { t } = useTranslation(['airdrop'], { useSuspense: false });
const setAllowTelemetry = useAppConfigStore((s) => s.setAllowTelemetry);
const { handleAuth } = useAirdropAuth();

const handleSubmit = useCallback(
async (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
e.stopPropagation();
await setAllowTelemetry(true);
return handleAuth();
},
[handleAuth, setAllowTelemetry]
);

return (
<Wrapper initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 10 }}>
<GemsWrapper>
<Gem1 src={gemLargeImage} alt="" />
<Gem2 src={gemLargeImage} alt="" />
<Gem3 src={gemLargeImage} alt="" />
</GemsWrapper>

<TextWrapper>
<Title>{t('claimModalTitle')}</Title>
<Text>{t('setupLoginText')}</Text>
</TextWrapper>

<ClaimButton onClick={handleSubmit}>
<span>{t('claimGems')}</span>
</ClaimButton>
</Wrapper>
);
}
141 changes: 141 additions & 0 deletions src/containers/phase/Setup/components/AirdropLogin/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { m } from 'framer-motion';
import styled, { keyframes } from 'styled-components';

export const Wrapper = styled(m.div)`
position: fixed;
top: 47px;
right: 40px;
z-index: 4;

width: 311px;

border-radius: 19.438px;
background: linear-gradient(180deg, #c9eb00 32.79%, #fff 69.42%);
box-shadow: 15.55px 15.55px 42.763px 0px rgba(0, 0, 0, 0.1);

padding: 10px;

display: flex;
flex-direction: column;
gap: 20px;
`;

const float = keyframes`
0% {
transform: translateY(0) rotate(0deg);
}
50% {
transform: translateY(-5px) rotate(2.5deg);
}
100% {
transform: translateY(0) rotate(0deg);
}
`;

export const GemsWrapper = styled('div')`
aspect-ratio: 226 / 125;
width: 226px;
margin: auto;
margin-bottom: 14px;

position: absolute;
top: -40px;
left: 50%;
transform: translateX(-50%);
pointer-events: none;
`;

export const Gem1 = styled('img')`
position: absolute;
top: 0;
left: 10px;
animation: ${float} 3s ease-in-out infinite;
width: 121px;
rotate: -40deg;
`;

export const Gem2 = styled('img')`
position: absolute;
top: 20px;
right: 60px;

width: 42px;
rotate: -20deg;
animation: ${float} 3.2s ease-in-out infinite;
`;

export const Gem3 = styled('img')`
position: absolute;
bottom: 0px;
right: 10px;
width: 80px;
rotate: 18deg;
animation: ${float} 3.8s ease-in-out infinite;
`;

export const TextWrapper = styled('div')`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 10px;

padding-top: 78px;
`;

export const Title = styled('div')`
color: #000;
text-align: center;
font-family: DrukWide, sans-serif;
font-size: 16px;
font-style: normal;
font-weight: 800;
line-height: 99.7%;
text-transform: uppercase;
max-width: 262px;

span {
color: #ff4a55;
}
`;

export const Text = styled('div')<{ $isError?: boolean }>`
color: #000;
text-align: center;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 120.7%;
max-width: 282px;
`;

export const ClaimButton = styled('button')`
color: #c9eb00;

font-size: 14px;
text-align: center;
font-family: DrukWide, sans-serif;
font-weight: 800;
text-transform: uppercase;

border-radius: 60px;
background: #000;
box-shadow: 28px 28px 77px 0px rgba(0, 0, 0, 0.1);

width: 100%;
height: 45px;

position: relative;
cursor: pointer;

span {
display: block;
transition: transform 0.2s ease;
}

&:hover {
span {
transform: scale(1.075);
}
}
`;
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useCallback } from 'react';
import gemImage from './images/gem.png';
import { useTranslation } from 'react-i18next';
import { ToggleSwitch } from '@app/components/elements/ToggleSwitch';
import { useAppConfigStore } from '@app/store/useAppConfigStore';
import { BoxWrapper, Gem1, Gem2, Gem3, Gem4, Position, Text, TextWrapper, Title } from './styles';
import { BoxWrapper, Position, Text, TextWrapper, Title } from './styles';

export default function AirdropPermission() {
const allowTelemetry = useAppConfigStore((s) => s.allow_telemetry);
Expand All @@ -17,11 +16,6 @@ export default function AirdropPermission() {
return (
<Position initial={{ x: 100, opacity: 0 }} animate={{ x: 0, opacity: 1 }}>
<BoxWrapper>
<Gem1 src={gemImage} alt="" />
<Gem2 src={gemImage} alt="" />
<Gem3 src={gemImage} alt="" />
<Gem4 src={gemImage} alt="" />

<TextWrapper>
<Title>{t('permission.title')}</Title>
<Text>{t('permission.text')}</Text>
Expand Down
Loading
Loading