Basic Integration Guide

A comprehensive guide to integrating MIMS SDK into your React application from start to finish.

Prerequisites

Before starting, ensure you have completed the installation and have your API key ready.

Integration Overview

This guide walks you through building a complete document signing flow with the following features:

  • Loading documents from your backend
  • Displaying the PDF with form fields
  • Capturing signatures
  • Submitting completed documents
  • Handling success and error states

Step 1: Set Up the Provider

Create a providers file that wraps your application with the MIMS provider:

app/providers.tsxtypescript
1'use client';
2
3import { MIMSProvider } from '@mims/sdk-react';
4import { ReactNode, useState, useEffect } from 'react';
5
6export function Providers({ children }: { children: ReactNode }) {
7 const [mounted, setMounted] = useState(false);
8
9 // Avoid hydration mismatch
10 useEffect(() => {
11 setMounted(true);
12 }, []);
13
14 if (!mounted) {
15 return null;
16 }
17
18 return (
19 <MIMSProvider
20 apiKey={process.env.NEXT_PUBLIC_MIMS_API_KEY!}
21 debug={process.env.NODE_ENV === 'development'}
22 onReady={() => {
23 console.log('MIMS SDK ready');
24 }}
25 onError={(error) => {
26 console.error('MIMS SDK error:', error);
27 }}
28 >
29 {children}
30 </MIMSProvider>
31 );
32}

Step 2: Create the Document Service

Create a service to fetch document details from your backend:

lib/documents.tstypescript
export interface Document {
  id: string;
  title: string;
  url: string;
  fields: FieldDefinition[];
  status: 'draft' | 'pending' | 'completed';
}

export async function getDocument(documentId: string): Promise<Document> {
  const response = await fetch(`/api/documents/${documentId}`);
  
  if (!response.ok) {
    throw new Error('Failed to fetch document');
  }
  
  return response.json();
}

export async function completeDocument(
  documentId: string,
  submissionData: {
    submittedAt: string;
    checksum: string;
  }
): Promise<void> {
  const response = await fetch(`/api/documents/${documentId}/complete`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(submissionData),
  });
  
  if (!response.ok) {
    throw new Error('Failed to complete document');
  }
}

Step 3: Build the Document Viewer Component

components/document-viewer.tsxtypescript
1'use client';
2
3import { useState, useEffect } from 'react';
4import { PDFViewer, useSDK, type DocumentSubmissionPayload } from '@mims/sdk-react';
5import { getDocument, completeDocument, type Document } from '@/lib/documents';
6
7interface DocumentViewerProps {
8 documentId: string;
9 onComplete?: () => void;
10}
11
12export function DocumentViewer({ documentId, onComplete }: DocumentViewerProps) {
13 const { isInitialized, validationError } = useSDK();
14 const [document, setDocument] = useState<Document | null>(null);
15 const [loading, setLoading] = useState(true);
16 const [error, setError] = useState<string | null>(null);
17 const [submitted, setSubmitted] = useState(false);
18
19 // Fetch document on mount
20 useEffect(() => {
21 if (!isInitialized) return;
22
23 async function fetchDocument() {
24 try {
25 const doc = await getDocument(documentId);
26 setDocument(doc);
27 } catch (err) {
28 setError(err instanceof Error ? err.message : 'Failed to load document');
29 } finally {
30 setLoading(false);
31 }
32 }
33
34 fetchDocument();
35 }, [documentId, isInitialized]);
36
37 // Handle submission
38 const handleSubmit = async (payload: DocumentSubmissionPayload) => {
39 try {
40 // Notify your backend
41 await completeDocument(documentId, {
42 submittedAt: payload.submittedAt,
43 checksum: payload.checksum,
44 });
45
46 setSubmitted(true);
47 onComplete?.();
48 } catch (err) {
49 throw err; // Let the SDK handle the error display
50 }
51 };
52
53 // Loading state
54 if (loading || !isInitialized) {
55 return (
56 <div className="flex items-center justify-center h-96">
57 <div className="animate-spin h-8 w-8 border-4 border-blue-500 border-t-transparent rounded-full" />
58 </div>
59 );
60 }
61
62 // Error state
63 if (error || validationError) {
64 return (
65 <div className="bg-red-50 border border-red-200 rounded-lg p-6 text-center">
66 <h3 className="text-red-800 font-semibold">Error Loading Document</h3>
67 <p className="text-red-600 mt-2">{error || validationError}</p>
68 <button
69 onClick={() => window.location.reload()}
70 className="mt-4 px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700"
71 >
72 Try Again
73 </button>
74 </div>
75 );
76 }
77
78 // Success state
79 if (submitted) {
80 return (
81 <div className="bg-green-50 border border-green-200 rounded-lg p-6 text-center">
82 <div className="text-green-500 text-5xl mb-4">✓</div>
83 <h3 className="text-green-800 font-semibold text-xl">
84 Document Submitted Successfully!
85 </h3>
86 <p className="text-green-600 mt-2">
87 Your signed document has been processed and saved.
88 </p>
89 </div>
90 );
91 }
92
93 // Render viewer
94 if (!document) return null;
95
96 return (
97 <div className="h-[80vh] border rounded-lg overflow-hidden">
98 <PDFViewer
99 documentId={document.id}
100 documentUrl={document.url}
101 initialFields={document.fields}
102 onSubmit={handleSubmit}
103 onSubmitError={(err) => {
104 setError(err.message);
105 }}
106 />
107 </div>
108 );
109}

