React Hooks
Custom React hooks for managing state and logic in NDPA-compliant applications
Overview
The NDPR Toolkit provides a set of custom React hooks to help manage state and logic in your NDPA-compliant applications. These hooks encapsulate common functionality and make it easier to implement complex features.
Installation
Install the NDPR Toolkit package which includes all hooks:
pnpm add @tantainnovative/ndpr-toolkitImport hooks from the main package:
import {
useConsent,
useDSR,
useDPIA,
useBreach,
usePrivacyPolicy,
useLawfulBasis,
useCrossBorderTransfer,
useROPA,
} from '@tantainnovative/ndpr-toolkit';Available Hooks
useConsent
A hook for managing consent state and preferences.
import { useConsent } from '@tantainnovative/ndpr-toolkit';
function ConsentManager() {
const {
settings, // Current consent settings (ConsentSettings | null)
hasConsent, // (optionId) => boolean — has consent for an option
updateConsent, // (consents: Record<string, boolean>) => void
acceptAll, // Accept all consent options
rejectAll, // Reject all non-required options
shouldShowBanner, // Whether the consent banner should be shown
isValid, // Whether current consent settings are valid
validationErrors, // Structured validation errors
resetConsent, // Clear consent settings from storage
isLoading, // Whether the storage adapter is still loading
} = useConsent({
options: [
{ id: 'necessary', label: 'Necessary', required: true },
{ id: 'analytics', label: 'Analytics' },
],
});
// Example usage
if (isLoading) return null;
return (
<div>
<h2>Consent Preferences</h2>
<label>
<input
type="checkbox"
checked={hasConsent('analytics')}
onChange={(e) => updateConsent({ analytics: e.target.checked })}
/>
Analytics Cookies
</label>
<button onClick={acceptAll}>Accept All</button>
<button onClick={rejectAll}>Reject Non-Essential</button>
</div>
);
}useDSR
A hook for managing Data Subject Rights (DSR) requests.
import { useDSR } from '@tantainnovative/ndpr-toolkit';
function DSRManager() {
const {
requests, // List of DSR requests
submitRequest, // Submit a new request
updateRequest, // Update an existing request
getRequest, // Get a request by id
getRequestsByStatus, // Filter requests by status
getRequestsByType, // Filter requests by type
} = useDSR({ requestTypes });
// Example usage
const handleSubmit = (formData) => {
submitRequest({
type: 'access',
subject: {
name: formData.name,
email: formData.email,
phone: formData.phone
},
description: formData.description
});
};
return (
<div>
<h2>DSR Requests</h2>
<ul>
{requests.map(request => (
<li key={request.id}>
{request.subject.name} - {request.type} - {request.status}
</li>
))}
</ul>
</div>
);
}useDPIA
A hook for managing Data Protection Impact Assessment (DPIA) state.
import { useDPIA } from '@tantainnovative/ndpr-toolkit';
function DPIAManager({ sections }) {
const {
currentSectionIndex, // Index of the active section
currentSection, // Active DPIASection | null
answers, // All answers (DPIAAnswerMap)
updateAnswer, // (questionId, value) => void
nextSection, // () => boolean — advance if current section valid
prevSection, // () => boolean — go back a section
goToSection, // (index) => boolean
isCurrentSectionValid, // () => boolean
getCurrentSectionErrors,// () => Record<string, string>
isComplete, // () => boolean
completeDPIA, // (assessorInfo, title, description) => DPIAResult
getVisibleQuestions, // () => DPIAQuestion[] (respects showWhen conditions)
resetDPIA, // () => void
progress, // number — completion percentage
isLoading, // Whether the storage adapter is still loading
} = useDPIA({ sections });
// Example usage
if (isLoading) return null;
return (
<div>
<h2>DPIA Questionnaire</h2>
<p>{currentSection?.title} — {progress}% complete</p>
<button onClick={prevSection} disabled={currentSectionIndex === 0}>Previous</button>
<button onClick={nextSection} disabled={!isCurrentSectionValid()}>Next</button>
<button
onClick={() =>
completeDPIA(
{ name: 'Jane Doe', role: 'DPO', email: 'dpo@acme.ng' },
'Customer Analytics DPIA',
'Assessment of customer analytics processing'
)
}
disabled={!isComplete()}
>
Complete DPIA
</button>
</div>
);
}useBreach
A hook for managing data breach notifications and assessments.
import { useBreach } from '@tantainnovative/ndpr-toolkit';
function BreachManager({ categories }) {
const {
reports, // All breach reports (BreachReport[])
assessments, // All risk assessments
notifications, // All regulatory notifications
reportBreach, // (reportData) => BreachReport
updateReport, // (id, updates) => BreachReport | null
getReport, // (id) => BreachReport | null
assessRisk, // (breachId, assessmentData) => RiskAssessment
getAssessment, // (breachId) => RiskAssessment | null
calculateNotificationRequirements,// (breachId) => NotificationRequirement | null
sendNotification, // (breachId, notificationData) => RegulatoryNotification
getNotification, // (breachId) => RegulatoryNotification | null
getBreachesRequiringNotification, // (hoursThreshold?) => due-breach list
clearBreachData, // () => void
isLoading, // Whether the storage adapter is still loading
} = useBreach({ categories });
// Example usage
if (isLoading) return null;
return (
<div>
<h2>Data Breach Management</h2>
<ul>
{reports.map(report => (
<li key={report.id}>
{report.title} - {report.status}
</li>
))}
</ul>
</div>
);
}useDefaultPrivacyPolicy
The recommended hook for the common case: generates an NDPA-compliant policy from your orgInfo automatically. Returns a non-null policy on the first useful render with autoGenerate: true (the default, added in v3.4.0).
import { useDefaultPrivacyPolicy } from '@tantainnovative/ndpr-toolkit';
import { PolicyPage } from '@tantainnovative/ndpr-toolkit/policy';
function PrivacyPage() {
const { policy } = useDefaultPrivacyPolicy({
orgInfo: {
name: 'Acme Nigeria Ltd',
email: 'privacy@acme.ng',
website: 'https://acme.ng',
address: '12 Marina, Lagos',
},
});
return policy ? <PolicyPage policy={policy} /> : null;
}Options:
orgInfo— name / email / website / address / industry / dpoName / dpoEmail. Maps directly to template variables.autoGenerate— defaults totrue. Setfalseto retain manual control viaselectTemplate/generatePolicy.persist— defaults totrue(writes to localStorage). Passfalsefor an in-memory no-op adapter. Renamed fromuseLocalStoragein v3.5.0; the old name still works as a deprecated alias and will be removed in 4.0.adapter— pluggable storage adapter. Takes precedence overpersist.
usePrivacyPolicy
The lower-level hook for managing privacy policy generation and customization. Use this when you need explicit control over template selection, variable values, and section toggling — for example when building a policy editor UI. For the common drop-in case prefer useDefaultPrivacyPolicy above.
import { usePrivacyPolicy } from '@tantainnovative/ndpr-toolkit';
function PrivacyPolicyManager() {
const {
policy, // Current privacy policy
selectedTemplate, // Selected policy template
organizationInfo, // Organization information
selectTemplate, // Function to select a template
updateOrganizationInfo, // Function to update organization info
toggleSection, // Function to toggle a section on/off
updateSectionContent, // Function to update section content
updateVariableValue, // Function to update a variable value
generatePolicy, // Function to generate the policy
getPolicyText, // Function to get the policy text
resetPolicy, // Function to reset the policy
isValid // Function to check if policy is valid
} = usePrivacyPolicy();
// Example usage
return (
<div>
<h2>Privacy Policy Generator</h2>
<button onClick={() => selectTemplate('standard')}>
Use Standard Template
</button>
<input
type="text"
value={organizationInfo.name}
onChange={(e) => updateOrganizationInfo('name', e.target.value)}
placeholder="Organization Name"
/>
<button onClick={generatePolicy} disabled={!isValid()}>
Generate Policy
</button>
<div>
<h3>Preview</h3>
<div>{policy?.fullText}</div>
</div>
</div>
);
}Best Practices
- Use hooks at the top level - Always use React hooks at the top level of your component, not inside loops, conditions, or nested functions.
- Combine with context - For global state management, consider using these hooks with React Context to share state across components.
- Customize storage options - Most hooks accept storage options to customize how data is persisted. Use this to implement your own storage mechanisms.
- Handle loading states - Check for loading states before rendering components that depend on data from hooks.