feat: add ui to handle code creation and stake requirements

This commit is contained in:
Matthew Russell
2023-09-18 22:17:42 -07:00
parent 4688d9b839
commit d3835bd67f
6 changed files with 197 additions and 51 deletions
@@ -16,8 +16,8 @@ export const ApplyCodeForm = () => {
setValue,
setError,
} = useForm();
const [params] = useSearchParams();
useEffect(() => {
const code = params.get('code');
if (code) setValue('code', code);
@@ -46,7 +46,7 @@ export const ApplyCodeForm = () => {
return (
<div className="w-1/2 mx-auto">
<h3 className="text-xl mb-5 text-center uppercase calt">
<h3 className="mb-5 text-xl text-center uppercase calt">
Apply a referral code
</h3>
<p className="mb-6 text-center">Enter a referral code</p>
@@ -57,7 +57,7 @@ export const ApplyCodeForm = () => {
onSubmit={handleSubmit(onSubmit)}
>
<label className="flex-grow">
<span className="block text-vega-clight-100 dark:text-vega-cdark-100 mb-1 text-sm">
<span className="block mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100">
Your referral code
</span>
<Input
@@ -5,25 +5,128 @@ import {
} from '@vegaprotocol/wallet';
import { RainbowButton } from './buttons';
import { useState } from 'react';
import classNames from 'classnames';
import {
Button,
CopyWithTooltip,
Dialog,
ExternalLink,
InputError,
Intent,
TradingAnchorButton,
TradingButton,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { gql, useQuery } from '@apollo/client';
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
import { DApp, TokenStaticLinks, useLinks } from '@vegaprotocol/environment';
export const CreateCodeForm = () => {
const CREATE_CODE_QUERY = gql`
query CreateCode($partyId: ID!) {
party(id: $partyId) {
stakingSummary {
currentStakeAvailable
}
}
networkParameter(key: "referralProgram.minStakedVegaTokens") {
value
}
}
`;
export const CreateCodeContainer = () => {
const { pubKey } = useVegaWallet();
const { data, loading } = useQuery(CREATE_CODE_QUERY, {
variables: { partyId: pubKey || '' },
skip: !pubKey,
// TOOD: remove when network params available
errorPolicy: 'ignore',
});
if (loading) return null;
const requiredStake = data?.networkParameter?.value || '0';
const currentStakeAvailable =
data?.party?.stakingSummary.currentStakeAvailable || '0';
return (
<CreateCodeForm
currentStakeAvailable={currentStakeAvailable}
requiredStake={requiredStake}
/>
);
};
export const CreateCodeForm = ({
currentStakeAvailable,
requiredStake,
}: {
currentStakeAvailable: string;
requiredStake: string;
}) => {
const [dialogOpen, setDialogOpen] = useState(false);
const openWalletDialog = useVegaWalletDialogStore(
(store) => store.openVegaWalletDialog
);
const { pubKey } = useVegaWallet();
return (
<div className="w-1/2 mx-auto">
<h3 className="mb-5 text-xl text-center uppercase calt">
Create a referral code
</h3>
<p className="mb-6 text-center">
Generate a referral code to share with your friends and start earning
commission.
</p>
<div className="mb-5">
<div className="text-center">
<RainbowButton
variant="border"
onClick={() => {
if (pubKey) {
setDialogOpen(true);
} else {
openWalletDialog();
}
}}
>
{pubKey ? 'Create a referral code' : 'Connect wallet'}
</RainbowButton>
</div>
</div>
<Dialog
title="Create a referral code"
open={dialogOpen}
onChange={() => setDialogOpen(false)}
size="small"
>
<CreateCodeDialog
currentStakeAvailable={currentStakeAvailable}
setDialogOpen={setDialogOpen}
requiredStake={requiredStake}
/>
</Dialog>
</div>
);
};
const CreateCodeDialog = ({
setDialogOpen,
currentStakeAvailable,
requiredStake,
}: {
setDialogOpen: (open: boolean) => void;
currentStakeAvailable: string;
requiredStake: string;
}) => {
const createLink = useLinks(DApp.Governance);
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
const [err, setErr] = useState<string | null>(null);
const [code, setCode] = useState<string | null>(null);
const [status, setStatus] = useState<
'idle' | 'loading' | 'success' | 'error'
>('idle');
const openWalletDialog = useVegaWalletDialogStore(
(store) => store.openVegaWalletDialog
);
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
const onSubmit = () => {
if (isReadOnly || !pubKey) {
setErr('Not connected');
@@ -56,44 +159,69 @@ export const CreateCodeForm = () => {
}
};
return (
<div className="w-1/2 mx-auto">
<h3 className="mb-5 text-xl text-center uppercase calt">
Create a referral code
</h3>
<p className="mb-6 text-center">
Generate a referral code to share with your friends and start earning
commission.
</p>
<div className="mb-5">
{pubKey ? (
<div className="text-center">
<RainbowButton
className={classNames({
'animate-shake': err,
})}
variant="border"
disabled={status === 'loading'}
onClick={() => onSubmit()}
>
{status === 'loading'
? 'Complete in wallet'
: 'Create a referral code'}
</RainbowButton>
</div>
) : (
<div className="text-center">
<RainbowButton variant="border" onClick={() => openWalletDialog()}>
Connect wallet
</RainbowButton>
</div>
)}
const getButtonProps = () => {
if (status === 'idle' || status === 'error') {
return {
children: 'Generate code',
onClick: () => onSubmit(),
};
}
if (status === 'loading') {
return {
children: 'Confirm in wallet...',
disabled: true,
};
}
if (status === 'success') {
return {
children: 'Close',
intent: Intent.Success,
onClick: () => setDialogOpen(false),
};
}
};
// TODO: Add when network parameters are updated
if (
currentStakeAvailable === '0' ||
BigInt(currentStakeAvailable) < BigInt(requiredStake)
) {
return (
<div className="flex flex-col gap-4">
<p>
You need at least {addDecimalsFormatNumber(requiredStake, 18)} VEGA
staked to generate a referral code and participate in the referral
program.
</p>
<TradingAnchorButton
href={createLink(TokenStaticLinks.ASSOCIATE)}
intent={Intent.Primary}
target="_blank"
>
Stake some $VEGA now
</TradingAnchorButton>
</div>
);
}
return (
<div className="flex flex-col gap-4">
{(status === 'idle' || status === 'loading' || status === 'error') && (
<p>
Generate a referral code to share with your friends aand start enaring
commission.
</p>
)}
{status === 'success' && code && (
<div className="flex gap-2">
<p className="flex items-center px-2 text-sm rounded bg-vega-clight-700 dark:bg-vega-cdark-700">
<span>{code}</span>
</p>
<div className="flex items-center gap-2">
<div className="flex-1 min-w-0 p-2 text-sm rounded bg-vega-clight-700 dark:bg-vega-cdark-700">
<p className="overflow-hidden whitespace-nowrap text-ellipsis">
{code}
</p>
</div>
<CopyWithTooltip text={code}>
<TradingButton
className="text-sm no-underline"
@@ -104,6 +232,17 @@ export const CreateCodeForm = () => {
</CopyWithTooltip>
</div>
)}
<TradingButton
fill={true}
intent={Intent.Primary}
{...getButtonProps()}
/>
{err && <InputError>{err}</InputError>}
{/* TODO: Add links */}
<div className="flex justify-center pt-5 mt-2 text-sm border-t gap-4 text-default border-default">
<ExternalLink>About the referral program</ExternalLink>
<ExternalLink>Disclaimer</ExternalLink>
</div>
</div>
);
};
@@ -1,8 +1,9 @@
import { gql, useQuery } from '@apollo/client';
import { gql } from '@apollo/client';
import { getNumberFormat } from '@vegaprotocol/utils';
import { addDays } from 'date-fns';
// TODO: Generate query
// eslint-disable-next-line
const REFERRAL_PROGRAM_QUERY = gql`
query ReferralProgram {
currentReferralProgram {
@@ -27,7 +28,9 @@ const REFERRAL_PROGRAM_QUERY = gql`
export const useReferralProgram = () => {
// TODO: get real data
// const { data, loading, error } = useQuery(REFERRAL_PROGRAM_QUERY);
// const { data, loading, error } = useQuery(REFERRAL_PROGRAM_QUERY, {
// fetchPolicy: 'cache-and-network',
// });
const dummyData = {
currentReferralProgram: {
@@ -59,6 +59,7 @@ export const Referrals = () => {
)}
>
<div aria-hidden>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/1x.png"
alt="1x multiplier"
@@ -84,6 +85,7 @@ export const Referrals = () => {
)}
>
<div aria-hidden>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/2x.png"
alt="2x multiplier"
@@ -108,6 +110,7 @@ export const Referrals = () => {
)}
>
<div aria-hidden>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/3x.png"
alt="3x multiplier"
+3 -3
View File
@@ -9,7 +9,7 @@ import { LayoutWithSidebar } from '../components/layouts';
import { LayoutWithSky } from '../client-pages/referrals/layout';
import { ReferralStatistics } from '../client-pages/referrals/referral-statistics';
import { ApplyCodeForm } from '../client-pages/referrals/apply-code-form';
import { CreateCodeForm } from '../client-pages/referrals/create-code-form';
import { CreateCodeContainer } from '../client-pages/referrals/create-code-form';
const LazyHome = dynamic(() => import('../client-pages/home'), {
ssr: false,
@@ -146,7 +146,7 @@ export const routerConfig: RouteObject[] = [
},
{
path: Routes.REFERRALS_CREATE_CODE,
element: <CreateCodeForm />,
element: <CreateCodeContainer />,
},
],
},
@@ -167,7 +167,7 @@ export const ClientRouter = () => {
return (
<Suspense
fallback={
<div className="w-full h-full flex justify-center items-center">
<div className="flex items-center justify-center w-full h-full">
<Loader />
</div>
}
+1
View File
@@ -175,4 +175,5 @@ export const ExternalLinks = {
export const TokenStaticLinks = {
PROPOSAL_PAGE: ':tokenUrl/proposals/:proposalId',
UPDATE_PROPOSAL_PAGE: ':tokenUrl/proposals/propose/update-market',
ASSOCIATE: 'token/associate',
};