Skip to content

Conversation

@nijil-deriv
Copy link
Collaborator

🤖 Auto-generated PR

This PR was automatically created by ShiftAI CLI.


chore: remove unclosed AI tag

@nijil-deriv
Copy link
Collaborator Author

nijil-deriv commented Oct 21, 2025

🤖 AI Code Analysis Results

📝 Manual Coding

⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%

0 of 29,242 characters (0%) in newly added lines are AI-generated


📊 Analysis Summary

Metric Value
📁 Files Changed 23
New Lines Added 29,242 chars
🤖 AI Characters 0
📈 AI Percentage 0%

📋 Per-File Breakdown (New Lines Only)

File Lines Added AI Content Percentage
...rketMessage/closed-market-message.tsx 95 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...s/MarketSelector/market-selector.scss 78 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...ts/MarketSelector/market-selector.tsx 275 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
.../Duration/__tests__/duration.spec.tsx 112 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...__tests__/duration_container.spec.tsx 320 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...ents/TradeParameters/Duration/day.tsx 1617 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...t/__tests__/payout-per-point.spec.tsx 691 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...utPerPoint/payout-per-point-wheel.tsx 635 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...ofit-and-stop-loss-container.spec.tsx 282 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...e-profit-and-stop-loss-input.spec.tsx 127 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...t/take-profit-and-stop-loss-input.tsx 1127 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...meters/Stake/__tests__/stake.spec.tsx 579 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...TradeParameters/Stake/stake-input.tsx 2680 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...ainers/Trade/__tests__/trade.spec.tsx 40 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...s/__tests__/useActiveSymbols.spec.tsx 2371 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...ks/__tests__/useContractsFor.spec.tsx 3234 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
.../Hooks/__tests__/useProposal.spec.tsx 10688 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...r/src/AppV2/Hooks/useActiveSymbols.ts 1799 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...er/src/AppV2/Hooks/useContractsFor.ts 330 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...rader/src/AppV2/Hooks/useProposal.tsx 1749 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...s/Modules/Trading/Helpers/proposal.ts 188 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
...Stores/Modules/Trading/trade-store.ts 61 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%
packages/trader/src/trader-providers.tsx 164 chars 0 chars ⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 0%

📝 This PR contains traditional hand-written code.

