/** * React Integration fuer @breakpilot/consent-sdk * * @example * ```tsx * import { ConsentProvider, useConsent, ConsentBanner } from '@breakpilot/consent-sdk/react'; * * function App() { * return ( * * * * * ); * } * ``` * * Phase 4 refactor: provider stays here; hooks + components live in sibling * files. Context definition is in ./context so hooks and provider can share it * without circular imports. */ import { useEffect, useState, useCallback, useMemo, type FC, type ReactNode, } from 'react'; import { ConsentManager } from '../core/ConsentManager'; import type { ConsentCategories, ConsentCategory, ConsentConfig, ConsentState, } from '../types'; import { ConsentContext, type ConsentContextValue } from './context'; import { useConsent, useConsentManager } from './hooks'; import { ConsentBanner, ConsentGate, ConsentPlaceholder, type ConsentBannerRenderProps, } from './components'; // ============================================================================= // Provider // ============================================================================= interface ConsentProviderProps { /** SDK-Konfiguration */ config: ConsentConfig; /** Kinder-Komponenten */ children: ReactNode; } /** * ConsentProvider - Stellt Consent-Kontext bereit. */ export const ConsentProvider: FC = ({ config, children, }) => { const [manager, setManager] = useState(null); const [consent, setConsent] = useState(null); const [isInitialized, setIsInitialized] = useState(false); const [isLoading, setIsLoading] = useState(true); const [isBannerVisible, setIsBannerVisible] = useState(false); // Manager erstellen und initialisieren useEffect(() => { const consentManager = new ConsentManager(config); setManager(consentManager); // Events abonnieren const unsubChange = consentManager.on('change', (newConsent) => { setConsent(newConsent); }); const unsubBannerShow = consentManager.on('banner_show', () => { setIsBannerVisible(true); }); const unsubBannerHide = consentManager.on('banner_hide', () => { setIsBannerVisible(false); }); // Initialisieren consentManager .init() .then(() => { setConsent(consentManager.getConsent()); setIsInitialized(true); setIsLoading(false); setIsBannerVisible(consentManager.isBannerVisible()); }) .catch((error) => { console.error('Failed to initialize ConsentManager:', error); setIsLoading(false); }); // Cleanup return () => { unsubChange(); unsubBannerShow(); unsubBannerHide(); }; }, [config]); // Callback-Funktionen const hasConsent = useCallback( (category: ConsentCategory): boolean => { return manager?.hasConsent(category) ?? category === 'essential'; }, [manager] ); const acceptAll = useCallback(async () => { await manager?.acceptAll(); }, [manager]); const rejectAll = useCallback(async () => { await manager?.rejectAll(); }, [manager]); const saveSelection = useCallback( async (categories: Partial) => { await manager?.setConsent(categories); manager?.hideBanner(); }, [manager] ); const showBanner = useCallback(() => { manager?.showBanner(); }, [manager]); const hideBanner = useCallback(() => { manager?.hideBanner(); }, [manager]); const showSettings = useCallback(() => { manager?.showSettings(); }, [manager]); const needsConsent = useMemo(() => { return manager?.needsConsent() ?? true; }, [manager, consent]); // Context-Wert const contextValue = useMemo( () => ({ manager, consent, isInitialized, isLoading, isBannerVisible, needsConsent, hasConsent, acceptAll, rejectAll, saveSelection, showBanner, hideBanner, showSettings, }), [ manager, consent, isInitialized, isLoading, isBannerVisible, needsConsent, hasConsent, acceptAll, rejectAll, saveSelection, showBanner, hideBanner, showSettings, ] ); return ( {children} ); }; // ============================================================================= // Re-exports for the public @breakpilot/consent-sdk/react entrypoint // ============================================================================= export { useConsent, useConsentManager }; export { ConsentBanner, ConsentGate, ConsentPlaceholder }; export { ConsentContext }; export type { ConsentContextValue, ConsentBannerRenderProps };