> ## Documentation Index
> Fetch the complete documentation index at: https://usegately.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# React Integration

> Use Gately with React applications

The Gately SDK provides first-class React support with hooks, components, and a context provider.

## Installation

```bash theme={null}
npm install @gately/sdk
```

<Note>
  The npm package is available but still in active development. Some features may be limited. Join our [Slack community](https://join.slack.com/t/usegately/shared_invite/zt-3llscjz41-PuVEY5Xu0M2DCi8WEojN0Q) for updates and support.
</Note>

## Setup

### Provider

Wrap your app with `GatelyProvider`:

```jsx theme={null}
// App.jsx
import { GatelyProvider } from '@gately/sdk'

function App() {
  return (
    <GatelyProvider projectId="YOUR_PROJECT_ID">
      <Router>
        <Routes />
      </Router>
    </GatelyProvider>
  )
}
```

### With Options

```jsx theme={null}
<GatelyProvider 
  projectId="YOUR_PROJECT_ID"
  options={{
    autoRefresh: true,
    suppressConsoleErrors: process.env.NODE_ENV === 'production'
  }}
>
  <App />
</GatelyProvider>
```

## Hooks

### useGately

The main hook for authentication:

```jsx theme={null}
import { useGately } from '@gately/sdk'

function Profile() {
  const { 
    user, 
    session,
    isAuthenticated, 
    isLoading,
    login,
    signup,
    logout,
    loginWithGoogle,
    loginWithGithub
  } = useGately()

  if (isLoading) {
    return <div>Loading...</div>
  }

  if (!isAuthenticated) {
    return <LoginForm />
  }

  return (
    <div>
      <h1>Welcome, {user.full_name || user.email}</h1>
      <button onClick={logout}>Log Out</button>
    </div>
  )
}
```

### useAuth

Simplified auth hook:

```jsx theme={null}
import { useAuth } from '@gately/sdk'

function AuthStatus() {
  const { user, isAuthenticated, isLoading } = useAuth()

  if (isLoading) return <Spinner />
  if (!isAuthenticated) return <Link to="/login">Log In</Link>
  
  return <span>Hello, {user.email}</span>
}
```

## Components

### Login Form

```jsx theme={null}
import { useState } from 'react'
import { useGately } from '@gately/sdk'

function LoginForm() {
  const { login, loginWithGoogle, loginWithGithub } = useGately()
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [error, setError] = useState('')
  const [loading, setLoading] = useState(false)

  const handleSubmit = async (e) => {
    e.preventDefault()
    setLoading(true)
    setError('')

    try {
      await login(email, password)
      // Redirect handled by SDK or manually
    } catch (err) {
      setError(err.message)
    } finally {
      setLoading(false)
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      {error && <div className="error">{error}</div>}
      
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
        required
      />
      
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
        required
      />
      
      <button type="submit" disabled={loading}>
        {loading ? 'Logging in...' : 'Log In'}
      </button>

      <div className="social-buttons">
        <button type="button" onClick={() => loginWithGoogle()}>
          Continue with Google
        </button>
        <button type="button" onClick={() => loginWithGithub()}>
          Continue with GitHub
        </button>
      </div>
    </form>
  )
}
```

### Signup Form

```jsx theme={null}
import { useState } from 'react'
import { useGately } from '@gately/sdk'

function SignupForm() {
  const { signup } = useGately()
  const [formData, setFormData] = useState({
    email: '',
    password: '',
    fullName: ''
  })
  const [error, setError] = useState('')
  const [loading, setLoading] = useState(false)

  const handleSubmit = async (e) => {
    e.preventDefault()
    setLoading(true)
    setError('')

    try {
      await signup(formData.email, formData.password, {
        full_name: formData.fullName
      })
    } catch (err) {
      setError(err.message)
    } finally {
      setLoading(false)
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      {error && <div className="error">{error}</div>}
      
      <input
        type="text"
        value={formData.fullName}
        onChange={(e) => setFormData({ ...formData, fullName: e.target.value })}
        placeholder="Full Name"
      />
      
      <input
        type="email"
        value={formData.email}
        onChange={(e) => setFormData({ ...formData, email: e.target.value })}
        placeholder="Email"
        required
      />
      
      <input
        type="password"
        value={formData.password}
        onChange={(e) => setFormData({ ...formData, password: e.target.value })}
        placeholder="Password"
        required
      />
      
      <button type="submit" disabled={loading}>
        {loading ? 'Creating account...' : 'Sign Up'}
      </button>
    </form>
  )
}
```

## Protected Routes

### With React Router

```jsx theme={null}
import { Navigate, Outlet } from 'react-router-dom'
import { useAuth } from '@gately/sdk'

function ProtectedRoute() {
  const { isAuthenticated, isLoading } = useAuth()

  if (isLoading) {
    return <LoadingSpinner />
  }

  if (!isAuthenticated) {
    return <Navigate to="/login" replace />
  }

  return <Outlet />
}

// Usage in routes
function AppRoutes() {
  return (
    <Routes>
      <Route path="/login" element={<LoginPage />} />
      <Route path="/signup" element={<SignupPage />} />
      
      <Route element={<ProtectedRoute />}>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/profile" element={<Profile />} />
        <Route path="/settings" element={<Settings />} />
      </Route>
    </Routes>
  )
}
```

### Plan-Based Protection

```jsx theme={null}
function PlanProtectedRoute({ requiredPlan, children }) {
  const { user, isAuthenticated, isLoading } = useAuth()

  if (isLoading) {
    return <LoadingSpinner />
  }

  if (!isAuthenticated) {
    return <Navigate to="/login" replace />
  }

  if (user.plan_id !== requiredPlan) {
    return <Navigate to="/upgrade" replace />
  }

  return children
}

// Usage
<Route 
  path="/premium-content" 
  element={
    <PlanProtectedRoute requiredPlan="pro">
      <PremiumContent />
    </PlanProtectedRoute>
  } 
/>
```

## User Profile Management

```jsx theme={null}
import { useState, useEffect } from 'react'
import { useGately } from '@gately/sdk'

function ProfileSettings() {
  const { user, updateProfile } = useGately()
  const [formData, setFormData] = useState({
    fullName: '',
    avatarUrl: ''
  })
  const [saving, setSaving] = useState(false)

  useEffect(() => {
    if (user) {
      setFormData({
        fullName: user.full_name || '',
        avatarUrl: user.avatar_url || ''
      })
    }
  }, [user])

  const handleSave = async () => {
    setSaving(true)
    try {
      await updateProfile({
        full_name: formData.fullName,
        avatar_url: formData.avatarUrl
      })
      alert('Profile updated!')
    } catch (error) {
      alert(error.message)
    } finally {
      setSaving(false)
    }
  }

  return (
    <div>
      <h2>Profile Settings</h2>
      
      <label>
        Full Name
        <input
          type="text"
          value={formData.fullName}
          onChange={(e) => setFormData({ ...formData, fullName: e.target.value })}
        />
      </label>

      <label>
        Avatar URL
        <input
          type="url"
          value={formData.avatarUrl}
          onChange={(e) => setFormData({ ...formData, avatarUrl: e.target.value })}
        />
      </label>

      <button onClick={handleSave} disabled={saving}>
        {saving ? 'Saving...' : 'Save Changes'}
      </button>
    </div>
  )
}
```

## TypeScript

Full TypeScript support:

```tsx theme={null}
import { useGately, User, Session } from '@gately/sdk'

interface ProfileProps {
  onLogout: () => void
}

function Profile({ onLogout }: ProfileProps) {
  const { user, logout } = useGately()

  const handleLogout = async () => {
    await logout()
    onLogout()
  }

  if (!user) return null

  return (
    <div>
      <h1>{user.full_name}</h1>
      <p>{user.email}</p>
      <button onClick={handleLogout}>Log Out</button>
    </div>
  )
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Error Boundaries">
    Wrap auth components in error boundaries to handle failures gracefully.
  </Accordion>

  <Accordion title="Loading States">
    Always show loading indicators during auth operations.
  </Accordion>

  <Accordion title="Optimistic Updates">
    Update UI optimistically for better perceived performance.
  </Accordion>

  <Accordion title="Session Persistence">
    The SDK handles session persistence automatically via localStorage.
  </Accordion>
</AccordionGroup>

## Need Help?

<CardGroup cols={2}>
  <Card title="Join our Community" icon="slack" href="https://join.slack.com/t/usegately/shared_invite/zt-3llscjz41-PuVEY5Xu0M2DCi8WEojN0Q">
    Get help from the Gately community on Slack
  </Card>

  <Card title="Contact Support" icon="envelope" href="mailto:support@usegately.com">
    Reach out to our support team
  </Card>
</CardGroup>
