page wrapper
This commit is contained in:
@@ -23,107 +23,26 @@ import { useAuth } from '@/lib/auth/AuthContext';
|
||||
import { useLogin } from '@/hooks/auth/useLogin';
|
||||
import AuthWorkflowMockup from '@/components/auth/AuthWorkflowMockup';
|
||||
import UserRolesPreview from '@/components/auth/UserRolesPreview';
|
||||
import { EnhancedFormError, FormErrorSummary } from '@/components/errors/EnhancedFormError';
|
||||
import { EnhancedFormError } from '@/components/errors/EnhancedFormError';
|
||||
import { useEnhancedForm } from '@/lib/hooks/useEnhancedForm';
|
||||
import { validateLoginForm, type LoginFormValues } from '@/lib/utils/validation';
|
||||
import { logErrorWithContext } from '@/lib/utils/errorUtils';
|
||||
import { StatefulPageWrapper } from '@/components/shared/state/StatefulPageWrapper';
|
||||
|
||||
export default function LoginPage() {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const { refreshSession, session } = useAuth();
|
||||
const returnTo = searchParams.get('returnTo') ?? '/dashboard';
|
||||
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [showErrorDetails, setShowErrorDetails] = useState(false);
|
||||
const [hasInsufficientPermissions, setHasInsufficientPermissions] = useState(false);
|
||||
|
||||
// Use login mutation hook
|
||||
const loginMutation = useLogin({
|
||||
onSuccess: async () => {
|
||||
// Refresh session in context so header updates immediately
|
||||
await refreshSession();
|
||||
router.push(returnTo);
|
||||
},
|
||||
onError: (error) => {
|
||||
// Show error details toggle in development
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
setShowErrorDetails(true);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Check if user is already authenticated
|
||||
useEffect(() => {
|
||||
console.log('[LoginPage] useEffect running', {
|
||||
session: session ? 'exists' : 'null',
|
||||
returnTo: searchParams.get('returnTo'),
|
||||
pathname: window.location.pathname,
|
||||
search: window.location.search,
|
||||
});
|
||||
|
||||
if (session) {
|
||||
// Check if this is a returnTo redirect (user lacks permissions)
|
||||
const isPermissionRedirect = searchParams.get('returnTo') !== null;
|
||||
|
||||
console.log('[LoginPage] Authenticated user check', {
|
||||
isPermissionRedirect,
|
||||
returnTo: searchParams.get('returnTo'),
|
||||
});
|
||||
|
||||
if (isPermissionRedirect) {
|
||||
// User was redirected here due to insufficient permissions
|
||||
// Show permission error instead of redirecting
|
||||
console.log('[LoginPage] Showing permission error');
|
||||
setHasInsufficientPermissions(true);
|
||||
} else {
|
||||
// User navigated here directly while authenticated, redirect to dashboard
|
||||
console.log('[LoginPage] Redirecting to dashboard');
|
||||
router.replace('/dashboard');
|
||||
}
|
||||
}
|
||||
}, [session, router, searchParams]);
|
||||
|
||||
// Use enhanced form hook
|
||||
// Template component for login UI
|
||||
function LoginTemplate({ data }: { data: { returnTo: string; hasInsufficientPermissions: boolean; showPassword: boolean; showErrorDetails: boolean; formState: any; handleChange: any; handleSubmit: any; setFormState: any; setShowPassword: any; setShowErrorDetails: any; } }) {
|
||||
const {
|
||||
returnTo,
|
||||
hasInsufficientPermissions,
|
||||
showPassword,
|
||||
showErrorDetails,
|
||||
formState,
|
||||
setFormState,
|
||||
handleChange,
|
||||
handleSubmit,
|
||||
setFormError,
|
||||
} = useEnhancedForm<LoginFormValues>({
|
||||
initialValues: {
|
||||
email: '',
|
||||
password: '',
|
||||
rememberMe: false,
|
||||
},
|
||||
validate: validateLoginForm,
|
||||
component: 'LoginPage',
|
||||
onSubmit: async (values) => {
|
||||
// Log the attempt for debugging
|
||||
logErrorWithContext(
|
||||
{ message: 'Login attempt', values: { ...values, password: '[REDACTED]' } },
|
||||
{
|
||||
component: 'LoginPage',
|
||||
action: 'login-submit',
|
||||
formData: { ...values, password: '[REDACTED]' },
|
||||
}
|
||||
);
|
||||
|
||||
await loginMutation.mutateAsync({
|
||||
email: values.email,
|
||||
password: values.password,
|
||||
rememberMe: values.rememberMe,
|
||||
});
|
||||
},
|
||||
onError: (error, values) => {
|
||||
// Error handling is done in the mutation's onError callback
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Reset error details on success
|
||||
setShowErrorDetails(false);
|
||||
},
|
||||
});
|
||||
setFormState,
|
||||
setShowPassword,
|
||||
setShowErrorDetails,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-deep-graphite flex">
|
||||
@@ -303,7 +222,7 @@ export default function LoginPage() {
|
||||
error={new Error(formState.submitError)}
|
||||
onDismiss={() => {
|
||||
// Clear the error by setting submitError to undefined
|
||||
setFormState(prev => ({ ...prev, submitError: undefined }));
|
||||
setFormState((prev: typeof formState) => ({ ...prev, submitError: undefined }));
|
||||
}}
|
||||
showDeveloperDetails={showErrorDetails}
|
||||
/>
|
||||
@@ -377,4 +296,131 @@ export default function LoginPage() {
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default function LoginPage() {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const { refreshSession, session } = useAuth();
|
||||
const returnTo = searchParams.get('returnTo') ?? '/dashboard';
|
||||
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [showErrorDetails, setShowErrorDetails] = useState(false);
|
||||
const [hasInsufficientPermissions, setHasInsufficientPermissions] = useState(false);
|
||||
|
||||
// Use login mutation hook
|
||||
const loginMutation = useLogin({
|
||||
onSuccess: async () => {
|
||||
// Refresh session in context so header updates immediately
|
||||
await refreshSession();
|
||||
router.push(returnTo);
|
||||
},
|
||||
onError: (error) => {
|
||||
// Show error details toggle in development
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
setShowErrorDetails(true);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Check if user is already authenticated
|
||||
useEffect(() => {
|
||||
console.log('[LoginPage] useEffect running', {
|
||||
session: session ? 'exists' : 'null',
|
||||
returnTo: searchParams.get('returnTo'),
|
||||
pathname: window.location.pathname,
|
||||
search: window.location.search,
|
||||
});
|
||||
|
||||
if (session) {
|
||||
// Check if this is a returnTo redirect (user lacks permissions)
|
||||
const isPermissionRedirect = searchParams.get('returnTo') !== null;
|
||||
|
||||
console.log('[LoginPage] Authenticated user check', {
|
||||
isPermissionRedirect,
|
||||
returnTo: searchParams.get('returnTo'),
|
||||
});
|
||||
|
||||
if (isPermissionRedirect) {
|
||||
// User was redirected here due to insufficient permissions
|
||||
// Show permission error instead of redirecting
|
||||
console.log('[LoginPage] Showing permission error');
|
||||
setHasInsufficientPermissions(true);
|
||||
} else {
|
||||
// User navigated here directly while authenticated, redirect to dashboard
|
||||
console.log('[LoginPage] Redirecting to dashboard');
|
||||
router.replace('/dashboard');
|
||||
}
|
||||
}
|
||||
}, [session, router, searchParams]);
|
||||
|
||||
// Use enhanced form hook
|
||||
const {
|
||||
formState,
|
||||
setFormState,
|
||||
handleChange,
|
||||
handleSubmit,
|
||||
} = useEnhancedForm<LoginFormValues>({
|
||||
initialValues: {
|
||||
email: '',
|
||||
password: '',
|
||||
rememberMe: false,
|
||||
},
|
||||
validate: validateLoginForm,
|
||||
component: 'LoginPage',
|
||||
onSubmit: async (values) => {
|
||||
// Log the attempt for debugging
|
||||
logErrorWithContext(
|
||||
{ message: 'Login attempt', values: { ...values, password: '[REDACTED]' } },
|
||||
{
|
||||
component: 'LoginPage',
|
||||
action: 'login-submit',
|
||||
formData: { ...values, password: '[REDACTED]' },
|
||||
}
|
||||
);
|
||||
|
||||
await loginMutation.mutateAsync({
|
||||
email: values.email,
|
||||
password: values.password,
|
||||
rememberMe: values.rememberMe,
|
||||
});
|
||||
},
|
||||
onError: (error, values) => {
|
||||
// Error handling is done in the mutation's onError callback
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Reset error details on success
|
||||
setShowErrorDetails(false);
|
||||
},
|
||||
});
|
||||
|
||||
// Prepare template data
|
||||
const templateData = {
|
||||
returnTo,
|
||||
hasInsufficientPermissions,
|
||||
showPassword,
|
||||
showErrorDetails,
|
||||
formState,
|
||||
handleChange,
|
||||
handleSubmit,
|
||||
setFormState,
|
||||
setShowPassword,
|
||||
setShowErrorDetails,
|
||||
};
|
||||
|
||||
// Mutation state for wrapper
|
||||
const isLoading = loginMutation.isPending;
|
||||
const error = loginMutation.error;
|
||||
|
||||
return (
|
||||
<StatefulPageWrapper
|
||||
data={templateData}
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
retry={() => loginMutation.mutate({ email: '', password: '', rememberMe: false })}
|
||||
Template={LoginTemplate}
|
||||
loading={{ variant: 'full-screen', message: 'Loading login...' }}
|
||||
errorConfig={{ variant: 'full-screen' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user