Feat/439 simple market list live update (#503)
* feat: [simple-app] - simple market list - improvements in apollo client * feat: [simple-app] - simple market list - add live update for state and price change * feat: [simple-app] - simple market list - add live update for state and price change * feat: [simple-app] - simple market list - add intersection observer, small improvements * feat: [simple-app] - simple market list - small improvements after review feedback * feat: [simple-app] - simple market list - small improvements after review feedback Co-authored-by: maciek <maciek@vegaprotocol.io>
This commit is contained in:
parent
3defb50739
commit
7b19d5e5e8
@ -1,4 +1,7 @@
|
|||||||
import '@testing-library/jest-dom';
|
import '@testing-library/jest-dom';
|
||||||
|
import { defaultFallbackInView } from 'react-intersection-observer';
|
||||||
|
|
||||||
|
defaultFallbackInView(true);
|
||||||
|
|
||||||
Object.defineProperty(window, 'matchMedia', {
|
Object.defineProperty(window, 'matchMedia', {
|
||||||
writable: true,
|
writable: true,
|
||||||
|
@ -43,7 +43,7 @@ function App() {
|
|||||||
<ApolloProvider client={client}>
|
<ApolloProvider client={client}>
|
||||||
<VegaWalletProvider>
|
<VegaWalletProvider>
|
||||||
<AppLoader>
|
<AppLoader>
|
||||||
<div className="h-full dark:bg-black dark:text-white-60 bg-white text-black-60 grid grid-rows-[min-content,1fr]">
|
<div className="max-h-full min-h-full dark:bg-black dark:text-white-60 bg-white text-black-60 grid grid-rows-[min-content,1fr]">
|
||||||
<div className="flex items-stretch border-b-[7px] border-vega-yellow">
|
<div className="flex items-stretch border-b-[7px] border-vega-yellow">
|
||||||
<DrawerToggle
|
<DrawerToggle
|
||||||
onToggle={onToggle}
|
onToggle={onToggle}
|
||||||
|
@ -10,5 +10,5 @@ export const DrawerContainer = ({ children }: Props) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const DrawerWrapper = ({ children }: Props) => (
|
export const DrawerWrapper = ({ children }: Props) => (
|
||||||
<div className="flex">{children}</div>
|
<div className="flex dark:bg-black">{children}</div>
|
||||||
);
|
);
|
||||||
|
27
apps/simple-trading-app/src/app/components/simple-market-list/__generated__/CandleLive.ts
generated
Normal file
27
apps/simple-trading-app/src/app/components/simple-market-list/__generated__/CandleLive.ts
generated
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL subscription operation: CandleLive
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface CandleLive_candles {
|
||||||
|
__typename: "Candle";
|
||||||
|
/**
|
||||||
|
* Close price (uint64)
|
||||||
|
*/
|
||||||
|
close: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CandleLive {
|
||||||
|
/**
|
||||||
|
* Subscribe to the candles updates
|
||||||
|
*/
|
||||||
|
candles: CandleLive_candles;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CandleLiveVariables {
|
||||||
|
marketId: string;
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
// @generated
|
// @generated
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { Interval, MarketState } from "@vegaprotocol/types";
|
import { MarketState } from "@vegaprotocol/types";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: SimpleMarkets
|
// GraphQL query operation: SimpleMarkets
|
||||||
@ -117,6 +117,5 @@ export interface SimpleMarkets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SimpleMarketsVariables {
|
export interface SimpleMarketsVariables {
|
||||||
CandleInterval: Interval;
|
|
||||||
CandleSince: string;
|
CandleSince: string;
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,9 @@ const MARKET_DATA_FRAGMENT = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const MARKETS_QUERY = gql`
|
export const MARKETS_QUERY = gql`
|
||||||
${MARKET_DATA_FRAGMENT}
|
${MARKET_DATA_FRAGMENT}
|
||||||
query SimpleMarkets($CandleInterval: Interval!, $CandleSince: String!) {
|
query SimpleMarkets($CandleSince: String!) {
|
||||||
markets {
|
markets {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
@ -41,7 +41,7 @@ const MARKETS_QUERY = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
candles(interval: $CandleInterval, since: $CandleSince) {
|
candles(interval: I1H, since: $CandleSince) {
|
||||||
open
|
open
|
||||||
close
|
close
|
||||||
}
|
}
|
||||||
@ -58,6 +58,14 @@ const MARKET_DATA_SUB = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const CANDLE_SUB = gql`
|
||||||
|
subscription CandleLive($marketId: ID!) {
|
||||||
|
candles(marketId: $marketId, interval: I1H) {
|
||||||
|
close
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const update = (
|
const update = (
|
||||||
draft: SimpleMarkets_markets[],
|
draft: SimpleMarkets_markets[],
|
||||||
delta: SimpleMarketDataSub_marketData
|
delta: SimpleMarketDataSub_marketData
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
import { MarketState } from '@vegaprotocol/types';
|
import { MarketState } from '@vegaprotocol/types';
|
||||||
import SimpleMarketList from './simple-market-list';
|
import SimpleMarketList from './simple-market-list';
|
||||||
|
import { MARKETS_QUERY } from './data-provider';
|
||||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||||
|
import type { SimpleMarkets } from './__generated__/SimpleMarkets';
|
||||||
|
|
||||||
const mockedNavigate = jest.fn();
|
const mockedNavigate = jest.fn();
|
||||||
|
|
||||||
@ -12,11 +15,8 @@ jest.mock('react-router-dom', () => ({
|
|||||||
useNavigate: () => mockedNavigate,
|
useNavigate: () => mockedNavigate,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('./data-provider', () => jest.fn());
|
jest.mock('date-fns', () => ({
|
||||||
|
subDays: () => new Date('2022-06-02T11:11:21.721Z'),
|
||||||
jest.mock('@vegaprotocol/react-helpers', () => ({
|
|
||||||
useDataProvider: jest.fn(),
|
|
||||||
t: (txt: string) => txt,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('SimpleMarketList', () => {
|
describe('SimpleMarketList', () => {
|
||||||
@ -24,16 +24,31 @@ describe('SimpleMarketList', () => {
|
|||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be properly renderer as empty', () => {
|
it('should be properly renderer as empty', async () => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
const mocks: MockedResponse<SimpleMarkets> = {
|
||||||
(useDataProvider as unknown as jest.SpyInstance<any>).mockImplementation(
|
request: {
|
||||||
() => ({ data: [], error: false, loading: false })
|
query: MARKETS_QUERY,
|
||||||
|
variables: {
|
||||||
|
CandleSince: '2022-06-02T11:11:21.721Z',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: { markets: [] },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
render(
|
||||||
|
<MockedProvider mocks={[mocks]}>
|
||||||
|
<SimpleMarketList />
|
||||||
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
render(<SimpleMarketList />);
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
|
|
||||||
expect(screen.getByText('No data to display')).toBeInTheDocument();
|
expect(screen.getByText('No data to display')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be properly rendered with some data', () => {
|
it('should be properly rendered with some data', async () => {
|
||||||
const data = [
|
const data = [
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
@ -76,11 +91,26 @@ describe('SimpleMarketList', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
] as unknown as SimpleMarkets_markets[];
|
] as unknown as SimpleMarkets_markets[];
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
(useDataProvider as unknown as jest.SpyInstance<any>).mockImplementation(
|
const mocks: MockedResponse<SimpleMarkets> = {
|
||||||
() => ({ data, error: false, loading: false })
|
request: {
|
||||||
|
query: MARKETS_QUERY,
|
||||||
|
variables: {
|
||||||
|
CandleSince: '2022-06-02T11:11:21.721Z',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: { markets: data },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MockedProvider mocks={[mocks]}>
|
||||||
|
<SimpleMarketList />
|
||||||
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
render(<SimpleMarketList />);
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
|
|
||||||
expect(screen.getByRole('list')).toBeInTheDocument();
|
expect(screen.getByRole('list')).toBeInTheDocument();
|
||||||
expect(screen.getAllByRole('listitem')).toHaveLength(2);
|
expect(screen.getAllByRole('listitem')).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { subDays } from 'date-fns';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import { t } from '@vegaprotocol/react-helpers';
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
import { AsyncRenderer, Lozenge, Splash } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Lozenge, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import type { MarketState } from '@vegaprotocol/types';
|
||||||
import SimpleMarketPercentChange from './simple-market-percent-change';
|
import SimpleMarketPercentChange from './simple-market-percent-change';
|
||||||
import SimpleMarketExpires from './simple-market-expires';
|
import SimpleMarketExpires from './simple-market-expires';
|
||||||
import DataProvider from './data-provider';
|
import DataProvider from './data-provider';
|
||||||
@ -11,18 +13,36 @@ import { MARKET_STATUS } from './constants';
|
|||||||
|
|
||||||
const SimpleMarketList = () => {
|
const SimpleMarketList = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const statusesRef = useRef<Record<string, MarketState | ''>>({});
|
||||||
const variables = useMemo(
|
const variables = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
CandleInterval: 'I1H',
|
CandleSince: subDays(Date.now(), 1).toJSON(),
|
||||||
CandleSince: new Date(Date.now() - 24 * 60 * 60 * 1000).toJSON(),
|
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
const update = useCallback(
|
||||||
|
(delta) => {
|
||||||
|
if (statusesRef.current[delta.market.id] !== delta.market.state) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[statusesRef]
|
||||||
|
);
|
||||||
|
|
||||||
const { data, error, loading } = useDataProvider(
|
const { data, error, loading } = useDataProvider(
|
||||||
DataProvider,
|
DataProvider,
|
||||||
undefined, // @TODO - if we need a live update in the future
|
update,
|
||||||
variables
|
variables
|
||||||
);
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
const statuses: Record<string, MarketState | ''> = {};
|
||||||
|
data?.forEach((market) => {
|
||||||
|
statuses[market.id] = market.data?.market.state || '';
|
||||||
|
});
|
||||||
|
statusesRef.current = statuses;
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
const onClick = useCallback(
|
const onClick = useCallback(
|
||||||
(marketId) => {
|
(marketId) => {
|
||||||
navigate(`/trading/${marketId}`);
|
navigate(`/trading/${marketId}`);
|
||||||
@ -52,7 +72,10 @@ const SimpleMarketList = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-full grid sm:grid-rows-2">
|
<div className="w-full grid sm:grid-rows-2">
|
||||||
<div>
|
<div>
|
||||||
<SimpleMarketPercentChange candles={market.candles} />
|
<SimpleMarketPercentChange
|
||||||
|
candles={market.candles}
|
||||||
|
marketId={market.id}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Lozenge
|
<Lozenge
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { theme } from '@vegaprotocol/tailwindcss-config';
|
import { theme } from '@vegaprotocol/tailwindcss-config';
|
||||||
|
import { MockedProvider } from '@apollo/react-testing';
|
||||||
import SimpleMarketPercentChange from './simple-market-percent-change';
|
import SimpleMarketPercentChange from './simple-market-percent-change';
|
||||||
import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets';
|
import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets';
|
||||||
|
|
||||||
@ -8,12 +9,20 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
|||||||
let candles: (SimpleMarkets_markets_candles | null)[] | null;
|
let candles: (SimpleMarkets_markets_candles | null)[] | null;
|
||||||
it('empty array', () => {
|
it('empty array', () => {
|
||||||
candles = [];
|
candles = [];
|
||||||
render(<SimpleMarketPercentChange candles={candles} />);
|
render(
|
||||||
|
<MockedProvider>
|
||||||
|
<SimpleMarketPercentChange candles={candles} marketId={'1'} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
expect(screen.getByText('-')).toBeInTheDocument();
|
expect(screen.getByText('-')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
it('null', () => {
|
it('null', () => {
|
||||||
candles = null;
|
candles = null;
|
||||||
render(<SimpleMarketPercentChange candles={candles} />);
|
render(
|
||||||
|
<MockedProvider>
|
||||||
|
<SimpleMarketPercentChange candles={candles} marketId={'1'} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
expect(screen.getByText('-')).toBeInTheDocument();
|
expect(screen.getByText('-')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
it('an appreciated one', () => {
|
it('an appreciated one', () => {
|
||||||
@ -22,7 +31,11 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
|||||||
{ close: '100' } as SimpleMarkets_markets_candles,
|
{ close: '100' } as SimpleMarkets_markets_candles,
|
||||||
null,
|
null,
|
||||||
];
|
];
|
||||||
render(<SimpleMarketPercentChange candles={candles} />);
|
render(
|
||||||
|
<MockedProvider>
|
||||||
|
<SimpleMarketPercentChange candles={candles} marketId={'1'} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
expect(screen.getByText('100.000%')).toBeInTheDocument();
|
expect(screen.getByText('100.000%')).toBeInTheDocument();
|
||||||
expect(screen.getByText('100.000%')).toHaveStyle(
|
expect(screen.getByText('100.000%')).toHaveStyle(
|
||||||
`color: ${theme.colors.vega.green}`
|
`color: ${theme.colors.vega.green}`
|
||||||
@ -34,7 +47,11 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
|||||||
{ close: '50' } as SimpleMarkets_markets_candles,
|
{ close: '50' } as SimpleMarkets_markets_candles,
|
||||||
null,
|
null,
|
||||||
];
|
];
|
||||||
render(<SimpleMarketPercentChange candles={candles} />);
|
render(
|
||||||
|
<MockedProvider>
|
||||||
|
<SimpleMarketPercentChange candles={candles} marketId={'1'} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
expect(screen.getByText('-50.000%')).toBeInTheDocument();
|
expect(screen.getByText('-50.000%')).toBeInTheDocument();
|
||||||
expect(screen.getByText('-50.000%')).toHaveStyle(
|
expect(screen.getByText('-50.000%')).toHaveStyle(
|
||||||
`color: ${theme.colors.vega.pink}`
|
`color: ${theme.colors.vega.pink}`
|
||||||
|
@ -1,22 +1,34 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { InView } from 'react-intersection-observer';
|
||||||
|
import { useSubscription } from '@apollo/client';
|
||||||
import { theme } from '@vegaprotocol/tailwindcss-config';
|
import { theme } from '@vegaprotocol/tailwindcss-config';
|
||||||
import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets';
|
import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets';
|
||||||
|
import type {
|
||||||
|
CandleLive,
|
||||||
|
CandleLiveVariables,
|
||||||
|
} from './__generated__/CandleLive';
|
||||||
|
import { CANDLE_SUB } from './data-provider';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
candles: (SimpleMarkets_markets_candles | null)[] | null;
|
candles: (SimpleMarkets_markets_candles | null)[] | null;
|
||||||
|
marketId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getChange = (
|
const getChange = (
|
||||||
candles: (SimpleMarkets_markets_candles | null)[] | null
|
candles: (SimpleMarkets_markets_candles | null)[] | null,
|
||||||
|
lastClose?: string
|
||||||
) => {
|
) => {
|
||||||
if (candles) {
|
if (candles) {
|
||||||
const first = parseInt(candles.find((item) => item?.open)?.open || '-1');
|
const first = parseInt(candles.find((item) => item?.open)?.open || '-1');
|
||||||
const last = candles.reduceRight((aggr, item) => {
|
const last =
|
||||||
|
typeof lastClose === 'undefined'
|
||||||
|
? candles.reduceRight((aggr, item) => {
|
||||||
if (aggr === -1 && item?.close) {
|
if (aggr === -1 && item?.close) {
|
||||||
aggr = parseInt(item.close);
|
aggr = parseInt(item.close);
|
||||||
}
|
}
|
||||||
return aggr;
|
return aggr;
|
||||||
}, -1);
|
}, -1)
|
||||||
|
: parseInt(lastClose);
|
||||||
if (first !== -1 && last !== -1) {
|
if (first !== -1 && last !== -1) {
|
||||||
return Number(((last - first) / first) * 100).toFixed(3) + '%';
|
return Number(((last - first) / first) * 100).toFixed(3) + '%';
|
||||||
}
|
}
|
||||||
@ -34,10 +46,25 @@ const getColor = (change: number | string) => {
|
|||||||
return theme.colors.intent.highlight;
|
return theme.colors.intent.highlight;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SimpleMarketPercentChange = ({ candles }: Props) => {
|
const SimpleMarketPercentChangeWrapper = (props: Props) => {
|
||||||
const change = getChange(candles);
|
const [inView, setInView] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
// @ts-ignore falsy wrong type?
|
||||||
|
<InView onChange={setInView}>
|
||||||
|
{inView && <SimpleMarketPercentChange {...props} />}
|
||||||
|
</InView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SimpleMarketPercentChange = ({ candles, marketId }: Props) => {
|
||||||
|
const { data: { candles: { close = undefined } = {} } = {} } =
|
||||||
|
useSubscription<CandleLive, CandleLiveVariables>(CANDLE_SUB, {
|
||||||
|
variables: { marketId },
|
||||||
|
});
|
||||||
|
const change = getChange(candles, close);
|
||||||
const color = getColor(change);
|
const color = getColor(change);
|
||||||
return <p style={{ color }}>{change}</p>;
|
return <p style={{ color }}>{change}</p>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SimpleMarketPercentChange;
|
export default SimpleMarketPercentChangeWrapper;
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
import { ApolloClient, from, HttpLink, InMemoryCache } from '@apollo/client';
|
import {
|
||||||
|
ApolloClient,
|
||||||
|
from,
|
||||||
|
HttpLink,
|
||||||
|
InMemoryCache,
|
||||||
|
split,
|
||||||
|
} from '@apollo/client';
|
||||||
import { onError } from '@apollo/client/link/error';
|
import { onError } from '@apollo/client/link/error';
|
||||||
import { RetryLink } from '@apollo/client/link/retry';
|
import { RetryLink } from '@apollo/client/link/retry';
|
||||||
|
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
|
||||||
|
import { createClient as createWSClient } from 'graphql-ws';
|
||||||
|
import { getMainDefinition } from '@apollo/client/utilities';
|
||||||
|
|
||||||
export function createClient(base?: string) {
|
export function createClient(base?: string) {
|
||||||
if (!base) {
|
if (!base) {
|
||||||
@ -40,6 +49,24 @@ export function createClient(base?: string) {
|
|||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const wsLink = new GraphQLWsLink(
|
||||||
|
createWSClient({
|
||||||
|
url: urlWS.href,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const splitLink = split(
|
||||||
|
({ query }) => {
|
||||||
|
const definition = getMainDefinition(query);
|
||||||
|
return (
|
||||||
|
definition.kind === 'OperationDefinition' &&
|
||||||
|
definition.operation === 'subscription'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
wsLink,
|
||||||
|
httpLink
|
||||||
|
);
|
||||||
|
|
||||||
const errorLink = onError(({ graphQLErrors, networkError }) => {
|
const errorLink = onError(({ graphQLErrors, networkError }) => {
|
||||||
console.log(graphQLErrors);
|
console.log(graphQLErrors);
|
||||||
console.log(networkError);
|
console.log(networkError);
|
||||||
@ -47,7 +74,7 @@ export function createClient(base?: string) {
|
|||||||
|
|
||||||
return new ApolloClient({
|
return new ApolloClient({
|
||||||
connectToDevTools: process.env['NODE_ENV'] === 'development',
|
connectToDevTools: process.env['NODE_ENV'] === 'development',
|
||||||
link: from([errorLink, retryLink, httpLink]),
|
link: from([errorLink, retryLink, splitLink]),
|
||||||
cache,
|
cache,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
"react-hook-form": "^7.27.0",
|
"react-hook-form": "^7.27.0",
|
||||||
"react-i18next": "^11.11.4",
|
"react-i18next": "^11.11.4",
|
||||||
|
"react-intersection-observer": "^9.2.2",
|
||||||
"react-router-dom": "^6.3.0",
|
"react-router-dom": "^6.3.0",
|
||||||
"react-syntax-highlighter": "^15.4.5",
|
"react-syntax-highlighter": "^15.4.5",
|
||||||
"react-use-websocket": "^3.0.0",
|
"react-use-websocket": "^3.0.0",
|
||||||
|
@ -18049,6 +18049,11 @@ react-inspector@^5.1.0:
|
|||||||
is-dom "^1.0.0"
|
is-dom "^1.0.0"
|
||||||
prop-types "^15.0.0"
|
prop-types "^15.0.0"
|
||||||
|
|
||||||
|
react-intersection-observer@^9.2.2:
|
||||||
|
version "9.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.2.2.tgz#4f72487e2e9c62b6a6f55f38c5b0b6b7dc6c196d"
|
||||||
|
integrity sha512-xrFOWo5DbDzayAuDn6WpLrXfw73mvfx4WjuAjjy7dY7jWeTTle5+18nGtvMlR7q0npJanmmh6/CaSaSg4JxTJQ==
|
||||||
|
|
||||||
react-is@17.0.2, react-is@^17.0.1, react-is@^17.0.2:
|
react-is@17.0.2, react-is@^17.0.1, react-is@^17.0.2:
|
||||||
version "17.0.2"
|
version "17.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||||
|
Loading…
Reference in New Issue
Block a user