Added LDAP config and auth

This commit is contained in:
2026-07-08 15:05:50 -07:00
parent 95dbd26ca8
commit 5447479d1b
13 changed files with 736 additions and 214 deletions
+123 -80
View File
@@ -1,91 +1,134 @@
import { useContext } from 'react';
import { useForm } from 'react-hook-form';
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import {
Button,
Field,
Input,
Stack,
useRecipe,
Center,
Text,
Flex,
Heading,
Highlight,
GridItem,
Grid
} from "@chakra-ui/react"
import { PasswordInput } from "@/components/ui/password-input.jsx";
Box, Heading, Stack, Input, Button, Text, Separator, Field, Link, Flex
} from '@chakra-ui/react';
import useAuthStore from '../../store/authStore';
import { toaster } from "../../components/ui/toaster.jsx"; // Ensure this path matches your project
export default function Login( signedIn, setSignedIn) {
const recipe = useRecipe({ key: "dashboard" }); // styling recipes option
const styles = recipe(); // use style
const Login = () => {
const navigate = useNavigate();
const {
register,
handleSubmit,
formState: { errors, isSubmitSuccessful },
} = useForm({
defaultValues: {
username: "",
password: "",
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const { login, isAuthenticated, isLoading, error } = useAuthStore();
// --- VDAP COLOR STYLES ---
const fieldStyles = {
borderRadius: "3xl",
bg: "gray.100",
borderColor: "gray.100",
px: 4,
_focus: {
bg: "white",
borderColor: "blue.400",
boxShadow: "0 0 0 1px #4299E1",
outline: "none"
}
});
};
const onSubmit = (data) => {
console.log(data);
// setUser(data.username);
const buttonStyles = {
borderRadius: "3xl",
bg: "blue.600",
color: "white",
_hover: { bg: 'blue.700', transform: 'translateY(-1px)' },
_active: { bg: 'blue.800', transform: 'translateY(0)' },
transition: 'all 0.2s'
};
// The Redirect Watcher
useEffect(() => {
if (isAuthenticated) {
navigate('/home', { replace: true });
}
}, [isAuthenticated, navigate]);
// The Error Watcher
useEffect(() => {
if (error) {
toaster.create({
title: "Login Failed",
description: error,
type: "error",
duration: 5000,
});
}
}, [error]);
const handleSubmit = async (e) => {
e.preventDefault();
if (username && password) {
await login(username, password);
}
};
return (
<Flex css={styles} width="100%" height="100%">
<Grid
templateRows="1fr 11fr"
height="100vh"
width="100vw"
>
<GridItem rowSpan={1} >
<Flex width="100%" height="100%" align="center" >
<Heading size="4xl" fontWeight="bold" pl="1rem" cursor="default" >
<Highlight query="A" styles={{ color: 'red.600'}}>
VDAP
</Highlight>
</Heading>
</Flex>
</GridItem>
<GridItem rowSpan={11} >
<Flex width="100%" height="100%" justify="center" align="center" direction="column" >
<Center background="white" width="40%" height="50%" borderRadius="1rem">
<form onSubmit={handleSubmit(onSubmit)}>
<Stack gap="4" align="center" maxW="sm">
<Text textStyle="2xl" fontWeight="bold" cursor="default">Sign In</Text>
<Field.Root invalid={!!errors.username}>
<Input
placeholder="username"
{...register("username", {required: "Required"})}
/>
<Field.ErrorText>{errors.username?.message}</Field.ErrorText>
</Field.Root>
<Flex p={8} bg="gray.50" _dark={{ bg: "gray.900" }} flex="1" minH="100vh" align="center" justify="center">
<Box w="full" maxW="450px" bg="white" _dark={{ bg: "gray.800", borderColor: "gray.700" }} p={8} borderRadius="2xl" boxShadow="sm" borderWidth="1px" borderColor="gray.200">
<Stack gap={6} align="stretch" as="form" onSubmit={handleSubmit}>
<Field.Root invalid={!!errors.password}>
<PasswordInput
placeholder="password"
{...register("password", {required: "Required"})}
/>
<Field.ErrorText>{errors.password?.message}</Field.ErrorText>
</Field.Root>
<Stack gap={2} textAlign="center">
<Heading as="h1" size="xl" color="gray.800" _dark={{ color: "white" }}>
VDAP System Login
</Heading>
<Text color="gray.500">Sign in with your LDAP credentials.</Text>
</Stack>
<Button
type="submit"
disabled={isSubmitSuccessful}
>
Submit
</Button>
</Stack>
</form>
</Center>
</Flex>
</GridItem>
</Grid>
</Flex>
<Separator />
<Field.Root required>
<Field.Label ml={1} fontSize="sm" fontWeight="medium" color="gray.700" _dark={{ color: "gray.300" }}>
Username
</Field.Label>
<Input
name="username"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="jdoe"
{...fieldStyles}
/>
</Field.Root>
<Field.Root required>
<Box display="flex" justifyContent="space-between" alignItems="center" w="full" mb={1} ml={1}>
<Field.Label mb={0} fontSize="sm" fontWeight="medium" color="gray.700" _dark={{ color: "gray.300" }}>
Password
</Field.Label>
</Box>
<Input
name="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="••••••••"
{...fieldStyles}
/>
</Field.Root>
<Button
type="submit"
loading={isLoading}
loadingText="Authenticating..."
size="lg"
mt={2}
w="full"
{...buttonStyles}
>
Sign In
</Button>
<Text textAlign="center" fontSize="sm" color="gray.500">
Need access?{' '}
<Link href="mailto:it-chight@usgs.gov" color="blue.600" _dark={{ color: "blue.400" }} fontWeight="medium">
Contact IT Administration
</Link>
</Text>
</Stack>
</Box>
</Flex>
);
}
};
export default Login;