fix(trading): rewordings in referrals, qusd tooltip, onboarding (#5477)

This commit is contained in:
Art 2023-12-08 15:48:12 +01:00 committed by GitHub
parent 2221e9faca
commit 345be81142
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 129 additions and 72 deletions

View File

@ -18,13 +18,35 @@ 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';
import { ns, useT } from '../../lib/use-t';
import { useFundsAvailable } from './hooks/use-funds-available';
import { ViewType, useSidebar } from '../../components/sidebar';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
import { QUSDTooltip } from './qusd-tooltip';
import { Trans } from 'react-i18next';
const RELOAD_DELAY = 3000;
const SPAM_PROTECTION_ERR = 'SPAM_PROTECTION_ERR';
const SpamProtectionErr = ({
requiredFunds,
}: {
requiredFunds?: string | number | bigint;
}) => {
if (!requiredFunds) return null;
// eslint-disable-next-line react/jsx-no-undef
return (
<Trans
defaults="To protect the network from spam, you must have at least {{requiredFunds}} <0>qUSD</0> of any asset on the network to proceed."
values={{
requiredFunds,
}}
components={[<QUSDTooltip key="qusd" />]}
ns={ns}
/>
);
};
const validateCode = (value: string, t: ReturnType<typeof useT>) => {
const number = +`0x${value}`;
if (!value || value.length !== 64) {
@ -76,7 +98,6 @@ export const ApplyCodeForm = ({ onSuccess }: { onSuccess?: () => void }) => {
setValue,
setError,
watch,
clearErrors,
} = useForm();
const [params] = useSearchParams();
@ -90,32 +111,11 @@ export const ApplyCodeForm = ({ onSuccess }: { onSuccess?: () => void }) => {
*/
const validateFundsAvailable = useCallback(() => {
if (requiredFunds && !isEligible) {
const err = t(
'To protect the network from spam, you must have at least {{requiredFunds}} qUSD of any asset on the network to proceed.',
{
requiredFunds,
}
);
const err = SPAM_PROTECTION_ERR;
return err;
}
return true;
}, [isEligible, requiredFunds, t]);
useEffect(() => {
if (codeField) {
const err = validateFundsAvailable();
if (err !== true) {
setStatus('no-funds');
setError('code', {
type: 'required',
message: err,
});
} else {
setStatus(null);
clearErrors('code');
}
}
}, [clearErrors, codeField, isEligible, setError, validateFundsAvailable]);
}, [isEligible, requiredFunds]);
/**
* Validates the set a user tries to apply to.
@ -140,6 +140,15 @@ export const ApplyCodeForm = ({ onSuccess }: { onSuccess?: () => void }) => {
if (code) setValue('code', code);
}, [params, setValue]);
useEffect(() => {
const err = validateFundsAvailable();
if (err !== true) {
setStatus('no-funds');
} else {
setStatus(null);
}
}, [isEligible, validateFundsAvailable]);
const onSubmit = ({ code }: FieldValues) => {
if (isReadOnly || !pubKey || !code || code.length === 0) {
return;
@ -323,10 +332,26 @@ export const ApplyCodeForm = ({ onSuccess }: { onSuccess?: () => void }) => {
</label>
<RainbowButton variant="border" {...getButtonProps()} />
</form>
{errors.code && (
<InputError className="overflow-auto break-words">
{errors.code.message?.toString()}
{status === 'no-funds' ? (
<InputError intent="warning" className="overflow-auto break-words">
<span>
<SpamProtectionErr requiredFunds={requiredFunds?.toString()} />
</span>
</InputError>
) : (
errors.code && (
<InputError intent="warning" className="overflow-auto break-words">
{errors.code.message === SPAM_PROTECTION_ERR ? (
<span>
<SpamProtectionErr
requiredFunds={requiredFunds?.toString()}
/>
</span>
) : (
errors.code.message?.toString()
)}
</InputError>
)
)}
</div>
{validateCode(codeField, t) === true && previewLoading && !previewData ? (

View File

@ -1,7 +1,7 @@
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useFundsAvailableQuery } from './__generated__/FundsAvailable';
import compact from 'lodash/compact';
import sum from 'lodash/sum';
import BigNumber from 'bignumber.js';
/**
* Gets the funds for given public key and required min for
@ -24,14 +24,16 @@ export const useFundsAvailable = (pubKey?: string) => {
? compact(data.party?.accountsConnection?.edges?.map((e) => e?.node))
: undefined;
const requiredFunds = data
? BigInt(data.networkParameter?.value || '0')
? BigNumber(data.networkParameter?.value || '0')
: undefined;
const sumOfFunds = sum(
fundsAvailable?.filter((fa) => fa.balance).map((fa) => BigInt(fa.balance))
);
const sumOfFunds =
fundsAvailable
?.filter((fa) => fa.balance)
.reduce((sum, fa) => sum.plus(BigNumber(fa.balance)), BigNumber(0)) ||
BigNumber(0);
if (requiredFunds && sumOfFunds >= requiredFunds) {
if (requiredFunds && sumOfFunds.isGreaterThanOrEqualTo(requiredFunds)) {
stopPolling();
}
@ -41,6 +43,6 @@ export const useFundsAvailable = (pubKey?: string) => {
isEligible:
fundsAvailable != null &&
requiredFunds != null &&
sumOfFunds >= requiredFunds,
sumOfFunds.isGreaterThanOrEqualTo(requiredFunds),
};
};

View File

@ -15,7 +15,7 @@ export const LandingBanner = () => {
</div>
<div className="pt-20 sm:w-[50%]">
<h1 className="text-6xl font-alpha calt mb-10">
{t('Vega community referral program')}
{t('Vega community referrals')}
</h1>
<p className="text-lg mb-1">
{t(

View File

@ -0,0 +1,28 @@
import { DocsLinks } from '@vegaprotocol/environment';
import { ExternalLink, Tooltip } from '@vegaprotocol/ui-toolkit';
import { useT } from '../../lib/use-t';
export const QUSDTooltip = () => {
const t = useT();
return (
<Tooltip
description={
<>
<p className="mb-1">
{t(
'qUSD provides a rough USD equivalent of balances across all assets using the value of "Quantum" for that asset'
)}
</p>
{DocsLinks && (
<ExternalLink href={DocsLinks.QUANTUM}>
{t('Find out more')}
</ExternalLink>
)}
</>
}
underline={true}
>
<span>{t('qUSD')}</span>
</Tooltip>
);
};

View File

@ -4,8 +4,6 @@ import {
VegaIcon,
VegaIconNames,
truncateMiddle,
ExternalLink,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
@ -28,10 +26,10 @@ import sortBy from 'lodash/sortBy';
import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { useCurrentEpochInfoQuery } from './hooks/__generated__/Epoch';
import BigNumber from 'bignumber.js';
import { DocsLinks } from '@vegaprotocol/environment';
import { useT, ns } from '../../lib/use-t';
import { Trans } from 'react-i18next';
import { ApplyCodeForm, ApplyCodeFormContainer } from './apply-code-form';
import { QUSDTooltip } from './qusd-tooltip';
export const ReferralStatistics = () => {
const { pubKey } = useVegaWallet();
@ -519,28 +517,3 @@ export const RefereesTable = ({
</>
);
};
export const QUSDTooltip = () => {
const t = useT();
return (
<Tooltip
description={
<>
<p className="mb-1">
{t(
'qUSD provides a rough USD equivalent of balances across all assets using the value of "Quantum" for that asset'
)}
</p>
{DocsLinks && (
<ExternalLink href={DocsLinks.QUANTUM}>
{t('Find out more')}
</ExternalLink>
)}
</>
}
underline={true}
>
<span>{t('qUSD')}</span>
</Tooltip>
);
};

View File

@ -159,11 +159,11 @@ export const TiersContainer = () => {
return (
<>
<h2 className="text-3xl mt-10">{t('Current Program Details')}</h2>
<h2 className="text-3xl mt-10">{t('Current program details')}</h2>
{details?.id && (
<p>
<Trans
defaults="As a result of <0>{{proposal}}</0> the program below is currently active on the Vega network."
defaults="As a result of governance proposal <0>{{proposal}}</0> the program below is currently active on the Vega network."
values={{ proposal: truncateMiddle(details.id) }}
components={[
<ExternalLink

View File

@ -1,17 +1,23 @@
import { useEffect } from 'react';
import { useMatch } from 'react-router-dom';
import { matchPath, useLocation } from 'react-router-dom';
import { Dialog, Intent } from '@vegaprotocol/ui-toolkit';
import { useEnvironment } from '@vegaprotocol/environment';
import { VegaConnectDialog } from '@vegaprotocol/wallet';
import { Connectors } from '../../lib/vega-connectors';
import { useT } from '../../lib/use-t';
import { Links } from '../../lib/links';
import { Routes } from '../../lib/links';
import { RiskMessage } from './risk-message';
import { WelcomeDialogContent } from './welcome-dialog-content';
import { useOnboardingStore } from './use-get-onboarding-step';
import { ensureSuffix } from '@vegaprotocol/utils';
/**
* A list of paths on which the welcome dialog should be omitted.
*/
const OMIT_ON_LIST = [ensureSuffix(Routes.REFERRALS, '/*')];
export const WelcomeDialog = () => {
const isReferrals = useMatch(Links.REFERRALS());
const { pathname } = useLocation();
const t = useT();
const { VEGA_ENV } = useEnvironment();
const dismissed = useOnboardingStore((store) => store.dismissed);
@ -26,10 +32,14 @@ export const WelcomeDialog = () => {
);
useEffect(() => {
if (dismissed) return;
if (isReferrals) return;
const shouldOmit = OMIT_ON_LIST.map((path) =>
matchPath(path, pathname)
).some((m) => !!m);
if (dismissed || shouldOmit) return;
setDialogOpen(true);
}, [dismissed, isReferrals, setDialogOpen]);
}, [dismissed, pathname, setDialogOpen]);
const content = walletDialogOpen ? (
<VegaConnectDialog

View File

@ -4,6 +4,7 @@ import {
shorten,
titlefy,
stripFullStops,
ensureSuffix,
} from './strings';
describe('truncateByChars', () => {
@ -88,3 +89,15 @@ describe('stripFullStops', () => {
});
});
});
describe('ensureSuffix', () => {
it.each([
['', 'abc', 'abc'],
['abc', '', 'abc'],
['def', 'abc', 'abcdef'],
['ąę', 'ae', 'aeąę'],
['🥪', '🍞+🔪=', '🍞+🔪=🥪'],
])('ensures "%s" at the end of "%s": "%s"', (suffix, input, expected) => {
expect(ensureSuffix(input, suffix)).toEqual(expected);
});
});

View File

@ -33,3 +33,9 @@ export function titlefy(words: (string | null | undefined)[]) {
export function stripFullStops(input: string) {
return input.replace(/\./g, '');
}
export function ensureSuffix(input: string, suffix: string) {
const maybeSuffix = input.substring(input.length - suffix.length);
if (maybeSuffix === suffix) return input;
return input + suffix;
}