npm package: @personql/react
Description: React SDK for PersonQL authentication and user management
Author: PersonQL Team
Latest version: 1.0.7

# PersonQL React SDK

A comprehensive React SDK for PersonQL authentication and user management. This SDK provides pre-built components, hooks, and utilities to quickly integrate PersonQL authentication into your React applications.

## Features

- 🚀 **Out-of-the-box components** - Ready-to-use Sign In, Sign Up, MFA, and Profile forms
- 🎣 **React Hooks** - Easy-to-use hooks for authentication state management
- 🔒 **Security First** - Built-in form validation, error handling, and secure token management
- 🎨 **Customizable UI** - Themeable components with Tailwind CSS
- 📱 **Responsive Design** - Mobile-friendly components
- 🔄 **MFA Support** - Multi-factor authentication with SMS, Email, and WhatsApp
- 🛡️ **Route Protection** - AuthGuard component for protecting routes
- 📝 **TypeScript Support** - Full TypeScript definitions included

## Installation

```bash
npm install @personql/react
# or
yarn add @personql/react
```

## Quick Start

### 1. Setup the Provider

Wrap your app with the `PersonQLProvider`:

```tsx
import React from 'react';
import { PersonQLProvider } from '@personql/react';

const config = {
  apiUrl: 'https://gateway.personql.com',
  clientId: 'your-client-id',
};

function App() {
  return (
    <PersonQLProvider config={config}>
      <YourAppContent />
    </PersonQLProvider>
  );
}
```

### 2. Use Authentication Components

```tsx
import React, { useState } from 'react';
import { SignInForm, SignUpForm, useAuth } from '@personql/react';

function AuthPage() {
  const [showSignUp, setShowSignUp] = useState(false);
  const { isAuthenticated } = useAuth();

  if (isAuthenticated) {
    return <Dashboard />;
  }

  return (
    <div className="min-h-screen flex items-center justify-center">
      {showSignUp ? (
        <SignUpForm
          onSuccess={() => console.log('Sign up successful!')}
          onSignIn={() => setShowSignUp(false)}
        />
      ) : (
        <SignInForm
          onSuccess={() => console.log('Sign in successful!')}
          onSignUp={() => setShowSignUp(true)}
        />
      )}
    </div>
  );
}
```

### 3. Protect Routes with AuthGuard

```tsx
import React from 'react';
import { AuthGuard } from '@personql/react';

function ProtectedPage() {
  return (
    <AuthGuard
      fallback={<div>Please sign in to access this page</div>}
      requireVerification={true}
    >
      <h1>Protected Content</h1>
      <p>Only authenticated and verified users can see this.</p>
    </AuthGuard>
  );
}
```

## Components

### Authentication Forms

#### SignInForm

```tsx
import { SignInForm } from '@personql/react';

<SignInForm
  onSuccess={() => navigate('/dashboard')}
  onSignUp={() => setShowSignUp(true)}
  onForgotPassword={() => setShowForgotPassword(true)}
  className="max-w-md mx-auto"
/>;
```

#### SignUpForm

```tsx
import { SignUpForm } from '@personql/react';

<SignUpForm
  onSuccess={() => navigate('/dashboard')}
  onSignIn={() => setShowSignUp(false)}
  className="max-w-md mx-auto"
/>;
```

#### MFAForm

```tsx
import { MFAForm } from '@personql/react';

<MFAForm
  onSuccess={() => navigate('/dashboard')}
  onCancel={() => navigate('/signin')}
/>;
```

#### ForgotPasswordForm

```tsx
import { ForgotPasswordForm } from '@personql/react';

<ForgotPasswordForm
  onSuccess={() => setEmailSent(true)}
  onBackToSignIn={() => navigate('/signin')}
/>;
```

#### ResetPasswordForm

```tsx
import { ResetPasswordForm } from '@personql/react';

<ResetPasswordForm token={resetToken} onSuccess={() => navigate('/signin')} />;
```

#### ProfileForm

```tsx
import { ProfileForm } from '@personql/react';

<ProfileForm
  onSuccess={() => setShowSuccess(true)}
  className="max-w-2xl mx-auto"
/>;
```

### Route Protection

#### AuthGuard

```tsx
import { AuthGuard } from '@personql/react';

<AuthGuard
  fallback={<SignInPrompt />}
  redirectTo="/signin"
  requireVerification={true}
>
  <ProtectedContent />
</AuthGuard>;
```

## Hooks

### useAuth

Main authentication hook:

```tsx
import { useAuth } from '@personql/react';

function MyComponent() {
  const {
    // State
    isAuthenticated,
    isLoading,
    error,
    user,
    requiresMFA,
    mfaMethods,

    // Methods
    signIn,
    signUp,
    signOut,
    sendMFACode,
    verifyMFACode,
    forgotPassword,
    resetPassword,
    clearError,
    isSessionExpired,
  } = useAuth();

  const handleSignIn = async () => {
    try {
      await signIn({
        email: 'user@example.com',
        password: 'password123',
        rememberMe: true,
      });
    } catch (error) {
      console.error('Sign in failed:', error);
    }
  };

  return (
    <div>
      {isAuthenticated ? (
        <p>Welcome, {user?.firstName}!</p>
      ) : (
        <button onClick={handleSignIn}>Sign In</button>
      )}
    </div>
  );
}
```

