Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(polymarket): add dismissable reducer and fix ticker #1128

Merged
merged 8 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
jaredvu marked this conversation as resolved.
Show resolved Hide resolved
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
Loading