import { Input, InputError, Loader, VegaIcon, VegaIconNames, } from '@vegaprotocol/ui-toolkit'; import type { FieldValues } from 'react-hook-form'; import { useForm } from 'react-hook-form'; import classNames from 'classnames'; import { Navigate, useNavigate, useSearchParams } from 'react-router-dom'; import type { ButtonHTMLAttributes, MouseEventHandler } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react'; import { RainbowButton } from './buttons'; import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet'; import { useReferral } from './hooks/use-referral'; import { Routes } from '../../lib/links'; import { useTransactionEventSubscription } from '@vegaprotocol/web3'; import { Statistics, useStats } from './referral-statistics'; import { useReferralProgram } from './hooks/use-referral-program'; import { useT } from '../../lib/use-t'; const RELOAD_DELAY = 3000; const validateCode = (value: string, t: ReturnType) => { const number = +`0x${value}`; if (!value || value.length !== 64) { return t('Code must be 64 characters in length'); } else if (Number.isNaN(number)) { return t('Code must be be valid hex'); } return true; }; export const ApplyCodeFormContainer = () => { const { pubKey } = useVegaWallet(); const { data: referee } = useReferral({ pubKey, role: 'referee' }); const { data: referrer } = useReferral({ pubKey, role: 'referrer' }); // go to main page if the current pubkey is already a referrer or referee if (referee || referrer) { return ; } return ; }; export const ApplyCodeForm = () => { const t = useT(); const program = useReferralProgram(); const navigate = useNavigate(); const openWalletDialog = useVegaWalletDialogStore( (store) => store.openVegaWalletDialog ); const [status, setStatus] = useState< 'requested' | 'failed' | 'successful' | null >(null); const txHash = useRef(null); const { isReadOnly, pubKey, sendTx } = useVegaWallet(); const { register, handleSubmit, formState: { errors }, setValue, setError, watch, } = useForm(); const [params] = useSearchParams(); const codeField = watch('code'); const { data: previewData, loading: previewLoading } = useReferral({ code: validateCode(codeField, t) ? codeField : undefined, }); /** * Validates the set a user tries to apply to. */ const validateSet = useCallback(() => { if ( codeField && !previewLoading && previewData && !previewData.isEligible ) { return t('The code is no longer valid.'); } if (codeField && !previewLoading && !previewData) { return t('The code is invalid'); } return true; }, [codeField, previewData, previewLoading, t]); useEffect(() => { const code = params.get('code'); if (code) setValue('code', code); }, [params, setValue]); const onSubmit = ({ code }: FieldValues) => { if (isReadOnly || !pubKey || !code || code.length === 0) { return; } setStatus('requested'); sendTx(pubKey, { applyReferralCode: { id: code as string, }, }) .then((res) => { if (!res) { setError('code', { type: 'required', message: t('The transaction could not be sent'), }); } if (res) { txHash.current = res.transactionHash.toLowerCase(); } }) .catch((err) => { if (err.message.includes('user rejected')) { setStatus(null); } else { setStatus(null); setError('code', { type: 'required', message: err instanceof Error ? err.message : t('Your code has been rejected'), }); } }); }; useTransactionEventSubscription({ variables: { partyId: pubKey || '' }, skip: !pubKey, fetchPolicy: 'no-cache', onData: ({ data: result }) => result.data?.busEvents?.forEach((event) => { if (event.event.__typename === 'TransactionResult') { const hash = event.event.hash.toLowerCase(); if (txHash.current && txHash.current === hash) { const err = event.event.error; const status = event.event.status; if (err) { setStatus(null); setError('code', { type: 'required', message: err, }); } if (status && !err) { setStatus('successful'); } } } }), }); const { epochsValue, nextBenefitTierValue } = useStats({ program }); // go to main page when successfully applied useEffect(() => { if (status === 'successful') { setTimeout(() => { navigate(Routes.REFERRALS); }, RELOAD_DELAY); } }, [navigate, status]); // show "code applied" message when successfully applied if (status === 'successful') { return (

{' '} {t('Code applied')}

); } const getButtonProps = () => { if (!pubKey) { return { disabled: false, children: t('Connect wallet'), type: 'button' as ButtonHTMLAttributes['type'], onClick: ((event) => { event.preventDefault(); openWalletDialog(); }) as MouseEventHandler, }; } if (isReadOnly) { return { disabled: true, children: t('Apply a code'), type: 'submit' as ButtonHTMLAttributes['type'], }; } if (status === 'requested') { return { disabled: true, children: t('Confirm in wallet...'), type: 'submit' as ButtonHTMLAttributes['type'], }; } return { disabled: false, children: t('Apply a code'), type: 'submit' as ButtonHTMLAttributes['type'], }; }; const nextBenefitTierEpochsValue = nextBenefitTierValue ? nextBenefitTierValue.epochs - epochsValue : 0; return ( <>

{t('Apply a referral code')}

{t('Enter a referral code to get trading discounts.')}

{errors.code && ( {errors.code.message?.toString()} )}
{validateCode(codeField, t) === true && previewLoading && !previewData ? (
) : null} {/* TODO: Re-check plural forms once i18n is updated */} {previewData && previewData.isEligible ? (

{t( 'youAreJoiningTheGroup', 'You are joining the group shown, but will not have access to benefits until you have completed at least {{count}} epochs.', { count: nextBenefitTierEpochsValue } )}

) : null} ); };