diff --git a/packages/trader/src/App/app.tsx b/packages/trader/src/App/app.tsx index 87ce015eddc5..79be0e1500fc 100644 --- a/packages/trader/src/App/app.tsx +++ b/packages/trader/src/App/app.tsx @@ -10,6 +10,7 @@ import initStore from './init-store'; import 'Sass/app.scss'; import type { TCoreStores } from '@deriv/stores/types'; import TraderProviders from '../trader-providers'; +import ModulesProvider from 'Stores/Providers/modules-providers'; type Apptypes = { passthrough: { @@ -31,12 +32,14 @@ const App = ({ passthrough }: Apptypes) => { return ( - - - - - - + + + + + + + + ); }; diff --git a/packages/trader/src/AppV2/Containers/Positions/positions.tsx b/packages/trader/src/AppV2/Containers/Positions/positions.tsx index 41a82df196ae..b4c18cd68e87 100644 --- a/packages/trader/src/AppV2/Containers/Positions/positions.tsx +++ b/packages/trader/src/AppV2/Containers/Positions/positions.tsx @@ -2,8 +2,11 @@ import React from 'react'; import { Localize } from '@deriv/translations'; import { Tab } from '@deriv-com/quill-ui'; import { TPortfolioPosition } from '@deriv/stores/types'; +import useClosedPositions from 'AppV2/Hooks/useClosedPositions'; +import { useModulesStore } from 'Stores/useModulesStores'; import { filterPositions } from '../../Utils/positions-utils'; import PositionsContent from './positions-content'; +import { observer } from '@deriv/stores'; type TPositionsProps = { onRedirectToTrade?: () => void; @@ -55,11 +58,20 @@ const mockPositions = [ }, ] as TPortfolioPosition[]; -const Positions = ({ onRedirectToTrade }: TPositionsProps) => { +const Positions = observer(({ onRedirectToTrade }: TPositionsProps) => { const [contractTypeFilter, setContractTypeFilter] = React.useState([]); const [filteredPositions, setFilteredPositions] = React.useState(mockPositions || []); const [noMatchesFound, setNoMatchesFound] = React.useState(false); + const { positions: positionsStore } = useModulesStore(); + const { closedContractTypeFilter } = positionsStore; + + const { closedPositions } = useClosedPositions({ contractTypes: closedContractTypeFilter }); + + // TODO: remove this line + // eslint-disable-next-line no-console + console.log('closedPositions', closedPositions); + const tabs = [ { id: 'open', @@ -111,6 +123,6 @@ const Positions = ({ onRedirectToTrade }: TPositionsProps) => { ); -}; +}); export default Positions; diff --git a/packages/trader/src/AppV2/Hooks/useClosedPositions.ts b/packages/trader/src/AppV2/Hooks/useClosedPositions.ts new file mode 100644 index 000000000000..e91b3793f862 --- /dev/null +++ b/packages/trader/src/AppV2/Hooks/useClosedPositions.ts @@ -0,0 +1,34 @@ +import { WS } from '@deriv/shared'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { ProfitTable, ProfitTableResponse } from '@deriv/api-types'; + +type TPros = { + contractTypes: string[]; +}; + +const useClosedPositions = ({ contractTypes }: TPros) => { + const [positions, setPositions] = useState>([]); + const [isLoading, setLoading] = React.useState(false); + const positionsRef = useRef>([]); + + const fetch = useCallback(async () => { + setLoading(true); + const data: ProfitTableResponse = await WS.profitTable(50, positionsRef.current.length, { + contract_type: contractTypes.length > 0 ? contractTypes : undefined, + }); + + setLoading(false); + // TODO: handle errors + setPositions(prevPositions => [...prevPositions, ...(data?.profit_table?.transactions ?? [])]); + }, [contractTypes]); + + useEffect(() => { + setPositions([]); + positionsRef.current = []; + fetch(); + }, [fetch, contractTypes]); + + return { closedPositions: positions, isLoading, fetchMore: fetch }; +}; + +export default useClosedPositions; diff --git a/packages/trader/src/AppV2/app.tsx b/packages/trader/src/AppV2/app.tsx index ba2a90e113f8..f6fadef0dd8e 100644 --- a/packages/trader/src/AppV2/app.tsx +++ b/packages/trader/src/AppV2/app.tsx @@ -2,6 +2,7 @@ import React from 'react'; import type { TWebSocket } from 'Types'; import initStore from 'App/init-store'; import type { TCoreStores } from '@deriv/stores/types'; +import ModulesProvider from 'Stores/Providers/modules-providers'; import TraderProviders from '../trader-providers'; import BottomNav from './Components/BottomNav'; import Trade from './Containers/Trade'; @@ -28,12 +29,14 @@ const App = ({ passthrough }: Apptypes) => { return ( - - - - setCurrentPageIdx(0)} /> - - + + + + + setCurrentPageIdx(0)} /> + + + ); }; diff --git a/packages/trader/src/Stores/Modules/Positions/positions-store.ts b/packages/trader/src/Stores/Modules/Positions/positions-store.ts new file mode 100644 index 000000000000..3786fc238f3b --- /dev/null +++ b/packages/trader/src/Stores/Modules/Positions/positions-store.ts @@ -0,0 +1,22 @@ +import { makeObservable, observable, action } from 'mobx'; +import { TRootStore } from 'Types'; +import BaseStore from 'Stores/base-store'; + +export default class PositionsStore extends BaseStore { + openContractTypeFilter: string[] = []; + closedContractTypeFilter: string[] = []; + + constructor({ root_store }: { root_store: TRootStore }) { + super({ root_store }); + + makeObservable(this, { + openContractTypeFilter: observable, + closedContractTypeFilter: observable, + addToClosedContractTypeFilter: action.bound, + }); + } + + addToClosedContractTypeFilter(contractType: string) { + this.closedContractTypeFilter = [...this.closedContractTypeFilter, contractType]; + } +} diff --git a/packages/trader/src/Stores/Modules/Trading/__tests__/trade-store.spec.ts b/packages/trader/src/Stores/Modules/Trading/__tests__/trade-store.spec.ts index cabfca201c7d..9b0b04621e59 100644 --- a/packages/trader/src/Stores/Modules/Trading/__tests__/trade-store.spec.ts +++ b/packages/trader/src/Stores/Modules/Trading/__tests__/trade-store.spec.ts @@ -5,6 +5,7 @@ import { mockStore } from '@deriv/stores'; import TradeStore from '../trade-store'; import { configure } from 'mobx'; import { ContractType } from '../Helpers/contract-type'; +import { TRootStore } from 'Types'; configure({ safeDescriptors: false }); @@ -248,7 +249,7 @@ beforeAll(async () => { common: { server_time: moment('2024-02-26T11:59:59.488Z'), }, - }), + }) as unknown as TRootStore, }); await ContractType.buildContractTypesConfig(symbol); mockedTradeStore.onMount(); diff --git a/packages/trader/src/Stores/Modules/Trading/trade-store.ts b/packages/trader/src/Stores/Modules/Trading/trade-store.ts index dc793ea00544..17a5c5a9a3e8 100644 --- a/packages/trader/src/Stores/Modules/Trading/trade-store.ts +++ b/packages/trader/src/Stores/Modules/Trading/trade-store.ts @@ -50,11 +50,10 @@ import { action, computed, makeObservable, observable, override, reaction, runIn import { createProposalRequests, getProposalErrorField, getProposalInfo } from './Helpers/proposal'; import { getHoveredColor } from './Helpers/barrier-utils'; import BaseStore from '../../base-store'; -import { TTextValueNumber, TTextValueStrings } from 'Types'; +import { TRootStore, TTextValueNumber, TTextValueStrings } from 'Types'; import { ChartBarrierStore } from '../SmartChart/chart-barrier-store'; import debounce from 'lodash.debounce'; import { setLimitOrderBarriers } from './Helpers/limit-orders'; -import type { TCoreStores } from '@deriv/stores/types'; import { ActiveSymbols, ActiveSymbolsRequest, @@ -319,7 +318,7 @@ export default class TradeStore extends BaseStore { is_initial_barrier_applied = false; is_digits_widget_active = false; should_skip_prepost_lifecycle = false; - constructor({ root_store }: { root_store: TCoreStores }) { + constructor({ root_store }: { root_store: TRootStore }) { const local_storage_properties = [ 'amount', 'currency', diff --git a/packages/trader/src/Stores/Modules/index.js b/packages/trader/src/Stores/Modules/index.js deleted file mode 100644 index 27463b9f10eb..000000000000 --- a/packages/trader/src/Stores/Modules/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import TradeStore from './Trading/trade-store'; - -export default class ModulesStore { - constructor(root_store, core_store) { - this.cashier = core_store.modules.cashier; - this.trade = new TradeStore({ root_store }); - } -} diff --git a/packages/trader/src/Stores/Modules/index.ts b/packages/trader/src/Stores/Modules/index.ts new file mode 100644 index 000000000000..2504e498067c --- /dev/null +++ b/packages/trader/src/Stores/Modules/index.ts @@ -0,0 +1,16 @@ +import TradeStore from './Trading/trade-store'; +import PositionsStore from './Positions/positions-store'; +import { TCoreStores } from '@deriv/stores/types'; +import { TRootStore } from 'Types'; + +export default class ModulesStore { + positions: PositionsStore; + trade: TradeStore; + cashier: any; + + constructor(root_store: TRootStore, core_store: TCoreStores) { + this.cashier = core_store.modules.cashier; + this.trade = new TradeStore({ root_store }); + this.positions = new PositionsStore({ root_store }); + } +} diff --git a/packages/trader/src/Stores/Providers/modules-providers.tsx b/packages/trader/src/Stores/Providers/modules-providers.tsx new file mode 100644 index 000000000000..fee7631e0fff --- /dev/null +++ b/packages/trader/src/Stores/Providers/modules-providers.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { StoreProvider } from '@deriv/stores'; +import { ModulesStoreProvider } from 'Stores/useModulesStores'; +import type { TCoreStores } from '@deriv/stores/types'; + +export const ModulesProvider = ({ children, store }: React.PropsWithChildren<{ store: TCoreStores }>) => { + return ( + + {children} + + ); +}; + +export default ModulesProvider; diff --git a/packages/trader/src/Stores/base-store.ts b/packages/trader/src/Stores/base-store.ts index 3d666736ba27..1037acd53796 100644 --- a/packages/trader/src/Stores/base-store.ts +++ b/packages/trader/src/Stores/base-store.ts @@ -1,12 +1,12 @@ import { action, intercept, observable, reaction, toJS, when, makeObservable } from 'mobx'; import { isProduction, isEmptyObject, Validator } from '@deriv/shared'; -import { TCoreStores } from '@deriv/stores/types'; import { getValidationRules } from './Modules/Trading/Constants/validation-rules'; +import { TRootStore } from 'Types'; type TValidationRules = ReturnType | Record; type TBaseStoreOptions = { - root_store: TCoreStores; + root_store: TRootStore; local_storage_properties?: string[]; session_storage_properties?: string[]; validation_rules?: TValidationRules; @@ -38,7 +38,7 @@ export default class BaseStore { pre_switch_account_listener: null | (() => Promise) = null; realAccountSignupEndedDisposer: null | (() => void) = null; real_account_signup_ended_listener: null | (() => Promise) = null; - root_store: TCoreStores; + root_store: TRootStore; session_storage_properties: string[]; store_name = ''; switchAccountDisposer: null | (() => void) = null; diff --git a/packages/trader/src/Stores/useModulesStores.tsx b/packages/trader/src/Stores/useModulesStores.tsx new file mode 100644 index 000000000000..3ac894968fa0 --- /dev/null +++ b/packages/trader/src/Stores/useModulesStores.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { useStore } from '@deriv/stores'; +import ModulesStore from './Modules'; + +const ModulesStoreContext = React.createContext(null); + +export const ModulesStoreProvider = ({ children }: React.PropsWithChildren) => { + const { modules } = useStore(); + return {children}; +}; + +export const useModulesStore = () => { + const store = React.useContext(ModulesStoreContext); + + if (!store) { + throw new Error('useModulesStore must be used within ModulesStoreProvider'); + } + + return store; +}; diff --git a/packages/trader/src/Types/common-prop.type.ts b/packages/trader/src/Types/common-prop.type.ts index 1ef702385b3d..0ff83bdbd3cc 100644 --- a/packages/trader/src/Types/common-prop.type.ts +++ b/packages/trader/src/Types/common-prop.type.ts @@ -19,10 +19,25 @@ import { UpdateContractRequest, } from '@deriv/api-types'; import { TCoreStores } from '@deriv/stores/types'; +import ModulesStore from 'Stores/Modules'; import { useTraderStore } from 'Stores/useTraderStores'; import { Redirect, RouteComponentProps } from 'react-router-dom'; import { TSocketEndpointNames, TSocketResponse } from '../../../api/types'; +export type TRootStore = { + client: TCoreStores['client']; + common: TCoreStores['common']; + modules: ModulesStore; + ui: TCoreStores['ui']; + gtm: TCoreStores['gtm']; + notifications: TCoreStores['notifications']; + contract_replay: TCoreStores['contract_replay']; + contract_trade: TCoreStores['contract_trade']; + portfolio: TCoreStores['portfolio']; + chart_barrier_store: TCoreStores['chart_barrier_store']; + active_symbols: TCoreStores['active_symbols']; +}; + export type TBinaryRoutesProps = { is_logged_in: boolean; is_logging_in: boolean;