Skip to content

Commit

Permalink
add product feature completed
Browse files Browse the repository at this point in the history
  • Loading branch information
shubh-mehrotra-encora committed Oct 5, 2021
1 parent 5bb61c1 commit 4e9982d
Show file tree
Hide file tree
Showing 16 changed files with 382 additions and 26 deletions.
10 changes: 10 additions & 0 deletions src/assets/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,14 @@
padding: 0;
display: grid;
grid-template-columns: auto auto;
}

.card-group .card {
margin-right: 10px;
margin-bottom: 10px;
}

.card-group .card .card-img-top {
width: 286px;
height: 180px;
}
106 changes: 106 additions & 0 deletions src/components/admin/AddOrEditProduct.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { useState } from "react";
import Form from "react-bootstrap/Form";
import { Button } from "react-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import { addProduct } from "../../store/actions/productActions";
import { setToast } from "../../store/actions/toastActions";

export default function AddOrEditProduct(props) {
var product = {};
const products = useSelector(state => state.products);

if (props.editProductId) {
product = products.find(product => product.id === props.editProductId) || {};
}

const dispatch = useDispatch();

const [title, setTitle] = useState(product.title);
const [price, setPrice] = useState(product.price);
const [description, setDescription] = useState(product.description);
const [validated, setValidated] = useState(false);

const handleSubmit = event => {
event.preventDefault();

if (event.currentTarget.checkValidity()) {
let action = "added";

const productDetails = {
id: Math.floor(Math.random() * 1000),
title,
price: +price,
description,
}

if (product.id) {
productDetails.id = product.id;

action = "updated";
}

dispatch(addProduct(productDetails));

dispatch(setToast({
type: "success",
title: "Success!",
message: `Kudos! Product has been ${action} successfully!`
}));

props.onProductFormToggle();
}

setValidated(true);
}

const handleInputChange = ({target}, fieldType) => {
switch (fieldType) {
case 'title':
setTitle(target.value);
break;

case 'description':
setDescription(target.value);
break;

case 'price':
setPrice(target.value);
break;

default:
break;
}
}

return (
<Form noValidate validated={validated} className="page-content" onSubmit={handleSubmit}>
<Form.Group className="mb-3" controlId="productName">
<Form.Label>Title</Form.Label>
<Form.Control type="text" placeholder="Enter product name" value={title} onChange={event => handleInputChange(event, "title")} required />
<Form.Control.Feedback type="invalid">
Please enter product's title.
</Form.Control.Feedback>
</Form.Group>

<Form.Group className="mb-3" controlId="productPrice">
<Form.Label>Price</Form.Label>
<Form.Control type="text" placeholder="price" value={price} onChange={event => handleInputChange(event, "price")} required />
<Form.Control.Feedback type="invalid">
Please enter product's price.
</Form.Control.Feedback>
</Form.Group>

<Form.Group className="mb-3" controlId="productDescription">
<Form.Label>Description</Form.Label>
<Form.Control type="textarea" placeholder="Description" value={description} onChange={event => handleInputChange(event, "description")} required />
<Form.Control.Feedback type="invalid">
Please enter product's description.
</Form.Control.Feedback>
</Form.Group>

<Button variant="primary" type="submit">
Submit
</Button>
</Form>
)
}
33 changes: 28 additions & 5 deletions src/components/admin/Dashboard.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,43 @@
import { useEffect } from "react";
import { useHistory } from "react-router-dom";
import Header from "./Header";
import Products from "./Products";
import { useSelector } from "react-redux";
import { useEffect, useState } from "react";
import { useHistory } from "react-router-dom";
import AddOrEditProduct from "./AddOrEditProduct";

