Skip to content

Commit

Permalink
feat(scaffold-explore): Scaffold explore page (#981)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredvu committed Sep 5, 2024
1 parent 0d07c65 commit 7b8e9c2
Show file tree
Hide file tree
Showing 17 changed files with 620 additions and 29 deletions.
2 changes: 2 additions & 0 deletions src/constants/dialogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export type GeoComplianceDialogProps = {};
export type GlobalCommandDialogProps = {};
export type HelpDialogProps = {};
export type ExternalNavKeplrDialogProps = {};
export type LaunchMarketDialogProps = {};
export type ManageFundsDialogProps = { selectedTransferType?: string };
export type MnemonicExportDialogProps = {};
export type MobileDownloadDialogProps = { mobileAppUrl: string };
Expand Down Expand Up @@ -111,6 +112,7 @@ export const DialogTypes = unionize(
GeoCompliance: ofType<GeoComplianceDialogProps>(),
GlobalCommand: ofType<GlobalCommandDialogProps>(),
Help: ofType<HelpDialogProps>(),
LaunchMarket: ofType<LaunchMarketDialogProps>(),
ManageFunds: ofType<ManageFundsDialogProps>(),
MnemonicExport: ofType<MnemonicExportDialogProps>(),
MobileDownload: ofType<MobileDownloadDialogProps>(),
Expand Down
24 changes: 20 additions & 4 deletions src/hooks/useCurrentMarketId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { LocalStorageKey } from '@/constants/localStorage';
import { DEFAULT_MARKETID, PREDICTION_MARKET } from '@/constants/markets';
import { AppRoute } from '@/constants/routes';

import { useLaunchableMarkets } from '@/hooks/useLaunchableMarkets';
import { useLocalStorage } from '@/hooks/useLocalStorage';

import { getOpenPositions } from '@/state/accountSelectors';
Expand All @@ -31,6 +32,7 @@ export const useCurrentMarketId = () => {
const marketIds = useAppSelector(getMarketIds, shallowEqual);
const hasMarketIds = marketIds.length > 0;
const activeTradeBoxDialog = useAppSelector(getActiveTradeBoxDialog);
const launchableMarkets = useLaunchableMarkets();

const [lastViewedMarket, setLastViewedMarket] = useLocalStorage({
key: LocalStorageKey.LastViewedMarket,
Expand All @@ -54,6 +56,13 @@ export const useCurrentMarketId = () => {
return marketId ?? lastViewedMarket;
}, [hasMarketIds, marketId]);

const isViewingUnlaunchedMarket = useMemo(() => {
if (launchableMarkets.data == null) return false;
return launchableMarkets.data.some((market) => {
return market.id === marketId;
});
}, [marketId, launchableMarkets.data]);

useEffect(() => {
// If v4_markets has not been subscribed to yet or marketId is not specified, default to validId
if (!hasMarketIds || !marketId) {
Expand All @@ -68,7 +77,7 @@ export const useCurrentMarketId = () => {
}
} else {
// If v4_markets has been subscribed to, check if marketId is valid
if (!marketIds.includes(marketId)) {
if (!marketIds.includes(marketId) && !isViewingUnlaunchedMarket) {
// If marketId is not valid (i.e. final settlement), navigate to markets page
navigate(AppRoute.Markets, {
replace: true,
Expand All @@ -95,13 +104,20 @@ export const useCurrentMarketId = () => {
dispatch(closeDialogInTradeBox());
}
}
}, [hasMarketIds, marketId]);
}, [hasMarketIds, isViewingUnlaunchedMarket, marketId, navigate]);

useEffect(() => {
// Check for marketIds otherwise Abacus will silently fail its isMarketValid check
if (hasMarketIds) {
if (isViewingUnlaunchedMarket) {
abacusStateManager.setMarket(DEFAULT_MARKETID);
abacusStateManager.setTradeValue({ value: null, field: null });
} else if (hasMarketIds) {
abacusStateManager.setMarket(marketId ?? DEFAULT_MARKETID);
abacusStateManager.setTradeValue({ value: null, field: null });
}
}, [selectedNetwork, hasMarketIds, marketId]);
}, [isViewingUnlaunchedMarket, selectedNetwork, hasMarketIds, marketId]);

return {
isViewingUnlaunchedMarket,
};
};
42 changes: 40 additions & 2 deletions src/hooks/useLaunchableMarkets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { shallowEqual } from 'react-redux';
import { useAppSelector } from '@/state/appTypes';
import { getMarketIds } from '@/state/perpetualsSelectors';

import { getTickerFromMarketmapId } from '@/lib/assetUtils';

import { useSelectedNetwork } from './useSelectedNetwork';

type MarketMapTicker = {
Expand Down Expand Up @@ -46,6 +48,42 @@ export type MarketMapResponse = {

export type HydratedMarketMap = MarketMapResponse['market_map']['markets'][string] & { id: string };

const MOCK_MARKETMAP_DATA = {
chain_id: '1',
last_updated: '2021-10-12T00:00:00Z',
market_map: {
markets: {
'BAG,raydium,D8r8XTuCrUhLheWeGXSwC3G92RhASficV3YA7B2XWcLv/USD': {
ticker: {
currency_pair: {
Base: 'BAG,raydium,D8r8XTuCrUhLheWeGXSwC3G92RhASficV3YA7B2XWcLv',
Quote: 'USD',
},
decimals: '12',
min_provider_count: '1',
enabled: false,
metadata_JSON:
'{"reference_price":1767877746,"liquidity":205137,"aggregate_ids":[{"venue":"coinmarketcap","ID":"30088"}]}',
},
provider_configs: [
{
name: 'raydium_api',
off_chain_ticker:
'BAG,raydium,D8r8XTuCrUhLheWeGXSwC3G92RhASficV3YA7B2XWcLv/SOL,raydium,So11111111111111111111111111111111111111112',
normalize_by_pair: {
Base: 'SOL',
Quote: 'USD',
},
invert: false,
metadata_JSON:
'{"base_token_vault":{"token_vault_address":"7eLwyCqfhxKLsKeFwcN4JdfspKK22rSC4uQHNy3zWNPB","token_decimals":9},"quote_token_vault":{"token_vault_address":"Cr7Yo8Uf5f8pzMsY3ZwgDFNx85nb3UDvPfQxuWG4acxc","token_decimals":9},"amm_info_address":"Bv7mM5TwLxsukrRrwzEc6TFAj22GAdVCcH5ViAZFNZC","open_orders_address":"Du6ZaABu8cxmCAvwoGMixZgZuw57cCQc8xE8yRenaxL4"}',
},
],
},
},
},
};

export const useMarketMap = () => {
const { selectedNetwork } = useSelectedNetwork();

Expand All @@ -67,14 +105,14 @@ export const useLaunchableMarkets = () => {
const marketIds = useAppSelector(getMarketIds, shallowEqual);

const filteredPotentialMarkets: HydratedMarketMap[] = useMemo(() => {
const marketMap = launchableMarkets.data?.market_map?.markets;
const marketMap = (launchableMarkets.data ?? MOCK_MARKETMAP_DATA)?.market_map?.markets;
if (!marketMap) {
return [];
}

return Object.entries(marketMap)
.map(([id, data]) => ({
id,
id: getTickerFromMarketmapId(id),
...data,
}))
.filter(({ id }) => {
Expand Down
2 changes: 2 additions & 0 deletions src/layout/DialogManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ExternalNavStrideDialog } from '@/views/dialogs/ExternalNavStrideDialog
import { GeoComplianceDialog } from '@/views/dialogs/GeoComplianceDialog';
import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog';
import { HelpDialog } from '@/views/dialogs/HelpDialog';
import { LaunchMarketDialog } from '@/views/dialogs/LaunchMarketDialog';
import { ManageFundsDialog } from '@/views/dialogs/ManageFundsDialog';
import { MnemonicExportDialog } from '@/views/dialogs/MnemonicExportDialog';
import { MobileDownloadDialog } from '@/views/dialogs/MobileDownloadDialog';
Expand Down Expand Up @@ -80,6 +81,7 @@ export const DialogManager = () => {
GlobalCommand: (args) => <GlobalCommandDialog {...args} {...modalProps} />,
Help: (args) => <HelpDialog {...args} {...modalProps} />,
ExternalNavKeplr: (args) => <ExternalNavKeplrDialog {...args} {...modalProps} />,
LaunchMarket: (args) => <LaunchMarketDialog {...args} {...modalProps} />,
ManageFunds: (args) => <ManageFundsDialog {...args} {...modalProps} />,
MnemonicExport: (args) => <MnemonicExportDialog {...args} {...modalProps} />,
MobileDownload: (args) => <MobileDownloadDialog {...args} {...modalProps} />,
Expand Down
26 changes: 25 additions & 1 deletion src/lib/__test__/assetUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { describe, expect, it } from 'vitest';

import { getDisplayableAssetFromBaseAsset, getDisplayableTickerFromMarket } from '../assetUtils';
import {
getDisplayableAssetFromBaseAsset,
getDisplayableTickerFromMarket,
getTickerFromMarketmapId,
} from '../assetUtils';

const ASSET_WITH_DEX_AND_ADDRESS = 'BUFFI,uniswap_v3,0x4c1b1302220d7de5c22b495e78b72f2dd2457d45';

Expand Down Expand Up @@ -65,3 +69,23 @@ describe('getDisplayableTickerFromMarket', () => {
expect(getDisplayableTickerFromMarket('ETH')).toEqual('');
});
});

describe('getTickerFromMarketmapId', () => {
it('should return a market ticker from a basic marketmap id', () => {
expect(getTickerFromMarketmapId('ETH/USD')).toEqual('ETH-USD');
});

it('should return a market ticker from a marketmap id w/ dex', () => {
expect(getTickerFromMarketmapId(`${ASSET_WITH_DEX_AND_ADDRESS}/USD`)).toEqual(
`${ASSET_WITH_DEX_AND_ADDRESS}-USD`
);
});

it('should handle invalid marketmap id', () => {
expect(getTickerFromMarketmapId('ETH')).toEqual('ETH');
});

it('should handle empty marketmap id', () => {
expect(getTickerFromMarketmapId('')).toEqual('');
});
});
4 changes: 4 additions & 0 deletions src/lib/assetUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ export const getDisplayableTickerFromMarket = (market: string): string => {

return `${base}-${quoteAsset}`;
};

export const getTickerFromMarketmapId = (marketmapId: string): string => {
return marketmapId.replace('/', '-');
};
13 changes: 9 additions & 4 deletions src/pages/trade/InnerPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { useAppSelector } from '@/state/appTypes';
import { getSelectedLocale } from '@/state/localizationSelectors';

import abacusStateManager from '@/lib/abacus';
import { isTruthy } from '@/lib/isTruthy';

enum Tab {
Price = 'Price',
Expand All @@ -24,7 +25,11 @@ enum Tab {
Details = 'Details',
}

export const InnerPanel = () => {
export const InnerPanel = ({
isViewingUnlaunchedMarket,
}: {
isViewingUnlaunchedMarket?: boolean;
}) => {
const stringGetter = useStringGetter();
const selectedLocale = useAppSelector(getSelectedLocale);

Expand All @@ -41,7 +46,7 @@ export const InnerPanel = () => {
label: stringGetter({ key: STRING_KEYS.PRICE_CHART_SHORT }),
value: Tab.Price,
},
{
!isViewingUnlaunchedMarket && {
content: (
<DepthChart
onChartClick={({ side, price, size }) => {
Expand All @@ -62,7 +67,7 @@ export const InnerPanel = () => {
label: stringGetter({ key: STRING_KEYS.DEPTH_CHART_SHORT }),
value: Tab.Depth,
},
{
!isViewingUnlaunchedMarket && {
content: <FundingChart selectedLocale={selectedLocale} />,
label: stringGetter({ key: STRING_KEYS.FUNDING_RATE_CHART_SHORT }),
value: Tab.Funding,
Expand All @@ -72,7 +77,7 @@ export const InnerPanel = () => {
label: stringGetter({ key: STRING_KEYS.DETAILS }),
value: Tab.Details,
},
]}
].filter(isTruthy)}
slotToolbar={<MarketLinks />}
withTransitions={false}
/>
Expand Down
Loading

0 comments on commit 7b8e9c2

Please sign in to comment.