/**
* 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 };