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>
This commit is contained in:
2026-04-07 03:41:22 -04:00
parent 24ff0ae66d
commit 27c30d7e50
50 changed files with 0 additions and 8 deletions

View File

@@ -0,0 +1,120 @@
'use client'
import { useState, useEffect } from 'react'
import { useAllauthAPI } from '../../contexts/APIContext'
import { useStyles } from '../../contexts/StylesContext'
import { useDjangoFormCore } from 'mizan'
import { SettingsSection, SettingsItem, SettingsList, Badge, Button } from './SettingsComponents'
interface Email {
email: string
primary: boolean
verified: boolean
}
export function EmailsSection() {
const api = useAllauthAPI()
const styles = useStyles()
const [emails, setEmails] = useState<Email[]>([])
const [loading, setLoading] = useState(true)
const addEmailForm = useDjangoFormCore<Record<string, unknown>>({ name: 'add_email' })
const fetchEmails = async () => {
const res = await api.account.emails.list()
if (res.status === 200 && res.data) {
setEmails(res.data)
}
setLoading(false)
}
useEffect(() => { fetchEmails() }, [])
const handleAdd = async (e: React.FormEvent) => {
e.preventDefault()
const result = await addEmailForm.submit()
if (result.success) {
addEmailForm.reset()
fetchEmails()
}
}
const handleRemove = async (email: string) => {
if (!confirm(`Remove ${email}?`)) return
await api.account.emails.remove(email)
fetchEmails()
}
const handleSetPrimary = async (email: string) => {
await api.account.emails.setPrimary(email)
fetchEmails()
}
const handleResendVerification = async (email: string) => {
await api.account.emails.verification.dispatch(email)
alert('Verification email sent!')
}
if (loading) return null
return (
<SettingsSection title="Email Addresses">
<SettingsList>
{emails.map(email => (
<SettingsItem
key={email.email}
label={
<>
{email.email}
{email.primary && <Badge variant="primary">Primary</Badge>}
{!email.verified && <Badge variant="warning">Unverified</Badge>}
</>
}
actions={
<>
{!email.verified && (
<Button variant="secondary" onClick={() => handleResendVerification(email.email)}>
Verify
</Button>
)}
{!email.primary && email.verified && (
<Button onClick={() => handleSetPrimary(email.email)}>
Make Primary
</Button>
)}
{!email.primary && (
<Button variant="danger" onClick={() => handleRemove(email.email)}>
Remove
</Button>
)}
</>
}
/>
))}
</SettingsList>
{!addEmailForm.loading && (
<form onSubmit={handleAdd} className={styles.inlineForm}>
<div className={styles.field}>
<label className={styles.fieldLabel}>
{addEmailForm.schema?.fields.email?.label || 'Add Email'}
</label>
<input
type="email"
value={(addEmailForm.data.email as string) || ''}
onChange={(e) => addEmailForm.set('email', e.target.value)}
onBlur={() => addEmailForm.touch('email')}
className={styles.fieldInput}
required
/>
{addEmailForm.getFieldErrors('email').map((err, i) => (
<p key={i} className={styles.fieldError}>{err.message}</p>
))}
</div>
<Button type="submit">
{addEmailForm.schema?.submit_label || 'Add'}
</Button>
</form>
)}
</SettingsSection>
)
}