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-toolkit

Import 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 to true. Set false to retain manual control via selectTemplate / generatePolicy.
  • persist — defaults to true (writes to localStorage). Pass false for an in-memory no-op adapter. Renamed from useLocalStorage in 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 over persist.

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.