chore(trading): disable apply code when applied (#4855)

This commit is contained in:
Art 2023-09-22 13:06:02 +02:00 committed by GitHub
parent 3d2b171de7
commit 41760f2956
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 142 additions and 27 deletions

View File

@ -7,13 +7,21 @@ import {
import type { FieldValues } from 'react-hook-form'; import type { FieldValues } from 'react-hook-form';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import classNames from 'classnames'; import classNames from 'classnames';
import { useSearchParams } from 'react-router-dom'; import { Navigate, useSearchParams } from 'react-router-dom';
import { useEffect, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { Button } from './buttons'; import { Button } from './buttons';
import { useVegaWallet } from '@vegaprotocol/wallet'; import {
useTransactionEventSubscription,
useVegaWallet,
} from '@vegaprotocol/wallet';
import { useReferral } from './hooks/use-referral';
import { Routes } from '../../lib/links';
export const ApplyCodeForm = () => { export const ApplyCodeForm = () => {
const [finalized, setFinalized] = useState<boolean>(false); const [status, setStatus] = useState<
'requested' | 'failed' | 'successful' | null
>(null);
const txHash = useRef<string | null>(null);
const { isReadOnly, pubKey, sendTx } = useVegaWallet(); const { isReadOnly, pubKey, sendTx } = useVegaWallet();
const { const {
register, register,
@ -24,6 +32,9 @@ export const ApplyCodeForm = () => {
} = useForm(); } = useForm();
const [params] = useSearchParams(); const [params] = useSearchParams();
const { data: referee } = useReferral(pubKey, 'referee');
const { data: referrer } = useReferral(pubKey, 'referrer');
useEffect(() => { useEffect(() => {
const code = params.get('code'); const code = params.get('code');
if (code) setValue('code', code); if (code) setValue('code', code);
@ -34,23 +45,67 @@ export const ApplyCodeForm = () => {
return; return;
} }
setStatus('requested');
sendTx(pubKey, { sendTx(pubKey, {
applyReferralCode: { applyReferralCode: {
id: code as string, id: code as string,
}, },
}) })
.then((res) => { .then((res) => {
setFinalized(true); if (!res) {
setError('code', {
type: 'required',
message: 'The transaction could not be sent',
});
}
if (res) {
txHash.current = res.transactionHash.toLowerCase();
}
}) })
.catch((err) => { .catch((err) => {
if (err.message.includes('user rejected')) {
setStatus(null);
} else {
setError('code', { setError('code', {
type: 'required', type: 'required',
message: 'Your code has been rejected', message: 'Your code has been rejected',
}); });
}
}); });
}; };
if (finalized) { 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');
}
}
}
}),
});
if (referee || referrer) {
return <Navigate to={Routes.REFERRALS} />;
}
if (status === 'successful') {
return ( return (
<div className="w-1/2 mx-auto"> <div className="w-1/2 mx-auto">
<h3 className="mb-5 text-xl text-center uppercase calt flex flex-row gap-2 justify-center items-center"> <h3 className="mb-5 text-xl text-center uppercase calt flex flex-row gap-2 justify-center items-center">
@ -63,6 +118,27 @@ export const ApplyCodeForm = () => {
); );
} }
const getButtonProps = () => {
if (isReadOnly || !pubKey) {
return {
disabled: true,
children: 'Apply',
};
}
if (status === 'requested') {
return {
disabled: true,
children: 'Confirm in wallet...',
};
}
return {
disabled: false,
children: 'Apply',
};
};
return ( return (
<div className="w-1/2 mx-auto"> <div className="w-1/2 mx-auto">
<h3 className="mb-5 text-xl text-center uppercase calt"> <h3 className="mb-5 text-xl text-center uppercase calt">
@ -86,13 +162,7 @@ export const ApplyCodeForm = () => {
})} })}
/> />
</label> </label>
<Button <Button className="w-full" type="submit" {...getButtonProps()} />
disabled={isReadOnly || !pubKey}
className="w-full"
type="submit"
>
Apply
</Button>
</form> </form>
{errors.code && ( {errors.code && (
<InputError>{errors.code.message?.toString()}</InputError> <InputError>{errors.code.message?.toString()}</InputError>

View File

@ -38,18 +38,36 @@ export const RainbowButton = ({
const RAINBOW_TAB_STYLE = classNames( const RAINBOW_TAB_STYLE = classNames(
'inline-block', 'inline-block',
'bg-vega-clight-500 dark:bg-vega-cdark-500 hover:bg-vega-clight-400 dark:hover:bg-vega-cdark-400', 'bg-vega-clight-500 dark:bg-vega-cdark-500',
'data-[state="active"]:text-white data-[state="active"]:bg-rainbow data-[state="active"]:hover:bg-none data-[state="active"]:hover:bg-vega-pink-500 dark:data-[state="active"]:hover:bg-vega-pink-500', 'hover:bg-vega-clight-400 dark:hover:bg-vega-cdark-400',
'[&.active]:text-white [&.active]:bg-rainbow [&.active]:hover:bg-none [&.active]:hover:bg-vega-pink-500 dark:[&.active]:hover:bg-vega-pink-500', 'data-[state="active"]:text-white data-[state="active"]:bg-rainbow',
'data-[state="active"]:hover:bg-none data-[state="active"]:hover:bg-vega-pink-500 dark:data-[state="active"]:hover:bg-vega-pink-500',
'[&.active]:text-white [&.active]:bg-rainbow',
'[&.active]:hover:bg-none [&.active]:hover:bg-vega-pink-500 dark:[&.active]:hover:bg-vega-pink-500',
'px-5 py-3', 'px-5 py-3',
'first:rounded-tl-lg last:rounded-tr-lg' 'first:rounded-tl-lg last:rounded-tr-lg'
); );
const DISABLED_RAINBOW_TAB_STYLE = classNames(
'pointer-events-none',
'text-vega-clight-100 dark:text-vega-cdark-100',
'data-[state="active"]:text-white',
'[&.active]:text-white'
);
export const RainbowTabButton = forwardRef< export const RainbowTabButton = forwardRef<
HTMLButtonElement, HTMLButtonElement,
ButtonHTMLAttributes<HTMLButtonElement> { disabled?: boolean } & ButtonHTMLAttributes<HTMLButtonElement>
>(({ children, ...props }, ref) => ( >(({ children, className, disabled = false, ...props }, ref) => (
<button ref={ref} className={RAINBOW_TAB_STYLE} {...props}> <button
ref={ref}
className={classNames(
RAINBOW_TAB_STYLE,
{ 'pointer-events-none': disabled },
className
)}
{...props}
>
{children} {children}
</button> </button>
)); ));
@ -58,9 +76,19 @@ RainbowTabButton.displayName = 'RainbowTabButton';
export const RainbowTabLink = ({ export const RainbowTabLink = ({
to, to,
children, children,
className,
disabled = false,
...props ...props
}: ComponentProps<typeof NavLink>) => ( }: { disabled?: boolean } & ComponentProps<typeof NavLink>) => (
<NavLink to={to} className={RAINBOW_TAB_STYLE} {...props}> <NavLink
to={to}
className={classNames(
RAINBOW_TAB_STYLE,
disabled && DISABLED_RAINBOW_TAB_STYLE,
typeof className === 'string' ? className : undefined
)}
{...props}
>
{children} {children}
</NavLink> </NavLink>
); );

View File

@ -9,8 +9,14 @@ import { TiersContainer } from './tiers';
import { RainbowTabLink } from './buttons'; import { RainbowTabLink } from './buttons';
import { Outlet } from 'react-router-dom'; import { Outlet } from 'react-router-dom';
import { Routes } from '../../lib/links'; import { Routes } from '../../lib/links';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useReferral } from './hooks/use-referral';
export const Referrals = () => { export const Referrals = () => {
const { pubKey } = useVegaWallet();
const { data: referee } = useReferral(pubKey, 'referee');
const { data: referrer } = useReferral(pubKey, 'referrer');
return ( return (
<> <>
<LandingBanner /> <LandingBanner />
@ -19,7 +25,10 @@ export const Referrals = () => {
<RainbowTabLink end to={Routes.REFERRALS}> <RainbowTabLink end to={Routes.REFERRALS}>
Your referrals Your referrals
</RainbowTabLink> </RainbowTabLink>
<RainbowTabLink to={Routes.REFERRALS_APPLY_CODE}> <RainbowTabLink
disabled={Boolean(referee || referrer)}
to={Routes.REFERRALS_APPLY_CODE}
>
Apply a code Apply a code
</RainbowTabLink> </RainbowTabLink>
</div> </div>

View File

@ -465,6 +465,11 @@ export const isTransferTransaction = (
transaction: Transaction transaction: Transaction
): transaction is TransferBody => 'transfer' in transaction; ): transaction is TransferBody => 'transfer' in transaction;
export const isReferralRelatedTransaction = (
transaction: Transaction
): transaction is CreateReferralSet | ApplyReferralCode =>
'createReferralSet' in transaction || 'applyReferralCode' in transaction;
export interface TransactionResponse { export interface TransactionResponse {
transactionHash: string; transactionHash: string;
signature: string; // still to be added by core signature: string; // still to be added by core

View File

@ -25,6 +25,7 @@ import {
VegaTxStatus, VegaTxStatus,
isStopOrdersSubmissionTransaction, isStopOrdersSubmissionTransaction,
isStopOrdersCancellationTransaction, isStopOrdersCancellationTransaction,
isReferralRelatedTransaction,
} from '@vegaprotocol/wallet'; } from '@vegaprotocol/wallet';
import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit'; import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit';
import { ToastHeading } from '@vegaprotocol/ui-toolkit'; import { ToastHeading } from '@vegaprotocol/ui-toolkit';
@ -97,6 +98,7 @@ const isTransactionTypeSupported = (tx: VegaStoredTxState) => {
const editOrder = isOrderAmendmentTransaction(tx.body); const editOrder = isOrderAmendmentTransaction(tx.body);
const batchMarketInstructions = isBatchMarketInstructionsTransaction(tx.body); const batchMarketInstructions = isBatchMarketInstructionsTransaction(tx.body);
const transfer = isTransferTransaction(tx.body); const transfer = isTransferTransaction(tx.body);
const referral = isReferralRelatedTransaction(tx.body);
return ( return (
withdraw || withdraw ||
submitOrder || submitOrder ||
@ -105,7 +107,8 @@ const isTransactionTypeSupported = (tx: VegaStoredTxState) => {
cancelStopOrder || cancelStopOrder ||
editOrder || editOrder ||
batchMarketInstructions || batchMarketInstructions ||
transfer transfer ||
referral
); );
}; };