### useUser

User-specific hook:

```tsx
import { useUser } from '@personql/react';

function UserProfile() {
  const {
    // State
    user,
    isLoading,
    error,

    // Methods
    updateProfile,
    refreshUser,

    // Computed values
    isVerified,
    fullName,
    initials,
  } = useUser();

  const handleUpdateProfile = async () => {
    await updateProfile({
      firstName: 'John',
      lastName: 'Doe',
    });
  };

  return (
    <div>
      <h1>Hello, {fullName}!</h1>
      <p>Verification status: {isVerified ? 'Verified' : 'Pending'}</p>
      <div className="avatar">{initials}</div>
    </div>
  );
}
```

### usePersonQL

Access to the full PersonQL context:

```tsx
import { usePersonQL } from '@personql/react';

function MyComponent() {
  const {
    authState,
    config,
    signIn,
    signUp,
    // ... all auth methods
  } = usePersonQL();

  return <div>...</div>;
}
```

## Configuration

### PersonQLConfig

```typescript
interface PersonQLConfig {
  apiUrl: string; // Your Gateway Worker URL
  clientId: string; // Your application client ID
  redirectUri?: string; // Redirect URI after auth
  scopes?: string[]; // Permission scopes
  theme?: Theme; // UI customization
}

interface Theme {
  primaryColor?: string;
  backgroundColor?: string;
  textColor?: string;
  borderColor?: string;
  borderRadius?: string;
  fontFamily?: string;
}
```

### Example with Custom Theme

```tsx
const config = {
  apiUrl: 'https://gateway.personql.com',
  clientId: 'your-client-id',
  theme: {
    primaryColor: '#3b82f6',
    backgroundColor: '#ffffff',
    textColor: '#1f2937',
    borderColor: '#d1d5db',
    borderRadius: '0.375rem',
    fontFamily: 'Inter, sans-serif',
  },
};

<PersonQLProvider config={config}>
  <App />
</PersonQLProvider>;
```

## Error Handling

The SDK provides comprehensive error handling:

```tsx
import { useAuth } from '@personql/react';

function MyComponent() {
  const { error, clearError } = useAuth();

  if (error) {
    return (
      <Alert
        variant="error"
        title={error.code}
        message={error.message}
        dismissible
        onDismiss={clearError}
      />
    );
  }

  return <div>No errors</div>;
}
```

## Validation

Built-in form validation utilities:

```tsx
import { validateEmail, validatePassword } from '@personql/react';

const emailValidation = validateEmail('user@example.com');
const passwordValidation = validatePassword('password123', {
  minLength: 8,
  requireUppercase: true,
  requireLowercase: true,
  requireNumbers: true,
  requireSpecialChars: true,
});

if (!emailValidation.isValid) {
  console.error(emailValidation.message);
}
```

## TypeScript Support

The SDK is fully typed with TypeScript:

```typescript
import type {
  PersonQLConfig,
  AuthState,
  User,
  SignInCredentials,
  SignUpCredentials,
  MFACredentials,
  AuthError,
} from '@personql/react';
```

## Examples

### Complete Authentication Flow

```tsx
import React, { useState } from 'react';
import {
  PersonQLProvider,
  SignInForm,
  SignUpForm,
  MFAForm,
  ForgotPasswordForm,
  ResetPasswordForm,
  useAuth,
} from '@personql/react';

const config = {
  apiUrl: 'https://gateway.personql.com',
  clientId: 'your-client-id',
};

function AuthFlow() {
  const [view, setView] = useState<
    'signin' | 'signup' | 'mfa' | 'forgot' | 'reset'
  >('signin');
  const { isAuthenticated, requiresMFA } = useAuth();

  if (isAuthenticated) {
    return <Dashboard />;
  }

  if (requiresMFA) {
    return (
      <MFAForm
        onSuccess={() => setView('signin')}
        onCancel={() => setView('signin')}
      />
    );
  }

  return (
    <div className="min-h-screen flex items-center justify-center">
      {view === 'signin' && (
        <SignInForm
          onSuccess={() => console.log('Signed in!')}
          onSignUp={() => setView('signup')}
          onForgotPassword={() => setView('forgot')}
        />
      )}
      {view === 'signup' && (
        <SignUpForm
          onSuccess={() => console.log('Signed up!')}
          onSignIn={() => setView('signin')}
        />
      )}
      {view === 'forgot' && (
        <ForgotPasswordForm
          onSuccess={() => setView('signin')}
          onBackToSignIn={() => setView('signin')}
        />
      )}
      {view === 'reset' && (
        <ResetPasswordForm
          token="reset-token"
          onSuccess={() => setView('signin')}
        />
      )}
    </div>
  );
}

function App() {
  return (
    <PersonQLProvider config={config}>
      <AuthFlow />
    </PersonQLProvider>
  );
}
```

