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,13 +18,15 @@ function App() {
const getCSRF = async ()=>{
try {
await http.get('/sanctum/csrf-cookie')
const res= await http.get('/api/user')
console.log(res.data);
} catch (error) {
console.error(error)
}
}
return (
<div className='App' style={{marginTop: '20px' }}>
<div className='App' style={{marginTop: '20px' }}>
<AppShell
header={{height: 50}}
navbar={{width: 300, breakpoint: 'sm', collapsed: {mobile: !opened}}}

View File

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

View File

@@ -1,12 +1,18 @@
import { Flex, AppShell, Burger, Button, Paper, useMantineColorScheme, useComputedColorScheme} from '@mantine/core';
import {FaSun, FaMoon} from 'react-icons/fa';
import { Text } from '@mantine/core';
import List from './Lists';
import { useNavigate } from 'react-router-dom';
const Header = ({toggle, opened}) => {
const {setColorScheme} = useMantineColorScheme();
const computedColorScheme = useComputedColorScheme('light');
const navigate= useNavigate();
const clickToBackHandler=()=>{
navigate("/*");
}
const toggleColorScheme = () => {
setColorScheme(computedColorScheme === "dark" ? "light" : "dark")}
@@ -22,7 +28,15 @@ const Header = ({toggle, opened}) => {
>
ADMIN MANAGEMENT
</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>
</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 {useState} from 'react';
import {http} from "../middleware/axiosConfig";
@@ -25,17 +25,38 @@ function Home() {
// Initialize state to handle loading state
const [loading,setLoading]=useState()
const [errors, setErrors] =useState({})
//Inserts new account to the Database{reactapp.users}.post
const onSubmitChange = async (e) => {
e.preventDefault();
try{
const response= await http.post("/api/addnew", userField);
console.log(response)
setLoading(true);
} catch(err){
console.error(err)
console.log("Something's Wrong!");
//validation for errors
const validationErrors = {}
if (!userField.name.trim()){
validationErrors.name = <Text size="xs" fw={500} fs="italic" c="red">Name is Required!</Text>
}
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 />
@@ -47,7 +68,7 @@ function Home() {
return (
<div className="container">
<h2 className='w-100 d-flex justify-content-center p-3'> ADD ACCOUNT </h2>
<form>
<form onSubmit={onSubmitChange}>
<div>
{/* Name Input */}
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
@@ -58,11 +79,13 @@ function Home() {
name='name'
id='name'
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 */}
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<TextInput
required
leftSectionPointerEvents="none"
leftSection={icon}
label="E-mail:"
@@ -73,20 +96,23 @@ function Home() {
onChange={e => changeUserFieldHandler(e)}
style={{ width: '400px', marginBottom: '10px' }}/>
</div>
{/* Validation Error */}
{errors.email && <div>{errors.email}</div>}
{/* Password Input */}
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<PasswordInput
required
name='password'
label="Password"
withAsterisk
description="Please ensure that no special characters are included."
placeholder="Enter Your Password"
onChange={e => changeUserFieldHandler(e)}
style={{ width: '400px', marginBottom: '10px' }}/>
</div>
{/* Validation Error */}
{errors.password && <div>{errors.password}</div>}
{/* Submit Button - triggers the onSubmitChange function*/}
<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>
</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 { Button, Table } from '@mantine/core';
import { Dialog, Button, Table, Text, Group } from '@mantine/core';
import { Link } from 'react-router-dom';
import {http} from "../middleware/axiosConfig";
import { useDisclosure } from '@mantine/hooks';
const List = () => {
// Initialize state for user data
const [ userData, setUserData] = useState([]);
const [opened, { toggle, close }] = useDisclosure(false);
//useEffect hook -
useEffect(() => {
fetchData();
@@ -60,14 +63,30 @@ const List = () => {
<Table.Td>
{/* Action.View Button - triggers the View module */}
<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>
{/* Action.Edit Button - triggers the Edit module */}
<Link to={`/edit/${users.id}`}>
<Button style={{ marginRight: '10px' }} variant="filled">Edit</Button>
<Button style={{ marginRight: '10px' }} variant="outline">Edit</Button>
</Link>
{/* 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.Tr>
)})

View File

@@ -4,38 +4,37 @@ import { Paper, Text, TextInput, PasswordInput, Button, rem} from "@mantine/core
import {useState} from 'react';
import {http} from "../middleware/axiosConfig";
import { useNavigate } from 'react-router-dom';
import {useForm} from 'react-hook-form'
const Login = () => {
const navigate = useNavigate();
const [userField, setUserField] = useState({
email:"",
password:""
});
const {register, handleSubmit, } = useForm({
defaultValue: {
email: '',
password: ''
}
})
const changeFieldHandler = (e) => {
setUserField({
...userField,
[e.target.email]: e.target.value
});
}
const {formState: { errors }} = useForm();
const [loginError, setloginError] = useState(false);
const onLogin = async (e) => {
try {
setloginError(false);
await http.get("/sanctum/csrf-cookie");
const res = await http.post("/api/login", {
email: e.email,
password: e.password,
});
const res = await http.post("/api/login", e);
if (res.status === 200){
navigate("/lists");
}
}
catch (err) {
console.error(err)
console.log("Something's Wrong!");
catch (error) {
if (error.response.status === 401) {
setloginError(true);
}
}
};
@@ -44,7 +43,7 @@ const Login = () => {
return (
<div>
<Paper radius="md" p="xl" withBorder>
<Paper shadow="md" radius="md" p="xl" withBorder>
<Text size="xl" fw={900} variant="gradient"
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>
@@ -52,26 +51,34 @@ const Login = () => {
<TextInput
style={{ width: '400px', marginBottom: '10px', marginTop: '15px' }}
label="Email"
leftSectionPointerEvents="none"
leftSection={icon}
withAsterisk
onChange={e => changeFieldHandler(e)}
{...register('email')}
placeholder="Enter your work email address"
error={errors.email ? "Please enter a valid email" : null}
/></div>
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<PasswordInput
style={{ width: '400px', marginBottom: '10px' }}
label="Password"
placeholder="Enter your Password"
withAsterisk
onChange={e => changeFieldHandler(e)}
{...register('password')}
visible={visible}
onVisibilityChange={toggle}
error={
errors.password
? "Please enter a valid password"
: null
}
/></div>
<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>
</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>
</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 View from './View';
import Edit from "./Edit";
// import Registration from "./Registration";
// import Login from "./Login";
import Login from "./Login";
const RouterSwitcher = () => {
return(
<Routes>
{/* <Route path="/*" element={<Registration />} /> */}
{/* <Route path="/*" element={<Login />} /> */}
<Route path="/*" element={<Login />} />
<Route path="/home" element={<Home />} />
<Route path="/lists" element={<List />} />
<Route path="/view/:id" element={<View />} />