diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-limit-amount.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-limit-amount.tsx index 31a0cd0e7..f7c22c6f0 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-limit-amount.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-limit-amount.tsx @@ -1,4 +1,4 @@ -import { FormGroup, Input, InputError } from '@vegaprotocol/ui-toolkit'; +import { FormGroup, Input, NotificationError } from '@vegaprotocol/ui-toolkit'; import { t, toDecimal, validateAmount } from '@vegaprotocol/react-helpers'; import type { DealTicketAmountProps } from './deal-ticket-amount'; @@ -20,17 +20,17 @@ export const DealTicketLimitAmount = ({ const renderError = () => { if (sizeError) { return ( - + {sizeError} - + ); } if (priceError) { return ( - + {priceError} - + ); } diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-market-amount.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-market-amount.tsx index 44cee49dd..ba2ccde89 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-market-amount.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-market-amount.tsx @@ -4,7 +4,7 @@ import { toDecimal, validateAmount, } from '@vegaprotocol/react-helpers'; -import { Input, InputError, Tooltip } from '@vegaprotocol/ui-toolkit'; +import { Input, NotificationError, Tooltip } from '@vegaprotocol/ui-toolkit'; import { isMarketInAuction } from '../../utils'; import type { DealTicketAmountProps } from './deal-ticket-amount'; import { getMarketPrice } from '../../utils/get-price'; @@ -76,12 +76,12 @@ export const DealTicketMarketAmount = ({ {sizeError && ( - {sizeError} - + )} ); diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.spec.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.spec.tsx index db4d33c59..e2609929b 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.spec.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.spec.tsx @@ -1,12 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { VegaWalletContext } from '@vegaprotocol/wallet'; -import { - fireEvent, - render, - screen, - act, - waitFor, -} from '@testing-library/react'; +import { fireEvent, render, screen, act } from '@testing-library/react'; import { generateMarket } from '../../test-helpers'; import { DealTicket } from './deal-ticket'; import * as Schema from '@vegaprotocol/types'; @@ -15,14 +9,6 @@ import type { MockedResponse } from '@apollo/client/testing'; import { MockedProvider } from '@apollo/client/testing'; import type { ChainIdQuery } from '@vegaprotocol/react-helpers'; import { ChainIdDocument, addDecimal } from '@vegaprotocol/react-helpers'; -import * as utils from '../../utils'; - -let mockHasNoBalance = false; -jest.mock('../../hooks/use-has-no-balance', () => { - return { - useHasNoBalance: () => mockHasNoBalance, - }; -}); const market = generateMarket(); const submit = jest.fn(); @@ -148,50 +134,6 @@ describe('DealTicket', () => { ); }); - it('validation should be reset', async () => { - mockHasNoBalance = true; - jest.spyOn(utils, 'validateMarketState').mockReturnValue('Wrong state'); - jest - .spyOn(utils, 'validateMarketTradingMode') - .mockReturnValue('Wrong trading mode'); - const { rerender } = render(generateJsx()); - - await act(async () => { - fireEvent.click(screen.getByTestId('place-order')); - }); - await waitFor(async () => { - expect( - await screen.getByTestId('dealticket-error-message-summary') - ).toHaveTextContent('Wrong state'); - }); - - jest.spyOn(utils, 'validateMarketState').mockReturnValue(true); - await act(async () => { - rerender(generateJsx()); - }); - await act(async () => { - fireEvent.click(screen.getByTestId('place-order')); - }); - await waitFor(async () => { - expect( - await screen.getByTestId('dealticket-error-message-zero-balance') - ).toHaveTextContent('Insufficient balance.'); - }); - - mockHasNoBalance = false; - await act(async () => { - rerender(generateJsx()); - }); - await act(async () => { - fireEvent.click(screen.getByTestId('place-order')); - }); - await waitFor(async () => { - expect( - await screen.getByTestId('dealticket-error-message-summary') - ).toHaveTextContent('Wrong trading mode'); - }); - }); - it('can edit deal ticket', async () => { render(generateJsx()); diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx index b4a12bdb9..47d53b333 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx @@ -15,7 +15,7 @@ import { normalizeOrderSubmission } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet'; import { ExternalLink, - InputError, + NotificationError, Intent, Notification, } from '@vegaprotocol/ui-toolkit'; @@ -282,11 +282,11 @@ const SummaryMessage = memo( if (isReadOnly) { return (
- + { 'You need to connect your own wallet to start trading on this market' } - +
); } @@ -325,9 +325,9 @@ const SummaryMessage = memo( if (errorMessage) { return (
- + {errorMessage} - +
); } diff --git a/libs/deal-ticket/src/components/deal-ticket/expiry-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/expiry-selector.tsx index dcebc4325..687aa7036 100644 --- a/libs/deal-ticket/src/components/deal-ticket/expiry-selector.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/expiry-selector.tsx @@ -1,4 +1,4 @@ -import { FormGroup, Input, InputError } from '@vegaprotocol/ui-toolkit'; +import { FormGroup, Input, NotificationError } from '@vegaprotocol/ui-toolkit'; import { formatForInput } from '@vegaprotocol/react-helpers'; import { t } from '@vegaprotocol/react-helpers'; import type { UseFormRegister } from 'react-hook-form'; @@ -35,9 +35,9 @@ export const ExpirySelector = ({ })} /> {errorMessage && ( - + {errorMessage} - + )} ); diff --git a/libs/deal-ticket/src/components/deal-ticket/time-in-force-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/time-in-force-selector.tsx index a64969d90..20459ecaa 100644 --- a/libs/deal-ticket/src/components/deal-ticket/time-in-force-selector.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/time-in-force-selector.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { FormGroup, - InputError, + NotificationError, Select, Tooltip, } from '@vegaprotocol/ui-toolkit'; @@ -137,9 +137,9 @@ export const TimeInForceSelector = ({ ))} {errorMessage && ( - + {renderError(errorMessage)} - + )} ); diff --git a/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx index c6add5c08..6f5aa3c90 100644 --- a/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx @@ -1,4 +1,8 @@ -import { FormGroup, InputError, Tooltip } from '@vegaprotocol/ui-toolkit'; +import { + FormGroup, + NotificationError, + Tooltip, +} from '@vegaprotocol/ui-toolkit'; import { DataGrid, t } from '@vegaprotocol/react-helpers'; import * as Schema from '@vegaprotocol/types'; import { Toggle } from '@vegaprotocol/ui-toolkit'; @@ -76,9 +80,9 @@ export const TypeSelector = ({ onChange={(e) => onSelect(e.target.value as Schema.OrderType)} /> {errorMessage && ( - + {renderError(errorMessage as MarketModeValidationType)} - + )} ); diff --git a/libs/ui-toolkit/src/components/input-error/input-error.tsx b/libs/ui-toolkit/src/components/input-error/input-error.tsx index efd8084ab..00492b8cb 100644 --- a/libs/ui-toolkit/src/components/input-error/input-error.tsx +++ b/libs/ui-toolkit/src/components/input-error/input-error.tsx @@ -3,39 +3,50 @@ import type { HTMLAttributes } from 'react'; import { Intent } from '../../utils/intent'; import { Notification } from '../notification'; -interface InputErrorInlineProps extends HTMLAttributes { +interface InputErrorProps extends HTMLAttributes { children?: React.ReactNode; intent?: 'danger' | 'warning'; forInput?: string; } -interface InputErrorProps extends HTMLAttributes { +interface NotificationErrorProps extends HTMLAttributes { children?: React.ReactNode; - intent?: Intent; + intent?: Intent | 'danger' | 'warning'; forInput?: string; } -export const InputError = ({ +const getIntent = (intent: Intent | 'danger' | 'warning') => { + switch (intent) { + case 'danger': + return Intent.Danger; + case 'warning': + return Intent.Warning; + default: + return intent; + } +}; + +export const NotificationError = ({ intent = Intent.Danger, children, forInput, -}: InputErrorProps) => { +}: NotificationErrorProps) => { return ( {children}} aria-describedby={forInput} /> ); }; -export const InputErrorInline = ({ +export const InputError = ({ intent = 'danger', children, forInput, ...props -}: InputErrorInlineProps) => { +}: InputErrorProps) => { const effectiveClassName = classNames( 'text-sm flex items-center first-letter:uppercase', 'mt-2',