## Multi-Tenant Support

PersonQL React SDK includes built-in support for multi-tenant applications with organizations, roles, and permissions.

### useOrganization Hook

Manage organizations in your multi-tenant application:

```tsx
import { useOrganization } from '@personql/react';

function MyComponent() {
  const {
    // State
    currentOrganization,
    organizations,
    loading,
    switching,
    currentRole,
    members,
    roles,

    // Methods
    switchOrganization,
    createOrganization,
    updateOrganization,
    hasPermission,
    loadMembers,
    loadRoles,
    refreshOrganizations,
  } = useOrganization();

  return (
    <div>
      <h2>{currentOrganization?.name}</h2>
      {hasPermission('users:write') && (
        <button>Add Team Member</button>
      )}
    </div>
  );
}
```

### OrganizationSwitcher Component

Pre-built UI component for switching organizations:

```tsx
import { OrganizationSwitcher } from '@personql/react';

function Header() {
  return (
    <header>
      <OrganizationSwitcher
        onOrganizationChange={(orgId) => {
          console.log('Switched to:', orgId);
        }}
        showCreateButton={true}
        onCreateClick={() => setShowCreateModal(true)}
      />
    </header>
  );
}
```

### Creating Organizations

```tsx
import { useOrganization } from '@personql/react';

function CreateOrganizationButton() {
  const { createOrganization } = useOrganization();

  const handleCreate = async () => {
    try {
      const newOrg = await createOrganization({
        name: 'My New Organization',
        slug: 'my-new-org',
      });
      console.log('Created:', newOrg);
    } catch (error) {
      console.error('Failed to create organization:', error);
    }
  };

  return <button onClick={handleCreate}>Create Organization</button>;
}
```

### Switching Organizations

```tsx
import { useOrganization } from '@personql/react';

function OrganizationList() {
  const { organizations, currentOrganization, switchOrganization } = useOrganization();

  return (
    <ul>
      {organizations.map((org) => (
        <li key={org.id}>
          <button
            onClick={() => switchOrganization(org.id)}
            disabled={org.id === currentOrganization?.id}
          >
            {org.name}
            {org.id === currentOrganization?.id && ' (Current)'}
          </button>
        </li>
      ))}
    </ul>
  );
}
```

### Permission-Based Rendering

```tsx
import { useOrganization } from '@personql/react';

function AdminPanel() {
  const { hasPermission } = useOrganization();

  if (!hasPermission('settings:write')) {
    return <div>Access Denied</div>;
  }

  return (
    <div>
      <h1>Admin Settings</h1>
      {/* Admin content */}
    </div>
  );
}
```

### Loading Organization Members

```tsx
import { useOrganization } from '@personql/react';
import { useEffect } from 'react';

function TeamMembers() {
  const { members, loadMembers, currentOrganization } = useOrganization();

  useEffect(() => {
    if (currentOrganization) {
      loadMembers();
    }
  }, [currentOrganization?.id]);

  return (
    <div>
      <h2>Team Members</h2>
      <ul>
        {members.map((member) => (
          <li key={member.id}>User ID: {member.user_id}</li>
        ))}
      </ul>
    </div>
  );
}
```

### Organization Types

```typescript
interface Organization {
  id: string;
  name: string;
  slug: string;
  domain?: string;
  logo_url?: string;
  primary_color?: string;
  plan_type: 'free' | 'starter' | 'pro' | 'enterprise';
  max_users: number;
  max_api_calls: number;
  settings?: Record<string, any>;
  status: 'active' | 'suspended' | 'deleted';
  created_at: string;
  updated_at: string;
}

interface Role {
  id: string;
  organization_id: string;
  name: string;
  description?: string;
  permissions: string[];
  is_system: boolean;
  created_at: string;
  updated_at: string;
}

interface OrganizationMember {
  id: string;
  organization_id: string;
  user_id: string;
  role_id: string;
  status: 'pending' | 'active' | 'suspended';
  created_at: string;
  updated_at: string;
}
```

### Permission Format

Permissions follow the format `resource:action` where action can be:
- `read` - View the resource
- `write` - Create/update the resource
- `delete` - Delete the resource
- `*` - All actions (wildcard)

Special permissions:
- `*` - Full access to everything
- `resource:*` - All actions on a specific resource (e.g., `users:*`)

Example permissions:
- `users:read` - Can view users
- `users:write` - Can create/update users
- `users:*` - All user operations
- `settings:write` - Can update settings
- `billing:read` - Can view billing information

## License

MIT License - see LICENSE file for details.

## Support

For support and questions:

- Documentation: [https://docs.personql.com](https://docs.personql.com)
- GitHub Issues: [https://github.com/PersonQL/personql/issues](https://github.com/PersonQL/personql/issues)
- Email: support@personql.com

## Usage

```js
import { PersonQLProvider } from '@personql/react';

<PersonQLProvider apiKey="your-api-key">{/* your app */}</PersonQLProvider>;
```

// All requests will use the gateway-worker URL automatically.