add-magic-link-endpoint
This commit is contained in:
parent
37a87af28d
commit
199a3197be
@ -3,6 +3,7 @@ import { useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import Link from 'next/link'
|
||||
import { useAuth } from '@/hooks/useAuth'
|
||||
import { sendMagicLink } from '@/lib/api'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
@ -12,6 +13,9 @@ import { AuthenticationError } from '@/lib/auth'
|
||||
export default function LoginPacientePage() {
|
||||
const [credentials, setCredentials] = useState({ email: '', password: '' })
|
||||
const [error, setError] = useState('')
|
||||
const [magicMessage, setMagicMessage] = useState('')
|
||||
const [magicError, setMagicError] = useState('')
|
||||
const [magicLoading, setMagicLoading] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const router = useRouter()
|
||||
const { login } = useAuth()
|
||||
@ -51,6 +55,27 @@ export default function LoginPacientePage() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleSendMagicLink = async () => {
|
||||
if (!credentials.email) {
|
||||
setMagicError('Por favor, preencha o email antes de solicitar o magic link.')
|
||||
return
|
||||
}
|
||||
|
||||
setMagicLoading(true)
|
||||
setMagicError('')
|
||||
setMagicMessage('')
|
||||
|
||||
try {
|
||||
const res = await sendMagicLink(credentials.email, { emailRedirectTo: `${window.location.origin}/` })
|
||||
setMagicMessage(res?.message ?? 'Magic link enviado. Verifique seu email.')
|
||||
} catch (err: any) {
|
||||
console.error('[MAGIC-LINK PACIENTE] erro ao enviar:', err)
|
||||
setMagicError(err?.message ?? String(err))
|
||||
} finally {
|
||||
setMagicLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-background py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-md w-full space-y-8">
|
||||
@ -115,6 +140,25 @@ export default function LoginPacientePage() {
|
||||
{loading ? 'Entrando...' : 'Entrar na Minha Área'}
|
||||
</Button>
|
||||
</form>
|
||||
<div className="mt-4 space-y-2">
|
||||
<div className="text-sm text-muted-foreground mb-2">Ou entre usando um magic link (sem senha)</div>
|
||||
|
||||
{magicError && (
|
||||
<Alert variant="destructive">
|
||||
<AlertDescription>{magicError}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{magicMessage && (
|
||||
<Alert>
|
||||
<AlertDescription>{magicMessage}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Button className="w-full" onClick={handleSendMagicLink} disabled={magicLoading}>
|
||||
{magicLoading ? 'Enviando magic link...' : 'Enviar magic link'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 text-center">
|
||||
<Button variant="outline" asChild className="w-full hover:!bg-primary hover:!text-white hover:!border-primary transition-all duration-200">
|
||||
|
||||
@ -3,6 +3,7 @@ import { useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import Link from 'next/link'
|
||||
import { useAuth } from '@/hooks/useAuth'
|
||||
import { sendMagicLink } from '@/lib/api'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
@ -12,6 +13,9 @@ import { AuthenticationError } from '@/lib/auth'
|
||||
export default function LoginPage() {
|
||||
const [credentials, setCredentials] = useState({ email: '', password: '' })
|
||||
const [error, setError] = useState('')
|
||||
const [magicMessage, setMagicMessage] = useState('')
|
||||
const [magicError, setMagicError] = useState('')
|
||||
const [magicLoading, setMagicLoading] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const router = useRouter()
|
||||
const { login } = useAuth()
|
||||
@ -53,6 +57,28 @@ export default function LoginPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleSendMagicLink = async () => {
|
||||
// basic client-side validation
|
||||
if (!credentials.email) {
|
||||
setMagicError('Por favor, preencha o email antes de solicitar o magic link.')
|
||||
return
|
||||
}
|
||||
|
||||
setMagicLoading(true)
|
||||
setMagicError('')
|
||||
setMagicMessage('')
|
||||
|
||||
try {
|
||||
const res = await sendMagicLink(credentials.email, { emailRedirectTo: `${window.location.origin}/` })
|
||||
setMagicMessage(res?.message ?? 'Magic link enviado. Verifique seu email.')
|
||||
} catch (err: any) {
|
||||
console.error('[MAGIC-LINK] erro ao enviar:', err)
|
||||
setMagicError(err?.message ?? String(err))
|
||||
} finally {
|
||||
setMagicLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-background py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-md w-full space-y-8">
|
||||
@ -117,6 +143,25 @@ export default function LoginPage() {
|
||||
{loading ? 'Entrando...' : 'Entrar'}
|
||||
</Button>
|
||||
</form>
|
||||
<div className="mt-4 space-y-2">
|
||||
<div className="text-sm text-muted-foreground mb-2">Ou entre usando um magic link (sem senha)</div>
|
||||
|
||||
{magicError && (
|
||||
<Alert variant="destructive">
|
||||
<AlertDescription>{magicError}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{magicMessage && (
|
||||
<Alert>
|
||||
<AlertDescription>{magicMessage}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Button className="w-full" onClick={handleSendMagicLink} disabled={magicLoading}>
|
||||
{magicLoading ? 'Enviando magic link...' : 'Enviar magic link'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 text-center">
|
||||
<Button variant="outline" asChild className="w-full hover:!bg-primary hover:!text-white hover:!border-primary transition-all duration-200">
|
||||
|
||||
@ -1623,10 +1623,11 @@ export async function criarUsuario(input: CreateUserInput): Promise<CreateUserRe
|
||||
// The OpenAPI for the new endpoint exposes POST /create-user at the
|
||||
// API root (API_BASE). Call that endpoint directly from the client.
|
||||
const url = `${API_BASE}/create-user`;
|
||||
const functionsUrl = `${API_BASE}/functions/v1/create-user`;
|
||||
|
||||
// Network/fetch errors (including CORS preflight failures) throw before we get a Response.
|
||||
// Catch them and provide a clearer, actionable error message for developers/operators.
|
||||
let res: Response;
|
||||
let res: Response | null = null;
|
||||
try {
|
||||
res = await fetch(url, {
|
||||
method: 'POST',
|
||||
@ -1635,15 +1636,39 @@ export async function criarUsuario(input: CreateUserInput): Promise<CreateUserRe
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error('[criarUsuario] fetch error for', url, err);
|
||||
// Do not attempt client-side signup fallback. Role assignment and user creation
|
||||
// must be performed by the backend endpoint `/create-user` which has the
|
||||
// necessary privileges. Surface a clear error so operators can fix the
|
||||
// backend (CORS / route availability) instead of silently creating an
|
||||
// auth user without roles.
|
||||
// Attempt functions fallback when primary endpoint can't be reached (network/CORS/route)
|
||||
try {
|
||||
console.warn('[criarUsuario] tentando fallback para', functionsUrl);
|
||||
const res2 = await fetch(functionsUrl, {
|
||||
method: 'POST',
|
||||
headers: { ...baseHeaders(), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
return await parse<CreateUserResponse>(res2 as Response);
|
||||
} catch (err2: any) {
|
||||
console.error('[criarUsuario] fallback functions also failed', err2);
|
||||
throw new Error(
|
||||
'Falha ao contatar o endpoint /create-user. Não será feito fallback via /auth/v1/signup. Verifique se o endpoint /create-user existe, está acessível e se o CORS/OPTIONS está configurado corretamente. Detalhes: ' + (err?.message ?? String(err))
|
||||
'Falha ao contatar o endpoint /create-user e o fallback /functions/v1/create-user também falhou. Verifique disponibilidade e CORS. Detalhes: ' +
|
||||
(err?.message ?? String(err)) + ' | fallback: ' + (err2?.message ?? String(err2))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If we got a response but it's 404 (route not found), try the functions path too
|
||||
if (res && !res.ok && res.status === 404) {
|
||||
try {
|
||||
console.warn('[criarUsuario] /create-user returned 404; trying functions path', functionsUrl);
|
||||
const res2 = await fetch(functionsUrl, {
|
||||
method: 'POST',
|
||||
headers: { ...baseHeaders(), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
return await parse<CreateUserResponse>(res2 as Response);
|
||||
} catch (err2: any) {
|
||||
console.error('[criarUsuario] fallback functions failed after 404', err2);
|
||||
// Fall through to parse original response to provide friendly error
|
||||
}
|
||||
}
|
||||
|
||||
return await parse<CreateUserResponse>(res as Response);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user