Skip to content
Draft
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
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,5 @@ VITE_FEATURE_EARN_TAB=true
# Userback feedback widget
VITE_FEATURE_USERBACK=true
VITE_USERBACK_TOKEN=A-3gHopRTd55QqxXGsJd0XLVVG3

VITE_FEATURE_REFERRAL=false
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

# feature flags
VITE_FEATURE_THORCHAIN_TCY_ACTIVITY=true
VITE_FEATURE_REFERRAL=true

# mixpanel
VITE_MIXPANEL_TOKEN=a867ce40912a6b7d01d088cf62b0e1ff
Expand Down
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useFeatureFlag } from '@/hooks/useFeatureFlag/useFeatureFlag'
import { useHasAppUpdated } from '@/hooks/useHasAppUpdated/useHasAppUpdated'
import { useModal } from '@/hooks/useModal/useModal'
import { useNotificationToast } from '@/hooks/useNotificationToast'
import { useReferralCapture } from '@/hooks/useReferralCapture/useReferralCapture'
import { isMobile as isMobileApp } from '@/lib/globals'
import { AppRoutes } from '@/Routes/Routes'

Expand All @@ -35,6 +36,7 @@ export const App = () => {

useAddAccountsGuard()
useAppleSearchAdsAttribution()
useReferralCapture()

useEffect(() => {
if (hasUpdated && !toast.isActive(updateId) && !isActionCenterEnabled) {
Expand Down
22 changes: 21 additions & 1 deletion src/Routes/RoutesCommon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TimeIcon } from '@chakra-ui/icons'
import { lazy } from 'react'
import { FaCreditCard, FaFlag } from 'react-icons/fa'
import { FaCreditCard, FaFlag, FaUsers } from 'react-icons/fa'
import { RiExchangeFundsLine } from 'react-icons/ri'
import { TbGraph, TbTrendingUp } from 'react-icons/tb'

Expand Down Expand Up @@ -147,6 +147,16 @@ const YieldDetailPage = makeSuspenseful(
true,
)

const Referral = makeSuspenseful(
lazy(() =>
import('@/pages/Referral/Referral').then(({ Referral }) => ({
default: Referral,
})),
),
{},
true,
)

const WalletConnectDeepLink = makeSuspenseful(
lazy(() =>
import('@/pages/WalletConnectDeepLink/WalletConnectDeepLink').then(
Expand Down Expand Up @@ -271,6 +281,16 @@ export const routes: Route[] = [
mobileNav: false,
disable: !getConfig().VITE_FEATURE_YIELD_XYZ || !getConfig().VITE_FEATURE_YIELDS_PAGE,
},
{
path: '/referral',
label: 'navBar.referral',
icon: <FaUsers />,
main: Referral,
category: RouteCategory.Featured,
mobileNav: false,
priority: 4,
disable: !getConfig().VITE_FEATURE_REFERRAL,
},
{
path: '/ramp/*',
label: 'navBar.buyCrypto',
Expand Down
38 changes: 37 additions & 1 deletion src/assets/translations/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"and": "and",
"balance": "Balance",
"next": "Next",
"actions": "Actions",
"edit": "Edit",
"error": "Error",
"show": "Show",
Expand Down Expand Up @@ -90,6 +91,7 @@
"terms": "Terms of Service",
"clear": "Clear",
"copy": "Copy",
"shareOnX": "Share on X",
"copied": "Copied to clipboard.",
"copyFailed": "Failed to copy to clipboard",
"copyFailedDescription": "Please copy manually",
Expand Down Expand Up @@ -523,7 +525,8 @@
"tokens": "Tokens",
"swap": "Swap",
"yields": "Yields",
"earn": "Earn"
"earn": "Earn",
"referral": "Referral"
},
"shapeShiftMenu": {
"products": "Products",
Expand Down Expand Up @@ -2152,6 +2155,39 @@
"emptyBody": "It appears you don't have any loans at the moment. Is this financial zen or just a break before your next big lending adventure? Either way, enjoy the calm!"
}
},
"referral": {
"description": "Earn rewards by referring friends to ShapeShift",
"totalReferrals": "Total Referrals",
"activeCodes": "Active Codes",
"feesCollected": "Fees Collected",
"currentMonth": "Current Month",
"yourReferralLink": "Your Referral Link",
"yourReferralCode": "Your Referral Code",
"currentRewards": "Current Rewards",
"totalRewards": "Total Rewards",
"totalReferred": "Total Referred",
"referrals": "Referrals",
"dashboard": "Dashboard",
"codes": "Codes",
"address": "Address",
"volume": "Volume",
"noCodeYet": "Create a referral code to get your link",
"createNewCode": "Create New Referral Code",
"enterCodeOrLeaveEmpty": "Enter a custom code or leave empty for random",
"random": "Random",
"create": "Create",
"yourCodes": "Your Referral Codes",
"code": "Code",
"usages": "Usages",
"status": "Status",
"createdAt": "Created",
"active": "Active",
"inactive": "Inactive",
"noCodes": "You don't have any referral codes yet. Create your first one above!",
"codeCreated": "Referral Code Created",
"codeCreatedDescription": "Your referral code %{code} has been created successfully",
"createCodeFailed": "Failed to create referral code. Please try again."
},
"chart": {
"interval": {
"5min": "Past five minutes",
Expand Down
68 changes: 68 additions & 0 deletions src/components/Referral/CreateCodeCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Button, Card, CardBody, CardHeader, Heading, HStack, Input } from '@chakra-ui/react'
import { FaPlus } from 'react-icons/fa'
import { useTranslate } from 'react-polyglot'

type CreateCodeCardProps = {
newCodeInput: string
isCreating: boolean
onInputChange: (value: string) => void
onGenerateRandom: () => void
onCreate: () => void
}

export const CreateCodeCard = ({
newCodeInput,
isCreating,
onInputChange,
onGenerateRandom,
onCreate,
}: CreateCodeCardProps) => {
const translate = useTranslate()

return (
<Card
bg='background.surface.raised.base'
borderRadius='xl'
borderTop='1px solid'
borderColor='gray.700'
py={2}
>
<CardHeader>
<Heading size='md'>{translate('referral.createNewCode')}</Heading>
</CardHeader>
<CardBody>
<HStack>
<Input
value={newCodeInput}
onChange={e => onInputChange(e.target.value.toUpperCase())}
placeholder={translate('referral.enterCodeOrLeaveEmpty')}
maxLength={20}
bg='background.surface.raised.base'
border='none'
/>
<Button
onClick={onGenerateRandom}
leftIcon={<FaPlus />}
variant='outline'
flexShrink={0}
borderRadius='full'
border='1px solid'
borderColor='gray.700'
backgroundColor='background.surface.raised.base'
>
{translate('referral.random')}
</Button>
<Button
onClick={onCreate}
colorScheme='blue'
isLoading={isCreating}
flexShrink={0}
borderRadius='full'
>
{translate('referral.create')}
</Button>
</HStack>
</CardBody>
</Card>
)
}
83 changes: 83 additions & 0 deletions src/components/Referral/ReferralCodeCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Card, CardBody, Flex, Heading, IconButton, Skeleton, Text } from '@chakra-ui/react'
import { FaCopy } from 'react-icons/fa'
import { FaXTwitter } from 'react-icons/fa6'
import { useTranslate } from 'react-polyglot'

type ReferralCodeCardProps = {
code: string | null
isLoading: boolean
onShareOnX: (code: string) => void
onCopyCode: (code: string) => void
}

export const ReferralCodeCard = ({
code,
isLoading,
onShareOnX,
onCopyCode,
}: ReferralCodeCardProps) => {
const translate = useTranslate()

if (isLoading) {
return (
<Card
color='white'
borderRadius='2xl'
overflow='hidden'
width='50%'
borderTop='1px solid'
borderColor='gray.700'
>
<CardBody px={6} py={4} display='flex' alignItems='center'>
<Skeleton height='60px' width='full' />
</CardBody>
</Card>
)
}

return (
<Card
color='white'
borderRadius='2xl'
overflow='hidden'
width='50%'
borderTop='1px solid'
borderColor='gray.700'
>
<CardBody px={6} py={4} display='flex' alignItems='center'>
<Flex alignItems='center' justifyContent='space-between' width='full'>
<Flex flexDirection='column' gap={0}>
<Text fontSize='md' opacity={0.7} mb={1}>
{translate('referral.yourReferralCode')}
</Text>
<Heading size='xl' fontWeight='bold' letterSpacing='wide'>
{code || 'N/A'}
</Heading>
</Flex>
{code && (
<Flex alignItems='center' gap={2}>
<IconButton
aria-label={translate('common.shareOnX')}
icon={<FaXTwitter />}
size='md'
colorScheme='whiteAlpha'
borderRadius='100%'
bg='whiteAlpha.200'
onClick={() => onShareOnX(code)}
/>
<IconButton
aria-label={translate('common.copy')}
icon={<FaCopy />}
size='md'
colorScheme='whiteAlpha'
bg='whiteAlpha.200'
borderRadius='100%'
onClick={() => onCopyCode(code)}
/>
</Flex>
)}
</Flex>
</CardBody>
</Card>
)
}
Loading