Skip to content

@msflib/react-certificate

Multi-Tenant Certificate module built on TanStack Query, following the same approach as other @msflib/react-* modules.

Install

pnpm add @msflib/core @msflib/react-certificate

Peer dependencies

  • react >= 18
  • @tanstack/react-query >= 5

Wrap your app with CertificateProvider inside your QueryClientProvider.

API Reference

CertificateProvider

A React context provider that manages certificate configurations, placeholder field names, and user certificates.

import { CertificateProvider } from '@msflib/react-certificate';

<QueryClientProvider client={queryClient}>
  <CertificateProvider>{/* your app */}</CertificateProvider>
</QueryClientProvider>;

Props

Prop Type Required Description
children React.ReactNode Yes Child component tree.
options object No Configuration options for the provider. See below for details.

options Configuration

Key Type Default Description
isWorkspaceScoped boolean true If true, all certificate data is isolated per workspace.
requireAuth boolean false If true, data will only be fetched when isAuthenticated is true.
isAuthenticated boolean false The authentication status of the user (e.g. from useAuth().status).

In Next.js App Router, CertificateProvider must be in a client component ("use client").

'use client';

import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { CertificateProvider } from '@msflib/react-certificate';

const qc = new QueryClient();

export default function Providers({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={qc}>
      <CertificateProvider options={{ isWorkspaceScoped: true }}>{children}</CertificateProvider>
    </QueryClientProvider>
  );
}

Multi-Tenancy

This module supports multi-tenancy using the options.isWorkspaceScoped setting and the useActiveWorkspace hook from @msflib/react-shared. All API calls are automatically scoped to the current workspace if isWorkspaceScoped is true (default).

Configuration

'use client';

import { configureApplication } from '@msflib/core';

configureApplication({
  baseURL: process.env.NEXT_PUBLIC_API_URL!,
  accessTokenKey: 'access_token',
  endpoints: {
    certificate: {
      me: '/certificates/me', // default
      adminConfig: '/admin/certificates/config', // default
      adminFieldNames: '/admin/certificates/fieldnames', // default
      adminFonts: '/admin/certificates/fonts', // default
      adminUsers: '/admin/certificates/users', // default
      adminPreview: '/admin/certificates/config/preview', // default
    },
  },
});

API

getMe

Automatically fetches the current user's certificate on mount (GET /certificates/me).

getConfigs

Automatically fetches all certificate configurations on mount (GET /admin/certificates/config).

getConfig

Synchronous local lookup by config id from the cached list. Returns undefined if not found.

const config = getConfig(10);

uploadConfig

Uploads a new certificate template and configuration (POST /admin/certificates/config/upload).

Expects multipart form data:

const formData = new FormData();
formData.append('certificate_template', file);
formData.append('name', 'My Certificate');
formData.append('placeholders', JSON.stringify([...]));
uploadConfig(formData);

updateConfig

Updates an existing certificate configuration (PUT /admin/certificates/config/{config_id}).

Expects multipart form data. Patches the matching config in the cache on success.

const formData = new FormData();
formData.append('name', 'Updated Name');
updateConfig(configId, formData);

deleteConfig

Deletes a certificate configuration (DELETE /admin/certificates/config/{config_id}).

Removes the deleted config from the cache on success.

previewCertificate

Generates a preview of a certificate template (POST /admin/certificates/config/preview).

Expects multipart form data with certificate_template and placeholders.

generateCertificates

Generates certificates for users matching the given filters (POST /admin/certificates/config/{config_id}/generate).

generateCertificates(configId, {
  level_ids: [1, 2],
  track_ids: [3],
  stage_ids: [],
  update_if_exist: true,
});

addUsersCertificate

Adds or updates certificates for specific users (POST /admin/certificates/config/{config_id}/users).

addUsersCertificate(configId, { user_ids: [1, 2, 3] });

deleteUsersCertificate

Deletes certificates for specific users (DELETE /admin/certificates/users).

