2023-12-06 17:51:39 +00:00
import {
addDecimalsFormatNumber ,
getDateTimeFormat ,
} from '@vegaprotocol/utils' ;
2023-09-21 13:25:19 +00:00
import { useReferralProgram } from './hooks/use-referral-program' ;
2024-01-02 15:50:04 +00:00
import { Table } from '../../components/table' ;
2023-09-21 13:25:19 +00:00
import classNames from 'classnames' ;
import { BORDER_COLOR , GRADIENT } from './constants' ;
2024-01-02 15:50:04 +00:00
import { Tag } from '../../components/helpers/tag' ;
import { getTierColor , getTierGradient } from '../../components/helpers/tiers' ;
import type { ReactNode } from 'react' ;
2023-12-06 17:51:39 +00:00
import { ExternalLink , truncateMiddle } from '@vegaprotocol/ui-toolkit' ;
2023-11-23 17:08:26 +00:00
import {
DApp ,
DocsLinks ,
2023-12-06 17:51:39 +00:00
TOKEN_PROPOSAL ,
2023-11-23 17:08:26 +00:00
TOKEN_PROPOSALS ,
useLinks ,
} from '@vegaprotocol/environment' ;
2023-11-16 03:10:39 +00:00
import { useT , ns } from '../../lib/use-t' ;
import { Trans } from 'react-i18next' ;
2023-09-21 13:25:19 +00:00
const Loading = ( { variant } : { variant : 'large' | 'inline' } ) = > (
< div
className = { classNames (
'bg-vega-clight-800 dark:bg-vega-cdark-800 rounded-lg animate-pulse' ,
{
'w-full h-20' : variant === 'large' ,
}
) }
> < / div >
) ;
const StakingTier = ( {
tier ,
referralRewardMultiplier ,
minimumStakedTokens ,
2024-01-02 15:50:04 +00:00
max ,
2023-09-21 13:25:19 +00:00
} : {
tier : number ;
referralRewardMultiplier : string ;
minimumStakedTokens : string ;
2024-01-02 15:50:04 +00:00
max? : number ;
2023-09-21 13:25:19 +00:00
} ) = > {
2023-11-16 03:10:39 +00:00
const t = useT ( ) ;
2023-12-06 17:51:39 +00:00
const minimum = addDecimalsFormatNumber ( minimumStakedTokens , 18 ) ;
// TODO: Decide what to do with the multiplier images
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const multiplierImage = (
< div
aria - hidden
className = { classNames (
'w-full max-w-[80px] h-full min-h-[80px]' ,
'bg-cover bg-right-bottom' ,
{
"bg-[url('/1x.png')]" : tier === 1 ,
"bg-[url('/2x.png')]" : tier === 2 ,
"bg-[url('/3x.png')]" : tier === 3 ,
}
) }
>
< span className = "sr-only" > { ` ${ referralRewardMultiplier } x multiplier ` } < / span >
< / div >
) ;
2023-09-21 13:25:19 +00:00
return (
< div
className = { classNames (
'overflow-hidden' ,
'border rounded-md w-full' ,
2023-10-23 14:57:18 +00:00
'flex flex-row' ,
2023-12-06 17:51:39 +00:00
'bg-white dark:bg-vega-cdark-900' ,
2023-10-23 14:57:18 +00:00
GRADIENT ,
2023-09-21 13:25:19 +00:00
BORDER_COLOR
) }
>
2023-12-06 17:51:39 +00:00
< div
className = { classNames (
'p-3 flex flex-row min-h-[80px] h-full items-center'
2023-09-21 13:25:19 +00:00
) }
2023-12-06 17:51:39 +00:00
>
< div >
2024-01-02 15:50:04 +00:00
< Tag color = { getTierColor ( tier , max ) } >
2023-12-06 17:51:39 +00:00
{ t ( 'Multiplier' ) } { referralRewardMultiplier } x
< / Tag >
< p className = "mt-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100" >
< Trans
defaults = "Stake a minimum of <0>{{minimum}}</0> $VEGA tokens"
values = { { minimum } }
components = { [ < b key = { minimum } > < / b > ] }
/ >
< / p >
< / div >
2023-09-21 13:25:19 +00:00
< / div >
< / div >
) ;
} ;
export const TiersContainer = ( ) = > {
2023-11-16 03:10:39 +00:00
const t = useT ( ) ;
2023-10-23 14:57:18 +00:00
const { benefitTiers , stakingTiers , details , loading , error } =
useReferralProgram ( ) ;
2023-09-21 13:25:19 +00:00
const ends = details ? . endOfProgramTimestamp
? getDateTimeFormat ( ) . format ( new Date ( details . endOfProgramTimestamp ) )
: undefined ;
2023-10-23 14:57:18 +00:00
const governanceLink = useLinks ( DApp . Governance ) ;
if ( ( ! loading && ! details ) || error ) {
return (
2023-12-06 17:51:39 +00:00
< div className = "bg-vega-clight-800 dark:bg-vega-cdark-800 text-black dark:text-white rounded-lg p-6 mt-1 mb-20 text-sm text-center" >
2023-11-16 03:10:39 +00:00
< Trans
2023-11-23 17:08:26 +00:00
defaults = "There are currently no active referral programs. Check the <0>Governance App</0> to see if there are any proposals in progress and vote."
2023-11-16 03:10:39 +00:00
components = { [
2023-12-06 17:51:39 +00:00
< ExternalLink
href = { governanceLink ( TOKEN_PROPOSALS ) }
key = "link"
className = "underline"
>
2023-11-23 17:08:26 +00:00
{ t ( 'Governance App' ) }
< / ExternalLink > ,
] }
ns = { ns }
2023-12-06 17:51:39 +00:00
/ > { ' ' }
2023-11-23 17:08:26 +00:00
< Trans
2023-12-06 17:51:39 +00:00
defaults = "Use the <0>docs</0> tutorial to propose a new program."
2023-11-23 17:08:26 +00:00
components = { [
2023-12-06 17:51:39 +00:00
< ExternalLink
href = { DocsLinks ? . REFERRALS }
key = "link"
className = "underline"
>
{ t ( 'docs' ) }
2023-11-16 03:10:39 +00:00
< / ExternalLink > ,
] }
ns = { ns }
/ >
2023-10-23 14:57:18 +00:00
< / div >
) ;
}
2023-09-21 13:25:19 +00:00
return (
< >
2024-01-02 15:50:04 +00:00
< h2 className = "text-3xl mt-10 font-alpha calt" >
{ t ( 'Current program details' ) }
< / h2 >
2023-12-06 17:51:39 +00:00
{ details ? . id && (
< p >
< Trans
2023-12-08 14:48:12 +00:00
defaults = "As a result of governance proposal <0>{{proposal}}</0> the program below is currently active on the Vega network."
2023-12-06 17:51:39 +00:00
values = { { proposal : truncateMiddle ( details . id ) } }
components = { [
< ExternalLink
key = "referral-program-proposal-link"
href = { governanceLink ( TOKEN_PROPOSAL . replace ( ':id' , details . id ) ) }
className = "underline"
>
proposal
< / ExternalLink > ,
] }
/ >
< / p >
) }
{ /* Meta */ }
< div className = "mt-10 flex flex-row items-baseline justify-between text-xs text-vega-clight-100 dark:text-vega-cdark-100 font-alpha calt" >
{ details ? . id && (
< span >
{ t ( 'Proposal ID:' ) } { ' ' }
< ExternalLink
href = { governanceLink ( TOKEN_PROPOSAL . replace ( ':id' , details . id ) ) }
>
< span > { truncateMiddle ( details . id ) } < / span >
< / ExternalLink >
< / span >
) }
2023-09-21 13:25:19 +00:00
{ ends && (
2023-12-06 17:51:39 +00:00
< span >
2023-10-24 15:43:33 +00:00
{ t ( 'Program ends:' ) } { ends }
2023-09-21 13:25:19 +00:00
< / span >
) }
< / div >
2023-12-06 17:51:39 +00:00
{ /* Container */ }
2024-01-02 15:50:04 +00:00
< div
className = { classNames (
'md:bg-vega-clight-800' ,
'md:dark:bg-vega-cdark-800' ,
'md:text-black' ,
'md:dark:text-white' ,
'md:rounded-lg' ,
'md:p-6' ,
'mt-1' ,
'mb-20'
) }
>
2023-12-06 17:51:39 +00:00
{ /* Benefit tiers */ }
< div className = "flex flex-col mb-5" >
< h3 className = "text-2xl calt" > { t ( 'Benefit tiers' ) } < / h3 >
< p className = "text-sm text-vega-clight-200 dark:text-vega-cdark-200" >
{ t (
'Members of a referral group can access the increasing commission and discount benefits defined in the program based on their combined running volume.'
) }
< / p >
< / div >
< div className = "mb-10" >
{ loading || ! benefitTiers || benefitTiers . length === 0 ? (
2023-09-21 13:25:19 +00:00
< Loading variant = "large" / >
2023-12-06 17:51:39 +00:00
) : (
< TiersTable
windowLength = { details ? . windowLength }
data = { benefitTiers . map ( ( bt ) = > ( {
. . . bt ,
tierElement : (
< div className = "rounded-full bg-vega-clight-900 dark:bg-vega-cdark-900 p-1 w-8 h-8 text-center" >
{ bt . tier }
< / div >
) ,
} ) ) }
/ >
) }
< / div >
{ /* Staking tiers */ }
< div className = "flex flex-col mb-5" >
< h3 className = "text-2xl calt" > { t ( 'Staking multipliers' ) } < / h3 >
< p className = "text-sm text-vega-clight-200 dark:text-vega-cdark-200" >
{ t (
'Referrers can access the commission multipliers defined in the program by staking VEGA tokens in the amounts shown.'
) }
< / p >
< / div >
< div className = "gap-5 grid lg:grid-cols-3" >
{ loading || ! stakingTiers || stakingTiers . length === 0 ? (
< >
< Loading variant = "large" / >
< Loading variant = "large" / >
< Loading variant = "large" / >
< / >
) : (
< StakingTiers data = { stakingTiers } / >
) }
< / div >
2023-09-21 13:25:19 +00:00
< / div >
< / >
) ;
} ;
const StakingTiers = ( {
data ,
} : {
data : ReturnType < typeof useReferralProgram > [ 'stakingTiers' ] ;
} ) = > (
< >
2023-12-06 17:51:39 +00:00
{ data . map ( ( { tier , referralRewardMultiplier , minimumStakedTokens } , i ) = > (
< StakingTier
key = { i }
tier = { tier }
2024-01-02 15:50:04 +00:00
max = { data . length }
2023-12-06 17:51:39 +00:00
referralRewardMultiplier = { referralRewardMultiplier }
minimumStakedTokens = { minimumStakedTokens }
/ >
) ) }
2023-09-21 13:25:19 +00:00
< / >
) ;
const TiersTable = ( {
data ,
2023-10-31 01:12:59 +00:00
windowLength ,
2023-09-21 13:25:19 +00:00
} : {
data : Array < {
tier : number ;
2023-10-23 14:57:18 +00:00
tierElement : ReactNode ;
2023-09-21 13:25:19 +00:00
commission : string ;
discount : string ;
volume : string ;
} > ;
2023-10-31 01:12:59 +00:00
windowLength? : number ;
2023-09-21 13:25:19 +00:00
} ) = > {
2023-11-16 03:10:39 +00:00
const t = useT ( ) ;
2023-09-21 13:25:19 +00:00
return (
< Table
columns = { [
2023-10-24 15:43:33 +00:00
{ name : 'tierElement' , displayName : t ( 'Tier' ) } ,
2023-09-21 13:25:19 +00:00
{
name : 'commission' ,
2023-10-24 15:43:33 +00:00
displayName : t ( 'Referrer commission' ) ,
2023-12-06 17:51:39 +00:00
tooltip : t (
"The proportion of the referee's taker fees to be rewarded to the referrer"
) ,
} ,
{
name : 'discount' ,
displayName : t ( 'Referee trading discount' ) ,
tooltip : t (
"The proportion of the referee's taker fees to be discounted"
) ,
2023-09-21 13:25:19 +00:00
} ,
2023-10-31 01:12:59 +00:00
{
name : 'volume' ,
2023-11-30 07:31:44 +00:00
displayName : t (
'minTradingVolume' ,
'Min. trading volume (last {{count}} epochs)' ,
{
count : windowLength ,
}
) ,
2023-12-06 17:51:39 +00:00
tooltip : t ( 'The minimum running notional for the given benefit tier' ) ,
} ,
{
name : 'epochs' ,
displayName : t ( 'Min. epochs' ) ,
tooltip : t (
'The minimum number of epochs the party needs to be in the referral set to be eligible for the benefit'
) ,
2023-10-31 01:12:59 +00:00
} ,
2023-09-21 13:25:19 +00:00
] }
2023-12-06 17:51:39 +00:00
className = "bg-white dark:bg-vega-cdark-900"
2023-09-21 13:25:19 +00:00
data = { data . map ( ( d ) = > ( {
. . . d ,
2024-01-02 15:50:04 +00:00
className : classNames ( getTierGradient ( d . tier , data . length ) ) ,
2023-09-21 13:25:19 +00:00
} ) ) }
/ >
) ;
} ;