Files
mizan/legacy/allauth/components/settings/ConnectionsSection.tsx
Ryth Azhur 27c30d7e50 Move allauth + auth UI to legacy/
allauth/ (44 files) is a django-allauth React UI — a separate concern
from the Mizan protocol. Moved to legacy/ pending extraction into a
standalone mizan-django-allauth package.

Also moved to legacy/:
- client/AuthContext.tsx — generic auth state from /me endpoint
- client/RouterContext.tsx — framework-agnostic router adapter
- client/routing.tsx — UserRoute/StaffRoute/AnonymousRoute guards
- client/nextjs.tsx — Next.js router adapter for auth

These are auth UI infrastructure, not Mizan protocol. The Mizan core
only needs JWT for auth header selection (jwt/ stays — MizanProvider
depends on useJWT() to decide between Bearer and session auth).

Cleaned up re-exports in client/react.ts and vitest aliases.

33 React tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 03:41:22 -04:00

88 lines
3.0 KiB
TypeScript

'use client'
import { useState, useEffect } from 'react'
import { useConfig } from '../../contexts/AuthContext'
import { useAllauthAPI } from '../../contexts/APIContext'
import { SettingsSection, SettingsItem, SettingsList, Button } from './SettingsComponents'
interface Connection {
uid: string
provider: { id: string; name: string }
display: string
}
interface ConnectionsSectionProps {
/** URL to redirect back to after OAuth connect */
redirectUrl?: string
}
export function ConnectionsSection({ redirectUrl = '/account' }: ConnectionsSectionProps) {
const api = useAllauthAPI()
const config = useConfig()
const [connections, setConnections] = useState<Connection[]>([])
const [loading, setLoading] = useState(true)
const availableProviders = config?.data?.socialaccount?.providers || []
const fetchConnections = async () => {
const res = await api.oauth.list()
if (res.status === 200 && res.data) {
setConnections(res.data)
}
setLoading(false)
}
useEffect(() => { fetchConnections() }, [])
const handleConnect = (providerId: string) => {
api.oauth.provider(providerId).connect.withRedirect(redirectUrl)
}
const handleDisconnect = async (providerId: string, uid: string) => {
if (!confirm('Disconnect this account?')) return
await api.oauth.provider(providerId).removeFrom(uid)
fetchConnections()
}
// Don't render if no providers configured or still loading
if (loading) return null
const connectedProviderIds = connections.map(c => c.provider.id)
const unconnectedProviders = availableProviders.filter(
(p: { id: string }) => !connectedProviderIds.includes(p.id)
)
// Hide section entirely if no social providers
if (connections.length === 0 && availableProviders.length === 0) return null
return (
<SettingsSection title="Connected Accounts">
<SettingsList>
{connections.map(conn => (
<SettingsItem
key={conn.uid}
label={conn.provider.name}
meta={conn.display}
actions={
<Button variant="danger" onClick={() => handleDisconnect(conn.provider.id, conn.uid)}>
Disconnect
</Button>
}
/>
))}
{unconnectedProviders.map((provider: { id: string; name: string }) => (
<SettingsItem
key={provider.id}
label={provider.name}
actions={
<Button onClick={() => handleConnect(provider.id)}>
Connect
</Button>
}
/>
))}
</SettingsList>
</SettingsSection>
)
}