Compare commits

...
16 changed files with 155 additions and 5 deletions
@@ -12,6 +12,7 @@ export const WelcomeDialog = () => {
return (
<Dialog
id="welcome-dialog"
open={dismissed ? false : dialogOpen}
title={
<span className="font-alpha calt" data-testid="welcome-title">
@@ -82,6 +82,7 @@ export const AssetDetailsDialog = ({
return (
<Dialog
id="asset-details"
title={title}
icon={<VegaIcon name={VegaIconNames.INFO} />}
open={open}
@@ -9,7 +9,7 @@ export const NodeSwitcherDialog = ({
setOpen: (x: boolean) => void;
}) => {
return (
<Dialog open={open} onChange={setOpen} size="large">
<Dialog open={open} onChange={setOpen} size="large" id="node-switcher">
<NodeSwitcher closeDialog={() => setOpen(false)} />
</Dialog>
);
@@ -26,6 +26,7 @@ export const OracleDialog = ({
const oracleMarkets = useOracleMarkets(provider);
return (
<Dialog
id="oracle-dialog"
title={
<OracleProfileTitle
provider={provider}
@@ -55,6 +55,7 @@ export const OrderEditDialog = ({
return (
<Dialog
id="order-edit-dialog"
open={isOpen}
onChange={onChange}
title={t('Edit order')}
@@ -35,7 +35,12 @@ export const OrderViewDialog = ({
}: OrderViewDialogProps) => {
const [, setCopied] = useCopyTimeout();
return (
<Dialog open={isOpen} title={t('Order details')} onChange={onChange}>
<Dialog
open={isOpen}
title={t('Order details')}
onChange={onChange}
id="order-view-dialog"
>
<KeyValueTable>
<KeyValueTableRow key={'order-market'}>
<div data-testid={'order-market-label'}>{t('Market')}</div>
@@ -0,0 +1,66 @@
import { useState } from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { Dialog } from './dialog';
const QueuedDialogs = () => {
const [open1, setOpen1] = useState(false);
const [open2, setOpen2] = useState(false);
const [open3, setOpen3] = useState(false);
const onChange = (open: boolean) => void 0;
return (
<>
<Dialog
open={open1}
dataTestId="dialog1"
onChange={onChange}
id="dialog1"
>
Dialog 1
</Dialog>
<Dialog
open={open2}
dataTestId="dialog2"
onChange={onChange}
id="dialog2"
>
Dialog 2
</Dialog>
<Dialog
open={open3}
dataTestId="dialog3"
onChange={onChange}
id="dialog3"
>
Dialog 3
</Dialog>
<button onClick={() => setOpen1(!open1)}>Open 1</button>
<button onClick={() => setOpen2(!open2)}>Open 2</button>
<button onClick={() => setOpen3(!open3)}>Open 3</button>
</>
);
};
describe('Dialog module', () => {
it('dialogs should be queued', async () => {
render(<QueuedDialogs />);
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
fireEvent.click(screen.getByText('Open 1'));
expect(screen.getByTestId('dialog1')).toBeInTheDocument();
fireEvent.click(screen.getByText('Open 2'));
expect(screen.queryByTestId('dialog1')).not.toBeInTheDocument();
expect(screen.getByTestId('dialog2')).toBeInTheDocument();
fireEvent.click(screen.getByText('Open 3'));
expect(screen.queryByTestId('dialog2')).not.toBeInTheDocument();
expect(screen.getByTestId('dialog3')).toBeInTheDocument();
fireEvent.click(screen.getByText('Open 3'));
expect(screen.queryByTestId('dialog3')).not.toBeInTheDocument();
expect(screen.getByTestId('dialog2')).toBeInTheDocument();
fireEvent.click(screen.getByText('Open 2'));
expect(screen.queryByTestId('dialog2')).not.toBeInTheDocument();
expect(screen.getByTestId('dialog1')).toBeInTheDocument();
fireEvent.click(screen.getByText('Open 1'));
expect(screen.queryByTestId('dialog1')).not.toBeInTheDocument();
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
});
@@ -1,13 +1,59 @@
import { useEffect } from 'react';
import React, { useEffect, useLayoutEffect } from 'react';
import * as DialogPrimitives from '@radix-ui/react-dialog';
import classNames from 'classnames';
import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
import { getIntentBorder } from '../../utils/intent';
import { VegaIcon, VegaIconNames } from '../icon';
import type { ReactNode } from 'react';
import type { Intent } from '../../utils/intent';
interface DialogProps {
type DialogManagerStore = {
openOne: string;
queueOpen: string[];
removeFromOpen: (id: string) => void;
setOpen: (id: string) => void;
};
export const useDialogManagerStore = create<DialogManagerStore>()(
subscribeWithSelector((set, get) => ({
openOne: '',
queueOpen: [],
removeFromOpen: (id) => {
const queueOpen = get().queueOpen;
let openOne = get().openOne;
const ind = queueOpen.indexOf(id);
if (ind > -1) {
queueOpen.splice(ind, 1);
}
if (openOne === id) {
openOne = queueOpen.shift() || '';
}
set({ queueOpen, openOne });
},
setOpen: (id: string) =>
set((store) => {
let openOne = store.openOne;
const queueOpen = store.queueOpen;
if (openOne !== id) {
const oldOne = store.openOne;
openOne = id;
const ind = queueOpen.indexOf(oldOne);
if (oldOne) {
if (ind > -1) {
queueOpen.splice(ind, 1);
}
queueOpen.unshift(oldOne);
}
}
return { queueOpen, openOne };
}),
}))
);
export interface DialogProps {
children: ReactNode;
open: boolean;
onChange?: (isOpen: boolean) => void;
@@ -18,9 +64,30 @@ interface DialogProps {
intent?: Intent;
size?: 'small' | 'medium' | 'large';
dataTestId?: string;
id?: string;
}
export function Dialog({
export const Dialog = ({ open, id, ...props }: DialogProps) => {
const openOne = useDialogManagerStore((store) => store.openOne);
const queueOpen = useDialogManagerStore((store) => store.queueOpen);
const removeFromOpen = useDialogManagerStore((store) => store.removeFromOpen);
const setOpen = useDialogManagerStore((store) => store.setOpen);
useLayoutEffect(() => {
if (id) {
if (open && openOne !== id && queueOpen.indexOf(id) === -1) {
setOpen(id);
} else if (!open && openOne === id && queueOpen.indexOf(id) === -1) {
removeFromOpen(id);
}
}
}, [openOne, id, open, removeFromOpen, setOpen, queueOpen]);
const isOpen = id ? id === openOne : open;
return <DialogInner {...props} open={isOpen} />;
};
export function DialogInner({
children,
open,
onChange,
@@ -82,6 +82,7 @@ export const VegaConnectDialog = ({
return (
<Dialog
id="connect-dialog"
open={vegaWalletDialogOpen}
size="small"
onChange={onVegaWalletDialogChange}
@@ -23,6 +23,7 @@ export const ViewAsDialog = ({ connector }: ViewAsDialogProps) => {
return (
<Dialog
id="view-as-dialog"
open={open}
size="small"
onChange={(open) => {
@@ -21,6 +21,7 @@ export const VegaManageDialog = ({
const { pubKey, pubKeys, selectPubKey, disconnect } = useVegaWallet();
return (
<Dialog
id="wallet-manage-dialog"
title={t('SELECT A VEGA KEY')}
open={dialogOpen}
onChange={setDialogOpen}
@@ -34,6 +34,7 @@ export const VegaTransactionDialog = ({
return (
<Dialog
id="vega-transaction-dialog"
open={isOpen}
onChange={onChange}
intent={computedIntent}
@@ -23,6 +23,7 @@ export const EthereumTransactionDialog = ({
const { status, error, confirmations, txHash } = transaction;
return (
<Dialog
id="ethereum-transaction-dialog"
open={transaction.dialogOpen}
onChange={onChange}
size="small"
@@ -31,6 +31,7 @@ export const Web3ConnectDialog = ({
desiredChainId,
}: Web3ConnectDialogProps) => (
<Dialog
id="web3-connect-wallet"
open={dialogOpen}
onChange={setDialogOpen}
onInteractOutside={(e) => {
@@ -30,6 +30,7 @@ export const WithdrawalApprovalDialog = ({
}: WithdrawalApprovalDialogProps) => {
return (
<Dialog
id="withdrawal-approval-dialog"
title={t('Save withdrawal details')}
icon={<VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />}
open={open}
@@ -15,6 +15,7 @@ export const CreateWithdrawalDialog = () => {
);
return (
<Dialog
id="create-withdrawal-dialog"
title={t('Withdraw')}
open={isOpen && !connectWalletDialogIsOpen}
onChange={(isOpen) => (isOpen ? open() : close())}