Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
23929c5
Implement drawer for Torque
nardevvv Apr 23, 2025
027a493
Change to prod server default
nardevvv Apr 23, 2025
2f4a005
Merge pull request #1 from torque-labs/torque/add-torque-with-drawer
nardevvv Apr 23, 2025
bbb95fe
Revert to devnet as default
nardevvv Apr 23, 2025
3e6217e
Add token data
nardevvv Apr 24, 2025
23fbb92
feat: add ability to see number of claims from reward button
urbentom Apr 24, 2025
ccc55ce
chore: cleaning up logic / styles for reward cards
urbentom Apr 24, 2025
3a755be
feat: handle polling refetching the status of the claim
urbentom Apr 24, 2025
18f5e24
feat: add spinner on pending claims
urbentom Apr 24, 2025
319d436
feat: handle coming soon sections
urbentom Apr 24, 2025
5fd4391
chore: resolve build warnings
urbentom Apr 24, 2025
431b8ec
feat: replace image with icon
urbentom Apr 24, 2025
a296dbe
chore: remove old deps
urbentom Apr 24, 2025
2187e7b
Merge branch 'tom/feedback'
urbentom Apr 24, 2025
a047983
Remove logo
nardevvv Apr 25, 2025
19f6006
Fix label and refresh interval
nardevvv Apr 25, 2025
6037ca4
Add project id env var
nardevvv Apr 25, 2025
7c7f7e4
chore: add live projectId as fallback
urbentom Apr 25, 2025
6291b14
chore: hadle token name fallback
urbentom Apr 25, 2025
3f82db1
wip
urbentom Apr 30, 2025
9791291
fix: pending and claimed switched when claiming an offer
urbentom Apr 30, 2025
9480573
chore: revert dev changes
urbentom Apr 30, 2025
a47eb90
Merge branch 'tom/updated-rewards'
urbentom Apr 30, 2025
fd9b74d
chore: add todo to update the twitter copy
urbentom Apr 30, 2025
119a1f4
Fix claim amount and token amount
nardevvv Apr 30, 2025
cf8012f
Merge remote-tracking branch 'origin/master' into tom/leaderboard
urbentom May 1, 2025
0e1611b
feat: added the base for the leaderboards UI
urbentom May 1, 2025
a807339
feat: improved UI for leaderboards
urbentom May 5, 2025
06a9e31
feat: hooked up leaderboard date
urbentom May 5, 2025
e761ed0
feat: grab the offer to populate the rewards
urbentom May 5, 2025
61c8a58
feat: switching where the leaderboard offer details comes from
urbentom May 5, 2025
890ffe2
feat: update the way we handle the reset for everyday
urbentom May 5, 2025
8a3513d
feat: add loading to claims tab
urbentom May 5, 2025
77230b9
fix: leaderboards timezone issues
urbentom May 6, 2025
62907d6
feat: cleanup numbers
urbentom May 6, 2025
adf418d
Merge pull request #2 from torque-labs/tom/leaderboard
urbentom May 6, 2025
5e4e45c
chore: temporarily hide campaigns
urbentom May 20, 2025
0b8614a
wip for raffles
urbentom May 30, 2025
945cd75
feat: add last sections to raffles
urbentom May 30, 2025
9491633
feat: hookup live data
urbentom Jun 2, 2025
3a3710d
feat: updating where the data is coming from
urbentom Jun 3, 2025
a75be06
feat: improve tooltips + icons in weekly activity
urbentom Jun 3, 2025
7013b2b
feat: add raffle skeleton
urbentom Jun 3, 2025
8941989
chore: replace URL
urbentom Jun 3, 2025
e2a0d7b
feat: update leaderboard to handle different reward
urbentom Jun 3, 2025
7f78bbe
fix: type
urbentom Jun 3, 2025
745c4b1
feat: filter offers to only show ones where the startdate has passed
urbentom Jun 3, 2025
6735125
Merge pull request #4 from torque-labs/feat/raffles
0xlarry Jun 3, 2025
0d57252
hotfix: format date into a valid string for safari
urbentom Jun 4, 2025
59edbae
fix: possible start date for UTC
urbentom Jun 4, 2025
baf8b31
fix: format the string dates correctly
urbentom Jun 4, 2025
ed73a0b
feat: hardcode 12am utc
urbentom Jun 4, 2025
f24fd76
Merge pull request #5 from torque-labs/hotfix/date-issues
urbentom Jun 4, 2025
2334b72
feat: improvements to raffle and leaderboards
urbentom Jun 4, 2025
496a13a
feat: increase size of total badge
urbentom Jun 4, 2025
ddddfb8
Merge pull request #6 from torque-labs/feat/raffle-improvements
urbentom Jun 4, 2025
2083920
Merge remote-tracking branch 'upstream/master'
urbentom Jun 5, 2025
f196a56
feat: add share modal
urbentom Jun 10, 2025
b363949
chore: update tweet copy
urbentom Jun 10, 2025
a575c38
chore: update copy
urbentom Jun 10, 2025
f91a082
Merge pull request #7 from torque-labs/tom/share-modal
urbentom Jun 10, 2025
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"recharts": "^2.15.3",
"rxjs": "^7.5.6",
"swr": "^2.2.0",
"tsparticles-confetti": "^2.12.0",
"unionize": "^3.1.0",
"uuid": "^9.0.1",
"yup": "^0.32.11",
Expand Down
Binary file added public/images/reward-icon.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/images/reward-icon.png
Binary file not shown.
174 changes: 130 additions & 44 deletions src/features/Torque/components/TorqueClaimRewards.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import { Heading, HStack, Stack, Text, VStack } from '@chakra-ui/react'
import { useMemo } from 'react'
import {
Button,
Heading,
HStack,
ModalBody,
ModalCloseButton,
ModalContent,
ModalOverlay,
Modal,
Stack,
Text,
VStack,
ModalHeader,
useColorMode
} from '@chakra-ui/react'
import { useMemo, useState } from 'react'
import TorqueOfferCard, { TorqueOfferCardSkeleton } from './TorqueOfferCard'
import { colors } from '@/theme/cssVariables'
import { TorqueCampaign } from '../types'
import HistoryIcon from '@/icons/misc/History'
import GiftIcon from '@/icons/misc/Gift'
import { useWallet } from '@solana/wallet-adapter-react'
import Image from 'next/image'
import { genericConfetti } from './TorqueConfetti'
import { twitterShareUrl } from '../utils'