deleteUsersCertificate([1, 2, 3]);

getUserCertificates

Automatically fetches all user certificates on mount (GET /admin/certificates/users).

getFieldNames

Automatically fetches available placeholder field names on mount (GET /admin/certificates/fieldnames).

getFonts

Automatically fetches available fonts on mount (GET /admin/certificates/fonts).

refetch

Manually refetch all queries.

Hook Usage

import { useCertificate } from '@msflib/react-certificate';

function CertificatePage() {
  const {
    certificate,
    configs,
    userCertificates,
    fieldNames,
    fonts,
    getConfig,
    uploadConfig,
    updateConfig,
    deleteConfig,
    previewCertificate,
    generateCertificates,
    addUsersCertificate,
    deleteUsersCertificate,
    refetch,
    loading,
  } = useCertificate();

  if (loading.certificate) return <div>Loading...</div>;

  return (
    <div>
      <h1>{certificate?.name}</h1>
      <ul>
        {configs.map((config) => (
          <li key={config.id}>
            {config.name}
            <button onClick={() => deleteConfig(config.id)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Returned Hook Shape

const {
  certificate,
  configs,
  getConfig,
  uploadConfig,
  updateConfig,
  deleteConfig,
  previewCertificate,
  generateCertificates,
  userCertificates,
  addUsersCertificate,
  deleteUsersCertificate,
  fieldNames,
  fonts,
  refetch,
  loading,
} = useCertificate();

// Shape:
{
  certificate: Certificate | null;
  configs: CertificateConfig[];
  getConfig: (id: number) => CertificateConfig | undefined;
  uploadConfig: (data: FormData, options?: MutateOptions) => Promise<CertificateConfig>;
  updateConfig: (configId: number, data: FormData, options?: MutateOptions) => Promise<CertificateConfig>;
  deleteConfig: (configId: number, options?: MutateOptions) => Promise<CertificateConfig>;
  previewCertificate: (data: FormData, options?: MutateOptions) => Promise<string>;
  generateCertificates: (configId: number, data: GenerateCertificatesPayload, options?: MutateOptions) => Promise<Certificate[]>;
  userCertificates: Certificate[];
  addUsersCertificate: (configId: number, data: AddUsersCertificatePayload, options?: MutateOptions) => Promise<Certificate[]>;
  deleteUsersCertificate: (userIds: number[], options?: MutateOptions) => Promise<Certificate[]>;
  fieldNames: FieldName[];
  fonts: Font[];
  refetch: () => void;
  loading: {
    certificate: boolean;
    configs: boolean;
    userCertificates: boolean;
    fieldNames: boolean;
    fonts: boolean;
    uploadConfig: boolean;
    updateConfig: boolean;
    deleteConfig: boolean;
    preview: boolean;
    generate: boolean;
    addUsers: boolean;
    deleteUsers: boolean;
  };
}

Types

export type Certificate = {
  id: number;
  created_at: string;
  updated_at: string;
  name: string;
  url: string;
  owner_id: number;
  document_type: string;
};

export type CertificateConfig = {
  id: number;
  created_at: string;
  updated_at: string;
  name: string;
  description: string;
  workspace_id: number;
  resolution: number;
  template_url: string;
  use_fallback: boolean;
  placeholders: Placeholder[];
  data: Record<string, unknown>;
};

export type FieldName = {
  id: number;
  field_name: string;
  type: 'text' | 'image';
};

export type Font = {
  font_family: string;
  type: 'system' | string;
  url: string;
};

Notes

  • CertificateProvider must be rendered in a client component in Next.js ("use client").
  • All queries are cached for 60 seconds by default.
  • getConfig performs a local cache lookup — it does not fire a network request.
  • uploadConfig and updateConfig expect FormData with the template file and a JSON-stringified placeholders field.
  • addUsersCertificate and deleteUsersCertificate invalidate the user certificates cache on success rather than patching it locally, since the returned list reflects server-side state.