function applySocketMessage(dashboard, payload, session) { if (!dashboard) return { dashboard, session }; switch (payload.type) { case 'session.ready': return { session: payload.session || session, dashboard: { ...dashboard, funds: { ...dashboard.funds, recent_quotes: payload.live?.recent_quotes || dashboard.funds.recent_quotes, }, strategy: payload.live?.recent_lifecycle_rows ? { ...dashboard.strategy, strategy_state: { ...dashboard.strategy.strategy_state, recent_lifecycle_rows: payload.live.recent_lifecycle_rows, maker_competitiveness: payload.live.maker_competitiveness || dashboard.strategy.strategy_state.maker_competitiveness, quote_lifecycle_statistics: { ...(dashboard.strategy.strategy_state.quote_lifecycle_statistics || {}), live: payload.live.quote_lifecycle_statistics || dashboard.strategy.strategy_state.quote_lifecycle_statistics?.live || null, }, }, } : dashboard.strategy, status_bar: { ...dashboard.status_bar, ...(payload.live?.status_bar || {}), }, }, }; case 'quotes.recent': return { session, dashboard: { ...dashboard, funds: { ...dashboard.funds, recent_quotes: payload.recent_quotes, }, }, }; case 'quote_lifecycle.updated': return { session, dashboard: { ...dashboard, strategy: { ...dashboard.strategy, strategy_state: { ...dashboard.strategy.strategy_state, recent_lifecycle_rows: payload.recent_lifecycle_rows || dashboard.strategy.strategy_state.recent_lifecycle_rows, maker_competitiveness: payload.maker_competitiveness || dashboard.strategy.strategy_state.maker_competitiveness, quote_lifecycle_statistics: { ...(dashboard.strategy.strategy_state.quote_lifecycle_statistics || {}), live: payload.quote_lifecycle_statistics || dashboard.strategy.strategy_state.quote_lifecycle_statistics?.live || null, }, }, }, }, }; case 'status_bar.updated': return { session, dashboard: { ...dashboard, status_bar: { ...dashboard.status_bar, ...payload.status_bar, }, funds: { ...dashboard.funds, profitability: { ...dashboard.funds.profitability, recent_submission_count: payload.status_bar.recent_submission_count ?? dashboard.funds.profitability.recent_submission_count, last_submission_at: payload.status_bar.last_submission_at || dashboard.funds.profitability.last_submission_at, }, }, }, }; case 'environment_status.updated': { const existing = dashboard.system?.environment_status || { recent_changes: [] }; return { session, dashboard: { ...dashboard, system: { ...dashboard.system, environment_status: { ...existing, current: payload.environment_status?.payload || existing.current || null, recent_changes: [ payload.environment_status, ...(existing.recent_changes || []), ].filter(Boolean).slice(0, 20), latest_durable_change_at: payload.environment_status?.payload?.changed_at || payload.environment_status?.observed_at || existing.latest_durable_change_at || null, }, }, }, }; } default: return { dashboard, session }; } } export const initialDashboardState = { session: null, dashboard: null, page: null, notice: null, error: null, websocketState: 'connecting', lastControlResult: null, }; export function dashboardReducer(state, action) { switch (action.type) { case 'session.loaded': return { ...state, session: action.session, }; case 'bootstrap.loaded': return { ...state, dashboard: action.dashboard, page: state.page || action.dashboard.default_page || 'funds', }; case 'submissionLedger.loaded': return { ...state, dashboard: { ...state.dashboard, funds: { ...state.dashboard.funds, submission_ledger: action.submissionLedger, }, }, }; case 'page.changed': return { ...state, page: action.page, }; case 'notice.changed': return { ...state, notice: action.notice, }; case 'error.changed': return { ...state, error: action.error, }; case 'control.result': return { ...state, lastControlResult: action.result, }; case 'websocket.state.changed': return { ...state, websocketState: action.websocketState, }; case 'socket.message.received': { const next = applySocketMessage(state.dashboard, action.payload, state.session); return { ...state, session: next.session, dashboard: next.dashboard, }; } default: return state; } }