update
This commit is contained in:
413
frontEnd/components/shared/layout/CookieConsentContext.tsx
Normal file
413
frontEnd/components/shared/layout/CookieConsentContext.tsx
Normal file
@@ -0,0 +1,413 @@
|
||||
'use client';
|
||||
|
||||
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
|
||||
|
||||
// Types for cookie consent
|
||||
export interface CookiePreferences {
|
||||
necessary: boolean;
|
||||
functional: boolean;
|
||||
}
|
||||
|
||||
export interface ConsentAuditLog {
|
||||
timestamp: string;
|
||||
action: 'consent_given' | 'consent_updated' | 'consent_withdrawn' | 'settings_opened';
|
||||
preferences: CookiePreferences;
|
||||
userAgent: string;
|
||||
ipAddress?: string;
|
||||
sessionId: string;
|
||||
}
|
||||
|
||||
export interface CookieConsentConfig {
|
||||
version: string;
|
||||
companyName: string;
|
||||
privacyPolicyUrl: string;
|
||||
cookiePolicyUrl: string;
|
||||
dataControllerEmail: string;
|
||||
retentionPeriod: number; // days
|
||||
enableAuditLog: boolean;
|
||||
enableDetailedSettings: boolean;
|
||||
showPrivacyNotice: boolean;
|
||||
}
|
||||
|
||||
export interface CookieConsentState {
|
||||
hasConsented: boolean;
|
||||
preferences: CookiePreferences;
|
||||
showBanner: boolean;
|
||||
showSettings: boolean;
|
||||
consentDate?: string;
|
||||
lastUpdated?: string;
|
||||
auditLog: ConsentAuditLog[];
|
||||
}
|
||||
|
||||
export interface CookieConsentContextType {
|
||||
state: CookieConsentState;
|
||||
config: CookieConsentConfig;
|
||||
acceptAll: () => void;
|
||||
acceptNecessary: () => void;
|
||||
acceptSelected: (preferences: Partial<CookiePreferences>) => void;
|
||||
showSettings: () => void;
|
||||
hideSettings: () => void;
|
||||
updatePreferences: (preferences: Partial<CookiePreferences>) => void;
|
||||
resetConsent: () => void;
|
||||
withdrawConsent: () => void;
|
||||
exportConsentData: () => string;
|
||||
getConsentSummary: () => any;
|
||||
}
|
||||
|
||||
// Default cookie preferences
|
||||
const defaultPreferences: CookiePreferences = {
|
||||
necessary: true, // Always true, cannot be disabled
|
||||
functional: false,
|
||||
};
|
||||
|
||||
// Enterprise configuration
|
||||
const defaultConfig: CookieConsentConfig = {
|
||||
version: '2.0',
|
||||
companyName: 'Your Company Name',
|
||||
privacyPolicyUrl: '/policy?type=privacy',
|
||||
cookiePolicyUrl: '/policy?type=privacy',
|
||||
dataControllerEmail: 'privacy@yourcompany.com',
|
||||
retentionPeriod: 365, // 1 year
|
||||
enableAuditLog: true,
|
||||
enableDetailedSettings: true,
|
||||
showPrivacyNotice: true,
|
||||
};
|
||||
|
||||
// Default state
|
||||
const defaultState: CookieConsentState = {
|
||||
hasConsented: false,
|
||||
preferences: defaultPreferences,
|
||||
showBanner: false,
|
||||
showSettings: false,
|
||||
auditLog: [],
|
||||
};
|
||||
|
||||
// Create context
|
||||
const CookieConsentContext = createContext<CookieConsentContextType | undefined>(undefined);
|
||||
|
||||
// Storage keys
|
||||
const CONSENT_STORAGE_KEY = 'cookie-consent-preferences';
|
||||
const CONSENT_VERSION = '2.0';
|
||||
|
||||
// Utility functions
|
||||
const generateSessionId = (): string => {
|
||||
return Math.random().toString(36).substring(2) + Date.now().toString(36);
|
||||
};
|
||||
|
||||
const createAuditLogEntry = (
|
||||
action: ConsentAuditLog['action'],
|
||||
preferences: CookiePreferences
|
||||
): ConsentAuditLog => {
|
||||
return {
|
||||
timestamp: new Date().toISOString(),
|
||||
action,
|
||||
preferences,
|
||||
userAgent: typeof window !== 'undefined' ? window.navigator.userAgent : '',
|
||||
sessionId: generateSessionId(),
|
||||
};
|
||||
};
|
||||
|
||||
// Provider component
|
||||
export const CookieConsentProvider: React.FC<{
|
||||
children: ReactNode;
|
||||
config?: Partial<CookieConsentConfig>;
|
||||
}> = ({ children, config: customConfig }) => {
|
||||
const [state, setState] = useState<CookieConsentState>(defaultState);
|
||||
const config = { ...defaultConfig, ...customConfig };
|
||||
|
||||
// Load saved preferences on mount
|
||||
useEffect(() => {
|
||||
const loadSavedPreferences = () => {
|
||||
try {
|
||||
const saved = localStorage.getItem(CONSENT_STORAGE_KEY);
|
||||
if (saved) {
|
||||
const parsed = JSON.parse(saved);
|
||||
// Check if saved version matches current version
|
||||
if (parsed.version === CONSENT_VERSION) {
|
||||
setState({
|
||||
hasConsented: true,
|
||||
preferences: parsed.preferences,
|
||||
showBanner: false,
|
||||
showSettings: false,
|
||||
consentDate: parsed.consentDate,
|
||||
lastUpdated: parsed.lastUpdated,
|
||||
auditLog: parsed.auditLog || [],
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
}
|
||||
|
||||
// Show banner if no valid consent found
|
||||
setState(prev => ({ ...prev, showBanner: true }));
|
||||
};
|
||||
|
||||
loadSavedPreferences();
|
||||
}, []);
|
||||
|
||||
// Save preferences to localStorage with audit logging
|
||||
const savePreferences = (preferences: CookiePreferences, action: ConsentAuditLog['action'] = 'consent_given') => {
|
||||
try {
|
||||
const auditEntry = config.enableAuditLog ? createAuditLogEntry(action, preferences) : null;
|
||||
|
||||
const data = {
|
||||
version: CONSENT_VERSION,
|
||||
preferences,
|
||||
timestamp: new Date().toISOString(),
|
||||
consentDate: state.consentDate || new Date().toISOString(),
|
||||
lastUpdated: new Date().toISOString(),
|
||||
auditLog: auditEntry ? [...state.auditLog, auditEntry] : state.auditLog,
|
||||
};
|
||||
|
||||
localStorage.setItem(CONSENT_STORAGE_KEY, JSON.stringify(data));
|
||||
|
||||
// Update state with audit log
|
||||
if (auditEntry) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
auditLog: [...prev.auditLog, auditEntry],
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
}
|
||||
};
|
||||
|
||||
// Accept all cookies
|
||||
const acceptAll = () => {
|
||||
const allAccepted: CookiePreferences = {
|
||||
necessary: true,
|
||||
functional: true,
|
||||
};
|
||||
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
hasConsented: true,
|
||||
preferences: allAccepted,
|
||||
showBanner: false,
|
||||
showSettings: false,
|
||||
consentDate: prev.consentDate || new Date().toISOString(),
|
||||
lastUpdated: new Date().toISOString(),
|
||||
}));
|
||||
|
||||
savePreferences(allAccepted, 'consent_given');
|
||||
};
|
||||
|
||||
// Accept only necessary cookies
|
||||
const acceptNecessary = () => {
|
||||
const necessaryOnly: CookiePreferences = {
|
||||
necessary: true,
|
||||
functional: false,
|
||||
};
|
||||
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
hasConsented: true,
|
||||
preferences: necessaryOnly,
|
||||
showBanner: false,
|
||||
showSettings: false,
|
||||
consentDate: prev.consentDate || new Date().toISOString(),
|
||||
lastUpdated: new Date().toISOString(),
|
||||
}));
|
||||
|
||||
savePreferences(necessaryOnly, 'consent_given');
|
||||
};
|
||||
|
||||
// Accept selected cookies
|
||||
const acceptSelected = (preferences: Partial<CookiePreferences>) => {
|
||||
const newPreferences: CookiePreferences = {
|
||||
necessary: true, // Always true
|
||||
functional: preferences.functional ?? false,
|
||||
};
|
||||
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
hasConsented: true,
|
||||
preferences: newPreferences,
|
||||
showBanner: false,
|
||||
showSettings: false,
|
||||
consentDate: prev.consentDate || new Date().toISOString(),
|
||||
lastUpdated: new Date().toISOString(),
|
||||
}));
|
||||
|
||||
savePreferences(newPreferences, 'consent_updated');
|
||||
};
|
||||
|
||||
// Show settings modal
|
||||
const showSettings = () => {
|
||||
setState(prev => ({ ...prev, showSettings: true }));
|
||||
|
||||
// Log settings opened
|
||||
if (config.enableAuditLog) {
|
||||
const auditEntry = createAuditLogEntry('settings_opened', state.preferences);
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
auditLog: [...prev.auditLog, auditEntry],
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// Hide settings modal
|
||||
const hideSettings = () => {
|
||||
setState(prev => ({ ...prev, showSettings: false }));
|
||||
};
|
||||
|
||||
// Update preferences (for settings modal)
|
||||
const updatePreferences = (preferences: Partial<CookiePreferences>) => {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
preferences: {
|
||||
...prev.preferences,
|
||||
...preferences,
|
||||
necessary: true, // Always keep necessary as true
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
// Reset consent (for testing or user request)
|
||||
const resetConsent = () => {
|
||||
try {
|
||||
localStorage.removeItem(CONSENT_STORAGE_KEY);
|
||||
} catch (error) {
|
||||
}
|
||||
|
||||
setState({
|
||||
hasConsented: false,
|
||||
preferences: defaultPreferences,
|
||||
showBanner: true,
|
||||
showSettings: false,
|
||||
auditLog: [],
|
||||
});
|
||||
};
|
||||
|
||||
// Withdraw consent (GDPR compliance)
|
||||
const withdrawConsent = () => {
|
||||
try {
|
||||
localStorage.removeItem(CONSENT_STORAGE_KEY);
|
||||
} catch (error) {
|
||||
}
|
||||
|
||||
const auditEntry = config.enableAuditLog ? createAuditLogEntry('consent_withdrawn', defaultPreferences) : null;
|
||||
|
||||
setState({
|
||||
hasConsented: false,
|
||||
preferences: defaultPreferences,
|
||||
showBanner: true,
|
||||
showSettings: false,
|
||||
auditLog: auditEntry ? [...state.auditLog, auditEntry] : state.auditLog,
|
||||
});
|
||||
};
|
||||
|
||||
// Export consent data (GDPR compliance)
|
||||
const exportConsentData = (): string => {
|
||||
const exportData = {
|
||||
consentData: {
|
||||
hasConsented: state.hasConsented,
|
||||
preferences: state.preferences,
|
||||
consentDate: state.consentDate,
|
||||
lastUpdated: state.lastUpdated,
|
||||
auditLog: state.auditLog,
|
||||
},
|
||||
config: {
|
||||
version: config.version,
|
||||
companyName: config.companyName,
|
||||
retentionPeriod: config.retentionPeriod,
|
||||
},
|
||||
exportDate: new Date().toISOString(),
|
||||
};
|
||||
|
||||
return JSON.stringify(exportData, null, 2);
|
||||
};
|
||||
|
||||
// Get consent summary
|
||||
const getConsentSummary = () => {
|
||||
return {
|
||||
hasConsented: state.hasConsented,
|
||||
preferences: state.preferences,
|
||||
consentDate: state.consentDate,
|
||||
lastUpdated: state.lastUpdated,
|
||||
auditLogCount: state.auditLog.length,
|
||||
config: {
|
||||
version: config.version,
|
||||
companyName: config.companyName,
|
||||
retentionPeriod: config.retentionPeriod,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const contextValue: CookieConsentContextType = {
|
||||
state,
|
||||
config,
|
||||
acceptAll,
|
||||
acceptNecessary,
|
||||
acceptSelected,
|
||||
showSettings,
|
||||
hideSettings,
|
||||
updatePreferences,
|
||||
resetConsent,
|
||||
withdrawConsent,
|
||||
exportConsentData,
|
||||
getConsentSummary,
|
||||
};
|
||||
|
||||
return (
|
||||
<CookieConsentContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</CookieConsentContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
// Hook to use cookie consent context
|
||||
export const useCookieConsent = (): CookieConsentContextType => {
|
||||
const context = useContext(CookieConsentContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useCookieConsent must be used within a CookieConsentProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
// Hook to check if specific cookie type is allowed
|
||||
export const useCookiePermission = (type: keyof CookiePreferences): boolean => {
|
||||
const { state } = useCookieConsent();
|
||||
return state.preferences[type];
|
||||
};
|
||||
|
||||
// Hook for functional features (only runs if functional cookies are allowed)
|
||||
export const useFunctional = () => {
|
||||
const { state } = useCookieConsent();
|
||||
const isEnabled = state.preferences.functional && state.hasConsented;
|
||||
|
||||
const saveUserPreference = (key: string, value: any) => {
|
||||
if (isEnabled && typeof window !== 'undefined') {
|
||||
try {
|
||||
localStorage.setItem(`user-preference-${key}`, JSON.stringify(value));
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const loadUserPreference = (key: string, defaultValue?: any) => {
|
||||
if (isEnabled && typeof window !== 'undefined') {
|
||||
try {
|
||||
const saved = localStorage.getItem(`user-preference-${key}`);
|
||||
return saved ? JSON.parse(saved) : defaultValue;
|
||||
} catch (error) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
const rememberUserAction = (action: string, data?: any) => {
|
||||
if (isEnabled) {
|
||||
// Implement your user action tracking logic here
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
saveUserPreference,
|
||||
loadUserPreference,
|
||||
rememberUserAction,
|
||||
isEnabled,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user