interface TorqueClaimRewardsProps {
claimOffer: (offerId: string) => void
campaigns: TorqueCampaign[]
Expand All @@ -15,6 +33,11 @@ interface TorqueClaimRewardsProps {

export default function TorqueClaimRewards({ claimOffer, campaigns, loading, error }: TorqueClaimRewardsProps) {
const { wallet } = useWallet()
const [isClaimModalOpen, setIsClaimModalOpen] = useState<boolean>(false)
const [shareAmount, setShareAmount] = useState<string>('')

const { colorMode } = useColorMode()
const isLight = colorMode === 'light'

const activeCampaigns = useMemo(() => {
return campaigns.filter((campaign) => campaign.offers.some((offer) => offer.status === 'ACTIVE'))
Expand All @@ -37,6 +60,12 @@ export default function TorqueClaimRewards({ claimOffer, campaigns, loading, err
})
}, [campaigns])

const handleOpenClaimModal = (amount: string) => {
setShareAmount(amount)
setIsClaimModalOpen(true)
genericConfetti()
}

if (loading) {
return (
<VStack gap={6} p={0} w="full">
Expand Down Expand Up @@ -69,49 +98,106 @@ export default function TorqueClaimRewards({ claimOffer, campaigns, loading, err
}

return (
<VStack gap={6} p={0} w="full">
<Section title="Ready to Claim" icon={<GiftIcon />}>
{activeCampaigns.length > 0 ? (
activeCampaigns.map((campaign) => <TorqueOfferCard key={campaign.id} {...campaign} claimOffer={claimOffer} />)
) : (
<Stack
w="full"
spacing={4}
p={3}
minH={24}
borderRadius="md"
bg={colors.backgroundDark}
opacity={0.7}
justify="center"
align="center"
>
<Text>{wallet?.adapter.publicKey ? "You don't have any available rewards." : 'Connect your wallet to view your rewards.'}</Text>
</Stack>
)}
</Section>
<>
<VStack gap={6} p={0} w="full">
<Section title="Ready to Claim" icon={<GiftIcon />}>
{activeCampaigns.length > 0 ? (
activeCampaigns.map((campaign) => (
<TorqueOfferCard key={campaign.id} {...campaign} claimOffer={claimOffer} handleOpenClaimModal={handleOpenClaimModal} />
))
) : (
<Stack
w="full"
spacing={4}
p={3}
minH={24}
borderRadius="md"
bg={colors.backgroundDark}
opacity={0.7}
justify="center"
align="center"
>
<Text>
{wallet?.adapter.publicKey ? "You don't have any available rewards." : 'Connect your wallet to view your rewards.'}
</Text>
</Stack>
)}
</Section>

<Section title="History" icon={<HistoryIcon />}>
{historicalCampaigns.length > 0 ? (
historicalCampaigns.map((campaign) => <TorqueOfferCard key={campaign.id} {...campaign} claimOffer={claimOffer} />)
) : (
<Stack
w="full"
spacing={4}
p={3}
minH={24}
borderRadius="md"
bg={colors.backgroundDark}
opacity={0.7}
justify="center"
align="center"
>
<Text>
{wallet?.adapter.publicKey ? 'Looks like there are no historical rewards.' : 'Connect your wallet to see historical rewards.'}
</Text>
</Stack>
)}
</Section>
</VStack>
<Section title="History" icon={<HistoryIcon />}>
{historicalCampaigns.length > 0 ? (
historicalCampaigns.map((campaign) => (
<TorqueOfferCard key={campaign.id} {...campaign} claimOffer={claimOffer} handleOpenClaimModal={handleOpenClaimModal} />
))
) : (
<Stack
w="full"
spacing={4}
p={3}
minH={24}
borderRadius="md"
bg={colors.backgroundDark}
opacity={0.7}
justify="center"
align="center"
>
<Text>
{wallet?.adapter.publicKey
? 'Looks like there are no historical rewards.'
: 'Connect your wallet to see historical rewards.'}
</Text>
</Stack>
)}
</Section>
</VStack>
{isClaimModalOpen && (
<Modal
isOpen={isClaimModalOpen}
onClose={() => {
setIsClaimModalOpen(false)
setShareAmount('')
}}
>
<ModalOverlay />
<ModalContent>
<ModalHeader>Hold Tight — Reward On The Way</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Stack justifyContent={'center'} alignItems={'center'} gap={4}>
<Image alt="Share Reward" src="/images/reward-icon.jpg" width={300} height={300} style={{ borderRadius: '8px' }} />
<Text textAlign={'center'}>
Your reward&apos;s en route. While the system does it&apos;s magic, share your referral link on X for more chances to earn
rewards!
</Text>
<HStack w="full" gap={2} justifyContent={'center'}>
<Button
size="md"
w="full"
flex={2}
background={
isLight
? 'linear-gradient(245.22deg, #DA2EEF 7.97%, #2B6AFF 49.17%, #39D0D8 92.1%)'
: 'linear-gradient(245.22deg, #FF2FC8 7.97%, #FFB12B 49.17%, #D3D839 92.1%)'
}
_hover={{
background: isLight
? 'linear-gradient(245.22deg, #DA2EEF 7.97%, #2B6AFF 49.17%, #39D0D8 92.1%)'
: 'linear-gradient(245.22deg, #FF2FC8 7.97%, #FFB12B 49.17%, #D3D839 92.1%)'
}}
onClick={() => {
const url = twitterShareUrl(shareAmount, wallet?.adapter.publicKey?.toString() ?? '')
window.open(url, '_blank')
}}
>
Share to Earn
</Button>
</HStack>
</Stack>
</ModalBody>
</ModalContent>
</Modal>
)}
</>
)
}

Expand Down
18 changes: 18 additions & 0 deletions src/features/Torque/components/TorqueConfetti.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { confetti } from 'tsparticles-confetti'

type ConfettiOptions = Parameters<typeof confetti>[0]
const confettiOptions: ConfettiOptions = {
// to layer on top of chakra overlay
zIndex: 10_000,
spread: 260,
ticks: 75,
gravity: 0.4,
decay: 0.95,
startVelocity: 30,
particleCount: 300,
scalar: 2
}

export const genericConfetti = () => {
return confetti(confettiOptions)
}
21 changes: 12 additions & 9 deletions src/features/Torque/components/TorqueOfferCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,11 @@ import Tooltip from '@/components/Tooltip'
import ClockIcon from '@/icons/misc/Clock'
import GiftIcon from '@/icons/misc/Gift'
import ShareIcon from '@/icons/misc/ShareIcon'
import { displayNumber } from '../utils'
import { displayNumber, twitterShareUrl } from '../utils'
import { useWallet } from '@solana/wallet-adapter-react'
interface TorqueOfferCardProps extends TorqueCampaign {
claimOffer: (offerId: string) => void
}

const twitterShareUrl = (amount: string) => {
const safeAmount = encodeURIComponent(amount)
// TODO: Need to add the final twitter copy here
return `https://twitter.com/intent/tweet?text=Thanks%20%40RaydiumProtocol%20for%20my%20${safeAmount},%20see%20if%20you%20are%20eligible%20for%20a%20reward%20too%20https%3A//raydium.io/launchpad/`
handleOpenClaimModal: (amount: string) => void
}

export default function TorqueOfferCard({
Expand All @@ -30,12 +26,14 @@ export default function TorqueOfferCard({
maxParticipants,
startTime,
endTime,
status
status,
handleOpenClaimModal
}: TorqueOfferCardProps) {
// State
const [claiming, setClaiming] = useState<boolean>(false)
const [showAdditionalOffers, setShowAdditionalOffers] = useState<boolean>(false)
const explorerUrl = useAppStore((s) => s.explorerUrl)
const { wallet } = useWallet()

const activeOffer = useMemo(() => {
// A user should not be eligible for multiple active offers per campaign
Expand All @@ -55,6 +53,8 @@ export default function TorqueOfferCard({
return
}

handleOpenClaimModal(`${activeOffer.rewardPerUser} ${rewardDenomination}`)

setClaiming(true)
await claimOffer(activeOffer.id)
setClaiming(false)
Expand Down Expand Up @@ -180,7 +180,10 @@ export default function TorqueOfferCard({

{pendingOrClaimedOffer?.rewardPerUser ? (
<Link
href={twitterShareUrl(`${pendingOrClaimedOffer.rewardPerUser} ${rewardDenomination}`)}
href={twitterShareUrl(
`${pendingOrClaimedOffer.rewardPerUser} ${rewardDenomination}`,
wallet?.adapter.publicKey?.toString() ?? ''
)}
target="_blank"
rel="noopener noreferrer"
>
Expand Down
5 changes: 5 additions & 0 deletions src/features/Torque/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,8 @@ export function formatBadDateString(date: string, makeUtc = false): string {

return makeUtc ? baseDate + 'T00:00:00Z' : baseDate
}

export const twitterShareUrl = (amount: string, wallet: string) => {
const safeAmount = encodeURIComponent(amount)
return `https://twitter.com/intent/post?text=Just%20claimed%20${safeAmount}%20for%20trading%20on%20LaunchLab%20%40RaydiumProtocol%20%F0%9F%92%AA%0A%0ABeen%20in%20the%20trenches%3F%20You%20may%20have%20rewards%20waiting.%20Trade%20using%20my%20link%20for%20more%20chances%20to%20win%20RAY%20%F0%9F%91%89%20https%3A%2F%2Fraydium.io%2Flaunchpad%2F%3Flreferrer%3D${wallet}`
}
Loading