export function Dashboard() {
const history = useHistory();
const isAdminLoggedIn = useSelector(state => state.admin);
const [addProductForm, setAddProductForm] = useState(false);

useEffect(() => {
if (localStorage.getItem("isUserLoggedIn") != "true") {
if (isAdminLoggedIn.toString() != "true") {
history.push("/admin/login");
}
}, [])

const handleformToggle = id => {
let param = !addProductForm;

if (typeof id == "number") {
param = id;
}

setAddProductForm(param);
}

return (
<div className="page-content">
<Header />
Welcome to admin dashboard
<h3 style={{textAlign: "center"}}>Welcome to admin dashboard</h3>

<Header onProductFormToggle={handleformToggle} isEditForm={addProductForm} />

{
addProductForm
? <AddOrEditProduct onProductFormToggle={handleformToggle} editProductId={addProductForm} />
: <Products onProductFormToggle={handleformToggle} />
}

</div>
)
}
9 changes: 7 additions & 2 deletions src/components/admin/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { Button } from "react-bootstrap";
import { useDispatch } from "react-redux";
import { useHistory } from 'react-router-dom';
import { setToast } from "../../store/actions/toastActions";
import { setAdmin } from "../../store/actions/userActions";

export default function Header() {
export default function Header(props) {
const history = useHistory();
const dispatch = useDispatch();

Expand All @@ -14,13 +15,17 @@ export default function Header() {
message: "Kudos! You're successfully logged out."
}));

localStorage.setItem("isUserLoggedIn", false);
dispatch(setAdmin(false));

history.push("/admin/login");
}

