la-flowerita 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +70 -0
- package/package.json +78 -0
- package/public/favicon.ico +0 -0
- package/public/images/1.jpg +0 -0
- package/public/images/2.jpg +0 -0
- package/public/images/3.jpg +0 -0
- package/public/images/Logo.png +0 -0
- package/public/images/add-user.png +0 -0
- package/public/images/contact-us.png +0 -0
- package/public/images/flower.png +0 -0
- package/public/images/flower_shop.png +0 -0
- package/public/images/flower_shop1.png +0 -0
- package/public/images/flowers/buttercup.png +0 -0
- package/public/images/flowers/daffodil.png +0 -0
- package/public/images/flowers/daisy.png +0 -0
- package/public/images/flowers/jasmine.png +0 -0
- package/public/images/flowers/lily.png +0 -0
- package/public/images/flowers/marigold.png +0 -0
- package/public/images/flowers/orchid.png +0 -0
- package/public/images/flowers/rose.png +0 -0
- package/public/images/flowers/sunflower.png +0 -0
- package/public/images/flowers/tulip.png +0 -0
- package/public/images/garbage.png +0 -0
- package/public/images/icon1.jpg +0 -0
- package/public/images/login.png +0 -0
- package/public/images/refresh.png +0 -0
- package/public/images/transaction.png +0 -0
- package/public/index.html +41 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +26 -0
- package/public/offline.html +44 -0
- package/public/robots.txt +3 -0
- package/public/serviceworker.js +44 -0
- package/server.js +97 -0
- package/src/App.css +38 -0
- package/src/App.js +25 -0
- package/src/App.test.js +8 -0
- package/src/Config/db.js +5 -0
- package/src/Config/mail.js +7 -0
- package/src/Config/passport.js +34 -0
- package/src/Controllers/catalog.controller.js +78 -0
- package/src/Controllers/shoppinglist.controller.js +186 -0
- package/src/Controllers/user.controller.js +214 -0
- package/src/Controllers/wishlist.controller.js +150 -0
- package/src/Middleware/sendMail.js +29 -0
- package/src/Middleware/uploadImage.js +26 -0
- package/src/Models/orderProducts.js +10 -0
- package/src/Models/products.js +17 -0
- package/src/Models/shoppinglists.js +12 -0
- package/src/Models/userShoppinglists.js +9 -0
- package/src/Models/users.js +57 -0
- package/src/Models/wishlists.js +9 -0
- package/src/Routes/auth.js +21 -0
- package/src/Routes/indexRouter.js +40 -0
- package/src/Services/ProductService.js +76 -0
- package/src/Services/ShoppinglistService.js +135 -0
- package/src/Services/UserService.js +63 -0
- package/src/Services/WishlistService.js +105 -0
- package/src/components/About.js +45 -0
- package/src/components/Auth.js +15 -0
- package/src/components/Catalog.js +118 -0
- package/src/components/Chat.js +77 -0
- package/src/components/Contact.js +48 -0
- package/src/components/Dashboard.js +13 -0
- package/src/components/DetailsProductModal.js +362 -0
- package/src/components/LoginModal.js +173 -0
- package/src/components/NewProductModal.js +271 -0
- package/src/components/NoPermission.js +10 -0
- package/src/components/OrderedProduct.js +104 -0
- package/src/components/PreChat.js +51 -0
- package/src/components/Product.js +158 -0
- package/src/components/ResetPassword.js +211 -0
- package/src/components/ShoppingCart.js +198 -0
- package/src/components/SideNav.js +76 -0
- package/src/components/SignupModal.js +306 -0
- package/src/components/Spinner.js +22 -0
- package/src/components/Wishlist.js +195 -0
- package/src/components/social-config.js +17 -0
- package/src/css/about.css +12 -0
- package/src/css/catalog.css +218 -0
- package/src/css/chat.css +191 -0
- package/src/css/contact.css +404 -0
- package/src/css/index.css +129 -0
- package/src/css/newProductModal.css +69 -0
- package/src/css/noPermission.css +89 -0
- package/src/css/orderedProduct.css +0 -0
- package/src/css/resetPassword.css +44 -0
- package/src/css/shoppingCart.css +10 -0
- package/src/css/sideNav.css +68 -0
- package/src/css/spinner.css +23 -0
- package/src/images/1.jpg +0 -0
- package/src/images/2.jpg +0 -0
- package/src/images/3.jpg +0 -0
- package/src/images/Logo.png +0 -0
- package/src/images/add-user.png +0 -0
- package/src/images/buttercup.png +0 -0
- package/src/images/contact-us.png +0 -0
- package/src/images/daffodil.png +0 -0
- package/src/images/daisy.png +0 -0
- package/src/images/flower.png +0 -0
- package/src/images/flower_shop.png +0 -0
- package/src/images/flower_shop1.png +0 -0
- package/src/images/flowers/buttercup.png +0 -0
- package/src/images/flowers/daffodil.png +0 -0
- package/src/images/flowers/daisy.png +0 -0
- package/src/images/flowers/jasmine.png +0 -0
- package/src/images/flowers/lily.png +0 -0
- package/src/images/flowers/marigold.png +0 -0
- package/src/images/flowers/orchid.png +0 -0
- package/src/images/flowers/rose.png +0 -0
- package/src/images/flowers/sunflower.png +0 -0
- package/src/images/flowers/tulip.png +0 -0
- package/src/images/garbage.png +0 -0
- package/src/images/icon1.jpg +0 -0
- package/src/images/jasmine.png +0 -0
- package/src/images/lily.png +0 -0
- package/src/images/login.png +0 -0
- package/src/images/marigold.png +0 -0
- package/src/images/orchid.png +0 -0
- package/src/images/refresh.png +0 -0
- package/src/images/rose.png +0 -0
- package/src/images/sunflower.png +0 -0
- package/src/images/transaction.png +0 -0
- package/src/images/tulip.png +0 -0
- package/src/index.js +371 -0
- package/src/logo.svg +1 -0
- package/src/reportWebVitals.js +13 -0
- package/src/setupTests.js +5 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
import { React, Component } from "react";
|
2
|
+
import sampleImage from "../logo.svg";
|
3
|
+
import "../css/catalog.css";
|
4
|
+
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
5
|
+
import { FaHeart, FaRegHeart, FaShoppingCart, FaEye } from "react-icons/fa";
|
6
|
+
import DetailsProductModal from "./DetailsProductModal.js";
|
7
|
+
import swal from "sweetalert";
|
8
|
+
import LoadingIndicator from "./Spinner";
|
9
|
+
import { usePromiseTracker, trackPromise } from "react-promise-tracker";
|
10
|
+
class Product extends Component {
|
11
|
+
constructor(props) {
|
12
|
+
super(props);
|
13
|
+
console.log(props);
|
14
|
+
this.state = {
|
15
|
+
isInWishList: props.isInWishList,
|
16
|
+
id: props.id,
|
17
|
+
name: props.name,
|
18
|
+
image: props.image,
|
19
|
+
color: props.color,
|
20
|
+
price: props.price,
|
21
|
+
description: props.description,
|
22
|
+
type: props.type,
|
23
|
+
maxAmount: props.maxAmount,
|
24
|
+
onUpdateCart: props.onUpdateCart,
|
25
|
+
onUpdateWishlist: props.onUpdateWishlist,
|
26
|
+
showModal:false
|
27
|
+
};
|
28
|
+
}
|
29
|
+
|
30
|
+
async intoCart(props) {
|
31
|
+
console.log(this.state);
|
32
|
+
var options = {
|
33
|
+
method: "POST",
|
34
|
+
headers: { "Content-Type": "application/json" },
|
35
|
+
body: JSON.stringify({ productId: this.state.id }),
|
36
|
+
};
|
37
|
+
await fetch("/addNewProductToCart", options).then(res => res.json()).then(
|
38
|
+
(result) => {
|
39
|
+
if (result.status == 200) {
|
40
|
+
this.state.onUpdateCart(result.cart.products.length);
|
41
|
+
swal("Success!", "Product Added To Cart!", "success");
|
42
|
+
}
|
43
|
+
},
|
44
|
+
(error) => {
|
45
|
+
console.log(error);
|
46
|
+
}
|
47
|
+
);
|
48
|
+
}
|
49
|
+
async intoWishList() {
|
50
|
+
console.log(this.state);
|
51
|
+
var options = {
|
52
|
+
method: "POST",
|
53
|
+
headers: { "Content-Type": "application/json" },
|
54
|
+
body: JSON.stringify({ productId: this.state.id }),
|
55
|
+
};
|
56
|
+
await fetch("/addNewProductToWishlist", options).then(res => res.json()).then(
|
57
|
+
(result) => {
|
58
|
+
if (result.status == 200) {
|
59
|
+
this.state.onUpdateWishlist(result.wishlist.products.length);
|
60
|
+
this.setState({ isInWishList: true });
|
61
|
+
swal("Success!", "Product Added To Wish List!", "success");
|
62
|
+
}
|
63
|
+
},
|
64
|
+
(error) => {
|
65
|
+
console.log(error);
|
66
|
+
}
|
67
|
+
);
|
68
|
+
}
|
69
|
+
async outOfWishList() {
|
70
|
+
console.log(this.state);
|
71
|
+
var options = {
|
72
|
+
method: "POST",
|
73
|
+
headers: { "Content-Type": "application/json" },
|
74
|
+
body: JSON.stringify({ productId: this.state.id }),
|
75
|
+
};
|
76
|
+
await fetch("/deleteProductFromWishlist", options).then(res => res.json()).then(
|
77
|
+
(result) => {
|
78
|
+
if (result.status == 200) {
|
79
|
+
this.state.onUpdateWishlist(result.wishlist.products.length);
|
80
|
+
this.setState({ isInWishList: false });
|
81
|
+
swal("Success!", "Product Removed From Wish List!", "success");
|
82
|
+
}
|
83
|
+
},
|
84
|
+
(error) => {
|
85
|
+
console.log(error);
|
86
|
+
}
|
87
|
+
); }
|
88
|
+
arrayBufferToBase64(buffer) {
|
89
|
+
var binary = "";
|
90
|
+
var bytes = [].slice.call(new Uint8Array(buffer.data));
|
91
|
+
bytes.forEach((b) => (binary += String.fromCharCode(b)));
|
92
|
+
return window.btoa(binary);
|
93
|
+
}
|
94
|
+
render() {
|
95
|
+
var path =
|
96
|
+
"data:/" +
|
97
|
+
this.props.image.contentType +
|
98
|
+
";base64," +
|
99
|
+
this.arrayBufferToBase64(this.props.image.data);
|
100
|
+
return (<div class="column">
|
101
|
+
<div class="product-img">
|
102
|
+
<img src={path} onError={(e) => {
|
103
|
+
e.target.src =
|
104
|
+
"https://www.freeiconspng.com/uploads/no-image-icon-11.PNG";
|
105
|
+
e.target.onerror = null; // prevents looping
|
106
|
+
}}/>
|
107
|
+
</div>
|
108
|
+
<div class="product-info">
|
109
|
+
<div class="product-text">
|
110
|
+
<h1>{this.props.name}</h1>
|
111
|
+
<h2>Seller {this.props.sellerName}</h2>
|
112
|
+
<p>{this.props.description}</p>
|
113
|
+
</div>
|
114
|
+
<div class="product-price-btn">
|
115
|
+
<p><span className=".product-span">{this.props.price}</span>$</p>
|
116
|
+
{this.state.isInWishList ? (
|
117
|
+
<button type="button" onClick={() => this.outOfWishList()}>
|
118
|
+
<FaHeart
|
119
|
+
id="inWishList"
|
120
|
+
style={{ cursor: "pointer" }}
|
121
|
+
/>
|
122
|
+
</button>
|
123
|
+
) : (
|
124
|
+
<button type="button" onClick={() => this.intoWishList()} >
|
125
|
+
<FaRegHeart
|
126
|
+
id="outWishList"
|
127
|
+
style={{ cursor: "pointer" }}
|
128
|
+
/>
|
129
|
+
</button>
|
130
|
+
)}
|
131
|
+
<button type="button" onClick={() => this.intoCart(this.props)}>
|
132
|
+
<FaShoppingCart
|
133
|
+
style={{ cursor: "pointer" }}
|
134
|
+
/>
|
135
|
+
</button>
|
136
|
+
<button type="button" onClick={() => this.setState({showModal:true})}>
|
137
|
+
<FaEye/>
|
138
|
+
{this.state.showModal? <DetailsProductModal id={this.props.id}
|
139
|
+
image={this.props.image}
|
140
|
+
path={path}
|
141
|
+
name={this.props.name}
|
142
|
+
color={this.props.color}
|
143
|
+
price={this.props.price}
|
144
|
+
description={this.props.description}
|
145
|
+
type={this.props.type}
|
146
|
+
maxAmount={this.state.maxAmount}
|
147
|
+
sellerName={this.state.sellerName}
|
148
|
+
showModal={true}
|
149
|
+
/>: ""}
|
150
|
+
</button>
|
151
|
+
</div>
|
152
|
+
</div>
|
153
|
+
</div>);
|
154
|
+
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
export default Product;
|
@@ -0,0 +1,211 @@
|
|
1
|
+
import React, { Component } from "react";
|
2
|
+
import Button from "react-bootstrap/Button";
|
3
|
+
import { Route, NavLink, HashRouter, Routes } from "react-router-dom";
|
4
|
+
import "../css/resetPassword.css"
|
5
|
+
import LoadingIndicator from "./Spinner";
|
6
|
+
import { usePromiseTracker, trackPromise } from "react-promise-tracker";
|
7
|
+
import swal from 'sweetalert';
|
8
|
+
|
9
|
+
class ResetPassword extends Component {
|
10
|
+
constructor() {
|
11
|
+
super();
|
12
|
+
this.state = {
|
13
|
+
emailSent: false,
|
14
|
+
emailReceived: false,
|
15
|
+
tokenChecked: false,
|
16
|
+
id: null,
|
17
|
+
ERROR: ""
|
18
|
+
};
|
19
|
+
}
|
20
|
+
|
21
|
+
resetPassword = async () => {
|
22
|
+
// this.setState({ [e.target.name]: e.target.value });
|
23
|
+
let email = document.getElementById("email").value;
|
24
|
+
var options = {
|
25
|
+
method: "POST",
|
26
|
+
headers: { "Content-Type": "application/json" },
|
27
|
+
body: JSON.stringify({email:email}),
|
28
|
+
};
|
29
|
+
trackPromise(
|
30
|
+
fetch("/emailForResetPassword", options)
|
31
|
+
.then(
|
32
|
+
(res) => {
|
33
|
+
console.log(res);
|
34
|
+
if (res.status == 200) {
|
35
|
+
console.log("email was sent successfully!");
|
36
|
+
this.setState({ emailSent: true });
|
37
|
+
}
|
38
|
+
else if (res.status == 404){
|
39
|
+
console.log("email was not sent!");
|
40
|
+
this.setState({ ERROR: "This email is not one of our users" });
|
41
|
+
}
|
42
|
+
},
|
43
|
+
// Note: it's important to handle errors here
|
44
|
+
// instead of a catch() block so that we don't swallow
|
45
|
+
// exceptions from actual bugs in components.
|
46
|
+
(error) => {
|
47
|
+
this.setState({
|
48
|
+
ERROR: error
|
49
|
+
});
|
50
|
+
}
|
51
|
+
))
|
52
|
+
};
|
53
|
+
|
54
|
+
checkToken = async () => {
|
55
|
+
let token = document.getElementById("token").value;
|
56
|
+
var options = {
|
57
|
+
method: "POST",
|
58
|
+
headers: { "Content-Type": "application/json" },
|
59
|
+
body: JSON.stringify({token:token}),
|
60
|
+
};
|
61
|
+
trackPromise(
|
62
|
+
fetch("/checkToken", options).then(res => res.json())
|
63
|
+
.then(
|
64
|
+
(res ) => {
|
65
|
+
console.log(res);
|
66
|
+
if (res.status == 200) {
|
67
|
+
console.log("token is good!");
|
68
|
+
this.setState({id:res.id, tokenChecked: true });
|
69
|
+
}
|
70
|
+
else if (res.status == 404){
|
71
|
+
console.log("token not good!");
|
72
|
+
this.setState({ ERROR: "This is not correct. Please try again" });
|
73
|
+
}
|
74
|
+
},
|
75
|
+
// Note: it's important to handle errors here
|
76
|
+
// instead of a catch() block so that we don't swallow
|
77
|
+
// exceptions from actual bugs in components.
|
78
|
+
(error) => {
|
79
|
+
this.setState({
|
80
|
+
ERROR: error
|
81
|
+
});
|
82
|
+
}
|
83
|
+
))
|
84
|
+
};
|
85
|
+
|
86
|
+
updatePassword = async () => {
|
87
|
+
// this.setState({ [e.target.name]: e.target.value });
|
88
|
+
let password = document.getElementById("password").value;
|
89
|
+
let repass = document.getElementById("repass").value;
|
90
|
+
if(password != repass){
|
91
|
+
this.setState({ ERROR: "This passwords are not the same" });
|
92
|
+
return;
|
93
|
+
}
|
94
|
+
var options = {
|
95
|
+
method: "POST",
|
96
|
+
headers: { "Content-Type": "application/json" },
|
97
|
+
body: JSON.stringify({password:password, id: this.state.id}),
|
98
|
+
};
|
99
|
+
trackPromise(
|
100
|
+
fetch("/updatePassword", options)
|
101
|
+
.then(
|
102
|
+
(res) => {
|
103
|
+
console.log(res);
|
104
|
+
if (res.status == 200) {
|
105
|
+
console.log("update password was successful!");
|
106
|
+
swal("Successful!","update password was successful! Please login.", "success")
|
107
|
+
document.location.href = "/";
|
108
|
+
}
|
109
|
+
},
|
110
|
+
// Note: it's important to handle errors here
|
111
|
+
// instead of a catch() block so that we don't swallow
|
112
|
+
// exceptions from actual bugs in components.
|
113
|
+
(error) => {
|
114
|
+
this.setState({
|
115
|
+
ERROR: error
|
116
|
+
});
|
117
|
+
}
|
118
|
+
))
|
119
|
+
};
|
120
|
+
render() {
|
121
|
+
if(!this.state.emailSent){
|
122
|
+
return (<GetEmailForReset resetPasswordFunction={this.resetPassword} ERROR={this.state.ERROR}></GetEmailForReset>
|
123
|
+
);
|
124
|
+
}
|
125
|
+
else if (!this.state.emailReceived && !this.state.tokenChecked){
|
126
|
+
return (<GetToken checkTokenFunction={this.checkToken} ERROR={this.state.ERROR}></GetToken>);
|
127
|
+
|
128
|
+
}
|
129
|
+
else if(this.state.tokenChecked){
|
130
|
+
return (<UpdatePassword updatePasswordfunction={this.updatePassword} ERROR={this.state.ERROR}></UpdatePassword>);
|
131
|
+
|
132
|
+
}
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
class GetEmailForReset extends Component{
|
137
|
+
|
138
|
+
render(){
|
139
|
+
return (
|
140
|
+
<div id="divForResetPassword" className="container d-flex justify-content-center align-items-center vh-100">
|
141
|
+
<LoadingIndicator/>
|
142
|
+
<div className="bg-white text-center p-5 mt-3 center">
|
143
|
+
<h3>Forgot Password </h3>
|
144
|
+
<p>Please enter your email and we will send you a link to reset your password.</p>
|
145
|
+
<form className="pb-3" action="#">
|
146
|
+
<div className="form-group">
|
147
|
+
<input name="email" id="email" type="email" className="form-control" placeholder="Your Username*" required/>
|
148
|
+
</div>
|
149
|
+
<h5>{this.props.ERROR}</h5>
|
150
|
+
</form>
|
151
|
+
<button onClick={() => this.props.resetPasswordFunction()} type="button" className="btn">Reset Password</button>
|
152
|
+
</div>
|
153
|
+
</div>);
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
class GetToken extends Component{
|
158
|
+
|
159
|
+
render(){
|
160
|
+
return(
|
161
|
+
<div className="container d-flex justify-content-center align-items-center vh-100">
|
162
|
+
<LoadingIndicator/>
|
163
|
+
<div className="bg-white text-center p-5 mt-3 center">
|
164
|
+
<h3>Forgot Password </h3>
|
165
|
+
<p>Please enter the token you got to your mail.</p>
|
166
|
+
<form className="pb-3" action="#">
|
167
|
+
<div className="form-group">
|
168
|
+
<input name="token" id="token" type="text" className="form-control" required/>
|
169
|
+
</div>
|
170
|
+
<h5>{this.props.ERROR}</h5>
|
171
|
+
</form>
|
172
|
+
<button onClick={() => this.props.checkTokenFunction()} type="button" className="btn">Submit</button>
|
173
|
+
{/* <NavLink
|
174
|
+
style={{cursor:"pointer"}}
|
175
|
+
onClick={() => this.checkToken()}
|
176
|
+
to="/updatePassword"
|
177
|
+
>
|
178
|
+
Submit
|
179
|
+
</NavLink> */}
|
180
|
+
</div>
|
181
|
+
</div>);
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
|
186
|
+
class UpdatePassword extends Component{
|
187
|
+
|
188
|
+
render() {
|
189
|
+
return (
|
190
|
+
<div className="container d-flex justify-content-center align-items-center vh-100">
|
191
|
+
<LoadingIndicator/>
|
192
|
+
<div className="bg-white text-center p-5 mt-3 center">
|
193
|
+
<h3>Change Password </h3>
|
194
|
+
<p>Please enter a new paswword.</p>
|
195
|
+
<form className="pb-3" action="#">
|
196
|
+
<div className="form-group">
|
197
|
+
<input name="password" id="password" type="password" className="form-control" placeholder="Your Password*" required/>
|
198
|
+
</div>
|
199
|
+
<div className="form-group">
|
200
|
+
<input name="repass" id="repass" type="password" className="form-control" placeholder="Write It Again*" required/>
|
201
|
+
</div>
|
202
|
+
<h5>{this.props.ERROR}</h5>
|
203
|
+
</form>
|
204
|
+
<button onClick={() => this.props.updatePasswordfunction()} type="button" className="btn">Save</button>
|
205
|
+
</div>
|
206
|
+
</div>
|
207
|
+
);
|
208
|
+
}
|
209
|
+
}
|
210
|
+
|
211
|
+
export default ResetPassword;
|
@@ -0,0 +1,198 @@
|
|
1
|
+
import {React, Component} from 'react';
|
2
|
+
import sampleImage from '../logo.svg';
|
3
|
+
import '../css/shoppingCart.css';
|
4
|
+
import { FaHeart, FaRegHeart, FaShoppingCart, FaEye } from "react-icons/fa";
|
5
|
+
import OrderedProduct from "./OrderedProduct.js"
|
6
|
+
import swal from "sweetalert";
|
7
|
+
import { Container, Table, Row, Button } from "react-bootstrap";
|
8
|
+
import LoadingIndicator from "./Spinner";
|
9
|
+
import { usePromiseTracker, trackPromise } from "react-promise-tracker";
|
10
|
+
class ShoppingCart extends Component {
|
11
|
+
constructor(props) {
|
12
|
+
super(props);
|
13
|
+
this.state = {
|
14
|
+
totalPrice: 0,
|
15
|
+
products: [],
|
16
|
+
loggedIn: false,
|
17
|
+
onUpdateCart: props.onUpdateCart,
|
18
|
+
};
|
19
|
+
}
|
20
|
+
componentDidMount = async () => {
|
21
|
+
var options = {
|
22
|
+
method: "GET",
|
23
|
+
headers: { "Content-Type": "application/json" },
|
24
|
+
};
|
25
|
+
trackPromise(
|
26
|
+
fetch("/getCurrentCart", options).then(res => res.json()).then(
|
27
|
+
(result) => {
|
28
|
+
console.log(result)
|
29
|
+
if (result.status == 200) {
|
30
|
+
this.setState({
|
31
|
+
products: result.cart.products,
|
32
|
+
totalPrice: result.cart.products.reduce(
|
33
|
+
(acc, item) => acc + item.price * item.quantity,
|
34
|
+
0
|
35
|
+
),
|
36
|
+
});
|
37
|
+
}
|
38
|
+
},
|
39
|
+
(error) => {
|
40
|
+
console.log(error);
|
41
|
+
}
|
42
|
+
));
|
43
|
+
}
|
44
|
+
|
45
|
+
componentDidUpdate(prevProps, prevState) {
|
46
|
+
if (this.state.products.length != prevState.products.length) {
|
47
|
+
this.state.onUpdateCart(this.state.products.length);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
async intoWishList() {}
|
52
|
+
async deleteFromCart(id) {
|
53
|
+
swal({
|
54
|
+
title: "Are you sure?",
|
55
|
+
text: "Do you want to delete this product from cart?",
|
56
|
+
icon: "warning",
|
57
|
+
buttons: true,
|
58
|
+
dangerMode: true,
|
59
|
+
}).then((willDelete) => {
|
60
|
+
if (willDelete) {
|
61
|
+
var options = {
|
62
|
+
method: "POST",
|
63
|
+
headers: { "Content-Type": "application/json" },
|
64
|
+
body: JSON.stringify({productId: id})
|
65
|
+
};
|
66
|
+
trackPromise(
|
67
|
+
fetch("/deleteProductFromCart", options).then(res => res.json()).then(
|
68
|
+
(result) => {
|
69
|
+
console.log(result)
|
70
|
+
if (result.status == 200) {
|
71
|
+
this.setState({
|
72
|
+
products: result.cart.products,
|
73
|
+
totalPrice: result.cart.products.reduce(
|
74
|
+
(acc, item) => acc + item.price * item.quantity,
|
75
|
+
0
|
76
|
+
),
|
77
|
+
});
|
78
|
+
swal("Success","Product Deleted Successfully From Cart", "success")
|
79
|
+
}
|
80
|
+
},
|
81
|
+
(error) => {
|
82
|
+
console.log(error);
|
83
|
+
}
|
84
|
+
));
|
85
|
+
}
|
86
|
+
})
|
87
|
+
}
|
88
|
+
async payNow(){
|
89
|
+
if(this.state.products.length < 1){
|
90
|
+
swal("Error", "Please add atleast one product to the cart","error")
|
91
|
+
return;
|
92
|
+
}
|
93
|
+
var options = {
|
94
|
+
method: "GET",
|
95
|
+
headers: { "Content-Type": "application/json" },
|
96
|
+
};
|
97
|
+
trackPromise(
|
98
|
+
await fetch("/payNow", options).then(res => {
|
99
|
+
if(res.status == 200){
|
100
|
+
swal("Success","Payment is successful","success");
|
101
|
+
this.setState({products:[], totalPrice: 0});
|
102
|
+
this.onUpdateCart(this.state.products.length);
|
103
|
+
}
|
104
|
+
else{
|
105
|
+
swal("Error","There was an error","error");
|
106
|
+
}
|
107
|
+
}))
|
108
|
+
|
109
|
+
}
|
110
|
+
async updateQuantity(e, id) {
|
111
|
+
var quantity = Number(e.target.value);
|
112
|
+
var product = this.state.products.filter(p => p.id == id);
|
113
|
+
product = product[0]
|
114
|
+
product.quantity = quantity;
|
115
|
+
var products = this.state.products;
|
116
|
+
products.map((p) => {if(p.id == id) p = product})
|
117
|
+
var options = {
|
118
|
+
method: "POST",
|
119
|
+
headers: { "Content-Type": "application/json" },
|
120
|
+
body:JSON.stringify({product:{productId: product.id, price: product.price, quantity: product.quantity}})
|
121
|
+
};
|
122
|
+
fetch("/updateProductInCart", options).then(res => res.json()).then(
|
123
|
+
(result) => {
|
124
|
+
console.log(result)
|
125
|
+
if (result.status == 200) {
|
126
|
+
this.setState({
|
127
|
+
products: result.cart.products,
|
128
|
+
totalPrice: result.cart.products.reduce(
|
129
|
+
(acc, item) => acc + item.price * item.quantity,
|
130
|
+
0
|
131
|
+
),
|
132
|
+
});
|
133
|
+
}
|
134
|
+
},
|
135
|
+
(error) => {
|
136
|
+
console.log(error);
|
137
|
+
}
|
138
|
+
);
|
139
|
+
}
|
140
|
+
|
141
|
+
render() {
|
142
|
+
return (
|
143
|
+
<div className="productSlider mb-5 mt-5">
|
144
|
+
<Container>
|
145
|
+
<h5 className="text-left mb-4 ps-2">Cart List</h5>
|
146
|
+
<Row>
|
147
|
+
<div className="col-9 cartShow">
|
148
|
+
<Table bordered hover responsive="sm">
|
149
|
+
<thead>
|
150
|
+
<tr>
|
151
|
+
<th>Product Img</th>
|
152
|
+
<th>Name</th>
|
153
|
+
<th>Price</th>
|
154
|
+
<th>Quantity</th>
|
155
|
+
<th>Sub Total</th>
|
156
|
+
<th>Delete</th>
|
157
|
+
</tr>
|
158
|
+
</thead>
|
159
|
+
<tbody>
|
160
|
+
<LoadingIndicator/>
|
161
|
+
{this.state.products.map((product, idx) => (
|
162
|
+
<OrderedProduct
|
163
|
+
key={product.id}
|
164
|
+
isCart={true}
|
165
|
+
product={product}
|
166
|
+
onDelete={(id) => this.deleteFromCart(id)}
|
167
|
+
onUpdate={(e, id) => this.updateQuantity(e, id)}
|
168
|
+
/>
|
169
|
+
))}
|
170
|
+
</tbody>
|
171
|
+
</Table>
|
172
|
+
</div>
|
173
|
+
<div className="col-3 cartSum boxShadaw bg-light p-4">
|
174
|
+
<h5 className="text-left mb-4 pb-2">Cart Price</h5>
|
175
|
+
<div className="d-flex justify-content-between mb-3">
|
176
|
+
<h6 className="fw-normal">Tax :</h6>
|
177
|
+
<span>{(this.state.totalPrice * (17 / 117)).toFixed(2)}$</span>
|
178
|
+
</div>
|
179
|
+
<div className="d-flex justify-content-between mb-4">
|
180
|
+
<h6 className="fw-normal">SubTotal Price :</h6>
|
181
|
+
<span>{(this.state.totalPrice * (100 / 117)).toFixed(2)}$</span>
|
182
|
+
</div>
|
183
|
+
<div className="d-flex justify-content-between fw-bold">
|
184
|
+
<h6>Total Price :</h6>
|
185
|
+
<span>{this.state.totalPrice}$</span>
|
186
|
+
</div>
|
187
|
+
<Button onClick={() => this.payNow()} variant="dark" size="md" className="mt-4 w-100">
|
188
|
+
pay now
|
189
|
+
</Button>
|
190
|
+
</div>
|
191
|
+
</Row>
|
192
|
+
</Container>
|
193
|
+
</div>
|
194
|
+
);
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
export default ShoppingCart;
|
@@ -0,0 +1,76 @@
|
|
1
|
+
//import useState hook to create menu collapse state
|
2
|
+
import React, { useState } from "react";
|
3
|
+
|
4
|
+
//import react pro sidebar components
|
5
|
+
import {
|
6
|
+
ProSidebar,
|
7
|
+
Menu,
|
8
|
+
MenuItem,
|
9
|
+
SidebarHeader,
|
10
|
+
SidebarFooter,
|
11
|
+
SidebarContent
|
12
|
+
} from "react-pro-sidebar";
|
13
|
+
|
14
|
+
//import icons from react icons
|
15
|
+
import { FaList, FaRegHeart } from "react-icons/fa";
|
16
|
+
import {
|
17
|
+
FiHome,
|
18
|
+
FiLogOut,
|
19
|
+
FiArrowLeftCircle,
|
20
|
+
FiArrowRightCircle
|
21
|
+
} from "react-icons/fi";
|
22
|
+
import { RiPencilLine } from "react-icons/ri";
|
23
|
+
import { BiCog } from "react-icons/bi";
|
24
|
+
|
25
|
+
//import sidebar css from react-pro-sidebar module and our custom css
|
26
|
+
import "react-pro-sidebar/dist/css/styles.css";
|
27
|
+
import "../css/sideNav.css";
|
28
|
+
|
29
|
+
const Header = () => {
|
30
|
+
//create initial menuCollapse state using useState hook
|
31
|
+
const [menuCollapse, setMenuCollapse] = useState(false);
|
32
|
+
|
33
|
+
//create a custom function that will change menucollapse state from false to true and true to false
|
34
|
+
const menuIconClick = () => {
|
35
|
+
//condition checking to change state from true to false and vice versa
|
36
|
+
menuCollapse ? setMenuCollapse(false) : setMenuCollapse(true);
|
37
|
+
};
|
38
|
+
|
39
|
+
return (
|
40
|
+
<>
|
41
|
+
<div id="header">
|
42
|
+
{/* collapsed props to change menu size using menucollapse state */}
|
43
|
+
<ProSidebar collapsed={menuCollapse}>
|
44
|
+
<SidebarHeader>
|
45
|
+
{/* <div className="logotext"> */}
|
46
|
+
{/* small and big change using menucollapse state */}
|
47
|
+
{/* <p>{menuCollapse ? "Logo" : "Big Logo"}</p> */}
|
48
|
+
{/* </div> */}
|
49
|
+
<div className="closemenu" onClick={menuIconClick}>
|
50
|
+
{/* changing menu collapse icon on click */}
|
51
|
+
{menuCollapse ? <FiArrowRightCircle /> : <FiArrowLeftCircle />}
|
52
|
+
</div>
|
53
|
+
</SidebarHeader>
|
54
|
+
<SidebarContent>
|
55
|
+
<Menu iconShape="square">
|
56
|
+
<MenuItem active={true} icon={<FiHome />}>
|
57
|
+
Home
|
58
|
+
</MenuItem>
|
59
|
+
<MenuItem icon={<FaList />}>Category</MenuItem>
|
60
|
+
<MenuItem icon={<FaRegHeart />}>Favourite</MenuItem>
|
61
|
+
<MenuItem icon={<RiPencilLine />}>Author</MenuItem>
|
62
|
+
<MenuItem icon={<BiCog />}>Settings</MenuItem>
|
63
|
+
</Menu>
|
64
|
+
</SidebarContent>
|
65
|
+
{/* <SidebarFooter>
|
66
|
+
<Menu iconShape="square">
|
67
|
+
<MenuItem icon={<FiLogOut />}>Logout</MenuItem>
|
68
|
+
</Menu>
|
69
|
+
</SidebarFooter> */}
|
70
|
+
</ProSidebar>
|
71
|
+
</div>
|
72
|
+
</>
|
73
|
+
);
|
74
|
+
};
|
75
|
+
|
76
|
+
export default Header;
|