Skip to content

Commit

Permalink
fix(polymarket): add dismissable reducer and fix ticker (#1128)
Browse files Browse the repository at this point in the history
Co-authored-by: Bill He <[email protected]>
  • Loading branch information
jaredvu and rosepuppy authored Oct 8, 2024
1 parent 0865e6e commit dded7ef
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 27 deletions.
3 changes: 0 additions & 3 deletions src/constants/localStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ export enum LocalStorageKey {
// Discoverability
HasSeenElectionBannerTRUMPWIN = 'dydx.HasSeenElectionBannerTRUMPWIN',
HasSeenTradeFormMessageTRUMPWIN = 'dydx.HasSeenTradeFormMessageTRUMPWIN',

// Informational
HasSeenPredictionMarketsIntro = 'dydx.HasSeenPredictionMarketsIntro',
}

export const LOCAL_STORAGE_VERSIONS = {
Expand Down
9 changes: 3 additions & 6 deletions src/hooks/useCurrentMarketId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { getSelectedNetwork } from '@/state/appSelectors';
import { useAppDispatch, useAppSelector } from '@/state/appTypes';
import { closeDialogInTradeBox, openDialog } from '@/state/dialogs';
import { getActiveTradeBoxDialog } from '@/state/dialogsSelectors';
import { getHasSeenPredictionMarketIntroDialog } from '@/state/dismissableSelectors';
import { setCurrentMarketId } from '@/state/perpetuals';
import { getMarketIds } from '@/state/perpetualsSelectors';

Expand All @@ -35,19 +36,15 @@ export const useCurrentMarketId = () => {
const launchableMarkets = useLaunchableMarkets();
const activeTradeBoxDialog = useAppSelector(getActiveTradeBoxDialog);
const hasLoadedLaunchableMarkets = launchableMarkets.data.length > 0;
const hasSeenPredictionMarketIntroDialog = useAppSelector(getHasSeenPredictionMarketIntroDialog);

const [lastViewedMarket, setLastViewedMarket] = useLocalStorage({
key: LocalStorageKey.LastViewedMarket,
defaultValue: DEFAULT_MARKETID,
});

const [hasSeenPredictionMarketsIntro] = useLocalStorage({
key: LocalStorageKey.HasSeenPredictionMarketsIntro,
defaultValue: false,
});

const onNavigateToPredictionMarket = () => {
if (!hasSeenPredictionMarketsIntro) {
if (!hasSeenPredictionMarketIntroDialog) {
dispatch(openDialog(DialogTypes.PredictionMarketIntro()));
}
};
Expand Down
6 changes: 4 additions & 2 deletions src/state/_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import appMiddleware from './appMiddleware';
import { assetsSlice } from './assets';
import { configsSlice } from './configs';
import { dialogsSlice } from './dialogs';
import { dismissableSlice } from './dismissable';
import { inputsSlice } from './inputs';
import { layoutSlice } from './layout';
import { localOrdersSlice } from './localOrders';
Expand All @@ -30,6 +31,7 @@ const reducers = {
assets: assetsSlice.reducer,
configs: configsSlice.reducer,
dialogs: dialogsSlice.reducer,
dismissable: dismissableSlice.reducer,
inputs: inputsSlice.reducer,
layout: layoutSlice.reducer,
localization: localizationSlice.reducer,
Expand All @@ -45,9 +47,9 @@ const rootReducer = combineReducers(reducers);

const persistConfig = {
key: 'root',
version: 1,
version: 2,
storage,
whitelist: ['tradingView', 'wallet', 'affiliates'],
whitelist: ['affiliates', 'dismissable', 'tradingView', 'wallet'],
migrate: customCreateMigrate({ debug: process.env.NODE_ENV !== 'production' }),
};

Expand Down
22 changes: 22 additions & 0 deletions src/state/dismissable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';

export interface DismissableState {
hasSeenPredictionMarketIntroDialog: boolean;
}

const initialState: DismissableState = {
hasSeenPredictionMarketIntroDialog: false,
};

export const dismissableSlice = createSlice({
name: 'Dismissable',
initialState,
reducers: {
setHasSeenPredictionMarketIntroDialog: (state, action: PayloadAction<boolean>) => {
state.hasSeenPredictionMarketIntroDialog = action.payload;
},
},
});

export const { setHasSeenPredictionMarketIntroDialog } = dismissableSlice.actions;
4 changes: 4 additions & 0 deletions src/state/dismissableSelectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { type RootState } from './_store';

export const getHasSeenPredictionMarketIntroDialog = (state: RootState) =>
state.dismissable.hasSeenPredictionMarketIntroDialog;
2 changes: 2 additions & 0 deletions src/state/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { MigrationConfig } from 'redux-persist/lib/createMigrate';

import { migration0 } from './migrations/0';
import { migration1 } from './migrations/1';
import { migration2 } from './migrations/2';

export const migrations = {
0: migration0,
1: migration1,
2: migration2,
} as const;

/*
Expand Down
2 changes: 1 addition & 1 deletion src/state/migrations/1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { WalletState } from '../wallet';
import { parseStorageItem } from './utils';

type V1State = PersistedState & { wallet: WalletState };
export type V1State = PersistedState & { wallet: WalletState };
/**
* Move over wallet data from localStorage into redux
* TODO (in future migration): Remove these localStorage items
Expand Down
28 changes: 28 additions & 0 deletions src/state/migrations/2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { PersistedState } from 'redux-persist';

import { DismissableState } from '../dismissable';
import { parseStorageItem } from './utils';

export type V2State = PersistedState & { dismissable: DismissableState };
/**
* Third migration, moving over the hasSeenPredictionMarketsIntro localStorage item
*
*/
export function migration2(state: PersistedState | undefined): V2State {
if (!state) {
throw new Error('state must be defined');
}

const hasSeenPredictionMarketsIntro = parseStorageItem<boolean>(
localStorage.getItem('dydx.HasSeenPredictionMarketsIntro')
);

localStorage.removeItem('dydx.HasSeenPredictionMarketsIntro');

return {
...state,
dismissable: {
hasSeenPredictionMarketIntroDialog: hasSeenPredictionMarketsIntro ?? false,
},
};
}
42 changes: 42 additions & 0 deletions src/state/migrations/__test__/2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { afterEach, describe, expect, it } from 'vitest';

import { V1State } from '../1';
import { migration2 } from '../2';

const V1_STATE: V1State = {
_persist: { version: 1, rehydrated: true },
wallet: {
sourceAccount: {
address: undefined,
chain: undefined,
encryptedSignature: undefined,
walletInfo: undefined,
},
},
};

describe('migration2', () => {
afterEach(() => {
localStorage.clear();
});

it('should add hasSeenPredictionMarketIntroDialog property set to false', () => {
const result = migration2(V1_STATE);
expect(result.dismissable.hasSeenPredictionMarketIntroDialog).toBe(false);
});

it('should overwrite hasSeenPredictionMarketIntroDialog if it already exists', () => {
const result = migration2(V1_STATE);
expect(result.dismissable.hasSeenPredictionMarketIntroDialog).toBe(false);
});

it('should copy localStorage values to dismissable object', () => {
localStorage.setItem('dydx.HasSeenPredictionMarketsIntro', 'true');

const result = migration2(V1_STATE);

expect(result.dismissable.hasSeenPredictionMarketIntroDialog).toBe(true);
// Check if localStorage items were removed
expect(localStorage.getItem('dydx.HasSeenPredictionMarketsIntro')).toBeNull();
});
});
9 changes: 2 additions & 7 deletions src/views/MarketDetails/CurrentMarketDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { MarketDetails } from './MarketDetails';

export const CurrentMarketDetails = () => {
const stringGetter = useStringGetter();
const { configs, displayId, market } = useAppSelector(getCurrentMarketData, shallowEqual) ?? {};
const { configs, displayId } = useAppSelector(getCurrentMarketData, shallowEqual) ?? {};
const { id, name, resources } = useAppSelector(getCurrentMarketAssetData, shallowEqual) ?? {};

if (!configs) return null;
Expand Down Expand Up @@ -50,15 +50,10 @@ export const CurrentMarketDetails = () => {
);

const items = [
{
key: 'market-name',
label: stringGetter({ key: STRING_KEYS.MARKET_NAME }),
value: displayId,
},
{
key: 'ticker',
label: stringGetter({ key: STRING_KEYS.TICKER }),
value: market,
value: displayId,
},
{
key: 'market-type',
Expand Down
21 changes: 13 additions & 8 deletions src/views/dialogs/PredictionMarketIntroDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { useCallback, useState } from 'react';

import { useDispatch } from 'react-redux';
import styled from 'styled-components';

import { ButtonAction } from '@/constants/buttons';
import type { DialogProps, PredictionMarketIntroDialogProps } from '@/constants/dialogs';
import { LocalStorageKey } from '@/constants/localStorage';
import { STRING_KEYS } from '@/constants/localization';

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

import { Button } from '@/components/Button';
Expand All @@ -16,20 +15,26 @@ import { Dialog } from '@/components/Dialog';
import { Icon, IconName } from '@/components/Icon';
import { NewTag } from '@/components/Tag';

import { setHasSeenPredictionMarketIntroDialog } from '@/state/dismissable';

export const PredictionMarketIntroDialog = ({
setIsOpen,
}: DialogProps<PredictionMarketIntroDialogProps>) => {
const stringGetter = useStringGetter();
const [doNotShowAgain, setDoNotShowAgain] = useState(false);
const [, setHasSeenPredictionMarketsIntro] = useLocalStorage({
key: LocalStorageKey.HasSeenPredictionMarketsIntro,
defaultValue: false,
});
const dispatch = useDispatch();

const onDismissPredictionMarketsIntro = useCallback(() => {
dispatch(setHasSeenPredictionMarketIntroDialog(true));
}, [dispatch]);

const onContinue = useCallback(() => {
setHasSeenPredictionMarketsIntro(doNotShowAgain);
if (doNotShowAgain) {
onDismissPredictionMarketsIntro();
}

setIsOpen(false);
}, [doNotShowAgain, setIsOpen, setHasSeenPredictionMarketsIntro]);
}, [doNotShowAgain, setIsOpen, onDismissPredictionMarketsIntro]);

const renderPoint = ({
icon,
Expand Down

0 comments on commit dded7ef

Please sign in to comment.