return (
<div style={{textAlign: 'right'}}>
<Button variant={props.isEditForm ? 'light' : 'primary'} onClick={props.onProductFormToggle}>
{props.isEditForm ? 'Back' : 'Add Product'}
</Button>{' '}

<Button variant="primary" onClick={handleLogout}>
Logout
</Button>
Expand Down
12 changes: 8 additions & 4 deletions src/components/admin/Login.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { useEffect, useState } from "react";
import Form from "react-bootstrap/Form";
import { useDispatch } from "react-redux";
import { Button } from "react-bootstrap";
import { useEffect, useState } from "react";
import { useHistory } from 'react-router-dom';
import { useDispatch, useSelector } from "react-redux";
import { setToast } from "../../store/actions/toastActions";
import { setAdmin } from "../../store/actions/userActions";

export function Login() {
const history = useHistory();
const dispatch = useDispatch();
const isAdminLoggedIn = useSelector(state => state.admin);

const [email, setEmail] = useState("admin@example.com");
const [password, setPassword] = useState("admin123");

useEffect(() => {
if (localStorage.getItem("isUserLoggedIn") == "true") {
if (isAdminLoggedIn == "true") {
dispatch(setToast({
type: "success",
title: "Warning!",
Expand All @@ -32,7 +34,7 @@ export function Login() {
message: "Kudos! You're logged in."
}));

localStorage.setItem("isUserLoggedIn", true);
dispatch(setAdmin(true));

history.push("/admin/dashboard");
} else {
Expand Down Expand Up @@ -72,6 +74,8 @@ export function Login() {

return (
<Form noValidate className="page-content" onSubmit={handleSubmit}>
<h3 style={{textAlign: "center"}}>Welcome to the admin panel</h3>

<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" placeholder="Enter email" value={email} onChange={event => handleInputChange(event, "email")} required />
Expand Down
31 changes: 31 additions & 0 deletions src/components/admin/Products.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Card, Button, CardGroup } from "react-bootstrap";
import { useSelector } from "react-redux";

export default function Products(props) {
const global = useSelector(state => state.global);
const products = useSelector(state => state.products);

return (
<CardGroup className="mt-4">
{products.map(product => (
<Card style={{ width: '18rem' }} key={product.id}>
<Card.Img variant="top" src={product.image || "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22286%22%20height%3D%22180%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20286%20180%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_17c4f217211%20text%20%7B%20fill%3A%23999%3Bfont-weight%3Anormal%3Bfont-family%3Avar(--bs-font-sans-serif)%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_17c4f217211%22%3E%3Crect%20width%3D%22286%22%20height%3D%22180%22%20fill%3D%22%23373940%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%22106.6640625%22%20y%3D%2296.3%22%3E286x180%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E"} />

<Card.Body>
<Card.Title>{product.title}</Card.Title>

<Card.Text>
{global.currencySymbol}{product.price}
</Card.Text>

<Card.Text>
{product.description}
</Card.Text>

<Button variant="primary" onClick={() => props.onProductFormToggle(product.id)}>Edit</Button>
</Card.Body>
</Card>
))}
</CardGroup>
)
}
2 changes: 1 addition & 1 deletion src/components/common/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function Header() {

return (
<div>
<h1 className="mt-4">Welcome to <Link to="/">e-commerce</Link> world!</h1>
<h1 className="mt-4 text-center">Welcome to <Link to="/">e-commerce</Link> world!</h1>

<ToastContainer position="top-end" className="p-3">
<Toast show={toast != false} onClose={() => dispatch(setToast(false))} bg={toast.type} delay={3000} autohide>
Expand Down
73 changes: 61 additions & 12 deletions src/components/customer/Login.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,65 @@
import Form from "react-bootstrap/Form";
import { Button } from "react-bootstrap";
import { useEffect, useState } from "react";
import { useHistory } from 'react-router-dom';
import { useDispatch, useSelector } from "react-redux";
import { setToast } from "../../store/actions/toastActions";
import { setCustomer } from "../../store/actions/userActions";

export function Login() {
const [validated, setValidated] = useState(false);
const history = useHistory();
const dispatch = useDispatch();
const isAdminLoggedIn = useSelector(state => state.admin);

const [email, setEmail] = useState("admin@example.com");
const [password, setPassword] = useState("admin123");

useEffect(() => {
}, [validated]);
if (isAdminLoggedIn == "true") {
dispatch(setToast({
type: "success",
title: "Warning!",
message: "Kudos! You're already logged in."
}));

history.push("/admin/dashboard");
}
}, [])

const loginAdmin = () => {
if (email == "admin@example.com" && password == "admin123") {
dispatch(setToast({
type: "success",
title: "Success!",
message: "Kudos! You're logged in."
}));

dispatch(setCustomer(true));

history.push("/admin/dashboard");
} else {
dispatch(setToast({
type: "danger",
title: "Error!",
message: "Oops! Please check your credentials once."
}));
}
}

const handleInputChange = ({target}, fieldType) => {
switch (fieldType) {
case 'email':
setEmail(target.value);
break;

case 'password':
setPassword(target.value);
break;

default:
break;
}
}

const handleSubmit = event => {
event.preventDefault();
Expand All @@ -15,29 +68,25 @@ export function Login() {
const form = event.currentTarget;

if (form.checkValidity()) {
setValidated(true);

loginCustomer(form);
loginAdmin(form);
}
}

const loginCustomer = form => {
console.log(validated);
}

return (
<Form noValidate className="page-content" validated={validated} onSubmit={handleSubmit}>
<Form noValidate className="page-content" onSubmit={handleSubmit}>
<h3 style={{textAlign: "center"}}>Welcome to the customer panel</h3>

<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" placeholder="Enter email" defaultValue="admin@example.com" required />
<Form.Control type="email" placeholder="Enter email" value={email} onChange={event => handleInputChange(event, "email")} required />
<Form.Control.Feedback type="invalid">
Please enter email address.
</Form.Control.Feedback>
</Form.Group>

<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password" defaultValue="admin123" required />
<Form.Control type="password" placeholder="Password" value={password} onChange={event => handleInputChange(event, "password")} required />
<Form.Control.Feedback type="invalid">
Please enter password.
</Form.Control.Feedback>
Expand Down
8 changes: 8 additions & 0 deletions src/store/actions/globalActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { SET_GLOBAL_DETAILS } from "../type";

export function setGlobalDetails(value) {
return {
type: SET_GLOBAL_DETAILS,
payload: value,
}
}
Loading

0 comments on commit 4e9982d

Please sign in to comment.