Step 4: Create the Page

app/documents/[id]/page.tsxtypescript
import { DocumentViewer } from '@/components/document-viewer';
import { Suspense } from 'react';

interface DocumentPageProps {
  params: { id: string };
}

export default function DocumentPage({ params }: DocumentPageProps) {
  return (
    <div className="container mx-auto py-8 px-4">
      <header className="mb-6">
        <h1 className="text-2xl font-bold">Review & Sign Document</h1>
        <p className="text-gray-600 mt-1">
          Please review the document and fill in all required fields.
        </p>
      </header>

      <Suspense fallback={<DocumentSkeleton />}>
        <DocumentViewer
          documentId={params.id}
          onComplete={() => {
            // Navigate to success page or show notification
            console.log('Document completed!');
          }}
        />
      </Suspense>
    </div>
  );
}

function DocumentSkeleton() {
  return (
    <div className="h-[80vh] border rounded-lg bg-gray-100 animate-pulse" />
  );
}

Step 5: Create the API Routes

app/api/documents/[id]/route.tstypescript
import { NextResponse } from 'next/server';

export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  // Fetch document from your database
  const document = await prisma.document.findUnique({
    where: { id: params.id },
    include: { fields: true },
  });

  if (!document) {
    return NextResponse.json(
      { error: 'Document not found' },
      { status: 404 }
    );
  }

  // Generate signed URL for PDF
  const url = await generateSignedUrl(document.s3Key);

  return NextResponse.json({
    id: document.id,
    title: document.title,
    url,
    fields: document.fields,
    status: document.status,
  });
}
app/api/documents/[id]/complete/route.tstypescript
import { NextResponse } from 'next/server';

export async function POST(
  request: Request,
  { params }: { params: { id: string } }
) {
  const body = await request.json();

  // Update document status
  await prisma.document.update({
    where: { id: params.id },
    data: {
      status: 'completed',
      completedAt: new Date(body.submittedAt),
      checksum: body.checksum,
    },
  });

  // Trigger any post-completion workflows
  await sendCompletionNotification(params.id);

  return NextResponse.json({ success: true });
}

Complete Flow Diagram

┌─────────────────────────────────────────────────────────────┐
│                        User Flow                             │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  1. User navigates to /documents/[id]                       │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  2. MIMSProvider validates API key                          │
│     POST /sdk/validate-key                                  │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  3. DocumentViewer fetches document details                 │
│     GET /api/documents/[id]                                 │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  4. PDFViewer loads and renders PDF                         │
│     - Displays form fields                                  │
│     - User fills fields and signs                           │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  5. User clicks Submit                                      │
│     - SDK validates all required fields                     │
│     - SDK sends submission to MIMS API                      │
│     POST /sdk/documents/submit                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  6. Your backend is notified                                │
│     POST /api/documents/[id]/complete                       │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  7. Success! Document is completed                          │
└─────────────────────────────────────────────────────────────┘

Next Steps

Now that you have a basic integration working, explore these advanced topics: