diff --git a/public/index.html b/public/index.html index 50e8cb60..506e68cc 100644 --- a/public/index.html +++ b/public/index.html @@ -5,7 +5,7 @@ - E-Commerce Ninjas FrontEnd + E-Commerce Ninjas
diff --git a/src/App.scss b/src/App.scss index b077491f..c415562e 100644 --- a/src/App.scss +++ b/src/App.scss @@ -44,10 +44,11 @@ @import "./assets//styles/UserProfile.scss"; @import "./assets/styles/SellerSideProduct.scss"; @import "./assets/styles/SellerDeleteItem.scss"; -@import "./assets/styles/ServicesPage.scss" -; @import "./assets/styles/verticalStepper.scss"; @import "./assets/styles/requests.scss"; @import "./assets/styles/AboutUs.scss"; @import "./assets/styles/UserDetails.scss"; -@import "./assets/styles/SellerRegistration.scss" \ No newline at end of file +@import "./assets/styles/SellerRegistration.scss"; +@import "./assets/styles/ServicesPage.scss"; +@import "./assets/styles/Settings.scss"; +@import "./assets/styles/HomePage.scss"; \ No newline at end of file diff --git a/src/assets/styles/HomePage.scss b/src/assets/styles/HomePage.scss new file mode 100644 index 00000000..fb8676ad --- /dev/null +++ b/src/assets/styles/HomePage.scss @@ -0,0 +1,28 @@ +.banner { + background-color: $primary-color; + display: flex; + justify-content: center; + align-items: center; + gap: 1rem; + color: $white; + font-size: 2rem; + padding: 1rem; + + .btn-link { + background-color: $primary-color-light; + border: none; + padding: 1rem 2rem; + border-radius: 5px; + cursor: pointer; + color: $white; + transition: all 0.5s ease-in-out; + + &:hover { + background-color: $menu-hover; + transition: all 0.5s ease-in-out; + color: $text2-color; + + } + } + +} \ No newline at end of file diff --git a/src/assets/styles/Settings.scss b/src/assets/styles/Settings.scss new file mode 100644 index 00000000..68352bca --- /dev/null +++ b/src/assets/styles/Settings.scss @@ -0,0 +1,201 @@ +.settings { + border: 1px solid $border-color; + width: 100%; + height: 100%; + background-color: $white-color; + + h2 { + margin: 0; + padding: 2%; + font-size: 2.5rem; + font-weight: bold; + text-align: left; + } + + .menu-bar { + display: flex; + margin: 0 2.5rem; + border-bottom: 1px solid #ddd; + + + .menu-item { + cursor: pointer; + font-size: 1.3rem; + + p { + margin-right: 1rem; + padding: 1rem; + + &.active { + background-color: $primary-color-light; + color: $primary-color; + padding: 1rem; + border-bottom: 1px solid $primary-color; + transition: padding .2s ease-in-out; + } + } + + } + } + + + .section_container { + flex-grow: 1; + padding: 0 2.5rem; + + .loading__spinner { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 50rem; + + } + + .section-content { + background-color: white; + overflow-y: auto; + padding: 10px; + height: 70vh; + + + label { + font-size: 2.5rem; + font-weight: bold; + } + + .password_exp { + background-color: $secondary-color-light; + padding: 2rem 5rem; + border-radius: .5rem; + margin-bottom: 2rem; + + .form-group { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + + input { + padding: 10px; + border: 1px solid #ddd; + border-radius: 5px; + font-size: 1.4rem; + width: 30%; + } + } + + .btn { + padding: 10px 20px; + background-color: $primary-color; + color: $white-color; + border: none; + border-radius: 5px; + font-size: 1.6rem; + width: 8rem; + cursor: pointer; + transition: width 0.5s linear; + + &:hover { + background-color: $primary-color-dark; + width: 10rem; + transition: width 0.5s linear; + } + } + } + + .terms { + background-color: $secondary-color-light; + padding: 2rem 5rem; + border-radius: .5rem; + margin-bottom: 2rem; + + .nav__terms { + padding-bottom: 1rem; + + .terms__link { + padding: 1rem; + + &.active { + background-color: $primary-color-light; + border-bottom: 1px solid $primary-color; + color: $primary-color; + } + } + + ul { + display: flex; + list-style: none; + margin: 0; + padding: 0; + cursor: pointer; + border-bottom: 1px solid rgba(0, 0, 0, 0.2); + + li { + font-size: 1.5rem; + } + } + } + + form { + padding: 0; + margin: 2rem 0; + + div:first-child { + margin: 20px 0; + display: flex; + flex-direction: column; + justify-content: space-between; + + textarea { + padding: 10px; + border: 1px solid #ddd; + border-radius: 5px; + font-size: 1.4rem; + width: 50%; + height: 100px; + + &:hover { + border-color: $primary-color; + } + } + + select { + border: 1px solid #ddd; + border-radius: 5px; + font-size: 1.4rem; + height: 30%; + width: 20%; + margin: 2rem 0; + + &:hover { + border-color: $primary-color; + } + } + } + + .form-group { + .btn { + padding: 10px 20px; + background-color: $primary-color; + color: $white-color; + border: none; + border-radius: 5px; + font-size: 1.6rem; + width: 8rem; + cursor: pointer; + transition: width 0.5s linear; + + &:hover { + background-color: $primary-color-dark; + width: 10rem; + transition: width 0.5s linear; + } + } + } + } + } + } + } + +} \ No newline at end of file diff --git a/src/assets/styles/adminDashboard.scss b/src/assets/styles/adminDashboard.scss index 78639605..e240b457 100644 --- a/src/assets/styles/adminDashboard.scss +++ b/src/assets/styles/adminDashboard.scss @@ -19,9 +19,7 @@ flex-direction: column; height: 100%; width: 100%; - .dashboard, - .users, - .logout { + .menu__item,.logout { display: flex; align-items: center; padding-left: 1rem; @@ -214,5 +212,17 @@ .dropdown-item:hover { background-color: #f1f1f1; } -@media only screen and (min-width: 76.8rem) { + +.password-expiration-container { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; +} + +.password-expiration-input { + padding: 8px; + font-size: 1rem; + border: 1px solid #ccc; + border-radius: 4px; } diff --git a/src/components/TermsAndCondition/EditTerms.tsx b/src/components/TermsAndCondition/EditTerms.tsx new file mode 100644 index 00000000..ab007891 --- /dev/null +++ b/src/components/TermsAndCondition/EditTerms.tsx @@ -0,0 +1,121 @@ +/* eslint-disable */ +import React, { useEffect, useState } from "react"; +import PropTypes from "prop-types"; +import { useAppDispatch, useAppSelector } from "../../store/store"; +import { getTerm, updateTerm } from "../../store/features/admin/adminSlice"; +import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions,Button } from "@mui/material"; + +export const EditTerms = ({ id }) => { + const [isDisabled, setIsDisabled] = useState(true); + const [isEdit, setIsEdit] = useState(true); + const [termType, setTermType] = useState(""); + const [termContent, setTermContent] = useState(""); + const [localState, setLocalState] = useState(); + const dispatch = useAppDispatch(); + + const term = useAppSelector((state) => state?.admin?.term); + + useEffect(() => { + const fetchTerm = async () => { + await dispatch(getTerm(id)); + }; + + fetchTerm(); + }, [dispatch, id]); + + useEffect(()=>{ + if (term) { + setIsDisabled(false); + setIsEdit(false); + setLocalState({ + type: term.type, + content: term.content, + }); + } + },[term]) + const handleSaveTerms = async (e) => { + e.preventDefault(); + const termData = { + id, + termType: localState.type, + termContent: localState.content, + }; + console.log("Saving Term: ", termData); + await dispatch(updateTerm(termData)); + setIsDisabled(true); + setIsEdit(true); + }; + + const handleTypeChange = (e) => { + const updatedType = e.target.value; + setLocalState((prevState) => ({ + ...prevState, + type: updatedType, + })); + setIsEdit(false); + }; + + const handleContentChange = (e) => { + const updatedContent = e.target.value; + setLocalState((prevState) => ({ + ...prevState, + content: updatedContent, + })); + setIsEdit(false); + }; + + + return ( + <> + +
+
+
+ {localState && ( + <> + + -
-
- - -
-
- - - - setOpen(false)} aria-labelledby="terms-and-conditions-title" aria-describedby="terms-and-conditions-description"> - Terms and Conditions - - - {/* Insert your Terms and Conditions content here */} -

Lorem ipsum...

-
-
- - - -
-
-
-
- -
-
+ useEffect(() => { + dispatch(getAllTerms()); + }, [dispatch]); + + useEffect(() => { + if (terms) { + const userTerms = terms.find((term) => term.type === "buyer"); + if (userTerms) { + setTerm(userTerms); + } + } + }, [terms]); + + return ( +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ {term ? (
+ + +
) : (
+ + +
)} + + + setOpen(false)} + aria-labelledby="terms-and-conditions-title" + aria-describedby="terms-and-conditions-description" + > + + Terms and Conditions + + + {term ? ( + + {/* Display the term content */} + {term.content} + + ) : ( + + No terms available for your role. + + )} + + + + + + +
+
+
- ); +
+
+ ); }; diff --git a/src/components/seller/SellerDetails.tsx b/src/components/seller/SellerDetails.tsx index 7678c929..cf2537bc 100644 --- a/src/components/seller/SellerDetails.tsx +++ b/src/components/seller/SellerDetails.tsx @@ -1,55 +1,109 @@ /* eslint-disable */ -import React, { useState } from 'react'; +import React, { useEffect, useState } from "react"; +import { useAppDispatch, useAppSelector } from "../../store/store"; +import { getAllTerms } from "../../store/features/admin/adminSlice"; interface Props { - nextStep: () => void; - prevStep: () => void; - formData: any; - updateFormData: (data: any) => void; + nextStep: () => void; + prevStep: () => void; + formData: any; + updateFormData: (data: any) => void; } -export const SellerDetails: React.FC = ({ nextStep, prevStep, formData, updateFormData }) => { - const [localData, setLocalData] = useState(formData); +export const SellerDetails: React.FC = ({ + nextStep, + prevStep, + formData, + updateFormData, +}) => { + const [localData, setLocalData] = useState(formData); + const handleChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setLocalData({ ...localData, [name]: value }); + }; - const handleChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; - setLocalData({ ...localData, [name]: value }); - }; + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + updateFormData(localData); + nextStep(); + }; - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - updateFormData(localData); - nextStep(); - }; - return ( -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
+ return ( +
+
+
+ +
- ); +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ ); }; diff --git a/src/components/settings/AccountSettings.tsx b/src/components/settings/AccountSettings.tsx new file mode 100644 index 00000000..e691d519 --- /dev/null +++ b/src/components/settings/AccountSettings.tsx @@ -0,0 +1,10 @@ +/* eslint-disable */ +import React from 'react' + +export const AccountSettings = () => { + return ( +
+

Account Settings

+
+ ) +} diff --git a/src/components/settings/GeneralSettings.tsx b/src/components/settings/GeneralSettings.tsx new file mode 100644 index 00000000..1bf2be3b --- /dev/null +++ b/src/components/settings/GeneralSettings.tsx @@ -0,0 +1,307 @@ +/* eslint-disable */ +import React, { useEffect, useState } from "react"; +import { useAppDispatch, useAppSelector } from "../../store/store"; +import { + deleteTerm, + fetchPasswordExpiration, + getAllTerms, + setTerms, + updateUserPasswordExpiration, +} from "../../store/features/admin/adminSlice"; +import Box from "@mui/material/Box"; +import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, IconButton, LinearProgress, Tooltip, Zoom } from "@mui/material"; +import Table from "../table/Table"; +import { Delete, Edit } from "@mui/icons-material"; +import { EditTerms } from "../TermsAndCondition/EditTerms"; + +export const GeneralSettings = () => { + const dispatch = useAppDispatch(); + const { users, isLoading, passwordExpiration, terms } = useAppSelector( + (state) => state?.admin + ); + const [minutes, setMinutes] = useState(passwordExpiration); + const [isDisabled, setIsDisabled] = useState(true); + const [isEdit, setIsEdit] = useState(true); + const [selected, setSelected] = useState("Terms & Conditions list"); + const [termType, setTermType] = useState(""); + const [termContent, setTermContent] = useState(""); + const [isEditTerms, setIsEditTerms] = useState(""); + const [termToDelete, setTermToDelete] = useState(null); + const [id, setId] = useState(); + const [open, setOpen] = useState(false); + const [localState, setLocalState] = useState([]) + + useEffect(() => { + const fun = async () => { + await dispatch(fetchPasswordExpiration()); + await dispatch(getAllTerms()); + setMinutes(passwordExpiration); + }; + fun(); + }, [dispatch, passwordExpiration]); + + useEffect(() => { + if (Array.isArray(terms)) { + setLocalState(terms); + } + }, [terms]); + + useEffect(() => { + if (selected === "Terms & Conditions list") { + dispatch(getAllTerms()); + } + }, [selected, dispatch]); + const handleMinutesChange = (e: React.ChangeEvent) => { + setMinutes(Number(e.target.value)); + }; + + const handleSavePasswordExpiration = () => { + if (minutes) { + dispatch(updateUserPasswordExpiration({ minutes })); + } + setIsDisabled(true); + setIsEdit(true); + }; + + const handleDeleteTerm = (id: string) => { + setTermToDelete(id); + setOpen(true); + setIsDisabled(true); + setIsEdit(true); + }; + + const handleConfirmDelete = async () => { + if (termToDelete) { + await dispatch(deleteTerm(termToDelete)); + setLocalState(localState?.filter((item) => item.id!== termToDelete)); + setOpen(false); + setTermToDelete(null); + } + }; + + const handleSaveTerms = async (e) => { + e.preventDefault(); + const termData = { + termType, + termContent, + }; + await dispatch(setTerms(termData)); + setIsDisabled(true); + setIsEdit(true); + setTermType(""); + setTermContent(""); + }; + + const headers = ["N0", "type", "content", "createdAt", "action"]; + + const rows = localState?.map((item, index) => { + return [ + index + 1, + item.type, + item.content, + new Date(item.createdAt).toLocaleDateString(), +
+ + { + setIsEditTerms("Edit Terms"), + setId(item.id), + setSelected("Edit Terms"); + }} + > + + + + + {handleDeleteTerm(item.id)}}> + + + +
, + ]; + }); + + const termLinks = [ + "Terms & Conditions list", + "Create New Terms", + `${isEditTerms}`, + ]; + const renderSection = () => { + switch (selected) { + case "Terms & Conditions list": + return ( + <> + + setOpen(false)} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > + + {"Confirm Role Change"} + + + + Are you sure you want to change this user's role to Admin? + + + + + + + + + ); + case "Create New Terms": + return ( + <> + +
+
+
+ +