Compare commits

...

11 Commits

11 changed files with 178 additions and 70 deletions

6
composer.json Normal file
View File

@@ -0,0 +1,6 @@
{
"require": {
"laravel/sanctum": "^4.0",
"laravel/ui": "^4.5"
}
}

View File

@@ -18,6 +18,8 @@ function App() {
const getCSRF = async ()=>{ const getCSRF = async ()=>{
try { try {
await http.get('/sanctum/csrf-cookie') await http.get('/sanctum/csrf-cookie')
const res= await http.get('/api/user')
console.log(res.data);
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} }

View File

@@ -2,7 +2,6 @@ import React,{ useEffect,useState } from 'react';
import {Button, TextInput, rem, PasswordInput} from '@mantine/core'; import {Button, TextInput, rem, PasswordInput} from '@mantine/core';
import { IconAt } from '@tabler/icons-react'; import { IconAt } from '@tabler/icons-react';
import { useParams,useNavigate } from 'react-router-dom'; import { useParams,useNavigate } from 'react-router-dom';
import axios from 'axios';
import {http} from "../middleware/axiosConfig"; import {http} from "../middleware/axiosConfig";
const Edit = () => { const Edit = () => {

View File

@@ -1,12 +1,18 @@
import { Flex, AppShell, Burger, Button, Paper, useMantineColorScheme, useComputedColorScheme} from '@mantine/core'; import { Flex, AppShell, Burger, Button, Paper, useMantineColorScheme, useComputedColorScheme} from '@mantine/core';
import {FaSun, FaMoon} from 'react-icons/fa'; import {FaSun, FaMoon} from 'react-icons/fa';
import { Text } from '@mantine/core'; import { Text } from '@mantine/core';
import List from './Lists'; import { useNavigate } from 'react-router-dom';
const Header = ({toggle, opened}) => { const Header = ({toggle, opened}) => {
const {setColorScheme} = useMantineColorScheme(); const {setColorScheme} = useMantineColorScheme();
const computedColorScheme = useComputedColorScheme('light'); const computedColorScheme = useComputedColorScheme('light');
const navigate= useNavigate();
const clickToBackHandler=()=>{
navigate("/*");
}
const toggleColorScheme = () => { const toggleColorScheme = () => {
setColorScheme(computedColorScheme === "dark" ? "light" : "dark")} setColorScheme(computedColorScheme === "dark" ? "light" : "dark")}
@@ -22,7 +28,15 @@ const Header = ({toggle, opened}) => {
> >
ADMIN MANAGEMENT ADMIN MANAGEMENT
</Text></div> </Text></div>
<Button size="sm" variant="link" onClick={toggleColorScheme}>{computedColorScheme === "dark" ? <FaSun/> : <FaMoon/>}</Button> <div>
<Button size="xs" variant="link" onClick={toggleColorScheme}>{computedColorScheme === "dark" ? <FaSun/> : <FaMoon/>}</Button>
<Button
style={{ marginLeft: '10px' }}
variant="gradient"
gradient={{ from: 'blue', to: 'green', deg: 229 }}
size="xs"
onClick={clickToBackHandler}>Log Out</Button>
</div>
</Flex> </Flex>
</AppShell.Header> </AppShell.Header>
); );

View File

@@ -1,4 +1,4 @@
import {Button, TextInput, rem, PasswordInput} from '@mantine/core'; import {Button, TextInput, rem, PasswordInput, Text} from '@mantine/core';
import { IconAt } from '@tabler/icons-react'; import { IconAt } from '@tabler/icons-react';
import {useState} from 'react'; import {useState} from 'react';
import {http} from "../middleware/axiosConfig"; import {http} from "../middleware/axiosConfig";
@@ -25,17 +25,38 @@ function Home() {
// Initialize state to handle loading state // Initialize state to handle loading state
const [loading,setLoading]=useState() const [loading,setLoading]=useState()
const [errors, setErrors] =useState({})
//Inserts new account to the Database{reactapp.users}.post //Inserts new account to the Database{reactapp.users}.post
const onSubmitChange = async (e) => { const onSubmitChange = async (e) => {
e.preventDefault(); e.preventDefault();
try{ //validation for errors
const response= await http.post("/api/addnew", userField); const validationErrors = {}
console.log(response) if (!userField.name.trim()){
setLoading(true); validationErrors.name = <Text size="xs" fw={500} fs="italic" c="red">Name is Required!</Text>
} catch(err){
console.error(err)
console.log("Something's Wrong!");
} }
if (!userField.email.trim()){
validationErrors.email = <Text size="xs" fw={500} fs="italic" c="red">Email is Required!</Text>
} else if(!/^\S+@\S+$/.test(userField.email)){
validationErrors.email = <Text size="xs" fw={500} fs="italic" c="red">Email is Invalid!</Text>
}
if (!userField.password.trim()){
validationErrors.password = <Text size="xs" fw={500} fs="italic" c="red">Password is Required!</Text>
} else if(userField.password.length < 6){
validationErrors.password = <Text size="xs" fw={500} fs="italic" c="red">Password should be at least 6 characters!</Text>
}
try {
setErrors(validationErrors)
const response = await http.post('/api/addnew', userField);
console.log(response);
} catch (err) {
console.error(err);
console.log("Something's Wrong!");
} finally {
setLoading(true);
}
} }
//If loading is true, return to <Home /> //If loading is true, return to <Home />
@@ -47,7 +68,7 @@ function Home() {
return ( return (
<div className="container"> <div className="container">
<h2 className='w-100 d-flex justify-content-center p-3'> ADD ACCOUNT </h2> <h2 className='w-100 d-flex justify-content-center p-3'> ADD ACCOUNT </h2>
<form> <form onSubmit={onSubmitChange}>
<div> <div>
{/* Name Input */} {/* Name Input */}
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}> <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
@@ -58,11 +79,13 @@ function Home() {
name='name' name='name'
id='name' id='name'
onChange={e => changeUserFieldHandler(e)} onChange={e => changeUserFieldHandler(e)}
style={{ width: '400px', marginBottom: '10px' }}/></div> style={{ width: '400px', marginBottom: '10px' }}/>
</div>
{/* Validation Error */}
{errors.name && <div>{errors.name}</div>}
{/* E-mail Input */} {/* E-mail Input */}
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}> <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<TextInput <TextInput
required
leftSectionPointerEvents="none" leftSectionPointerEvents="none"
leftSection={icon} leftSection={icon}
label="E-mail:" label="E-mail:"
@@ -73,20 +96,23 @@ function Home() {
onChange={e => changeUserFieldHandler(e)} onChange={e => changeUserFieldHandler(e)}
style={{ width: '400px', marginBottom: '10px' }}/> style={{ width: '400px', marginBottom: '10px' }}/>
</div> </div>
{/* Validation Error */}
{errors.email && <div>{errors.email}</div>}
{/* Password Input */} {/* Password Input */}
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}> <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<PasswordInput <PasswordInput
required name='password'
label="Password" label="Password"
withAsterisk
description="Please ensure that no special characters are included." description="Please ensure that no special characters are included."
placeholder="Enter Your Password" placeholder="Enter Your Password"
onChange={e => changeUserFieldHandler(e)} onChange={e => changeUserFieldHandler(e)}
style={{ width: '400px', marginBottom: '10px' }}/> style={{ width: '400px', marginBottom: '10px' }}/>
</div> </div>
{/* Validation Error */}
{errors.password && <div>{errors.password}</div>}
{/* Submit Button - triggers the onSubmitChange function*/} {/* Submit Button - triggers the onSubmitChange function*/}
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}> <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<Button style={{ margin: 25 }} variant="filled" color="rgba(30, 128, 10, 1)" size="sm" radius="xl" onClick={e => onSubmitChange(e)}>Sign Up</Button> <Button type="submit" style={{ margin: 25 }} variant="filled" color="rgba(30, 128, 10, 1)" size="sm" radius="xl" onClick={e => onSubmitChange(e)}>Sign Up</Button>
</div> </div>
</div> </div>
</form> </form>
@@ -94,4 +120,4 @@ function Home() {
); );
} }
export default Home; export default Home

View File

@@ -1,13 +1,16 @@
import React, { useState,useEffect } from 'react'; import React, { useState,useEffect } from 'react';
import { Button, Table } from '@mantine/core'; import { Dialog, Button, Table, Text, Group } from '@mantine/core';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import {http} from "../middleware/axiosConfig"; import {http} from "../middleware/axiosConfig";
import { useDisclosure } from '@mantine/hooks';
const List = () => { const List = () => {
// Initialize state for user data // Initialize state for user data
const [ userData, setUserData] = useState([]); const [ userData, setUserData] = useState([]);
const [opened, { toggle, close }] = useDisclosure(false);
//useEffect hook - //useEffect hook -
useEffect(() => { useEffect(() => {
fetchData(); fetchData();
@@ -60,14 +63,30 @@ const List = () => {
<Table.Td> <Table.Td>
{/* Action.View Button - triggers the View module */} {/* Action.View Button - triggers the View module */}
<Link to={`/view/${users.id}`}> <Link to={`/view/${users.id}`}>
<Button style={{ marginRight: '10px' }} variant="filled" color="rgba(81, 194, 52, 1)">View</Button> <Button style={{ marginRight: '10px' }} variant="outline" color="rgba(81, 194, 52, 1)">View</Button>
</Link> </Link>
{/* Action.Edit Button - triggers the Edit module */} {/* Action.Edit Button - triggers the Edit module */}
<Link to={`/edit/${users.id}`}> <Link to={`/edit/${users.id}`}>
<Button style={{ marginRight: '10px' }} variant="filled">Edit</Button> <Button style={{ marginRight: '10px' }} variant="outline">Edit</Button>
</Link> </Link>
{/* Delete Button - triggers the handleDelete function */} {/* Delete Button - triggers the handleDelete function */}
<Button onClick={()=>handleDelete(users.id)} style={{ marginRight: '10px' }} variant="filled" color="rgba(227, 9, 9, 1)">Delete</Button> {/* <Button onClick={()=>handleDelete(users.id)} style={{ marginRight: '10px' }} variant="filled" color="rgba(227, 9, 9, 1)">Delete</Button> */}
<Button onClick={toggle} style={{ marginRight: '10px' }} variant="outline" color="rgba(227, 9, 9, 1)">Delete</Button>
<Dialog
position={{ top: 200, left: 500 }} opened={opened}
shadow="xl"
onclose={close}
size="lg"
radius="md"
withBorder
style={{ backgroundColor: 'lightblue' }} >
<Text size="sm" mb="xs" fw={500} align="center">
Are you sure you want to Delete this account? </Text>
<Group algin="flex-end">
<Button onClick={close} style={{ marginLeft: '90px', marginTop: '10px' }} variant="filled" color="rgba(5, 66, 1, 1)">Cancel</Button>
<Button onClick={()=>handleDelete(users.id)} style={{ marginRight: '45px', marginTop: '10px' }} variant="filled" color="rgba(227, 9, 9, 1)">Delete</Button>
</Group>
</Dialog>
</Table.Td> </Table.Td>
</Table.Tr> </Table.Tr>
)}) )})

View File

@@ -4,38 +4,37 @@ import { Paper, Text, TextInput, PasswordInput, Button, rem} from "@mantine/core
import {useState} from 'react'; import {useState} from 'react';
import {http} from "../middleware/axiosConfig"; import {http} from "../middleware/axiosConfig";
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import {useForm} from 'react-hook-form'
const Login = () => { const Login = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const [userField, setUserField] = useState({ const {register, handleSubmit, } = useForm({
email:"", defaultValue: {
password:"" email: '',
}); password: ''
}
})
const changeFieldHandler = (e) => { const {formState: { errors }} = useForm();
setUserField({
...userField, const [loginError, setloginError] = useState(false);
[e.target.email]: e.target.value
});
}
const onLogin = async (e) => { const onLogin = async (e) => {
try { try {
setloginError(false);
await http.get("/sanctum/csrf-cookie"); await http.get("/sanctum/csrf-cookie");
const res = await http.post("/api/login", { const res = await http.post("/api/login", e);
email: e.email,
password: e.password,
});
if (res.status === 200){ if (res.status === 200){
navigate("/lists"); navigate("/lists");
} }
} }
catch (err) { catch (error) {
console.error(err) if (error.response.status === 401) {
console.log("Something's Wrong!"); setloginError(true);
}
} }
}; };
@@ -44,7 +43,7 @@ const Login = () => {
return ( return (
<div> <div>
<Paper radius="md" p="xl" withBorder> <Paper shadow="md" radius="md" p="xl" withBorder>
<Text size="xl" fw={900} variant="gradient" <Text size="xl" fw={900} variant="gradient"
gradient={{ from: 'red', to: 'rgba(227, 0, 0, 1)', deg: 227 }}>WELCOME ADMIN!</Text> gradient={{ from: 'red', to: 'rgba(227, 0, 0, 1)', deg: 227 }}>WELCOME ADMIN!</Text>
<Text size="sm">Please login to access the Admin Account Management Site</Text> <Text size="sm">Please login to access the Admin Account Management Site</Text>
@@ -52,26 +51,34 @@ const Login = () => {
<TextInput <TextInput
style={{ width: '400px', marginBottom: '10px', marginTop: '15px' }} style={{ width: '400px', marginBottom: '10px', marginTop: '15px' }}
label="Email" label="Email"
leftSectionPointerEvents="none"
leftSection={icon} leftSection={icon}
withAsterisk {...register('email')}
onChange={e => changeFieldHandler(e)}
placeholder="Enter your work email address" placeholder="Enter your work email address"
error={errors.email ? "Please enter a valid email" : null}
/></div> /></div>
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}> <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<PasswordInput <PasswordInput
style={{ width: '400px', marginBottom: '10px' }} style={{ width: '400px', marginBottom: '10px' }}
label="Password" label="Password"
placeholder="Enter your Password" placeholder="Enter your Password"
withAsterisk {...register('password')}
onChange={e => changeFieldHandler(e)}
visible={visible} visible={visible}
onVisibilityChange={toggle} onVisibilityChange={toggle}
error={
errors.password
? "Please enter a valid password"
: null
}
/></div> /></div>
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}> <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<Button variant="filled" color="lime" style={{ margin: 25 }} onClick={e => onLogin(e)}>Log In <Button variant="filled" color="lime" style={{ margin: 25 }} onClick={e => handleSubmit(onLogin)()}>Log In
</Button> </Button>
</div> </div>
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
{loginError && (
<Text fw={500} fs="italic" c="red">
Login failed! Please verify your credentials and try again.
</Text>)}</div>
</Paper> </Paper>
</div> </div>
); );

View File

@@ -0,0 +1,19 @@
import { Navigate } from "react-router-dom"
import React from "react"
import Root from "../routes/Root"
export default function ProtectedRoute({ user, loading }) {
return (
<>
{!loading ? (
user ? (
<Root />
) : (
<Navigate to="/login" />
)
) : (
<div>loading....</div>
)}
</>
)
}

View File

@@ -1,18 +0,0 @@
// import { Paper, Text, TextInput } from "@mantine/core";
// const Registration = () => {
// return (
// <div>
// <Paper radius="md" p="xl" withBorder>
// <Text size="xl" fw={900} variant="gradient"
// gradient={{ from: 'orange', to: 'yellow', deg: 102 }}>WELCOME ADMIN!</Text>
// <Text size="sm">Please login to access the Admin Account Management Site</Text>
// <TextInput>
// </TextInput>
// </Paper>
// </div>
// );
// };
// export default Registration;

36
src/components/Root.js Normal file
View File

@@ -0,0 +1,36 @@
import { useDisclosure } from "@mantine/hooks";
import { useLocation } from "react-router-dom";
import NavBar from './components/NavBar';
import Header from './components/Header';
import RouterSwitcher from './components/RouterSwitcher';
import {AppShell} from '@mantine/core';
export default function Root({ logout }) {
const location = useLocation();
const [active, setActive] = useState(
data.findIndex((item) => item.link === location.pathname)
);
const [opened, {toggle}] = useDisclosure();
return(
<div className='App' style={{marginTop: '20px' }}>
<AppShell
header={{height: 50}}
navbar={{width: 300, breakpoint: 'sm', collapsed: {mobile: !opened}}}
padding="md">
<Header toggle={toggle} opened={opened}/>
<NavBar />
<AppShell.Main>
<RouterSwitcher>
</RouterSwitcher>
</ AppShell.Main>
<AppShell.Footer zIndex={opened ? 'auto': 201}>
Built by Maritoni V. Benjamin
</AppShell.Footer>
</AppShell>
</div>
);
}

View File

@@ -4,15 +4,13 @@ import NotFound from "./NotFound";
import List from "./Lists"; import List from "./Lists";
import View from './View'; import View from './View';
import Edit from "./Edit"; import Edit from "./Edit";
// import Registration from "./Registration"; import Login from "./Login";
// import Login from "./Login";
const RouterSwitcher = () => { const RouterSwitcher = () => {
return( return(
<Routes> <Routes>
{/* <Route path="/*" element={<Registration />} /> */} <Route path="/*" element={<Login />} />
{/* <Route path="/*" element={<Login />} /> */}
<Route path="/home" element={<Home />} /> <Route path="/home" element={<Home />} />
<Route path="/lists" element={<List />} /> <Route path="/lists" element={<List />} />
<Route path="/view/:id" element={<View />} /> <Route path="/view/:id" element={<View />} />