From 52e6f7b522c2c1bc775447190383b3186b6619ae Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Sun, 2 Mar 2025 04:50:42 +0000 Subject: [PATCH] better form --- packages/client/src/hooks/useAuth.tsx | 10 +++- packages/client/src/pages/LoginPage.tsx | 79 +++++++++++++++++++------ 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/packages/client/src/hooks/useAuth.tsx b/packages/client/src/hooks/useAuth.tsx index 7fe187e..927689a 100644 --- a/packages/client/src/hooks/useAuth.tsx +++ b/packages/client/src/hooks/useAuth.tsx @@ -75,7 +75,15 @@ export function AuthProvider({ children }: { children: ReactNode }) { setError(null) try { - const result = await api.login(handle) + // Add a small artificial delay for UX purposes + const loginPromise = api.login(handle) + + // Ensure the loading state shows for at least 800ms for better UX + const result = await Promise.all([ + loginPromise, + new Promise(resolve => setTimeout(resolve, 800)) + ]).then(([loginResult]) => loginResult) + return result } catch (err) { const message = err instanceof Error ? err.message : 'Login failed' diff --git a/packages/client/src/pages/LoginPage.tsx b/packages/client/src/pages/LoginPage.tsx index 2f6b897..2974dc7 100644 --- a/packages/client/src/pages/LoginPage.tsx +++ b/packages/client/src/pages/LoginPage.tsx @@ -1,5 +1,6 @@ import { useState } from 'react' import { Link } from 'react-router-dom' +import { useMutation } from '@tanstack/react-query' import Header from '#/components/Header' import { useAuth } from '#/hooks/useAuth' @@ -7,26 +8,42 @@ import { useAuth } from '#/hooks/useAuth' const LoginPage = () => { const [handle, setHandle] = useState('') const [error, setError] = useState(null) - const { login, loading } = useAuth() + const { login } = useAuth() - const handleSubmit = async (e: React.FormEvent) => { + const mutation = useMutation({ + mutationFn: async (handleValue: string) => { + const result = await login(handleValue) + + // Add a small delay before redirecting for better UX + await new Promise((resolve) => setTimeout(resolve, 500)) + + return result + }, + onSuccess: (data) => { + // Redirect to ATProto OAuth flow + window.location.href = data.redirectUrl + }, + onError: (err) => { + const message = err instanceof Error ? err.message : 'Login failed' + setError(message) + }, + }) + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault() + setError(null) if (!handle.trim()) { setError('Handle cannot be empty') return } - try { - const { redirectUrl } = await login(handle) - // Redirect to ATProto OAuth flow - window.location.href = redirectUrl - } catch (err) { - const message = err instanceof Error ? err.message : 'Login failed' - setError(message) - } + mutation.mutate(handle) } + // count success as also pending, since the browser should be redirecting + const pending = mutation.isPending || mutation.isSuccess + return (
@@ -42,7 +59,10 @@ const LoginPage = () => {
-
-- 2.51.2