@documedis/prescription-sign

A React component library for signing electronic prescriptions using HIN authentication. This library provides both a usePrescriptionSigning hook for custom implementations and a PrescriptionSign component for quick integration. The library intelligently handles session restoration to minimize authentication flows when valid session data exists.

Quick Start

Installation

npm install @documedis-components/prescription-sign

Basic Usage

import { PrescriptionSign } from '@documedis-components/prescription-sign/react';

function MyApp() {
  return (
    <PrescriptionSign
      environment="demo"
      accessToken="your-access-token"
      chmed="encoded-chmed-data"
      onSuccess={(signedCHMED) => console.log('Success!', signedCHMED)}
      onError={(error) => alert(error.userMessage)} // Show user-friendly message
    />
  );
}

API Reference

PrescriptionSign Component Props

ParameterTypeRequiredDescription
environment'demo' | 'prod'Environment configuration for the prescription service ('demo' for testing and development, 'prod' for production)
accessTokenstringAuthentication token for backend service
chmedstringEncoded CHMED prescription data
sessionTokenstringOptional existing session token to reuse authentication state
onSessionTokenUpdate(token: string) => voidOptional callback invoked when the session token is updated
onSuccess(signedCHMED: string) => voidOptional callback invoked when prescription signing succeeds
onError(error: DomainError) => voidOptional callback invoked when prescription signing fails
classNamestringAdditional CSS classes

usePrescriptionSigning Hook

For advanced use cases, you can use the usePrescriptionSigning hook directly to build custom UI components while leveraging the same robust signing logic. The hook accepts configuration parameters similar to the component props, but requires calling start(chmed) to initiate signing rather than passing chmed as a parameter.

Hook Parameters

ParameterTypeRequiredDescription
environment'demo' | 'prod'Environment configuration for the prescription service ('demo' for testing and development, 'prod' for production)
accessTokenstringAuthentication token for backend service
sessionTokenstringOptional existing session token to reuse authentication state
onSessionTokenUpdate(token: string) => voidOptional callback invoked when the session token is updated
onSuccess(signedCHMED: string) => voidOptional callback invoked when prescription signing succeeds
onError(error: DomainError) => voidOptional callback invoked when prescription signing fails

Hook Return Values

PropertyTypeDescription
start(chmed: string) => voidInitiates the signing process with base64-encoded CHMED prescription data
interrupt() => voidTerminates the signing process at any time
isIdlebooleanTrue when ready to start signing (initial state)
isActivebooleanTrue when actively processing (excludes error/success states)
isErrorbooleanTrue when in error state (persists until retry)
isSuccessbooleanTrue when signing completed successfully
isSigningbooleanTrue during the actual signature operation
signedCHMEDstring | undefinedThe signed prescription data (available after success)

Environment Configuration

  • demo - Demo environment with non-production data (safe for testing and development)
  • prod - Production environment with real data (for live prescriptions)

Error Handling with DomainError

All errors are instances of DomainError with three key properties:

  • code - Stable error code for programmatic handling (e.g., "POPUP_CLOSED", "INVALID_TOKEN")
  • message - Technical message for debugging (not for end users)
  • userMessage - User-friendly message safe to display in UI

Example Usage:

onError={(error) => {
  // Show user-friendly message in UI
  showNotification(error.userMessage);
  
  // Handle specific errors programmatically
  switch (error.code) {
    case 'POPUP_CLOSED':
      // User closed the popup, maybe offer to retry
      break;
    case 'SESSION_EXPIRED':
      // Session expired, clear cache and retry
      clearSession();
      break;
    case 'INVALID_FORMAT':
      // Invalid prescription data format
      highlightFormErrors();
      break;
  }
  
  // Log technical details for debugging
  console.error(error.message, error.code);
}}

Common Error Codes:

  • POPUP_CLOSED - User closed authentication popup
  • POPUP_BLOCKED - Browser blocked popup window
  • SESSION_EXPIRED - Authentication session expired
  • INVALID_TOKEN - Invalid or expired access token
  • INVALID_FORMAT - Malformed prescription data
  • HIN_ERROR - HIN service error
  • API_CONNECTION_FAILED - Network connection failed
  • TIMEOUT - Operation timed out

Session Restoration vs Fresh Flows

The library intelligently optimizes the signing process by checking session state first. This can result in two different flow patterns:

🚀 Fast Path: Session Restoration

When valid authentication data exists in session, the process can skip the authorization phase while maintaining all security checks:

initialization → securisation → authentication → validation → signing

Events like saml_handle_retrieved_from_session and oauth_token_retrieved_from_sessionindicate the process found valid session data and can skip the authorization phase.

🔐 Full Path: Fresh Authentication

When no valid session data exists, the full OAuth/SAML flow executes:

initialization → securisation → authentication → authorization → validation → signing

Events like oauth_flow_initiated and saml_handle_receivedindicate fresh authentication flows are being executed.

Usage Examples

Basic Implementation

<PrescriptionSign
  environment="demo"
  accessToken="your-token"
  chmed="CHMED16A1H4sI..."
/>

With Event Handlers

<PrescriptionSign
  environment="demo"
  accessToken="your-token"
  chmed="CHMED16A1H4sI..."
  onSuccess={(signedCHMED) => {
    console.log('Prescription signed:', signedCHMED);
    // Save to database, redirect user, etc.
  }}
  onError={(error) => {
    // Display user-friendly message
    showNotification(error.userMessage);
    // Log technical details for debugging
    console.error('Error code:', error.code, error.message);
  }}
/>

Using the Hook for Custom UI

import { usePrescriptionSigning } from '@documedis-components/prescription-sign/react';

function CustomSigningButton({ chmed, environment, accessToken }) {
  const { start, interrupt, isActive, isSuccess, isError, signedCHMED } = 
    usePrescriptionSigning({
      environment,
      accessToken,
      onSuccess: (signedCHMED) => console.log('Signed!', signedCHMED),
      onError: (error) => {
        // You can access error.userMessage for UI display
        console.error('Error:', error.code, '-', error.userMessage);
      },
    });

  if (isSuccess) {
    return <div>✅ Prescription signed: {signedCHMED?.substring(0, 20)}...</div>;
  }

  if (isError) {
    return <div>❌ Signing failed. <button onClick={() => start(chmed)}>Retry</button></div>;
  }

  return (
    <div>
      <button 
        onClick={() => start(chmed)} 
        disabled={isActive}
      >
        {isActive ? 'Signing...' : 'Sign Prescription'}
      </button>
      {isActive && <button onClick={interrupt}>Cancel</button>}
    </div>
  );
}

Interactive Demo

Try the component below with real CHMED data. Success and error events are displayed in the Event Log below for educational purposes.

Event Log (Success/Error)

No events yet. Try the demo component above to see structured events emitted here.

Design System Integration

This component uses the Documedis design system CSS variables and utility classes. You can customize the appearance by overriding these variables:

:root {
  --documedis-color-primary: #2d4e9b;
  --documedis-color-success: #3b9977;
  --documedis-color-error: #e5232a;
  --documedis-spacing-md: 1rem;
  --documedis-border-radius-md: 0.25rem;
  /* ... and many more */
}