📊 Raw Data (for dashboard)
{
  "timestamp": "2025-10-22T11:47:55.804Z",
  "repository": "deriv-com/derivatives-trader",
  "branch": "unknown",
  "author": "unknown",
  "summary": {
    "totalCharacters": 29242,
    "aiCharacters": 0,
    "percentage": 0
  },
  "files": [
    {
      "name": "packages/trader/src/AppV2/Components/ClosedMarketMessage/closed-market-message.tsx",
      "totalCharacters": 95,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { toMoment, useIsMounted, WS } from '@deriv/shared';\n    }, [symbol, is_market_closed]);"
    },
    {
      "name": "packages/trader/src/AppV2/Components/MarketSelector/market-selector.scss",
      "totalCharacters": 78,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "    &__skeleton {\n        padding: 0 var(--semantic-spacing-general-sm);\n    }"
    },
    {
      "name": "packages/trader/src/AppV2/Components/MarketSelector/market-selector.tsx",
      "totalCharacters": 275,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "    const { activeSymbols, isLoading } = useActiveSymbols();\n        if (!currentSymbol && !isLoading) {\n        return (\n            <div className='market-selector__skeleton'>\n                <Skeleton.Square width={200} height={42} rounded />\n            </div>\n        );"
    },
    {
      "name": "packages/trader/src/AppV2/Components/TradeParameters/Duration/__tests__/duration.spec.tsx",
      "totalCharacters": 112,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "jest.mock('../day', () => ({\n    __esModule: true,\n    default: jest.fn(() => <div>Mocked DayInput</div>),\n}));\n"
    },
    {
      "name": "packages/trader/src/AppV2/Components/TradeParameters/Duration/__tests__/duration_container.spec.tsx",
      "totalCharacters": 320,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { render, screen } from '@testing-library/react';\njest.mock('../day', () => ({\n    __esModule: true,\n    default: jest.fn(() => <div>Mocked DayInput</div>),\n}));\n\n    it('should render DayInput component when days unit is selected', () => {\n        expect(screen.getByText('Mocked DayInput')).toBeInTheDocument();"
    },
    {
      "name": "packages/trader/src/AppV2/Components/TradeParameters/Duration/day.tsx",
      "totalCharacters": 1617,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { useInvalidateQuery } from '@deriv/api';\nimport { Localize } from '@deriv-com/translations';\nimport { useProposal } from 'AppV2/Hooks/useProposal';\nimport { getClosestTimeToCurrentGMT, getDatePickerStartDate } from 'AppV2/Utils/trade-params-utils';\n        ...(barrier_1 && !is_turbos && !barrier_value ? { barrier_1: Math.round(tick_data?.quote as number) } : {}),\n    const { data: response, error: queryError } = useProposal({\n        proposal_request_values: new_values,\n        contract_..."
    },
    {
      "name": "packages/trader/src/AppV2/Components/TradeParameters/PayoutPerPoint/__tests__/payout-per-point.spec.tsx",
      "totalCharacters": 691,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "jest.mock('../payout-per-point-wheel', () => ({\n    __esModule: true,\n    default: jest.fn(({ barrier, onPayoutPerPointSelect, onClose, payout_per_point_list }) => (\n        <div>\n            <p>WheelPicker</p>\n            <ul>\n                {payout_per_point_list.map(({ value }: { value: string }) => (\n                    <li key={value}>\n                        <button onClick={() => onPayoutPerPointSelect(value)}>{value}</button>\n                    </li>\n                ))}\n            </u..."
    },
    {
      "name": "packages/trader/src/AppV2/Components/TradeParameters/PayoutPerPoint/payout-per-point-wheel.tsx",
      "totalCharacters": 635,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { Localize } from '@deriv-com/translations';\nimport { useProposal } from 'AppV2/Hooks/useProposal';\n\n        // Sending proposal without subscription to get a new barrier value\n        const { data: response } = useProposal({\n            proposal_request_values: new_values,\n            contract_type: Object.keys(trade_types)[0],\n            is_enabled: is_open,\n            if (response) {\n                const { proposal } = response;\n                const { barrier_spot_distance } = prop..."
    },
    {
      "name": "packages/trader/src/AppV2/Components/TradeParameters/RiskManagement/__tests__/take-profit-and-stop-loss-container.spec.tsx",
      "totalCharacters": 282,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "        send: jest.fn(),\n        authorized: {\n            send: jest.fn(),\n        },\njest.mock('AppV2/Hooks/useProposal', () => ({\n    useProposal: jest.fn(() => ({\n        data: {\n            proposal: {},\n        },\n        error: null,\n        isFetching: false,\n    })),\n}));\n"
    },
    {
      "name": "packages/trader/src/AppV2/Components/TradeParameters/RiskManagement/__tests__/take-profit-and-stop-loss-input.spec.tsx",
      "totalCharacters": 127,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "jest.mock('AppV2/Hooks/useProposal', () => ({\n    useProposal: jest.fn(() => ({\n        error: null,\n        isFetching: false,"
    },
    {
      "name": "packages/trader/src/AppV2/Components/TradeParameters/RiskManagement/take-profit-and-stop-loss-input.tsx",
      "totalCharacters": 1127,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { useProposal } from 'AppV2/Hooks/useProposal';\nimport { focusAndOpenKeyboard } from 'AppV2/Utils/trade-params-utils';\n    const { data: response, error: queryError } = useProposal({\n        proposal_request_values: new_values,\n        contract_type: Object.keys(trade_types)[0],\n        is_enabled,\n        // Exclude the opposite field when validating tp/sl independently\n        should_skip_validation: is_take_profit_input ? 'stop_loss' : 'take_profit',\n        if (queryError) {\n         ..."
    },
    {
      "name": "packages/trader/src/AppV2/Components/TradeParameters/Stake/__tests__/stake.spec.tsx",
      "totalCharacters": 579,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "\n\njest.mock('AppV2/Hooks/useProposal', () => ({\n    useProposal: jest.fn(() => ({\n        error: null,\n        isFetching: false,\n                            [CONTRACT_TYPES.CALL]: { stake: { max: '50000.00', min: '0.35' } },\n                            [CONTRACT_TYPES.PUT]: { stake: { max: '50000.00', min: '0.35' } },\n        default_mock_store.modules.trade.validation_params = {\n            CALL: { stake: { max: '50000.00', min: '0.35' } },\n\n        // Verify the acceptable range message is sh..."
    },
    {
      "name": "packages/trader/src/AppV2/Components/TradeParameters/Stake/stake-input.tsx",
      "totalCharacters": 2680,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { TPriceProposalResponse, TSocketError } from '@deriv/api';\nimport { useProposal } from 'AppV2/Hooks/useProposal';\n            is_first_payout_exceeded: !!first_payout_error && first_contract_payout > Number(max_payout),\n            is_second_payout_exceeded: !!second_payout_error && second_contract_payout > Number(max_payout),\n    const {\n        data: response_1,\n        error: error_1,\n        isFetching: is_fetching_1,\n    } = useProposal({\n    const {\n        data: response_2,\n      ..."
    },
    {
      "name": "packages/trader/src/AppV2/Containers/Trade/__tests__/trade.spec.tsx",
      "totalCharacters": 40,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "    ...jest.requireActual('@deriv/api'),"
    },
    {
      "name": "packages/trader/src/AppV2/Hooks/__tests__/useActiveSymbols.spec.tsx",
      "totalCharacters": 2371,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { useQuery } from '@deriv/api';\nimport { CONTRACT_TYPES, TRADE_TYPES } from '@deriv/shared';\njest.mock('@deriv/api', () => ({\n    ...jest.requireActual('@deriv/api'),\n    useQuery: jest.fn(() => ({\n        data: {\n            active_symbols: not_logged_in_active_symbols,\n        },\n        error: null,\n        isLoading: false,\n    })),\n}));\n\n        jest.clearAllMocks();\n        (useQuery as jest.Mock).mockReturnValue({\n            data: { active_symbols: not_logged_in_active_symbols },\n..."
    },
    {
      "name": "packages/trader/src/AppV2/Hooks/__tests__/useContractsFor.spec.tsx",
      "totalCharacters": 3234,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { useQuery } from '@deriv/api';\nimport { cloneObject, getContractCategoriesConfig, getContractTypesConfig } from '@deriv/shared';\n\njest.mock('@deriv/api', () => ({\n    ...jest.requireActual('@deriv/api'),\n    useQuery: jest.fn(() => ({\n        data: null,\n        error: null,\n        isLoading: false,\n    })),\n}));\n        jest.clearAllMocks();\n        (useQuery as jest.Mock).mockReturnValue({\n            data: {\n                contracts_for: {\n                    available: [\n          ..."
    },
    {
      "name": "packages/trader/src/AppV2/Hooks/__tests__/useProposal.spec.tsx",
      "totalCharacters": 10688,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import React from 'react';\n\nimport { APIProvider } from '@deriv/api';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { renderHook } from '@testing-library/react-hooks';\n\nimport { getProposalRequestObject } from 'AppV2/Utils/trade-params-utils';\nimport { useTraderStore } from 'Stores/useTraderStores';\nimport type { TTradeStore } from 'Types';\n\nimport { useProposal } from '../useProposal';\n\njest.mock('Stores/useTraderStores', () => ({\n    useTraderStore: jest.fn()..."
    },
    {
      "name": "packages/trader/src/AppV2/Hooks/useActiveSymbols.ts",
      "totalCharacters": 1799,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { useCallback, useEffect } from 'react';\nimport { TActiveSymbolsRequest, useQuery } from '@deriv/api';\nimport { CONTRACT_TYPES, getContractTypesConfig } from '@deriv/shared';\ntype TContractTypesList = NonNullable<TActiveSymbolsRequest['contract_type']>;\n// Cache configuration for active symbols query\nconst ACTIVE_SYMBOLS_CACHE_CONFIG = {\n    CACHE_TIME: 10 * 60 * 1000, // 10 minutes - keep in cache even if unused\n} as const;\n/**\n * Hook to fetch and manage active symbols for trading\n */\n ..."
    },
    {
      "name": "packages/trader/src/AppV2/Hooks/useContractsFor.ts",
      "totalCharacters": 330,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { useQuery } from '@deriv/api';\n        isLoading,\n    } = useQuery('contracts_for', {\n        payload: {\n        options: {\n            refetchOnWindowFocus: false, // Don't refetch when window regains focus\n        },\n    });\n    const is_fetching_ref = useRef(isLoading);\n            is_fetching_ref.current = isLoading;"
    },
    {
      "name": "packages/trader/src/AppV2/Hooks/useProposal.tsx",
      "totalCharacters": 1749,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import React from 'react';\n\nimport { TPriceProposalRequest, useQuery } from '@deriv/api';\n\nimport { getProposalRequestObject } from 'AppV2/Utils/trade-params-utils';\nimport { useTraderStore } from 'Stores/useTraderStores';\n\ntype TNewValues = {\n    amount?: string | number;\n    payout_per_point?: string | number;\n    barrier_1?: string | number;\n    has_take_profit?: boolean;\n    has_stop_loss?: boolean;\n    take_profit?: string | number;\n    stop_loss?: string | number;\n};\n\nexport const usePropo..."
    },
    {
      "name": "packages/trader/src/Stores/Modules/Trading/Helpers/proposal.ts",
      "totalCharacters": 188,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { TPriceProposalResponse, TSocketError } from '@deriv/api';\nimport { TTradeStore } from 'Types';\n    response: TPriceProposalResponse & { error?: TSocketError<'proposal'>['error'] }"
    },
    {
      "name": "packages/trader/src/Stores/Modules/Trading/trade-store.ts",
      "totalCharacters": 61,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "            [contract_type]: getProposalInfo(this, response),"
    },
    {
      "name": "packages/trader/src/trader-providers.tsx",
      "totalCharacters": 164,
      "aiCharacters": 0,
      "percentage": 0,
      "status": "modified",
      "hasAddedContent": true,
      "addedContent": "import { APIProvider } from '@deriv/api';\n            <APIProvider>\n                <TraderStoreProvider>{children}</TraderStoreProvider>\n            </APIProvider>"
    }
  ]
}

🚀 Analysis powered by ShiftAI • Analyzes only PR changes, not entire files

@claude
Copy link

claude bot commented Oct 21, 2025

Claude finished @nijil-deriv's task —— View job


Code Review Complete ✅

I've completed a thorough review of PR #384. This PR refactors the custom useDtraderQuery hook by replacing it with the standard useQuery from @deriv/api and introduces a new useProposal hook.


📊 Review Summary

High Priority Issues

  1. Missing Error Boundary in useProposal Hook - packages/trader/src/AppV2/Hooks/useProposal.tsx:18

    • The useProposal hook directly passes trade_store as a parameter but doesn't validate if it exists or has required properties
    • If getProposalRequestObject throws an error or returns invalid data, it could crash components
    • Recommendation: Add defensive checks and error handling
  2. Type Safety Issue in useProposal - packages/trader/src/AppV2/Hooks/useProposal.tsx:46

    • Type assertion as TPriceProposalRequest bypasses TypeScript's type checking
    • If getProposalRequestObject returns unexpected shape, runtime errors will occur
    • Recommendation: Validate the proposal_request shape or use type guards
  3. Race Condition in Stake Component - packages/trader/src/AppV2/Components/TradeParameters/Stake/stake-input.tsx:200-219

    • Two parallel useProposal calls without proper synchronization
    • If component unmounts while requests are in flight, state updates on unmounted component possible
    • Recommendation: Add cleanup in useEffect or use isMounted ref pattern

Medium Priority Issues

  1. Inconsistent Error Handling - packages/trader/src/AppV2/Hooks/useActiveSymbols.ts:43-47

    • Error handling shows generic message, doesn't distinguish between network errors vs API errors
    • queryError object structure not validated before accessing properties
    • Recommendation: Add more granular error handling with proper error type checks
  2. Missing Memoization - packages/trader/src/AppV2/Hooks/useProposal.tsx:31-43

    • proposal_request object is recreated on every render
    • This causes unnecessary re-renders and API calls even when dependencies haven't changed
    • Recommendation: Wrap in useMemo with proper dependencies
  3. Stale Closure in useContractsFor - packages/trader/src/AppV2/Hooks/useContractsFor.ts:115-209

    • Large useEffect with many dependencies not listed in dependency array (line 209)
    • eslint-disable react-hooks/exhaustive-deps comment hides potential bugs
    • Recommendation: Either add all dependencies or extract logic into separate functions
  4. Potential Memory Leak - packages/trader/src/AppV2/Components/TradeParameters/Duration/day.tsx:88-133

    • useProposal called conditionally based on trigger_date
    • State updates in useEffect (line 97) may occur after unmount
    • Recommendation: Add cleanup function to cancel ongoing requests

Low Priority Issues

  1. Test Coverage Gaps - packages/trader/src/AppV2/Hooks/__tests__/useProposal.spec.tsx:1-166

    • Tests don't cover error scenarios with should_skip_validation parameter
    • No tests for edge cases where trade_store has missing/undefined values
    • No tests for mutation/deletion of limit_order properties (lines 38-43 in useProposal)
    • Recommendation: Add tests for error paths and edge cases
  2. Magic Numbers - packages/trader/src/AppV2/Hooks/useActiveSymbols.ts:36-38

    • Hardcoded cache times (5 minutes, 10 minutes) without constants
    • Makes it harder to tune performance across the application
    • Recommendation: Extract to named constants or config file
  3. Verbose Test Mocks - Multiple test files

    • Many test files have duplicated mock setup (e.g., useQuery mocks)
    • Recommendation: Create shared test utilities for common mocks

🔍 Detailed Analysis

Architecture & Design

✅ Positive Changes:

  • Removing custom useDtraderQuery in favor of standard useQuery improves maintainability
  • The new useProposal hook provides better separation of concerns
  • Moving to @deriv/api's APIProvider standardizes data fetching patterns
  • Good use of React Query's caching (staleTime, cacheTime in useActiveSymbols)

⚠️ Concerns:

  • useProposal hook signature is verbose (5 parameters). Consider using a single options object
  • The hook accepts trade_store directly, creating tight coupling between hook and store structure
  • No loading state aggregation for multiple parallel proposals in components

TypeScript & Type Safety

Issues Found:

  • packages/trader/src/AppV2/Hooks/useProposal.tsx:46 - Unsafe type assertion
  • packages/trader/src/AppV2/Hooks/useContractsFor.ts:68-70 - ReturnType<typeof getContractTypesConfig> | undefined is verbose, could use a type alias
  • packages/trader/src/Stores/Modules/Trading/Helpers/proposal.ts:85 - Combining response types inline makes type checking weaker

Recommendations:

  • Create proper interfaces for proposal request/response types
  • Use type guards instead of type assertions
  • Consider using zod or similar for runtime validation of API responses

Performance Considerations

Potential Issues:

  1. stake-input.tsx:200-219 - Two simultaneous API calls on every amount change could be rate-limited by API
  2. No debouncing in stake-input.tsx:354-376 - onInputChange triggers proposal requests immediately
  3. useActiveSymbols.ts:50-63 - Effect runs on every response change, could batch store updates

Recommendations:

  • Add debouncing to stake input changes (already has validation, just needs debounce)
  • Consider using useDeferredValue for non-critical updates
  • Batch MobX store updates where possible

Security

✅ No major security concerns identified

  • No direct user input passed to API without validation
  • No obvious XSS vectors
  • Error messages don't leak sensitive information

Minor note: Error objects from API may contain sensitive details - ensure they're sanitized before displaying to users

Testing

Coverage Analysis:

  • New useProposal hook has basic tests but missing edge cases
  • Mock implementations in tests are comprehensive
  • useActiveSymbols and useContractsFor tests updated appropriately

Gaps:

  • No integration tests showing how hooks work together
  • Error recovery scenarios not tested
  • No tests for concurrent request handling
  • Missing tests for cleanup on unmount

💡 Specific Recommendations

Immediate Fixes (Pre-merge):

  1. Add memoization to useProposal:
const proposal_request = React.useMemo(() => {
    const request = getProposalRequestObject({
        new_values: proposal_request_values,
        trade_store,
        trade_type: contract_type,
    });
    
    // Validation logic here
    if (should_skip_validation === 'take_profit' && request.limit_order?.take_profit) {
        delete request.limit_order.take_profit;
    }
    if (should_skip_validation === 'stop_loss' && request.limit_order?.stop_loss) {
        delete request.limit_order.stop_loss;
    }
    
    return request;
}, [proposal_request_values, trade_store, contract_type, should_skip_validation]);
  1. Add cleanup for proposal requests:
// In components using useProposal
React.useEffect(() => {
    return () => {
        // Cleanup function to cancel any pending requests
        invalidate('proposal');
    };
}, []);
  1. Add type guard instead of assertion:
const isValidProposalRequest = (obj: unknown): obj is TPriceProposalRequest => {
    // Add validation logic
    return typeof obj === 'object' && obj !== null && 'proposal' in obj;
};

// Then use it:
if (!isValidProposalRequest(proposal_request)) {
    throw new Error('Invalid proposal request');
}

Follow-up Tasks (Post-merge):

  1. Add debouncing to stake input component
  2. Create shared test utilities for React Query mocks
  3. Add integration tests for proposal flow
  4. Extract magic numbers to constants
  5. Improve error handling granularity in useActiveSymbols

🎯 Priority Breakdown

Priority Count Should Block Merge?
High 3 ⚠️ Consider fixing #1 and #2
Medium 4 No, but track in follow-up
Low 3 No

✅ Final Verdict

Overall Assessment: APPROVE with recommendations

This is a solid refactoring that improves code maintainability by standardizing on @deriv/api's useQuery. The migration is well-executed with comprehensive test updates.

Key Strengths:

  • Clean removal of custom query hook reduces maintenance burden
  • Proper use of React Query features (caching, enabled flags)
  • Tests updated to reflect new structure
  • No breaking changes to component APIs

Suggested Actions Before Merge:

  1. Add memoization to useProposal hook (High priority build(deps-dev): bump form-data from 4.0.1 to 4.0.4 #5)
  2. Add type validation instead of type assertion (High priority build(deps-dev): bump axios from 1.7.9 to 1.11.0 #2)
  3. Consider adding cleanup for race condition (High priority build(deps): bump @babel/helpers from 7.26.7 to 7.27.6 #3)

Post-Merge Actions:

  • Monitor for any performance regressions related to proposal requests
  • Add integration tests for the full proposal flow
  • Track follow-up tasks for error handling improvements

The refactoring achieves its goal effectively. The identified issues are mostly about defensive programming and performance optimization rather than functional correctness.


CI Status: ✅ 2 passed, 2 in progress
| Branch: refactor/remove-useDtraderQuery

@github-actions
Copy link
Contributor

github-actions bot commented Oct 21, 2025

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

PackageVersionScoreDetails

Scanned Manifest Files

@nijil-deriv nijil-deriv changed the title chore: remove unclosed AI tag Nijil / Replace useDtraderQuery with useQuery in AppV2 Oct 21, 2025
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Oct 21, 2025

Deploying derivatives-trader with  Cloudflare Pages  Cloudflare Pages

Latest commit: 089a49a
Status: ✅  Deploy successful!
Preview URL: https://2b2ab438.derivatives-trader.pages.dev
Branch Preview URL: https://refactor-remove-usedtraderqu.derivatives-trader.pages.dev

View logs

@claude
Copy link

claude bot commented Oct 22, 2025

Claude finished @nijil-deriv's task —— View job


Code Review Complete ✅

I've completed a thorough review of PR #384. This PR successfully refactors the custom useDtraderQuery hook by replacing it with the standard useQuery from @deriv/api and introduces a new useProposal hook.


📊 Review Summary

Overall Assessment: Approve with minor recommendations

This is a well-executed refactoring that improves code maintainability by standardizing on @deriv/api's useQuery. The migration is comprehensive with proper test updates and no breaking changes to component APIs.

Key Statistics

  • Files Changed: 26 files (+458/-815 lines)
  • Deleted: useDtraderQuery.ts, useFetchProposalData.tsx, active-symbols-store.js
  • Added: useProposal.tsx
  • Modified: Multiple components and hooks updated to use new patterns

🎯 Priority Issues

High Priority

1. Missing Memoization in useProposal Hook

File: packages/trader/src/AppV2/Hooks/useProposal.tsx:31-46

The proposal_request object is recreated on every render, potentially causing unnecessary API calls.

// Current implementation
const proposal_request = getProposalRequestObject({
    new_values: proposal_request_values,
    trade_store,
    trade_type: contract_type,
});

Recommendation: Wrap in useMemo to prevent unnecessary re-renders:

const proposal_request = React.useMemo(() => {
    const request = getProposalRequestObject({
        new_values: proposal_request_values,
        trade_store,
        trade_type: contract_type,
    });
    
    if (should_skip_validation === 'take_profit' && request.limit_order?.take_profit) {
        delete request.limit_order.take_profit;
    }
    if (should_skip_validation === 'stop_loss' && request.limit_order?.stop_loss) {
        delete request.limit_order.stop_loss;
    }
    
    return request;
}, [proposal_request_values, trade_store, contract_type, should_skip_validation]);

2. Type Safety Issue with Type Assertion

File: packages/trader/src/AppV2/Hooks/useProposal.tsx:46

The as TPriceProposalRequest type assertion bypasses TypeScript's type checking.

payload: proposal_request as TPriceProposalRequest,

Recommendation: Add runtime validation or use a type guard to ensure type safety.

3. Potential Race Condition in Multiple Proposal Calls

File: packages/trader/src/AppV2/Components/TradeParameters/Stake/stake-input.tsx:200-219

Two parallel useProposal calls without proper cleanup could cause state updates on unmounted components.

Recommendation: Add cleanup logic or use isMounted pattern to prevent state updates after unmount.

Medium Priority

4. Disabled ESLint Rule Without Full Dependency Array

File: packages/trader/src/AppV2/Hooks/useContractsFor.ts:209

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [response]);

The large useEffect (lines 122-210) has many dependencies not listed in the array, which could lead to stale closures.

Recommendation: Either add all dependencies or refactor into separate functions with proper memoization.

5. Missing Error Context in useActiveSymbols

File: packages/trader/src/AppV2/Hooks/useActiveSymbols.ts:49-53

Error handling shows generic message without distinguishing between network errors vs API errors.

Recommendation: Add more granular error handling with proper error type checks.

6. Potential Memory Leak in Day Component

File: packages/trader/src/AppV2/Components/TradeParameters/Duration/day.tsx:88-133

The useProposal hook is called based on trigger_date state, but state updates in the useEffect (line 97-133) may occur after unmount.

Recommendation: Add cleanup function to cancel ongoing requests when component unmounts.

Low Priority

7. Test Coverage Gaps

File: packages/trader/src/AppV2/Hooks/__tests__/useProposal.spec.tsx

Tests don't cover:

  • Error scenarios with should_skip_validation parameter
  • Edge cases where trade_store has missing/undefined values
  • The mutation/deletion of limit_order properties (lines 38-43)

Recommendation: Add tests for error paths and edge cases.

8. Magic Numbers in Cache Configuration

File: packages/trader/src/AppV2/Hooks/useActiveSymbols.ts:13-16

const ACTIVE_SYMBOLS_CACHE_CONFIG = {
    STALE_TIME: 5 * 60 * 1000, // 5 minutes
    CACHE_TIME: 10 * 60 * 1000, // 10 minutes
} as const;

While better than before, these could be centralized if used across multiple hooks.

Recommendation: Good practice already implemented. Consider centralizing if more hooks need similar config.


✅ Positive Aspects

Architecture & Design

  • ✅ Excellent removal of custom query hook reduces maintenance burden
  • ✅ Proper use of React Query caching (staleTime, cacheTime)
  • ✅ Good separation of concerns with new useProposal hook
  • ✅ Consistent API across all hooks using @deriv/api

Code Quality

  • ✅ Comprehensive test updates across all modified hooks
  • ✅ Good use of refetchOnWindowFocus: false to prevent unnecessary refetches
  • ✅ Proper TypeScript types throughout (mostly)
  • ✅ Clear comments explaining complex logic

Performance

  • ✅ Cache configuration in useActiveSymbols reduces API calls
  • ✅ Proper use of is_enabled flag to conditionally trigger queries
  • ✅ Good use of useCallback and useMemo in most components

🔍 Detailed Analysis

Type Safety

Overall: Good - TypeScript usage is solid throughout, with only one type assertion that could be improved.

Performance

Overall: Good - Proper caching, conditional queries, and mostly good memoization. Main issue is missing memoization in useProposal hook.

Security

Overall: Excellent - No security concerns identified:

  • ✅ No XSS vectors
  • ✅ No direct user input passed to API without validation
  • ✅ Error messages don't leak sensitive information

Test Coverage

Overall: Good - Tests updated comprehensively, but some edge cases missing.


💡 Specific Recommendations

Immediate Fixes (Consider Before Merge)

  1. Add memoization to useProposal hook (High Priority build(deps-dev): bump webpack-dev-server from 5.2.0 to 5.2.1 #1)
  2. Consider adding type guard instead of type assertion (High Priority build(deps-dev): bump axios from 1.7.9 to 1.11.0 #2)

Post-Merge Tasks

  1. Add cleanup for race condition in stake component
  2. Improve error handling in useActiveSymbols
  3. Add missing test cases for edge scenarios
  4. Consider refactoring large useEffect in useContractsFor

🎯 Priority Breakdown

Priority Count Blocking?
High 3 Consider fixing #1
Medium 3 No, track in follow-up
Low 2 No

✅ Final Verdict

Recommendation: APPROVE

This refactoring successfully achieves its goals and improves the codebase:

Strengths

  • Clean removal of custom query logic
  • Proper migration to standard React Query patterns
  • Comprehensive test coverage
  • No breaking changes to component APIs
  • Good performance optimizations with caching

Minor Concerns

  • Missing memoization in one hook (easy fix)
  • One type assertion that could be safer
  • Some edge cases not covered in tests

The identified issues are mostly about defensive programming and optimization rather than functional correctness. The code works well as-is, but the recommendations would make it more robust.

Suggested Actions

  1. Optional pre-merge: Add memoization to useProposal hook
  2. Post-merge: Monitor for any performance regressions
  3. Follow-up: Add missing test cases and improve error handling

Great work on this refactoring! The migration from custom hooks to standard React Query patterns is well-executed. 🎉


CI Status: ✅ 2 passed, 2 in progress | View CI
| Branch: refactor/remove-useDtraderQuery

@claude
Copy link

claude bot commented Oct 22, 2025

Claude finished @nijil-deriv's task —— View job


Code Review Complete ✅

I've completed a thorough review of PR #384, focusing on correctness, code quality, performance, security, and testing.


📊 Overall Assessment

Verdict: Approve with Minor Recommendations

This is a well-executed refactoring that successfully migrates from custom useDtraderQuery to standard @deriv/api hooks. The changes improve maintainability and reduce technical debt while maintaining functional correctness.

Key Metrics:

  • 28 files changed (+799/-961 lines)
  • 3 custom hooks removed, 1 new standard hook added
  • Comprehensive test updates
  • No breaking changes to component APIs

🎯 Priority Findings

High Priority

1. Missing Memoization in useProposal Hook ⚠️

Location: packages/trader/src/AppV2/Hooks/useProposal.tsx:31-46

The proposal_request object is recreated on every render, potentially causing unnecessary React Query cache invalidations and API calls.

// Current - recreates object on every render
const proposal_request = getProposalRequestObject({
    new_values: proposal_request_values,
    trade_store,
    trade_type: contract_type,
});

Impact: Performance degradation with unnecessary re-renders and API calls

Recommendation:

const proposal_request = React.useMemo(() => {
    const request = getProposalRequestObject({
        new_values: proposal_request_values,
        trade_store,
        trade_type: contract_type,
    });
    
    // Apply skip validation logic
    if (should_skip_validation === 'take_profit' && request.limit_order?.take_profit) {
        delete request.limit_order.take_profit;
    }
    if (should_skip_validation === 'stop_loss' && request.limit_order?.stop_loss) {
        delete request.limit_order.stop_loss;
    }
    
    return request;
}, [proposal_request_values, trade_store, contract_type, should_skip_validation]);

2. Type Safety Issue with Type Assertion ⚠️

Location: packages/trader/src/AppV2/Hooks/useProposal.tsx:46

Using as TPriceProposalRequest bypasses TypeScript's type checking.

payload: proposal_request as TPriceProposalRequest,

Impact: Runtime errors possible if getProposalRequestObject returns unexpected shape

Recommendation: Add runtime validation or use a type guard to ensure type safety


Medium Priority

3. Potential Race Condition in Stake Component

Location: packages/trader/src/AppV2/Components/TradeParameters/Stake/stake-input.tsx:200-219

Two parallel useProposal calls without proper cleanup could cause state updates on unmounted components.

const { data: response_1, error: error_1, isFetching: is_fetching_1 } = useProposal({...});
const { data: response_2, error: error_2, isFetching: is_fetching_2 } = useProposal({...});

Recommendation: React Query handles cleanup internally, but consider adding explicit cleanup if issues arise. Current implementation is acceptable but could be improved with proper unmount handling.

4. Disabled ESLint Rule Hiding Dependencies

Location: packages/trader/src/AppV2/Hooks/useContractsFor.ts:209

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [response]);

Large useEffect with many undeclared dependencies could lead to stale closures.

Recommendation: Either add all dependencies or refactor into smaller, focused effects.

5. Error Handling Lacks Granularity

Location: packages/trader/src/AppV2/Hooks/useActiveSymbols.ts:49-52

if (queryError) {
    showError({ message: localize('Failed to load market data. Please refresh the page.') });
}

Doesn't distinguish between network errors, API errors, or temporary failures.

Recommendation: Add more specific error handling based on error type for better UX.

6. No Debouncing on Stake Input

Location: packages/trader/src/AppV2/Components/TradeParameters/Stake/stake-input.tsx:354-376

The onInputChange handler triggers proposal requests immediately on every keystroke.

Recommendation: Add debouncing to reduce API load, especially for users typing quickly.


Low Priority

7. Test Coverage Gaps

Location: packages/trader/src/AppV2/Hooks/__tests__/useProposal.spec.tsx

Tests cover basic scenarios but miss:

  • Error scenarios with should_skip_validation parameter
  • Edge cases where trade_store has missing/undefined values (test exists but could be more thorough)
  • Concurrent request handling

Recommendation: Add tests for error paths and edge cases in follow-up PR.

8. Magic Number in Cache Config

Location: packages/trader/src/AppV2/Hooks/useActiveSymbols.ts:13-16

const ACTIVE_SYMBOLS_CACHE_CONFIG = {
    STALE_TIME: 5 * 60 * 1000, // 5 minutes
    CACHE_TIME: 10 * 60 * 1000, // 10 minutes
} as const;

Note: This is actually good practice! Consider centralizing if more hooks need similar config.


✅ Strengths

Architecture & Design

  • ✅ Clean removal of custom query logic reduces maintenance burden
  • ✅ Proper use of React Query features (caching, enabled flags, refetchOnWindowFocus)
  • ✅ Good separation of concerns with new useProposal hook
  • ✅ Consistent API across all hooks using @deriv/api

Code Quality

  • ✅ Comprehensive test updates across all modified hooks
  • ✅ TypeScript types properly used throughout (except one assertion)
  • ✅ Clear comments explaining complex logic
  • ✅ Proper error handling in most components

Performance

  • ✅ Cache configuration in useActiveSymbols reduces API calls
  • ✅ Proper use of is_enabled flag to conditionally trigger queries
  • ✅ Good use of useCallback and useMemo in components

Security

  • ✅ No security concerns identified
  • ✅ No XSS vectors
  • ✅ No direct user input passed to API without validation
  • ✅ Error messages don't leak sensitive information

🔍 Detailed Analysis

Correctness & Edge Cases

The refactoring maintains functional parity with the previous implementation. All edge cases from the old hooks appear to be handled:

  • ✅ Conditional query execution based on is_enabled
  • ✅ Proper handling of empty/undefined values
  • ✅ Barrier/payout validation logic preserved in components
  • ✅ Take profit/stop loss independent validation working correctly

React & TypeScript Best Practices

Render Cost & Performance

Test Coverage

Test files reviewed:

  • useProposal.spec.tsx - Good coverage of basic scenarios
  • useActiveSymbols.spec.tsx - Properly tests contract type filtering
  • useContractsFor.spec.tsx - Tests complex contract type logic
  • Component tests - Properly mock new hooks

💡 Recommendations

Pre-Merge (Optional but Recommended)

  1. Add memoization to useProposal hook (10-minute fix, significant performance benefit)
  2. Consider adding type guard instead of type assertion

Post-Merge

  1. Monitor for any performance regressions in production
  2. Add debouncing to stake input in follow-up PR
  3. Improve error handling granularity in useActiveSymbols
  4. Add missing test cases for edge scenarios
  5. Consider refactoring large useEffect in useContractsFor

📈 Priority Breakdown

Priority Count Blocking? Should Address
High 2 No Consider #1 for performance
Medium 4 No Track in follow-up
Low 2 No Optional improvements

🎉 Conclusion

This refactoring successfully achieves its goals and improves the codebase. The migration from custom hooks to standard React Query patterns is well-executed with comprehensive test updates and no breaking changes.

Key Achievements:

  • Reduced custom code by ~200 lines
  • Standardized data fetching patterns
  • Improved type safety (mostly)
  • Maintained functional correctness
  • Good performance characteristics with caching

Minor Issues:
The identified issues are mostly about defensive programming and optimization rather than functional correctness. The code works well as-is, but the recommendations would make it more robust and performant.

Suggested Actions:

  1. Recommended: Add memoization to useProposal hook before merge
  2. Optional: Address type assertion for better type safety
  3. Post-merge: Monitor performance and track follow-up improvements

Great work on this refactoring! The codebase is cleaner and more maintainable. 🚀


CI Status: ✅ 1 passed, 3 in progress | View CI
| Branch: refactor/remove-useDtraderQuery

@claude
Copy link

claude bot commented Oct 22, 2025

Claude finished @nijil-deriv's task —— View job


Code Review Complete ✅

I've completed a comprehensive review of PR #384, which refactors the custom useDtraderQuery hook to use standard useQuery from @deriv/api and introduces the new useProposal hook.


📊 Overall Assessment

Verdict: ✅ APPROVE with Minor Recommendations

This is a well-executed refactoring that successfully standardizes data fetching patterns by migrating from custom hooks to @deriv/api's useQuery. The changes improve maintainability, reduce technical debt, and maintain functional correctness.

Key Metrics:

  • 30 files changed: +809/-964 lines
  • 3 custom hooks removed: useDtraderQuery.ts, useFetchProposalData.tsx, active-symbols-store.js
  • 1 new hook added: useProposal.tsx
  • Comprehensive test updates across all modified hooks and components
  • No breaking changes to component APIs

🎯 Findings by Priority

✅ Strengths

Architecture & Design

  • Clean removal of custom query logic reduces maintenance burden
  • Proper use of React Query features (caching, conditional queries, refetchOnWindowFocus)
  • Good separation of concerns with new useProposal hook
  • Consistent API across all hooks using @deriv/api
  • Excellent cache configuration in useActiveSymbols (10-minute cache time)

Code Quality

  • Comprehensive test updates across all modified hooks
  • TypeScript types properly used throughout (with minor exceptions noted below)
  • Clear comments explaining complex logic
  • Proper error handling in most components
  • Good commit history showing iterative improvements (memoization added in commit 4a74604)

Performance

  • Cache configuration in useActiveSymbols reduces unnecessary API calls
  • Proper use of is_enabled flag to conditionally trigger queries
  • Good use of useCallback and useMemo in components
  • refetchOnWindowFocus: false prevents unnecessary refetches

Security

  • ✅ No security concerns identified
  • No XSS vectors
  • No direct user input passed to API without validation
  • Error messages don't leak sensitive information

⚠️ High Priority Issues

1. Type Safety Issue in useProposal Hook

Location: packages/trader/src/AppV2/Hooks/useProposal.tsx:50

payload: proposal_request as TPriceProposalRequest,

Issue: Type assertion bypasses TypeScript's type checking. If getProposalRequestObject returns an unexpected shape, runtime errors could occur.

Impact: Potential runtime errors if the proposal request structure doesn't match expectations.

Recommendation: Consider adding runtime validation or use a type guard:

const isValidProposalRequest = (obj: unknown): obj is TPriceProposalRequest => {
    return typeof obj === 'object' && obj !== null && 'proposal' in obj;
};

// Then validate before use
if (!isValidProposalRequest(proposal_request)) {
    throw new Error('Invalid proposal request structure');
}

📝 Medium Priority Observations

2. Parallel Proposal Requests in Stake Component

Location: packages/trader/src/AppV2/Components/TradeParameters/Stake/stake-input.tsx:200-219

Two parallel useProposal calls are made for Rise/Fall contracts:

const { data: response_1, error: error_1, isFetching: is_fetching_1 } = useProposal({...});
const { data: response_2, error: error_2, isFetching: is_fetching_2 } = useProposal({...});

Observation: React Query handles cleanup internally, but there's potential for state updates if component unmounts during fetch.

Status: Acceptable - React Query's built-in cleanup should handle this, but keep an eye on it if issues arise.

3. Missing Debouncing on Input Changes

Location: packages/trader/src/AppV2/Components/TradeParameters/Stake/stake-input.tsx:354-376

The onInputChange handler triggers proposal requests immediately on every keystroke.

Impact: Could lead to excessive API calls for users typing quickly.

Recommendation: Consider adding debouncing (e.g., 300ms) to reduce API load:

const debouncedOnChange = useMemo(
    () => debounce((value: string) => {
        dispatch({ type: 'SET_PROPOSAL_VALUES', payload: { amount: value } });
    }, 300),
    []
);

4. Large useEffect with Disabled Exhaustive Deps

Location: packages/trader/src/AppV2/Hooks/useContractsFor.ts:209

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [response]);

Issue: Large useEffect (lines 122-210) has many undeclared dependencies, which could lead to stale closures.

Recommendation: Either add all dependencies or refactor into smaller, focused effects. This is a pre-existing pattern but worth addressing in a follow-up.

5. Error Handling Lacks Granularity

Location: packages/trader/src/AppV2/Hooks/useActiveSymbols.ts:47-51

if (queryError) {
    showError({ message: localize('Failed to load market data. Please refresh the page.') });
}

Observation: Doesn't distinguish between network errors, API errors, or temporary failures.

Recommendation: Add more specific error handling for better UX:

if (queryError) {
    const errorMessage = queryError.error?.code === 'NetworkError'
        ? localize('Network connection lost. Please check your connection.')
        : localize('Failed to load market data. Please refresh the page.');
    showError({ message: errorMessage });
}

💡 Low Priority / Nice to Have

6. Test Coverage Observations

Location: packages/trader/src/AppV2/Hooks/__tests__/useProposal.spec.tsx

Good coverage includes:

  • ✅ Basic proposal request scenarios
  • ✅ Conditional execution with is_enabled
  • ✅ Skip validation for take profit/stop loss
  • ✅ Incomplete trade store handling

Minor gaps:

  • Error scenarios with specific API error codes
  • Concurrent request handling
  • Edge cases with rapid re-renders

Status: Test coverage is solid overall. Missing edge cases are not blockers.

7. Memoization Already Added! ✅

Location: packages/trader/src/AppV2/Hooks/useProposal.tsx:31-47

Excellent: I noticed in commit 4a74604 that memoization was already added to the useProposal hook. This addresses a potential performance concern proactively. Great work!

const proposal_request = React.useMemo(() => {
    // ... proposal logic
}, [proposal_request_values, trade_store, contract_type, should_skip_validation]);

🔍 Detailed Analysis

Correctness & Edge Cases ✅

The refactoring maintains functional parity with the previous implementation:

  • ✅ Conditional query execution based on is_enabled
  • ✅ Proper handling of empty/undefined values
  • ✅ Barrier/payout validation logic preserved
  • ✅ Independent validation for take profit/stop loss working correctly
  • ✅ Proper cache invalidation in Duration component

React & TypeScript Best Practices ⭐

  • ✅ Proper use of hooks (no rule violations beyond acknowledged eslint-disable)
  • ✅ Observer pattern correctly used with MobX
  • ✅ Props properly typed throughout
  • ⚠️ One type assertion that could be safer (noted above)
  • ✅ Good use of useMemo and useCallback where appropriate

Performance Considerations 🚀

  • ✅ React Query's intelligent caching prevents duplicate requests
  • ✅ Proper cache configuration (10-minute cache in useActiveSymbols)
  • ✅ Memoization added in useProposal hook (commit 4a74604)
  • ⚠️ No debouncing on rapid input changes (minor issue)

Test Quality 🧪

All hooks have corresponding tests with good coverage:

  • useProposal.spec.tsx - 9 test cases covering main scenarios
  • useActiveSymbols.spec.tsx - Tests contract type filtering
  • useContractsFor.spec.tsx - Tests complex contract type logic
  • ✅ Component tests properly mock new hooks
  • ✅ Mocks are well-structured and realistic

📋 Recommendations

Optional Pre-Merge

  1. Consider adding runtime validation for the type assertion in useProposal (High Priority build(deps-dev): bump webpack-dev-server from 5.2.0 to 5.2.1 #1)
    • Risk: Low (current code works, but defensive programming is good practice)
    • Effort: ~15 minutes

Post-Merge Follow-Up

  1. Monitor performance in production for any regressions related to proposal requests
  2. Consider adding debouncing to stake input in a follow-up PR
  3. Track refactoring of large useEffect in useContractsFor
  4. Add more granular error handling in useActiveSymbols

🎉 Final Verdict

APPROVE ✅

This refactoring successfully achieves its goals and improves the codebase. The migration from custom hooks to standard React Query patterns is well-executed with comprehensive test updates and no breaking changes.

Key Achievements:

  • ✅ Reduced custom code by ~155 lines
  • ✅ Standardized data fetching patterns across the app
  • ✅ Improved performance with proper caching
  • ✅ Maintained functional correctness throughout
  • ✅ Comprehensive test coverage updates
  • ✅ Proactive performance optimization (memoization added)

Why This Can Merge:

  • All high-priority issues are minor and non-blocking
  • The code is functionally correct and well-tested
  • Performance characteristics are good
  • No security concerns
  • The identified issues are about defensive programming and polish, not correctness

Great work on this refactoring! The codebase is cleaner, more maintainable, and follows better patterns. 🚀


CI Status: Monitoring | | Branch: refactor/remove-useDtraderQuery

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants