useOrganization
Access and manage organization data in your components
useOrganization Hook ๐ข
The useOrganization
hook is your primary way to access and manage organization data in client components! โจ
What It Does ๐ฏ
The hook provides:
- ๐ข Current organization data (name, slug, plan, etc.)
- ๐ฅ User's membership info (role, permissions)
- ๐ Loading and error states
- ๐ Ability to refresh data
- ๐ Function to switch organizations
Client Components Only
This hook uses SWR and must be used in client components. Add 'use client'
at the top of your file!
Basic Usage ๐
'use client'
import { useOrganization } from '@/lib/organizations/useOrganization'
export default function Dashboard() {
const { organization, isLoading, error } = useOrganization()
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error loading organization</div>
return (
<div>
<h1>Welcome to {organization.name}</h1>
<p>Your role: {organization.role}</p>
</div>
)
}
Return Values ๐ฆ
The hook returns an object with the following properties:
{
organization: {
id: string
name: string
slug: string
image?: string
onboardingDone: boolean
role: 'owner' | 'admin' | 'user'
plan: {
id: string
name: string
codename: string
default: boolean
quotas: object
requiredCouponCount: number
} | null
}
isLoading: boolean
error: Error | null
mutate: () => void
switchOrganization: (organizationId: string) => Promise<void>
}
Plan Can Be Null
The plan
property can be null
if the organization doesn't have a plan assigned yet. Always check for null before accessing plan properties!
Common Use Cases ๐
Display Organization Info
'use client'
import { useOrganization } from '@/lib/organizations/useOrganization'
export function OrganizationHeader() {
const { organization, isLoading } = useOrganization()
if (isLoading) return <div>Loading...</div>
return (
<div className="flex items-center gap-4">
{organization.image && (
<img
src={organization.image}
alt={organization.name}
className="w-10 h-10 rounded"
/>
)}
<div>
<h2 className="font-bold">{organization.name}</h2>
<p className="text-sm text-gray-500">
{organization.plan?.name || 'No Plan'} Plan
</p>
</div>
</div>
)
}
Check User Role
'use client'
import { useOrganization } from '@/lib/organizations/useOrganization'
export function MembersButton() {
const { organization } = useOrganization()
const isAdmin = ['admin', 'owner'].includes(organization.role)
if (!isAdmin) return null
return (
<button>
Invite Members
</button>
)
}
Access Plan Quotas
'use client'
import { useOrganization } from '@/lib/organizations/useOrganization'
export function ProjectsPage() {
const { organization } = useOrganization()
if (!organization.plan) {
return <div>No plan assigned</div>
}
const { projects } = organization.plan.quotas
const currentProjects = 5 // Fetch from your data
const canCreateMore = currentProjects < projects
return (
<div>
<p>Projects: {currentProjects} / {projects}</p>
{!canCreateMore && (
<p className="text-red-500">
Upgrade your plan to create more projects
</p>
)}
</div>
)
}
Refresh Organization Data
'use client'
import { useOrganization } from '@/lib/organizations/useOrganization'
import { toast } from 'sonner'
export function OrganizationSettings() {
const { organization, mutate } = useOrganization()
const updateSettings = async (settings: any) => {
try {
await fetch(`/api/app/org/${organization.slug}/settings`, {
method: 'PATCH',
body: JSON.stringify(settings)
})
// Refresh organization data
mutate()
toast.success('Settings updated!')
} catch (error) {
toast.error('Failed to update settings')
}
}
return (
<div>
<button onClick={() => updateSettings({ name: 'New Name' })}>
Update Settings
</button>
</div>
)
}
Switch Organizations
'use client'
import { useOrganization } from '@/lib/organizations/useOrganization'
import { useRouter } from 'next/navigation'
export function OrganizationSwitcher({ organizations }) {
const { organization, switchOrganization } = useOrganization()
const handleSwitch = async (organizationId: string) => {
await switchOrganization(organizationId)
// Redirects to /app automatically
}
return (
<select
value={organization.id}
onChange={(e) => handleSwitch(e.target.value)}
className="border rounded px-3 py-2"
>
{organizations.map(org => (
<option key={org.id} value={org.id}>
{org.name}
</option>
))}
</select>
)
}
Loading States ๐
Always handle loading and error states:
'use client'
import { useOrganization } from '@/lib/organizations/useOrganization'
import { Skeleton } from '@/components/ui/skeleton'
export default function Dashboard() {
const { organization, isLoading, error } = useOrganization()
// Loading state with skeleton
if (isLoading) {
return (
<div className="space-y-4">
<Skeleton className="h-12 w-full" />
<Skeleton className="h-32 w-full" />
<Skeleton className="h-32 w-full" />
</div>
)
}
// Error state
if (error) {
return (
<div className="p-4 bg-red-50 text-red-600 rounded">
<p>Failed to load organization</p>
<button onClick={() => window.location.reload()}>
Retry
</button>
</div>
)
}
// Success state
return (
<div>
<h1>{organization.name}</h1>
{/* Your content */}
</div>
)
}
Real-World Example ๐ผ
Complete dashboard component with organization data:
'use client'
import { useOrganization } from '@/lib/organizations/useOrganization'
import { Skeleton } from '@/components/ui/skeleton'
export default function OrganizationDashboard() {
const { organization, isLoading, error, mutate } = useOrganization()
if (isLoading) {
return (
<div className="p-6 space-y-4">
<Skeleton className="h-8 w-64" />
<Skeleton className="h-32 w-full" />
</div>
)
}
if (error) {
return (
<div className="p-6">
<div className="p-4 bg-red-50 text-red-600 rounded">
Error loading organization
</div>
</div>
)
}
const isOwner = organization.role === 'owner'
const isAdmin = ['admin', 'owner'].includes(organization.role)
return (
<div className="p-6 space-y-6">
{/* Header */}
<div>
<h1 className="text-3xl font-bold">{organization.name}</h1>
<p className="text-gray-500">
{organization.plan?.name || 'No Plan'} ยท {organization.role}
</p>
</div>
{/* Stats */}
<div className="grid grid-cols-3 gap-4">
<div className="p-4 border rounded">
<p className="text-sm text-gray-500">Plan</p>
<p className="text-2xl font-bold">
{organization.plan?.name || 'No Plan'}
</p>
</div>
<div className="p-4 border rounded">
<p className="text-sm text-gray-500">Your Role</p>
<p className="text-2xl font-bold capitalize">
{organization.role}
</p>
</div>
<div className="p-4 border rounded">
<p className="text-sm text-gray-500">Onboarding</p>
<p className="text-2xl font-bold">
{organization.onboardingDone ? 'โ' : 'Pending'}
</p>
</div>
</div>
{/* Actions */}
<div className="flex gap-2">
{isAdmin && (
<>
<button className="px-4 py-2 bg-blue-500 text-white rounded">
Invite Members
</button>
<button className="px-4 py-2 border rounded">
Settings
</button>
</>
)}
{isOwner && (
<button className="px-4 py-2 border rounded">
Billing
</button>
)}
</div>
</div>
)
}
Best Practices ๐ก
1. Always Handle Loading States
if (isLoading) return <LoadingSkeleton />
2. Handle Errors Gracefully
if (error) return <ErrorMessage />
3. Check Role Before Actions
const canInvite = ['admin', 'owner'].includes(organization.role)
if (!canInvite) return null
4. Refresh After Mutations
await updateOrganization()
mutate() // Refresh data
5. Use TypeScript
import type { Organization } from '@/lib/organizations/types'
const { organization }: { organization: Organization } = useOrganization()
Troubleshooting ๐ง
"organization is undefined"
Make sure the component is inside an organization route:
// โ
Good - Inside /app/org/[slug]/
'use client'
import { useOrganization } from '@/lib/organizations/useOrganization'
export default function Page() {
const { organization } = useOrganization()
// organization will be available
}
"Must be used in client component"
Add 'use client'
at the top:
'use client' // Add this!
import { useOrganization } from '@/lib/organizations/useOrganization'
Data Not Updating
Call mutate()
after making changes:
const { mutate } = useOrganization()
await updateOrganization()
mutate() // Force refresh
Switch Organization Not Working
The function automatically redirects to /app
:
const { switchOrganization } = useOrganization()
// This will switch and redirect automatically
await switchOrganization(newOrganizationId)
// No need to manually navigate - it's handled for you!
Toast Notifications
The switchOrganization
function shows toast notifications automatically for loading, success, and error states!
API Reference ๐
Parameters
The hook takes no parameters.
Returns
Property | Type | Description |
---|---|---|
organization | UserOrganizationWithPlan | Current organization data with plan and role |
isLoading | boolean | True while loading organization data |
error | Error | null | Error object if request failed |
mutate | () => void | Function to refresh organization data |
switchOrganization | (organizationId: string) => Promise<void> | Switch to a different organization (shows toast and redirects) |
Summary ๐
You now know how to:
- โ Use the useOrganization hook in components
- โ Access organization and membership data
- โ Handle loading and error states
- โ Check user roles and permissions
- โ Refresh organization data
- โ Switch between organizations
- โ Build role-based UIs
Ready to Build
The useOrganization hook gives you everything you need to build organization-aware components! ๐