9ecd3b2d84
All four files split into focused sibling modules so every file lands
comfortably under the 300-LOC soft target (hard cap 500):
hooks.ts (474→43) → hooks-core / hooks-dsgvo / hooks-compliance
hooks-rag-security / hooks-ui
dsr-portal.ts (464→129) → dsr-portal-translations / dsr-portal-render
provider.tsx (462→247) → provider-effects / provider-callbacks
sync.ts (435→299) → sync-storage / sync-conflict
Zero behaviour changes. All public APIs remain importable from the
original paths (hooks.ts re-exports every hook, provider.tsx keeps all
named exports, sync.ts preserves StateSyncManager + factory).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
248 lines
7.3 KiB
TypeScript
248 lines
7.3 KiB
TypeScript
'use client'
|
|
|
|
import React, {
|
|
useReducer,
|
|
useMemo,
|
|
useRef,
|
|
useState,
|
|
} from 'react'
|
|
import {
|
|
ComplianceClient,
|
|
sdkReducer,
|
|
initialState,
|
|
StateSyncManager,
|
|
createDSGVOModule,
|
|
createComplianceModule,
|
|
createRAGModule,
|
|
createSecurityModule,
|
|
} from '@breakpilot/compliance-sdk-core'
|
|
import type { SyncState } from '@breakpilot/compliance-sdk-types'
|
|
import {
|
|
getStepById,
|
|
getNextStep,
|
|
getPreviousStep,
|
|
getCompletionPercentage,
|
|
getPhaseCompletionPercentage,
|
|
} from '@breakpilot/compliance-sdk-types'
|
|
import {
|
|
ComplianceContext,
|
|
type ComplianceContextValue,
|
|
type ComplianceProviderProps,
|
|
} from './provider-context'
|
|
import {
|
|
useSyncManagerEffect,
|
|
useLoadInitialStateEffect,
|
|
useAutoSaveEffect,
|
|
useKeyboardShortcutsEffect,
|
|
} from './provider-effects'
|
|
import {
|
|
useValidateCheckpoint,
|
|
useOverrideCheckpoint,
|
|
useGetCheckpointStatus,
|
|
useUpdateUseCase,
|
|
useAddRisk,
|
|
useUpdateControl,
|
|
useSaveState,
|
|
useLoadState,
|
|
useResetState,
|
|
useForceSyncToServer,
|
|
useExportState,
|
|
} from './provider-callbacks'
|
|
import { useCallback, useMemo as useMemoReact } from 'react'
|
|
|
|
export {
|
|
ComplianceContext,
|
|
type ComplianceContextValue,
|
|
type ComplianceProviderProps,
|
|
} from './provider-context'
|
|
|
|
// Re-export useCompliance so legacy component imports (`from '../provider'`)
|
|
// keep resolving. Pre-existing cross-file import that was broken in baseline.
|
|
export { useCompliance } from './hooks'
|
|
|
|
// =============================================================================
|
|
// PROVIDER
|
|
// =============================================================================
|
|
|
|
export function ComplianceProvider({
|
|
children,
|
|
apiEndpoint,
|
|
apiKey,
|
|
tenantId,
|
|
userId = 'default',
|
|
enableBackendSync = true,
|
|
onNavigate,
|
|
onError,
|
|
}: ComplianceProviderProps) {
|
|
const [state, dispatch] = useReducer(sdkReducer, {
|
|
...initialState,
|
|
tenantId,
|
|
userId,
|
|
})
|
|
const [isCommandBarOpen, setCommandBarOpenRaw] = useState(false)
|
|
const [isInitialized, setIsInitialized] = useState(false)
|
|
const [isLoading, setIsLoading] = useState(true)
|
|
const [error, setError] = useState<Error | null>(null)
|
|
const [syncState, setSyncState] = useState<SyncState>({
|
|
status: 'idle',
|
|
lastSyncedAt: null,
|
|
localVersion: 0,
|
|
serverVersion: 0,
|
|
pendingChanges: 0,
|
|
error: null,
|
|
})
|
|
const [isOnline, setIsOnline] = useState(true)
|
|
|
|
// Refs
|
|
const clientRef = useRef<ComplianceClient | null>(null)
|
|
const syncManagerRef = useRef<StateSyncManager | null>(null)
|
|
|
|
// Initialize client (once)
|
|
if (!clientRef.current) {
|
|
clientRef.current = new ComplianceClient({
|
|
apiEndpoint,
|
|
apiKey,
|
|
tenantId,
|
|
onError: err => {
|
|
setError(err)
|
|
onError?.(err)
|
|
},
|
|
})
|
|
}
|
|
|
|
const client = clientRef.current
|
|
|
|
// Modules
|
|
const dsgvo = useMemo(() => createDSGVOModule(client, () => state), [client, state])
|
|
const compliance = useMemo(() => createComplianceModule(client, () => state), [client, state])
|
|
const rag = useMemo(() => createRAGModule(client), [client])
|
|
const security = useMemo(() => createSecurityModule(client, () => state), [client, state])
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Effects (extracted to provider-effects.ts)
|
|
// -------------------------------------------------------------------------
|
|
|
|
const syncStateSetters = useMemo(
|
|
() => ({ setSyncState, setIsOnline, setError, dispatch }),
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
[]
|
|
)
|
|
|
|
useSyncManagerEffect(enableBackendSync, tenantId, client, state, syncManagerRef, syncStateSetters)
|
|
|
|
useLoadInitialStateEffect(tenantId, enableBackendSync, syncManagerRef, {
|
|
setIsLoading,
|
|
setIsInitialized,
|
|
setError,
|
|
dispatch,
|
|
onError,
|
|
})
|
|
|
|
useAutoSaveEffect(state, tenantId, isInitialized, enableBackendSync, syncManagerRef)
|
|
|
|
const setCommandBarOpen = useCallback(
|
|
(fn: boolean | ((prev: boolean) => boolean)) => {
|
|
setCommandBarOpenRaw(typeof fn === 'function' ? fn : () => fn)
|
|
},
|
|
[]
|
|
)
|
|
|
|
useKeyboardShortcutsEffect(isCommandBarOpen, setCommandBarOpen as (fn: (prev: boolean) => boolean) => void)
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Navigation
|
|
// -------------------------------------------------------------------------
|
|
|
|
const currentStep = useMemo(() => getStepById(state.currentStep), [state.currentStep])
|
|
|
|
const goToStep = useCallback(
|
|
(stepId: string) => {
|
|
const step = getStepById(stepId)
|
|
if (step) {
|
|
dispatch({ type: 'SET_CURRENT_STEP', payload: stepId })
|
|
onNavigate?.(step.url)
|
|
}
|
|
},
|
|
[onNavigate]
|
|
)
|
|
|
|
const goToNextStep = useCallback(() => {
|
|
const nextStep = getNextStep(state.currentStep)
|
|
if (nextStep) goToStep(nextStep.id)
|
|
}, [state.currentStep, goToStep])
|
|
|
|
const goToPreviousStep = useCallback(() => {
|
|
const prevStep = getPreviousStep(state.currentStep)
|
|
if (prevStep) goToStep(prevStep.id)
|
|
}, [state.currentStep, goToStep])
|
|
|
|
const canGoNext = useMemo(() => getNextStep(state.currentStep) !== undefined, [state.currentStep])
|
|
const canGoPrevious = useMemo(
|
|
() => getPreviousStep(state.currentStep) !== undefined,
|
|
[state.currentStep]
|
|
)
|
|
|
|
const completionPercentage = useMemo(() => getCompletionPercentage(state), [state])
|
|
const phase1Completion = useMemo(() => getPhaseCompletionPercentage(state, 1), [state])
|
|
const phase2Completion = useMemo(() => getPhaseCompletionPercentage(state, 2), [state])
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Callbacks (extracted to provider-callbacks.ts)
|
|
// -------------------------------------------------------------------------
|
|
|
|
const validateCheckpoint = useValidateCheckpoint(state, enableBackendSync, client, dispatch)
|
|
const overrideCheckpoint = useOverrideCheckpoint(state, dispatch)
|
|
const getCheckpointStatus = useGetCheckpointStatus(state)
|
|
const updateUseCase = useUpdateUseCase(dispatch)
|
|
const addRisk = useAddRisk(dispatch)
|
|
const updateControl = useUpdateControl(dispatch)
|
|
const saveState = useSaveState(state, tenantId, enableBackendSync, syncManagerRef, e => setError(e))
|
|
const loadState = useLoadState(tenantId, enableBackendSync, syncManagerRef, setIsLoading, dispatch, e => setError(e))
|
|
const resetState = useResetState(tenantId, dispatch)
|
|
const forceSyncToServer = useForceSyncToServer(state, enableBackendSync, syncManagerRef)
|
|
const exportState = useExportState(state, client)
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Context value
|
|
// -------------------------------------------------------------------------
|
|
|
|
const value: ComplianceContextValue = {
|
|
state,
|
|
dispatch,
|
|
client,
|
|
dsgvo,
|
|
compliance,
|
|
rag,
|
|
security,
|
|
currentStep,
|
|
goToStep,
|
|
goToNextStep,
|
|
goToPreviousStep,
|
|
canGoNext,
|
|
canGoPrevious,
|
|
completionPercentage,
|
|
phase1Completion,
|
|
phase2Completion,
|
|
validateCheckpoint,
|
|
overrideCheckpoint,
|
|
getCheckpointStatus,
|
|
updateUseCase,
|
|
addRisk,
|
|
updateControl,
|
|
saveState,
|
|
loadState,
|
|
resetState,
|
|
syncState,
|
|
forceSyncToServer,
|
|
isOnline,
|
|
exportState,
|
|
isCommandBarOpen,
|
|
setCommandBarOpen: setCommandBarOpenRaw,
|
|
isInitialized,
|
|
isLoading,
|
|
error,
|
|
}
|
|
|
|
return <ComplianceContext.Provider value={value}>{children}</ComplianceContext.Provider>
|
|
}
|