matarial-init 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/bin/cli.js +7 -0
- package/bin/copy-src.js +86 -0
- package/bin/postinstall.js +6 -0
- package/index.js +9 -0
- package/package.json +49 -0
- package/src/App.css +24 -0
- package/src/App.jsx +51 -0
- package/src/components/Button.jsx +21 -0
- package/src/components/Header.jsx +29 -0
- package/src/components/Input.jsx +33 -0
- package/src/components/Modal.jsx +43 -0
- package/src/components/Navbar.jsx +19 -0
- package/src/components/Sidebar.jsx +30 -0
- package/src/components/Table.jsx +56 -0
- package/src/constants/permissions.js +27 -0
- package/src/constants/storageKeys.js +151 -0
- package/src/context/DataContext.jsx +19 -0
- package/src/context/dataContext.js +22 -0
- package/src/context/useData.jsx +98 -0
- package/src/hooks/usePermission.jsx +14 -0
- package/src/index.css +0 -0
- package/src/layout/DashboardLayout.jsx +31 -0
- package/src/layout/PublicLayout.jsx +13 -0
- package/src/main.jsx +10 -0
- package/src/pages/Books.jsx +121 -0
- package/src/pages/DashBoard.jsx +414 -0
- package/src/pages/Home.jsx +9 -0
- package/src/pages/Members.jsx +80 -0
- package/src/pages/MyBooks.jsx +79 -0
- package/src/pages/Penalty.jsx +9 -0
- package/src/pages/SignUp.jsx +69 -0
- package/src/pages/Signin.jsx +73 -0
- package/src/routes/ProtectedRoute.jsx +11 -0
- package/src/routes/PublicRoute.jsx +11 -0
- package/src/uttils/persistence.js +49 -0
- package/src/validation/Validation.jsx +41 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import Button from "../components/Button";
|
|
3
|
+
import Input from "../components/Input";
|
|
4
|
+
import { useFormik } from "formik";
|
|
5
|
+
import { signInSchema } from "../validation/Validation";
|
|
6
|
+
import { STORAGE_KEYS } from "../constants/storageKeys";
|
|
7
|
+
import { findData, setData } from "../uttils/persistence";
|
|
8
|
+
import { toast } from "react-toastify";
|
|
9
|
+
import { useNavigate } from "react-router-dom";
|
|
10
|
+
|
|
11
|
+
const fields = [
|
|
12
|
+
{
|
|
13
|
+
name: "email",
|
|
14
|
+
type: "email",
|
|
15
|
+
placeholder: "Email"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: "password",
|
|
19
|
+
type: "password",
|
|
20
|
+
placeholder: "Password"
|
|
21
|
+
},
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
const SignIn = () => {
|
|
25
|
+
const navigate = useNavigate()
|
|
26
|
+
const handleSignIn = (values) => {
|
|
27
|
+
const { email, password } = values;
|
|
28
|
+
const user = findData(STORAGE_KEYS.USERS, (user) => user.email === email && user.password === password);
|
|
29
|
+
if (!user) {
|
|
30
|
+
toast.error("Invalid email or password.");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
setData(STORAGE_KEYS.CURRENT_USER, user);
|
|
34
|
+
toast.success("Sign In successful!");
|
|
35
|
+
navigate("/dashboard");
|
|
36
|
+
}
|
|
37
|
+
const formik = useFormik({
|
|
38
|
+
initialValues: {
|
|
39
|
+
email: "",
|
|
40
|
+
password: "",
|
|
41
|
+
},
|
|
42
|
+
validationSchema: signInSchema,
|
|
43
|
+
onSubmit: handleSignIn
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className="flex flex-col gap-4 items-center justify-center h-screen">
|
|
48
|
+
<form onSubmit={formik.handleSubmit} className="w-[20%] flex flex-col gap-4 border p-4 rounded-md shadow-md">
|
|
49
|
+
<h1 className="border-b-1 p-2 font-bold">Please Sign In</h1>
|
|
50
|
+
{fields.map((field, index) =>
|
|
51
|
+
<div key={field.name}>
|
|
52
|
+
<Input
|
|
53
|
+
type={field.type}
|
|
54
|
+
name={field.name}
|
|
55
|
+
value={formik.values[field.name]}
|
|
56
|
+
onChange={formik.handleChange}
|
|
57
|
+
onBlur={formik.handleBlur}
|
|
58
|
+
placeholder={field.placeholder}
|
|
59
|
+
/>
|
|
60
|
+
{formik.touched[field.name] && formik.errors[field.name] && (
|
|
61
|
+
<div>
|
|
62
|
+
<p className="text-red-400">{formik.errors[field.name]}</p>
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
</div>
|
|
66
|
+
)}
|
|
67
|
+
<Button text="Sign In" type="submit" />
|
|
68
|
+
</form>
|
|
69
|
+
</div>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default SignIn
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Navigate } from "react-router-dom";
|
|
2
|
+
import { STORAGE_KEYS } from "../constants/storageKeys";
|
|
3
|
+
import { getData } from "../uttils/persistence";
|
|
4
|
+
|
|
5
|
+
export const ProtectedRoute = ({children}) => {
|
|
6
|
+
const currentUser = getData(STORAGE_KEYS.CURRENT_USER)
|
|
7
|
+
if(!currentUser){
|
|
8
|
+
return <Navigate to="/signin" replace />
|
|
9
|
+
}
|
|
10
|
+
return children;
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Navigate } from "react-router-dom";
|
|
2
|
+
import { STORAGE_KEYS } from "../constants/storageKeys";
|
|
3
|
+
import { getData } from "../uttils/persistence";
|
|
4
|
+
|
|
5
|
+
export const PublicRoute = ({children}) => {
|
|
6
|
+
const currentUser = getData(STORAGE_KEYS.CURRENT_USER)
|
|
7
|
+
if(currentUser){
|
|
8
|
+
return <Navigate to="/dashboard" replace />
|
|
9
|
+
}
|
|
10
|
+
return children;
|
|
11
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const getData = (key) => {
|
|
2
|
+
const data = localStorage.getItem(key)
|
|
3
|
+
return data ? JSON.parse(data) : null
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const getCollection = (key) => {
|
|
7
|
+
return getData(key) || []
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const setData = (key, data) => {
|
|
11
|
+
localStorage.setItem(key, JSON.stringify(data))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const addData = (key, data) => {
|
|
15
|
+
const existingData = getCollection(key)
|
|
16
|
+
existingData.push(data)
|
|
17
|
+
setData(key, existingData)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const findData = (key, callback) => {
|
|
21
|
+
const existingData = getCollection(key)
|
|
22
|
+
return existingData.find(callback)
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const filterData = (key, callback) => {
|
|
27
|
+
const existingData = getCollection(key)
|
|
28
|
+
return existingData.filter(callback)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const updateData = (key, callback) => {
|
|
32
|
+
const existingData = getCollection(key)
|
|
33
|
+
const updatedData = existingData.map(callback)
|
|
34
|
+
setData(key, updatedData)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const deleteData = (key, callback) => {
|
|
38
|
+
const existingData = getCollection(key)
|
|
39
|
+
const updatedData = existingData.filter(callback)
|
|
40
|
+
setData(key, updatedData)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const clearData = (key) => {
|
|
44
|
+
localStorage.removeItem(key)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const existData = (key) => {
|
|
48
|
+
return localStorage.getItem(key) !== null
|
|
49
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as yup from "yup";
|
|
2
|
+
|
|
3
|
+
export const signUpSchema = yup.object({
|
|
4
|
+
username: yup.string().required("Username is required").min(3, "Username must be atleast 3 characters long").max(20, "Username must be less than 20 characters long"),
|
|
5
|
+
email: yup.string().email("Invalid email address").required("Email is required"),
|
|
6
|
+
password: yup.string().required("Password is required").min(8, "Password must be at least 8 characters long"),
|
|
7
|
+
confirmPassword: yup.string().oneOf([yup.ref("password"), null], "Passwords must match")
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export const signInSchema = yup.object({
|
|
11
|
+
email: yup.string().email("Invalid email address").required("Email is required"),
|
|
12
|
+
password: yup.string().required("Password is required").min(8, "Password must be at least 8 characters long"),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export const addMemberSchema = yup.object({
|
|
16
|
+
username: yup.string().required("Username is required").min(3, "Username must be atleast 3 characters long").max(20, "Username must be less than 20 characters long"),
|
|
17
|
+
email: yup.string().email("Invalid email address").required("Email is required"),
|
|
18
|
+
password: yup.string().required("Password is required").min(8, "Password must be at least 8 characters long"),
|
|
19
|
+
confirmPassword: yup.string().oneOf([yup.ref("password"), null], "Passwords must match")
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export const addBookSchema = yup.object({
|
|
23
|
+
title: yup.string().required("title is required").min(3, "title must be atleast 3 characters long").max(25, "title must be less than 20 characters long"),
|
|
24
|
+
author: yup.string().required("author is required").min(3, "author must be atleast 3 characters long").max(20, "author must be less than 20 characters long"),
|
|
25
|
+
isbn: yup.string().required("isbn is required").min(3, "isbn must be atleast 3 characters long").max(10, "isbn must be less than 20 characters long"),
|
|
26
|
+
category: yup.string().required("category is required").min(3, "category must be atleast 3 characters long").max(10, "category must be less than 20 characters long"),
|
|
27
|
+
quantity: yup.number().required("Books quantity is required").min(1, "quantity must be atleast 1").max(100, "quantity must less than 100")
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
export const myBookSchema = (borrowDate) => {
|
|
31
|
+
const maxDate = new Date(borrowDate);
|
|
32
|
+
maxDate.setDate(maxDate.getDate() + 7);
|
|
33
|
+
return yup.object({
|
|
34
|
+
return_date: yup
|
|
35
|
+
.date()
|
|
36
|
+
.required("Return date is required")
|
|
37
|
+
.min(borrowDate,"Return date cannot be before today")
|
|
38
|
+
.max(maxDate,"Return date cannot be more than 7 days")
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
};
|