feat: F021 market intelligence & signal discovery
Signal domain types, mock data (8 signals), provider interface + MockupMarketIntelligenceProvider, marketIntelligenceService, TanStack Query hooks, 10 ops components (SignalInbox, MarketSignalCard, MarketSignalFilterBar, MarketSignalSkeleton, MarketSignalEmptyState, SignalConfidenceBadge, SourceReliabilityBadge, SensitivityWarningPanel, SignalConversionPanel, SignalEvidenceList), MarketIntelligence page wired into AppShell nav and App router. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,22 +1,61 @@
|
||||
import { create } from 'zustand'
|
||||
import { WorkspaceType } from '../domain/enums'
|
||||
|
||||
export const RightPanelContentType = {
|
||||
AI_CONTEXT: 'ai_context',
|
||||
DETAIL_PREVIEW: 'detail_preview',
|
||||
COMPARE_PREVIEW: 'compare_preview',
|
||||
ACTIVITY_FEED: 'activity_feed',
|
||||
} as const
|
||||
export type RightPanelContentType = typeof RightPanelContentType[keyof typeof RightPanelContentType]
|
||||
|
||||
interface LayoutState {
|
||||
activeWorkspace: WorkspaceType
|
||||
sidebarCollapsed: boolean
|
||||
pinnedPanels: string[]
|
||||
isRightPanelOpen: boolean
|
||||
rightPanelContentType: RightPanelContentType | null
|
||||
compareTrayVisible: boolean
|
||||
selectedResultId: string | null
|
||||
notificationsOpen: boolean
|
||||
// Actions
|
||||
setActiveWorkspace: (workspace: WorkspaceType) => void
|
||||
toggleSidebar: () => void
|
||||
pinPanel: (panelId: string) => void
|
||||
unpinPanel: (panelId: string) => void
|
||||
openRightPanel: (type: RightPanelContentType) => void
|
||||
closeRightPanel: () => void
|
||||
toggleRightPanel: (type: RightPanelContentType) => void
|
||||
setCompareTrayVisible: (visible: boolean) => void
|
||||
setSelectedResultId: (id: string | null) => void
|
||||
toggleNotifications: () => void
|
||||
}
|
||||
|
||||
export const useLayoutStore = create<LayoutState>((set) => ({
|
||||
export const useLayoutStore = create<LayoutState>((set, get) => ({
|
||||
activeWorkspace: WorkspaceType.SUPPLY,
|
||||
sidebarCollapsed: false,
|
||||
pinnedPanels: [],
|
||||
isRightPanelOpen: false,
|
||||
rightPanelContentType: null,
|
||||
compareTrayVisible: false,
|
||||
selectedResultId: null,
|
||||
notificationsOpen: false,
|
||||
|
||||
setActiveWorkspace: (workspace) => set({ activeWorkspace: workspace }),
|
||||
toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),
|
||||
pinPanel: (panelId) => set((state) => ({ pinnedPanels: [...state.pinnedPanels, panelId] })),
|
||||
unpinPanel: (panelId) => set((state) => ({ pinnedPanels: state.pinnedPanels.filter(id => id !== panelId) })),
|
||||
toggleSidebar: () => set((s) => ({ sidebarCollapsed: !s.sidebarCollapsed })),
|
||||
pinPanel: (panelId) => set((s) => ({ pinnedPanels: [...s.pinnedPanels, panelId] })),
|
||||
unpinPanel: (panelId) => set((s) => ({ pinnedPanels: s.pinnedPanels.filter(id => id !== panelId) })),
|
||||
openRightPanel: (type) => set({ isRightPanelOpen: true, rightPanelContentType: type }),
|
||||
closeRightPanel: () => set({ isRightPanelOpen: false, rightPanelContentType: null }),
|
||||
toggleRightPanel: (type) => {
|
||||
const { isRightPanelOpen, rightPanelContentType } = get()
|
||||
if (isRightPanelOpen && rightPanelContentType === type) {
|
||||
set({ isRightPanelOpen: false, rightPanelContentType: null })
|
||||
} else {
|
||||
set({ isRightPanelOpen: true, rightPanelContentType: type })
|
||||
}
|
||||
},
|
||||
setCompareTrayVisible: (visible) => set({ compareTrayVisible: visible }),
|
||||
setSelectedResultId: (id) => set({ selectedResultId: id }),
|
||||
toggleNotifications: () => set((s) => ({ notificationsOpen: !s.notificationsOpen })),
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user