Code For Project Documentation
Code For Project Documentation
py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
Name = models.CharField(max_length=200,null=True,blank=True)
image = models.ImageField(null=True,blank=True, default='/forProject.jpg')
Brand = models.CharField(max_length=200,null=True,blank=True)
Category = models.CharField(max_length=200,null=True,blank=True)
Description = models.TextField(null=True, blank=True)
rating = models.DecimalField(max_digits=7,decimal_places=2,
null=True,blank=True)
TotalReview = models.IntegerField(null=True,blank=True,default=0)
Price = models.DecimalField(max_digits=7,decimal_places=2,null=True,blank=True)
InStock = models.IntegerField(null=True,blank=True,default=0)
createdAt = models.DateTimeField(auto_now_add=True)
_Id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return self.Name
class Review(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
Name = models.CharField(max_length=200,null=True,blank=True)
rating = models.IntegerField(null=True,blank=True,default=0)
comment = models.TextField(null=True, blank=True)
_Id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return str(self.rating)
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
paymentMethod = models.CharField(max_length=200,null=True,blank=True)
taxPrice =
models.DecimalField(max_digits=7,decimal_places=2,null=True,blank=True)
shippingPrice =
models.DecimalField(max_digits=7,decimal_places=2,null=True,blank=True)
totalPrice =
models.DecimalField(max_digits=7,decimal_places=2,null=True,blank=True)
isPaid = models.BooleanField(default=False)
paidAt = models.DateTimeField(auto_now_add=False, null=True,blank=True)
isDelivered = models.BooleanField(default=False)
deliveredAt = models.DateTimeField(auto_now_add=False,null=True,blank=True)
createdAt = models.DateTimeField(auto_now_add=True)
_Id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return str(self.createdAt)
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
Name = models.CharField(max_length=200,null=True,blank=True)
qty = models.IntegerField(null=True,blank=True,default=0)
Price = models.DecimalField(max_digits=7,decimal_places=2,null=True,blank=True)
image = models.CharField(max_length=200,null=True,blank=True)
_Id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return str(self.Name)
class ShippingAddress(models.Model):
order = models.OneToOneField(Order, on_delete=models.CASCADE, null=
True,blank=True)
address = models.CharField(max_length=200,null=True,blank=True)
name = models.CharField(max_length=200,null=True,blank=True)
phoneNumber = models.CharField(max_length=200,null=True,blank=True)
city = models.CharField(max_length=200,null=True,blank=True)
pinCode = models.CharField(max_length=200,null=True,blank=True)
country = models.CharField(max_length=200,null=True,blank=True)
shippingPrice =
models.DecimalField(max_digits=7,decimal_places=2,null=True,blank=True)
_Id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return str(self.address)
2.Serializers.py
class UserSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField(read_only=True)
_id = serializers.SerializerMethodField(read_only=True)
isAdmin = serializers.SerializerMethodField(read_only=True)
class Meta:
model = User
fields = ['id', '_id', 'username','email', 'name', 'isAdmin']
def get__id(self,obj):
return obj.id
def get_isAdmin(self,obj):
return obj.is_staff
class UserSerializerWithToken(UserSerializer):
token = serializers.SerializerMethodField(read_only=True)
class Meta:
model = User
fields = ['id', '_id', 'username','email', 'name', 'isAdmin', 'token']
def get_token(self, obj):
token = RefreshToken.for_user(obj)
return str(token.access_token)
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class ShippingAddressSerializer(serializers.ModelSerializer):
class Meta:
model = ShippingAddress
fields = '__all__'
class OrderItemSerializer(serializers.ModelSerializer):
class Meta:
model = OrderItem
fields = '__all__'
class OrderSerializer(serializers.ModelSerializer):
orderItems = serializers.SerializerMethodField(read_only=True)
shippingAddress = serializers.SerializerMethodField(read_only=True)
user = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Order
fields = '__all__'
3,order_views.py
from django.shortcuts import render
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.response import Response
from base.models import Product, Order, OrderItem, ShippingAddress
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def addOrderItems(request):
user= request.user
data = request.data
orderItems = data['orderItems']
shipping = ShippingAddress.objects.create(
order=order,
name=data['shippingAddress']['name'],
phoneNumber=data['shippingAddress']['phoneNumber'],
address=data['shippingAddress']['address'],
city=data['shippingAddress']['city'],
pinCode=data['shippingAddress']['pinCode'],
country=data['shippingAddress']['country']
for i in orderItems:
product=Product.objects.get(_Id=i['product'])
item = OrderItem.objects.create(
product=product,
order=order,
Name=product.Name,
qty=i['qty'],
Price=i['Price'],
image=product.image.url,
product.InStock -= item.qty
product.save()
serializer = OrderSerializer(order, many=False)
return Response(serializer.data)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def getMyOrders(request):
user=request.user
orders=user.order_set.all()
serializer = OrderSerializer(orders, many=True)
return Response(serializer.data)
@api_view(['GET'])
@permission_classes([IsAdminUser])
def getOrders(request):
orders=Order.objects.all()
serializer = OrderSerializer(orders, many=True)
return Response(serializer.data)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def getOrderById(request, pk):
user=request.user
try:
order=Order.objects.get(_Id=pk)
if user.is_staff or order.user==user:
serializer = OrderSerializer(order, many=False)
return Response(serializer.data)
else:
Response({'detail': 'Restricted View You Cannot See It'},
status=status.HTTP_400_BAD_REQUEST)
except:
return Response({'detail': 'Order Does Not Exist'}, status=
status.HTTP_400_BAD_REQUEST)
@api_view(['PUT'])
@permission_classes([IsAuthenticated])
def updateOrderToPaid(request, pk):
order = Order.objects.get(_Id=pk)
order.isPaid = True
order.paidAt = datetime.now()
order.save()
return Response('Order Has Been Paid')
4.Product_views.py
from django.shortcuts import render
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.response import Response
from base.models import Product
@api_view(['GET'])
def getProducts(request):
products = Product.objects.all()
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)
@api_view(['GET'])
def getProduct(request,pk):
product = Product.objects.get(_Id=pk)
serializer = ProductSerializer(product, many=False)
return Response(serializer.data)
@api_view(['POST'])
@permission_classes([IsAdminUser])
def createProduct(request):
user = request.user
product = Product.objects.create(
user=user,
Name= 'Sample Name',
Price=0,
Brand= 'sample brand',
InStock=0,
Category='Sample category',
Description=''
)
serializer = ProductSerializer(product, many=False)
return Response(serializer.data)
@api_view(['PUT'])
@permission_classes([IsAdminUser])
def updateProduct(request,pk):
data = request.data
product = Product.objects.get(_Id=pk)
product.Name = data['Name']
product.Price = data['Price']
product.Brand = data['Brand']
product.Category = data['Category']
product.InStock = data['InStock']
product.Description = data['Description']
product.save()
serializer = ProductSerializer(product, many=False)
return Response(serializer.data)
@api_view(['DELETE'])
@permission_classes([IsAdminUser])
def deleteProduct(request,pk):
product = Product.objects.get(_Id=pk)
product.delete()
return Response('Product Deleted')
@api_view(['POST'])
def uploadImage(request):
data = request.data
product_Id = data['product_Id']
product = Product.objects.get(_Id=product_Id)
product.image = request.FILES.get('image')
product.save()
return Response('Image Uploaded Successfully')
5.User_views.py
from django.shortcuts import render
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from django.contrib.auth.models import User
from rest_framework.response import Response
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
data = super().validate(attrs)
serializer = UserSerializerWithToken(self.user).data
for k, v in serializer.items():
data[k] = v
return data
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
@api_view(['POST'])
def registerUser(request):
data = request.data
try:
user = User.objects.create(
first_name=data['name'],
username=data['email'],
email=data['email'],
password=make_password(data['password'])
)
serializer = UserSerializerWithToken(user, many=False)
return Response(serializer.data)
except:
message = {'detail':'User with this email already exists'}
return Response(message, status=status.HTTP_400_BAD_REQUEST)
@api_view(['PUT'])
@permission_classes([IsAuthenticated])
def updateUserProfile(request):
user = request.user
serializer = UserSerializerWithToken(user, many=False)
data = request.data
user.first_name = data['name']
user.username = data['email']
user.email = data['email']
if data['password'] != '':
user.password = make_password(data['password'])
user.save()
return Response(serializer.data)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def getUserProfile(request):
user = request.user
serializer = UserSerializer(user, many=False)
return Response(serializer.data)
@api_view(['GET'])
@permission_classes([IsAdminUser])
def getUsers(request):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
@api_view(['GET'])
@permission_classes([IsAdminUser])
def getUserById(request,pk):
user = User.objects.get(id=pk)
serializer = UserSerializer(user, many=False)
return Response(serializer.data)
@api_view(['PUT'])
@permission_classes([IsAuthenticated])
def updateUser(request, pk):
user = User.objects.get(id=pk)
data = request.data
user.first_name = data['name']
user.username = data['email']
user.email = data['email']
user.is_staff = data['isAdmin']
user.save()
return Response(serializer.data)
@api_view(['DELETE'])
@permission_classes([IsAdminUser])
def deleteUser(request, pk):
userForDeletion = User.objects.get(id=pk)
userForDeletion.delete()
return Response('User Deleted Successfully')
6. Order_urls.py
from django.urls import path
from base.views import order_views as views
urlpatterns = [
path('', views.getOrders, name='orders'),
path('add/', views.addOrderItems, name='orders-add'),
path('myorders/', views.getMyOrders, name='myorders'),
path('<str:pk>/', views.getOrderById, name='user-order'),
path('<str:pk>/pay/', views.updateOrderToPaid, name='pay'),
]
7. Product_urls.py
from django.urls import path
from base.views import product_views as views
urlpatterns = [
path('', views.getProducts, name="products"),
path('create/', views.createProduct, name="product-create"),
path('upload/', views.uploadImage, name="image-upload"),
path('<str:pk>/', views.getProduct, name="product"),
8. User_Urls.py
from django.urls import path
from base.views import user_views as views
urlpatterns = [
path('login/', views.MyTokenObtainPairView.as_view(),
name='token_obtain_pair'),
path('register/', views.registerUser, name='register'),
path('profile/',views.getUserProfile, name="users-profile"),
path('profile/update/',views.updateUserProfile, name="users-profile-update"),
path('',views.getUsers, name="users"),
FRONTEND
FOR ACTIONS
1. CARTACTIONS.py
import axios from 'axios'
import { CART_ADD_ITEM, CART_REMOVE_ITEM, CART_SAVE_SHIPPING_ADDRESS,
CART_SAVE_PAYMENT_METHOD } from '../constants/cartConstants'
dispatch({
type:CART_ADD_ITEM,
payload:{
product:data._Id,
Name:data.Name,
Image:data.image,
Price:data.Price,
InStock:data.InStock,
qty
}
})
localStorage.setItem(`cartItems`, JSON.stringify(getState().cart.cartItems))
}
2. OrderActions.py
import axios from 'axios'
import {ORDER_CREATE_SUCCESS,
ORDER_CREATE_REQUEST,
ORDER_CREATE_FAIL,
ORDER_DETAILS_SUCCESS,
ORDER_DETAILS_REQUEST,
ORDER_DETAILS_FAIL,
ORDER_PAY_SUCCESS,
ORDER_PAY_REQUEST,
ORDER_PAY_FAIL,
ORDER_PAY_RESET,
ORDER_LIST_MY_SUCCESS,
ORDER_LIST_MY_REQUEST,
ORDER_LIST_MY_FAIL,
ORDER_LIST_MY_RESET,
ORDER_LIST_SUCCESS,
ORDER_LIST_REQUEST,
ORDER_LIST_FAIL,
} from '../constants/orderConstants'
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'Content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.post(`/api/order/add/`, order, config)
dispatch({
type:ORDER_CREATE_SUCCESS,
payload:data
})
dispatch({
type:CART_CLEAR_ITEMS,
payload:data
})
localStorage.removeItem('cartItems')
}catch(error){
dispatch({
type : ORDER_CREATE_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'Content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.get(`/api/order/${id}/`, config)
dispatch({
type:ORDER_DETAILS_SUCCESS,
payload:data
})
}catch(error){
dispatch({
type : ORDER_DETAILS_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
export const payOrder = (id, paymentResult) => async (dispatch, getState) => {
try{
dispatch({
type: ORDER_PAY_REQUEST
})
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'Content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.put(`/api/order/${id}/pay/`, paymentResult,
config)
dispatch({
type:ORDER_PAY_SUCCESS,
payload:data
})
}catch(error){
dispatch({
type : ORDER_PAY_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'Content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.get(`/api/order/myorders/`, config)
dispatch({
type:ORDER_LIST_MY_SUCCESS,
payload:data
})
}catch(error){
dispatch({
type : ORDER_LIST_MY_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'Content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.get(`/api/order/`, config)
dispatch({
type:ORDER_LIST_SUCCESS,
payload:data
})
}catch(error){
dispatch({
type : ORDER_LIST_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
3. ProductActions.py
import axios from 'axios'
import { PRODUCT_LIST_REQUEST,
PRODUCT_LIST_SUCCESS,
PRODUCT_LIST_FAIL,
PRODUCT_DETAILS_REQUEST,
PRODUCT_DETAILS_SUCCESS,
PRODUCT_DETAILS_FAIL,
PRODUCT_DELETE_REQUEST,
PRODUCT_DELETE_SUCCESS,
PRODUCT_DELETE_FAIL,
PRODUCT_CREATE_REQUEST,
PRODUCT_CREATE_SUCCESS,
PRODUCT_CREATE_FAIL,
PRODUCT_UPDATE_REQUEST,
PRODUCT_UPDATE_SUCCESS,
PRODUCT_UPDATE_FAIL,
} from '../constants/productConstants'
})
}catch(error){
dispatch({ type : PRODUCT_LIST_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
})
}catch(error){
dispatch({ type : PRODUCT_DETAILS_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'Content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.delete(`/api/products/delete/${id}/`, config)
dispatch({
type:PRODUCT_DELETE_SUCCESS,
})
}catch(error){
dispatch({
type : PRODUCT_DELETE_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'Content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.post(`/api/products/create/`, {}, config)
dispatch({
type:PRODUCT_CREATE_SUCCESS,
payload: data,
})
}catch(error){
dispatch({
type : PRODUCT_CREATE_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'Content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.put(`/api/products/update/${product._Id}/`,
product, config)
dispatch({
type:PRODUCT_UPDATE_SUCCESS,
payload: data,
})
dispatch({type:PRODUCT_DETAILS_SUCCESS, payload:data})
}catch(error){
dispatch({
type : PRODUCT_UPDATE_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
4. UserActions.py
import axios from 'axios'
import { USER_LOGIN_REQUEST,
USER_LOGIN_FAIL,
USER_LOGIN_SUCCESS,
USER_LOGOUT,
USER_REGISTER_REQUEST,
USER_REGISTER_FAIL,
USER_REGISTER_SUCCESS,
USER_DETAILS_REQUEST,
USER_DETAILS_FAIL,
USER_DETAILS_SUCCESS,
USER_DETAILS_RESET,
USER_UPDATE_PROFILE_REQUEST,
USER_UPDATE_PROFILE_FAIL,
USER_UPDATE_PROFILE_SUCCESS,
USER_UPDATE_PROFILE_RESET,
USER_LIST_REQUEST,
USER_LIST_FAIL,
USER_LIST_SUCCESS,
USER_LIST_RESET,
USER_DELETE_REQUEST,
USER_DELETE_FAIL,
USER_DELETE_SUCCESS,
USER_UPDATE_REQUEST,
USER_UPDATE_FAIL,
USER_UPDATE_SUCCESS,
} from '../constants/userConstants'
dispatch({
type:USER_LOGIN_SUCCESS,
payload:data
})
localStorage.setItem('userInfo', JSON.stringify(data))
}catch(error){
dispatch({ type : USER_LOGIN_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
export const register = (name, email, password) => async (dispatch) => {
try{
dispatch({
type: USER_REGISTER_REQUEST
})
const config = {
headers:{
'content-type': 'application/json'
}
}
const { data } = await axios.post(
'/api/users/register/',
{ 'name':name, 'email':email, 'password':password },
config
)
dispatch({
type:USER_REGISTER_SUCCESS,
payload:data
})
dispatch({
type:USER_LOGIN_SUCCESS,
payload:data
})
localStorage.setItem('userInfo', JSON.stringify(data))
}catch(error){
dispatch({ type : USER_REGISTER_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.get(
`/api/users/${id}/`,
config
)
dispatch({
type:USER_DETAILS_SUCCESS,
payload:data
})
}catch(error){
dispatch({ type : USER_DETAILS_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.put(
`/api/users/profile/update/`,
user,
config
)
dispatch({
type:USER_UPDATE_PROFILE_SUCCESS,
payload:data
})
dispatch({
type:USER_LOGIN_SUCCESS,
payload:data
})
localStorage.setItem('userInfo', JSON.stringify(data))
}catch(error){
dispatch({ type : USER_UPDATE_PROFILE_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
dispatch({
type:USER_LIST_SUCCESS,
payload:data
})
}catch(error){
dispatch({ type : USER_LIST_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.delete(
`/api/users/delete/${id}/`,
config
)
dispatch({
type:USER_DELETE_SUCCESS,
payload:data
})
}catch(error){
dispatch({ type : USER_DELETE_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.put(
`/api/users/update/${user._id}/`,
user,
config
)
dispatch({
type:USER_UPDATE_SUCCESS,
})
dispatch({
type:USER_DETAILS_SUCCESS,
payload:data
})
}catch(error){
dispatch({ type : USER_UPDATE_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
COMPONENTS
1. CheckoutProgress.js
import React from 'react'
import { Nav } from 'react-bootstrap'
import { LinkContainer } from 'react-router-bootstrap'
<Nav.Item>
{step2 ? (
<LinkContainer to= '/shipping'>
<Nav.Link>Shipping</Nav.Link>
</LinkContainer>
):(
<Nav.Link disabled>Shipping</Nav.Link>
)}
</Nav.Item>
<Nav.Item>
{step3 ? (
<LinkContainer to= '/payment'>
<Nav.Link>Payment</Nav.Link>
</LinkContainer>
):(
<Nav.Link disabled>Payment</Nav.Link>
)}
</Nav.Item>
<Nav.Item>
{step4 ? (
<LinkContainer to= '/placeorder'>
<Nav.Link>Place Order</Nav.Link>
</LinkContainer>
):(
<Nav.Link disabled>Place Order</Nav.Link>
)}
</Nav.Item>
</Nav>
)
}
2. Footer.js
import { Container,Row,Col } from 'react-bootstrap'
import React from 'react'
function Footer() {
return (
<footer>
<Container>
<Row>
<Col className="text-center py-3">copyright ©
Mittals</Col>
</Row>
</Container>
</footer>
)
}
3. FormContainer.js
import React from 'react'
import { Container, Row, Col } from 'react-bootstrap'
function FormContainer({variant,children}) {
return (
<Container>
<Row className="justify-content-md-center">
<Col xs={12} md={6}>
{children}
</Col>
</Row>
</Container>
)
}
export default FormContainer
4. Header.js
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import {Navbar, Nav, Component,Row, Container, NavDropdown } from 'react-
bootstrap'
import { LinkContainer } from 'react-router-bootstrap'
import SearchBar from './SearchBar'
import {logout} from '../actions/userActions'
function Header() {
const userLogin = useSelector(state => state.userLogin)
const {userInfo} = userLogin
return (
<header>
<Navbar bg="dark" variant="dark" expand="lg" collapseOnSelect>
<Container>
<LinkContainer to='/'>
<Navbar.Brand>The Digital Shop</Navbar.Brand>
</LinkContainer>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<SearchBar/>
<Navbar.Collapse id="basic-navbar-nav"></Navbar.Collapse>
<Nav className="mr-auto">
<LinkContainer to='/cart'>
<Nav.Link><i className="fas fa-shopping-cart"></i> Cart</Nav.Link>
</LinkContainer>
{userInfo ? (
<NavDropdown title={userInfo.name} id='username'>
<LinkContainer to='/profile'>
<NavDropdown.Item>Profile</NavDropdown.Item>
</LinkContainer>
<NavDropdown.Item
onClick={logoutHandler}>Logout</NavDropdown.Item>
</NavDropdown>
):(
<LinkContainer to='/login'>
<Nav.Link><i className="fas fa-user"></i> login</Nav.Link>
</LinkContainer>
)}
<LinkContainer to='/admin/productlist'>
<NavDropdown.Item>Products</NavDropdown.Item>
</LinkContainer>
<LinkContainer to='/admin/orderlist'>
<NavDropdown.Item>Orders</NavDropdown.Item>
</LinkContainer>
</NavDropdown>
)}
</Nav>
</Container>
</Navbar>
</header>
)
}
5. Loader.js
import React from 'react'
import { Spinner } from 'react-bootstrap'
function Loader() {
return (
<Spinner
animation = 'grow'
role = 'status'
style = {{
height : '100px',
width : '100px',
margin : 'auto',
display : 'block'
}}
>
<span className='sr-only'>.....LOADING......</span>
</Spinner>
)
}
6.Product.js
import React from 'react'
import { Card } from 'react-bootstrap'
import Rating from './Rating'
import { Link } from 'react-router-dom'
function Product({product}) {
return (
<Card className="my-3 p-3 rounded">
<Link to={`/product/${product._Id}`}>
<Card.Img src={product.image} width='1200' height='400px' />
</Link>
<Card.Body>
<Link to={`/product/${product._Id}`}>
<Card.Title as="div">
<strong>{product.Name}</strong>
</Card.Title>
</Link>
<Card.Text as="div">
<div className="my-3">
< Rating value = {product.rating} text={`$
{product.TotalReview}reviews`} color= {'#f8e825'}/>
</div>
</Card.Text>
<Card.Text as="h3">
₹{product.Price}
</Card.Text>
</Card.Body>
</Card>
)
}
7. Rating.js
import React from 'react'
function Rating({value,text,color}) {
return (
<div className ="rating">
<span>
<i style ={{color}} className={
value >= 1
? 'fas fa-star'
: value >=0.5
? 'fas fa-star-half-alt'
: 'far fa-star'
}>
</i>
</span>
<span>
<i style ={{color}} className={
value >= 2
? 'fas fa-star'
: value >=1.5
? 'fas fa-star-half-alt'
: 'far fa-star'
}>
</i>
</span>
<span>
<i style ={{color}} className={
value >= 3
? 'fas fa-star'
: value >=2.5
? 'fas fa-star-half-alt'
: 'far fa-star'
}>
</i>
</span>
<span>
<i style ={{color}} className={
value >= 4
? 'fas fa-star'
: value >=3.5
? 'fas fa-star-half-alt'
: 'far fa-star'
}>
</i>
</span>
<span>
<i style ={{color}} className={
value >= 5
? 'fas fa-star'
: value >=4.5
? 'fas fa-star-half-alt'
: 'far fa-star'
}>
</i>
</span>
<span>
{text && text}
</span>
</div>
)
}
8. SearchBar.js
import React, {useState} from 'react'
import { Button, Form } from 'react-bootstrap'
function SearchBar() {
CONSTANTS
1. CartConstant.js
export const CART_ADD_ITEM = 'CART_ADD_ITEM'
export const CART_REMOVE_ITEM = 'CART_REMOVE_ITEM'
export const CART_SAVE_SHIPPING_ADDRESS = 'CART_SAVE_SHIPPING_ADDRESS'
export const CART_SAVE_PAYMENT_METHOD = 'CART_SAVE_PAYMENT_METHOD'
export const CART_CLEAR_ITEMS = 'CART_CLEAR_ITEMS'
2. OrderConstant.js
export const ORDER_CREATE_REQUEST ='ORDER_CREATE_REQUEST'
export const ORDER_CREATE_SUCCESS ='ORDER_CREATE_SUCCESS'
export const ORDER_CREATE_FAIL ='ORDER_CREATE_FAIL'
3. ProductConstant.js
export const PRODUCT_LIST_REQUEST = 'PRODUCT_LIST_REQUEST'
export const PRODUCT_LIST_SUCCESS = 'PRODUCT_LIST_SUCCESS'
export const PRODUCT_LIST_FAIL = 'PRODUCT_LIST_FAIL'
export const PRODUCT_DETAILS_REQUEST = 'PRODUCT_DETAILS_REQUEST'
export const PRODUCT_DETAILS_SUCCESS = 'PRODUCT_DETAILS_SUCCESS'
export const PRODUCT_DETAILS_FAIL = 'PRODUCT_DETAILS_FAIL'
4. UserConstants.js
export const USER_LOGIN_REQUEST = 'USER_LOGIN_REQUEST'
export const USER_LOGIN_SUCCESS = 'USER_LOGIN_SUCCESS'
export const USER_LOGIN_FAIL = 'USER_LOGIN_FAIL'
REDUCERS
1. CartReducers.js
import { CART_ADD_ITEM, CART_REMOVE_ITEM, CART_SAVE_SHIPPING_ADDRESS,
CART_SAVE_PAYMENT_METHOD, CART_CLEAR_ITEMS} from '../constants/cartConstants'
if(existItem){
return{
...state,
cartItems: state.cartItems.map( x =>
x.product === existItem.product ? item : x)
}
}else{
return{
...state,
cartItems:[...state.cartItems,item]
}
}
case CART_REMOVE_ITEM:
return{
...state,
cartItems:state.cartItems.filter(x => x.product !== action.payload)
}
case CART_SAVE_SHIPPING_ADDRESS:
return{
...state,
shippingAddress:action.payload
}
case CART_SAVE_PAYMENT_METHOD:
return {
...state,
paymentMethod:action.payload
}
case CART_CLEAR_ITEMS:
return {
...state,
cartItems:[]
}
default:
return state
}
}
2. OrderReducer.js
import { ORDER_CREATE_FAIL,
ORDER_CREATE_REQUEST,
ORDER_CREATE_SUCCESS,
ORDER_CREATE_RESET,
ORDER_DETAILS_REQUEST,
ORDER_DETAILS_SUCCESS,
ORDER_DETAILS_FAIL,
ORDER_PAY_REQUEST,
ORDER_PAY_SUCCESS,
ORDER_PAY_FAIL,
ORDER_PAY_RESET,
ORDER_LIST_MY_REQUEST,
ORDER_LIST_MY_SUCCESS,
ORDER_LIST_MY_FAIL,
ORDER_LIST_MY_RESET,
ORDER_LIST_REQUEST,
ORDER_LIST_SUCCESS,
ORDER_LIST_FAIL,
} from '../constants/orderConstants'
case ORDER_CREATE_SUCCESS:
return {
loading: false,
success: true,
order: action.payload
}
case ORDER_CREATE_FAIL:
return {
loading: false,
error: action.payload
}
case ORDER_CREATE_RESET:
return {}
default:
return state
}
}
case ORDER_DETAILS_SUCCESS:
return {
loading: false,
order: action.payload
}
case ORDER_DETAILS_FAIL:
return {
loading: false,
error: action.payload
}
default:
return state
}
}
case ORDER_PAY_SUCCESS:
return {
loading: false,
success: true
}
case ORDER_PAY_FAIL:
return {
loading: false,
error: action.payload
}
case ORDER_PAY_RESET:
return {}
default:
return state
}
}
case ORDER_LIST_MY_SUCCESS:
return {
loading: false,
orders: action.payload
}
case ORDER_LIST_MY_FAIL:
return {
loading: false,
error: action.payload
}
case ORDER_LIST_MY_RESET:
return {
orders: []
}
default:
return state
}
}
case ORDER_LIST_SUCCESS:
return {
loading: false,
orders: action.payload
}
case ORDER_LIST_FAIL:
return {
loading: false,
error: action.payload
}
default:
return state
}
}
3. ProductReducer.js
import { PRODUCT_LIST_REQUEST,
PRODUCT_LIST_SUCCESS,
PRODUCT_LIST_FAIL,
PRODUCT_DETAILS_REQUEST,
PRODUCT_DETAILS_SUCCESS,
PRODUCT_DETAILS_FAIL,
PRODUCT_DELETE_REQUEST,
PRODUCT_DELETE_SUCCESS,
PRODUCT_DELETE_FAIL,
PRODUCT_CREATE_REQUEST,
PRODUCT_CREATE_SUCCESS,
PRODUCT_CREATE_FAIL,
PRODUCT_CREATE_RESET,
PRODUCT_UPDATE_REQUEST,
PRODUCT_UPDATE_SUCCESS,
PRODUCT_UPDATE_FAIL,
PRODUCT_UPDATE_RESET,
} from '../constants/productConstants'
case PRODUCT_LIST_SUCCESS:
return {loading:false, products:action.payload}
case PRODUCT_LIST_FAIL:
return {loading:false, error: action.payload}
default:
return state
}
}
export const productDetailsReducer = (state = {product:{reviews:[]}}, action)=>
{
switch(action.type){
case PRODUCT_DETAILS_REQUEST:
return {loading:true, ...state}
case PRODUCT_DETAILS_SUCCESS:
return {loading:false, product:action.payload}
case PRODUCT_DETAILS_FAIL:
return {loading:false, error: action.payload}
default:
return state
}
}
case PRODUCT_DELETE_SUCCESS:
return {loading:false, success:true}
case PRODUCT_DELETE_FAIL:
return {loading:false, error: action.payload}
default:
return state
}
}
case PRODUCT_CREATE_SUCCESS:
return {loading:false, success:true,
product:action.payload}
case PRODUCT_CREATE_FAIL:
return {loading:false, error: action.payload}
case PRODUCT_CREATE_RESET:
return {}
default:
return state
}
}
case PRODUCT_UPDATE_SUCCESS:
return {loading:false, success:true,
product:action.payload}
case PRODUCT_UPDATE_FAIL:
return {loading:false, error: action.payload}
case PRODUCT_UPDATE_RESET:
return {product:{}}
default:
return state
}
}
4. UserReducer.js
import { USER_LOGIN_REQUEST,
USER_LOGIN_FAIL,
USER_LOGIN_SUCCESS,
USER_LOGOUT,
USER_REGISTER_REQUEST,
USER_REGISTER_FAIL,
USER_REGISTER_SUCCESS,
USER_DETAILS_REQUEST,
USER_DETAILS_FAIL,
USER_DETAILS_SUCCESS,
USER_DETAILS_RESET,
USER_UPDATE_PROFILE_REQUEST,
USER_UPDATE_PROFILE_FAIL,
USER_UPDATE_PROFILE_SUCCESS,
USER_UPDATE_PROFILE_RESET,
USER_LIST_REQUEST,
USER_LIST_FAIL,
USER_LIST_SUCCESS,
USER_LIST_RESET,
USER_DELETE_REQUEST,
USER_DELETE_FAIL,
USER_DELETE_SUCCESS,
USER_UPDATE_REQUEST,
USER_UPDATE_FAIL,
USER_UPDATE_SUCCESS,
USER_UPDATE_RESET,
} from '../constants/userConstants'
case USER_LOGIN_SUCCESS:
return {loading:false, userInfo:action.payload}
case USER_LOGIN_FAIL:
return {loading:false, error: action.payload}
case USER_LOGOUT:
return {}
default:
return state
}
}
case USER_REGISTER_SUCCESS:
return {loading:false, userInfo:action.payload}
case USER_REGISTER_FAIL:
return {loading:false, error: action.payload}
case USER_LOGOUT:
return {}
default:
return state
}
}
case USER_DETAILS_SUCCESS:
return {loading:false, user:action.payload}
case USER_DETAILS_FAIL:
return {loading:false, error: action.payload}
case USER_DETAILS_RESET:
return {user:{}}
default:
return state
}
}
case USER_UPDATE_PROFILE_SUCCESS:
return {loading:false,success:true,
userInfo:action.payload}
case USER_UPDATE_PROFILE_FAIL:
return {loading:false, error: action.payload}
case USER_UPDATE_PROFILE_RESET:
return {}
default:
return state
}
}
case USER_LIST_SUCCESS:
return {loading:false, users:action.payload}
case USER_LIST_FAIL:
return {loading:false, error: action.payload}
case USER_LIST_RESET:
return {users:[]}
default:
return state
}
}
export const userDeleteReducer = (state = {}, action)=> {
switch(action.type){
case USER_DELETE_REQUEST:
return {loading:true}
case USER_DELETE_SUCCESS:
return {loading:false, success:true}
case USER_DELETE_FAIL:
return {loading:false, error: action.payload}
default:
return state
}
}
case USER_UPDATE_SUCCESS:
return {loading:false, success:true}
case USER_UPDATE_FAIL:
return {loading:false, error: action.payload}
case USER_UPDATE_RESET:
return {user : {}}
default:
return state
}
}
SCREENS
1. CartScreen.js
import React, {useEffect} from 'react'
import { Link } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { Row, Col, ListGroup, Image, Form, Button, Card, Alert } from 'react-
bootstrap'
import Message from '../Components/Message'
import { addToCart, removeFromCart } from '../actions/cartActions'
useEffect(() =>{
if(productId){
dispatch(addToCart(productId, qty))
}
}, [dispatch, productId, qty])
return (
<Row>
<Col md={8}>
<h1>The Cart</h1>
{cartItems.length === 0 ? (
<Alert variant='info'>
<Alert.Heading>Add Something In Your Cart </Alert.Heading>
<Link to='/' className='btn btn-light my-3'>Go Back</Link>
</Alert>
) :(
<ListGroup variant= 'flush'>
{cartItems.map(item => (
<ListGroup.Item key={item.product}>
<Row>
<Col md ={2} >
<Image src={item.Image} alt={item.Name} fluid
rounded/>
</Col>
<Col md={3}>
<Link to={`/product/$
{item.product}`}>{item.Name}</Link>
</Col>
<Col md={2}>
₹{item.Price}
</Col>
<Col md={3}>
<Form.Control
as="select"
value = {item.qty}
onChange={(e) =>
dispatch(addToCart(item.product, Number(e.target.value)))}
>
{
[...Array(item.InStock).keys()].map((x)=>(
<option key={x + 1} value={x +
1}>
{x+1}
</option>
))
}
</Form.Control>
</Col>
<Col md={1}>
<Button type= 'button'
variant='light'
onClick={() =>
removeFromCartHandler(item.product)}
>
<i className='fas fa-trash-alt'></i>
</Button>
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</Col>
<Col md={4}>
<Card>
<ListGroup variant='flush'>
<ListGroup.Item>
<h2>CART TOTAL ({cartItems.reduce((acc, item)=> acc +
item.qty, 0)})</h2>
₹{cartItems.reduce((acc, item)=> acc + item.qty *
item.Price, 0).toFixed(2)}
</ListGroup.Item>
</ListGroup>
<ListGroup.Item>
<Button
type='button'
className='btn-block'
disabled={cartItems.length === 0}
onClick={checkoutHandler}
>
Proceed To Pay
</Button>
</ListGroup.Item>
</Card>
</Col>
</Row>
)
}
2. HomeScreen.js
import React, {useState, useEffect} from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Row,Col} from 'react-bootstrap'
import Product from '../Components/Product'
import Loader from '../Components/Loader'
import Message from '../Components/Message'
import { listProducts } from '../actions/productActions'
function Homescreen() {
const dispatch = useDispatch()
const productList = useSelector(state => state.productList)
const {error, loading, products} = productList
useEffect(()=>{
dispatch(listProducts())
},[dispatch])
return (
<div>
<h1>Trending Products</h1>
{loading ? <Loader />
:error ? <Message variant='dark'>{error}</Message>
:
<Row>
{products.map(product =>
(
<Col key={product._Id} sm={12}md={6}lg={4}xl={3}>
<Product product={product}/>
</Col>
)
)}
</Row>
}
</div>
)
}
3. LoginScreen.js
import React from 'react'
import { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { Form, Button, Row, Col, Alert } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Loader from '../Components/Loader'
import Message from '../Components/Message'
import FormContainer from '../Components/FormContainer'
import { login } from '../actions/userActions'
return (
<FormContainer>
<h1>SIGN IN</h1>
{error && <Alert variant='danger'>{error}</Alert>}
{loading && <Loader/>}
<Form onSubmit={submitHandler}>
<Form.Group controlId='email'>
<Form.Label>Email Address</Form.Label>
<Form.Control type='email' placeholder='Enter Email'
value={email} onChange={(e)=> setEmail(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='password'>
<Form.Label>Enter Password</Form.Label>
<Form.Control type='password' placeholder='Enter Passowrd'
value={password} onChange={(e)=> setPassword(e.target.value)}>
</Form.Control>
</Form.Group>
</Row>
</FormContainer>
)
}
4. OrderListScreen.js
import React from 'react'
import { useState, useEffect } from 'react'
import { LinkContainer } from 'react-router-bootstrap'
import { Table, Button, Alert } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Loader from '../Components/Loader'
import { ListOrders } from '../actions/orderActions'
function OrderListScreen({history}) {
const dispatch=useDispatch()
const orderList = useSelector(state => state.orderList)
const {loading, error, orders} = orderList
useEffect(() =>{
if(userInfo && userInfo.isAdmin){
dispatch(ListOrders())
} else {
history.push('/login')
}
}, [dispatch, history, userInfo])
return (
<div>
<h1>ORDERS</h1>
{loading
?(<Loader/>)
: error
?(<Alert variant='danger'>{error}</Alert>)
: (
<Table striped bordered hover responsive className='table-sm'>
<thead>
<tr>
<th>ID</th>
<th>USER</th>
<th>DATE</th>
<th>TOTAL</th>
<th>PAID</th>
<th>DELIVERED</th>
<th></th>
</tr>
</thead>
<tbody>
{orders.map(order => (
<tr key={order._Id}>
<td>{order._Id}</td>
<td>{order.user && order.user.name}</td>
<td>{order.createdAt.substring(0, 10)}</td>
<td>₹{order.totalPrice}</td>
<td>{order.isPaid ? (
order.paidAt.substring(0, 10)
): (
<i className='fas fa-cross'
style={{color:'red'}}></i>
)}
</td>
<td>{order.isDelivered ? (
order.deliveredAt.substring(0, 10)
): (
<i className='fas fa-cross'
style={{color:'red'}}></i>
)}
</td>
<td>
<LinkContainer to={`/orders/${order._Id}`}>
<Button variant='light' className='btn-
sm'>
DETAILS
</Button>
</LinkContainer>
</td>
</tr>
))}
</tbody>
</Table>
)}
</div>
)
}
function OrderScreen({match}) {
useEffect(()=> {
if(!order || successPay || order._Id !== Number(orderId)){
dispatch({type:ORDER_PAY_RESET})
dispatch(getOrderDetails(orderId))
}else if(!order.isPaid){
if(!window.paypal){
addPayPalScript()
}else {
setSdkReady(true)
}
}
const successPaymentHandler=(paymentResult)=>{
dispatch(payOrder(orderId, paymentResult))
}
return loading ?(
<Loader/>
):error ? (
<Alert variant='danger'>{error}</Alert>
): (
<div>
<h1>Order Number:{order._Id}</h1>
<Row>
<Col md={8}>
<ListGroup variant='flush'>
<ListGroup.Item>
<h2>Shipping</h2>
<p>
<strong>Shipping To: </strong>
<br></br>
<strong>Name:</strong>{order.shippingAddress.name},
{order.shippingAddress.phoneNumber},
<br></br>
<strong>Email:</strong><a href={`mailto:$
{order.user.email}`}>{order.user.email}</a>
<br></br>
<strong>Address:</strong>
{order.shippingAddress.address},{order.shippingAddress.city},
<br></br>
{order.shippingAddress.pinCode},
{order.shippingAddress.country}
</p>
{order.isDelivered ? (
<Alert variant='success'>Delivered on
{order.deliveredAt}</Alert>
):(
<Alert variant='warning'>Delivery Is
pending</Alert>
)}
</ListGroup.Item>
<ListGroup.Item>
<h2>Payment Method</h2>
<p>
<strong>Method : </strong>
{order.paymentMethod}
</p>
{order.isPaid ? (
<Alert variant='success'>Paid on
{order.paidAt}</Alert>
):(
<Alert variant='warning'>Payment Is
pending</Alert>
)}
</ListGroup.Item>
<ListGroup.Item>
<h2>Items Ordered</h2>
{order.orderItems.length === 0 ? <Alert
variant='info'>
Your Order Has No Items
</Alert> :(
<ListGroup variant='flush'>
{order.orderItems.map((item, index) => (
<ListGroup.Item key={index}>
<Row>
<Col md={2}>
<Image src ={item.image}
alt={item.Name} fluid rounded />
</Col>
<Col>
<Link to={`/product/$
{item.product}`}>{item.Name}</Link>
</Col>
<Col md={4}>
{item.qty} X ₹{item.Price}
= ₹{item.qty*item.Price}
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={4}>
<Card>
<ListGroup variant='flush'>
<ListGroup.Item>
<h2>Order summary</h2>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Item:</Col>
<Col>₹{order.itemsPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Shipping:</Col>
<Col>₹{order.shippingPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Tax:</Col>
<Col>₹{order.taxPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Total:</Col>
<Col>₹{order.totalPrice}</Col>
</Row>
</ListGroup.Item>
{!order.isPaid && (
<ListGroup.Item>
{loadingPay && <Loader/>}
{!sdkReady ? (
<Loader/>
): (
<PayPalButton
amount={order.totalPrice*0.01}
onSuccess={successPaymentHandler}
/>
)}
</ListGroup.Item>
)}
</ListGroup>
</Card>
</Col>
</Row>
</div>
)
}
6. PaymentScreen.js
import React from 'react'
import { useState, useEffect } from 'react'
import { Form, Button,Col, Alert } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import FormContainer from '../Components/FormContainer'
import CheckoutProgress from '../Components/CheckoutProgress'
import { savePaymentMethod } from '../actions/cartActions'
function PaymentScreen({history}) {
if(!shippingAddress.address){
history.push('/shipping')
}
const submitHandler = (e) => {
e.preventDefault()
dispatch(savePaymentMethod(paymentMethod))
history.push('/placeorder')
}
return (
<FormContainer>
<CheckoutProgress step1 step2 step3/>
<Form onSubmit={submitHandler}>
<Form.Group>
<Form.Label as='legend'>Select Desired Payment
Method</Form.Label>
<Col>
<Form.Check type='radio'
label ='PayPal Or Other Bank Cards'
id='paypal'
name='paymentMethod'
checked
onChange={(e) =>
setPaymentMethod(e.target.value)}
>
</Form.Check>
</Col>
</Form.Group>
</Form>
</FormContainer>
)
}
7. PlaceOrderScreen.js
import React from 'react'
import { useState, useEffect } from 'react'
import { Button,Row, Col, ListGroup, Image, Card, Alert} from 'react-bootstrap'
import { Link } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import CheckoutProgress from '../Components/CheckoutProgress'
import { createOrder } from '../actions/orderActions'
import { ORDER_CREATE_RESET } from '../constants/orderConstants'
function PlaceOrderScreen({history}) {
const dispatch=useDispatch()
const cart = useSelector(state => state.cart)
cart.itemsPrice = cart.cartItems.reduce((acc, item) => acc +
item.Price*item.qty, 0)
cart.shippingPrice = cart.itemsPrice > 1000 ? 0 : 50
cart.taxPrice = Number((0.18)*cart.itemsPrice).toFixed(2)
cart.totalPrice = (Number(cart.itemsPrice) + Number(cart.shippingPrice) +
Number(cart.taxPrice)).toFixed(3)
if(!cart.paymentMethod){
history.push('/payment')
}
useEffect(()=> {
if(success){
history.push(`/orders/${order._Id}`)
dispatch({type:ORDER_CREATE_RESET})
}
},[success, history])
}))
}
return (
<div>
<CheckoutProgress step1 step2 step3 step4/>
<Row>
<Col md={8}>
<ListGroup variant='flush'>
<ListGroup.Item>
<h2>Shipping</h2>
<p>
<strong>Shipping To: </strong>
<br></br>
{cart.shippingAddress.name},
{cart.shippingAddress.phoneNumber},
<br></br>
{cart.shippingAddress.address},
{cart.shippingAddress.city},
<br></br>
{cart.shippingAddress.pinCode},
{cart.shippingAddress.country}
</p>
</ListGroup.Item>
<ListGroup.Item>
<h2>Payment Method</h2>
<p>
<strong>Method : </strong>
{cart.paymentMethod}
</p>
</ListGroup.Item>
<ListGroup.Item>
<h2>Items Ordered</h2>
{cart.cartItems.length === 0 ? <Alert variant='info'>
Your Cart Is Empty
</Alert> :(
<ListGroup variant='flush'>
{cart.cartItems.map((item, index) => (
<ListGroup.Item key={index}>
<Row>
<Col md={2}>
<Image src ={item.Image}
alt={item.Name} fluid rounded />
</Col>
<Col>
<Link to={`/product/$
{item.product}`}>{item.Name}</Link>
</Col>
<Col md={4}>
{item.qty} X ₹{item.Price} = ₹
{item.qty*item.Price}
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={4}>
<Card>
<ListGroup variant='flush'>
<ListGroup.Item>
<h2>Order summary</h2>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Item:</Col>
<Col>₹{cart.itemsPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Shipping:</Col>
<Col>₹{cart.shippingPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Tax:</Col>
<Col>₹{cart.taxPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Total:</Col>
<Col>₹{cart.totalPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
{error && <Alert variant='danger'>{error}</Alert>}
</ListGroup.Item>
<ListGroup.Item>
<Button
type='button'
className='btn-block'
disabled={cart.cartItems===0}
onClick={placeOrder}
>
Proceed To Payment
</Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
</div>
)
}
8.ProductEditScreen.js
import React from 'react'
import { useState, useEffect } from 'react'
import axios from 'axios'
import { Link } from 'react-router-dom'
import { Form, Button, Alert } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Loader from '../Components/Loader'
import FormContainer from '../Components/FormContainer'
import { listProductDetails, updateProduct } from '../actions/productActions'
import { PRODUCT_UPDATE_RESET, PRODUCT_UPDATE_SUCCESS } from
'../constants/productConstants'
useEffect(()=>{
if(successUpdate){
dispatch({type:PRODUCT_UPDATE_RESET})
history.push('/admin/productlist')
}else{
if(!product.Name || product._Id !== Number(productId)) {
dispatch(listProductDetails(productId))
}else {
setName(product.Name)
setPrice(product.Price)
setBrand(product.Brand)
setCategory(product.Category)
setInStock(product.InStock)
setImage(product.image)
setDescription(product.Description)
}
}
}, [dispatch, product, productId, history, successUpdate])
formData.append('image', file)
formData.append('product_Id', productId)
setUploading(true)
try{
const config = {
headers:{
'Content-Type':'multipart/form-data'
}
}
setImage(data)
setUploading(false)
}catch(error){
setUploading(false)
}
}
return (
<div>
<Link to='/admin/productlist'>Go Back</Link>
<FormContainer>
<h1>EDIT PRODUCTS</h1>
{loadingUpdate && <Loader/>}
{errorUpdate && <Alert variant='danger'>{errorUpdate}</Alert>}
<Form.Group controlId='price'>
<Form.Label>Price</Form.Label>
<Form.Control type='number' placeholder='Enter Price'
value={Price} onChange={(e)=> setPrice(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='image'>
<Form.Label>Image</Form.Label>
<Form.Control type='text' placeholder='Upload Image'
value={image} onChange={(e)=> setImage(e.target.value)}>
</Form.Control>
<Form.File id='image-file' Label='Click to Select Image'
custom onChange={uploadFileHandler}></Form.File>
{uploading && <Loader/>}
</Form.Group>
<Form.Group controlId='brand'>
<Form.Label>Brand</Form.Label>
<Form.Control type='text' placeholder='Enter brand'
value={Brand} onChange={(e)=> setBrand(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='instock'>
<Form.Label>Stock</Form.Label>
<Form.Control type='number' placeholder='Enter Stock
Available' value={InStock} onChange={(e)=> setInStock(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='category'>
<Form.Label>Category</Form.Label>
<Form.Control type='text' placeholder='Enter Category'
value={Category} onChange={(e)=> setCategory(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='description'>
<Form.Label>Description</Form.Label>
<Form.Control type='text' placeholder='Enter Category'
value={Description} onChange={(e)=> setDescription(e.target.value)}>
</Form.Control>
</Form.Group>
</FormContainer>
</div>
)
}
9.ProductListScreen.js
import React, { useState, useEffect } from 'react'
import { LinkContainer } from 'react-router-bootstrap'
import {Table, Button, Row, Col, Alert} from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Loader from '../Components/Loader'
import { listProducts, deleteProduct, createProduct} from
'../actions/productActions'
import { PRODUCT_CREATE_RESET } from '../constants/productConstants'
function ProductListScreen({ history, match }) {
useEffect(()=>{
dispatch({ type:PRODUCT_CREATE_RESET })
if (!userInfo.isAdmin) {
history.push('/login')
}
if(successCreate){
history.push(`/admin/product/${createdProduct._Id}/edit`)
}else{
dispatch(listProducts())
}
},[dispatch, history, successDelete, userInfo, successCreate, createdProduct])
return (
<div>
<Row className='align-items-center'>
<Col>
<h1>Products</h1>
</Col>
<Col className='text-right'>
<Button className='my-3' onClick={createProductHandler}>
<i className='fas fa-plus'></i> Create Product
</Button>
</Col>
</Row>
{loading
? (<Loader />)
: error
? (<Alert variant='danger'>{error}</Alert>)
: (
<div>
<Table striped bordered hover responsive
className='table-sm'>
<thead>
<tr>
<th>ID</th>
<th>NAME</th>
<th>PRICE</th>
<th>CATEGORY</th>
<th>BRAND</th>
<th></th>
</tr>
</thead>
<tbody>
{products.map(product => (
<tr key={product._Id}>
<td>{product._Id}</td>
<td>{product.Name}</td>
<td>₹{product.Price}</td>
<td>{product.Category}</td>
<td>{product.Brand}</td>
<td>
<LinkContainer to={`/admin/product/
${product._Id}/edit`}>
<Button variant='light'
className='btn-sm'>
<i className='fas fa-
edit'></i>
</Button>
</LinkContainer>
<Button variant='danger'
className='btn-sm' onClick={() => deleteHandler(product._Id)}>
<i className='fas fa-
trash'></i>
</Button>
</td>
</tr>
))}
</tbody>
</Table>
</div>
)}
</div>
)
}
10. ProductScreen.js
import React, {useState, useEffect} from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import { Row,Col,Image,ListGroup,Button,Card, Form } from 'react-bootstrap'
import Rating from '../Components/Rating'
import Loader from '../Components/Loader'
import Message from '../Components/Message'
import { listProductDetails } from '../actions/productActions'
useEffect(()=>{
dispatch(listProductDetails(match.params.id))
console.log(qty)
},[dispatch, match])
const addToCartHandler = () =>{
history.push(`/cart/${match.params.id}?qty=${qty}`)
}
return (
<div>
<Link to='/' className='btn btn-light my-3'>Go Back</Link>
{loading ?
<Loader />
: error
? <Message variant ='danger' >{error}</Message>
: (
<Row>
<Col md={6}>
<Image src={product.image} alt={product.Name} width='550px'
height='400px' fluid/>
</Col>
<Col md={3}>
<ListGroup variant="flush">
<ListGroup.Item>
<h3>{product.Name}</h3>
</ListGroup.Item>
<ListGroup.Item>
<Rating value ={product.rating} text= {`$
{product.TotalReview}reviews`} color={'#f8e825'}/>
</ListGroup.Item>
<ListGroup.Item>
Price: ₹{product.Price}
</ListGroup.Item>
<ListGroup.Item>
Description: {product.Description}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={3}>
<Card>
<ListGroup variant='flush'>
<ListGroup.Item>
<Row>
<Col>Price:</Col>
<Col>
<strong>₹{product.Price}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Status:</Col>
<Col>
{product.InStock > 0 ? 'In Stock' : 'Out
Of Stock'}
</Col>
</Row>
</ListGroup.Item>
{product.InStock > 0 && (
<ListGroup.Item>
<Row>
<Col>Qty</Col>
<Col xs='auto' className='my-1'>
<Form.Control
as="select"
value = {qty}
onChange={(e) => setQty(e.target.value)}
>
{
[...Array(product.InStock).keys()].map((x)=>(
<option key={x + 1} value={x +
1}>
{x+1}
</option>
))
}
</Form.Control>
</Col>
</Row>
</ListGroup.Item>
)}
<ListGroup.Item>
<Button
onClick={addToCartHandler}
className='btn-block'
disabled={product.InStock===0}
type='button'>
Add To Cart
</Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
</div>
)
}
function ProfileScreen({history}) {
}else{
setName(user.name)
setEmail(user.email)
}
}
}, [dispatch, history, userInfo, user, success])
}))
setMessage('')
}
}
return (
<Row>
<Col md={3}>
<h2>DashBoard</h2>
</Form.Control>
</Form.Group>
<Form.Group controlId='email'>
<Form.Label>Email Address</Form.Label>
<Form.Control required type='email' placeholder='Enter Email'
value={email} onChange={(e)=> setEmail(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='password'>
<Form.Label>Enter Password</Form.Label>
<Form.Control type='password' placeholder='Enter Passowrd'
value={password} onChange={(e)=> setPassword(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='confirmPassword'>
<Form.Label>Confirm Password</Form.Label>
<Form.Control type='password' placeholder='Confirm Passowrd'
value={confirmPassword} onChange={(e)=> setConfirmPassword(e.target.value)}>
</Form.Control>
</Form.Group>
<Col md={9}>
<h2>My Orders</h2>
{loadingOrders ? (
<Loader/>
): errorOrders ? (
<Alert variant='danger'>{errorOrders}</Alert>
): (
<Table striped responsive className='table-sm'>
<thead>
<tr>
<th>ID</th>
<th>DATE</th>
<th>TOTAL</th>
<th>PAID</th>
<th>DELIVERED</th>
<th></th>
</tr>
</thead>
<tbody>
{orders.map(order => (
<tr key={order._Id}>
<td>{order._Id}</td>
<td>{order.createdAt.substring(0, 10)}</td>
<td>₹{order.totalPrice}</td>
<td>{order.isPaid ? order.paidAt.substring(0,
10) : (
<i className= 'fas fa-times'
style={{color:'red'}}></i>
)}</td>
<td>
<LinkContainer to={`/order/${order._Id}`}>
<Button className='btn-
sm'>Details</Button>
</LinkContainer>
</td>
</tr>
))}
</tbody>
</Table>
)}
</Col>
</Row>
)
}
12. RegisterScreen.js
import React from 'react'
import { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { Form, Button, Row, Col, Alert } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Loader from '../Components/Loader'
import FormContainer from '../Components/FormContainer'
import { register } from '../actions/userActions'
import PasswordStrengthMeter from '../Components/PasswordStrengthMeter'
}
return (
<FormContainer>
<h1>SIGN IN</h1>
{message && <Alert variant='danger'>{message}</Alert>}
{error && <Alert variant='danger'>{error}</Alert>}
{loading && <Loader/>}
<Form onSubmit={submitHandler}>
<Form.Group controlId='name'>
<Form.Label>Name</Form.Label>
<Form.Control required type='name' placeholder='Enter Name'
value={name} onChange={(e)=> setName(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='email'>
<Form.Label>Email Address</Form.Label>
<Form.Control required type='email' placeholder='Enter Email'
value={email} onChange={(e)=> setEmail(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='password'>
<Form.Label>Enter Password</Form.Label>
<Form.Control required type='password' placeholder='Enter
Passowrd' value={password} onChange={(e)=> setPassword(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='confirmPassword'>
<Form.Label>Confirm Password</Form.Label>
<Form.Control required type='password' placeholder='Confirm
Passowrd' value={confirmPassword} onChange={(e)=>
setConfirmPassword(e.target.value)}>
</Form.Control>
</Form.Group>
<Row className='py-3'>
<Col>
Already Registered? <Link to={redirect ? `/login?redirect=$
{redirect}` : '/login'}>Sign In</Link>
</Col>
</Row>
</FormContainer>
)
}
13. ShippingScreen.js
import React from 'react'
import { useState, useEffect } from 'react'
import { Form, Button } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import FormContainer from '../Components/FormContainer'
import CheckoutProgress from '../Components/CheckoutProgress'
import { saveShippingAddress } from '../actions/cartActions'
function ShippingScreen({history}) {
<Form.Group controlId='name'>
<Form.Label>Name</Form.Label>
<Form.Control required type='text' placeholder='Enter Name'
value={name ? name: ''} onChange={(e)=> setName(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='address'>
<Form.Label>Address</Form.Label>
<Form.Control required type='text' placeholder='Enter Address'
value={address ? address: ''} onChange={(e)=> setAddress(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='city'>
<Form.Label>City</Form.Label>
<Form.Control required type='text' placeholder='Enter City Name'
value={city ? city: ''} onChange={(e)=> setCity(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='pinCode'>
<Form.Label>PinCode</Form.Label>
<Form.Control required type='number' placeholder='Enter PinCode
Here' value={pinCode ? pinCode: ''} onChange={(e)=> setPinCode(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='country'>
<Form.Label>Country</Form.Label>
<Form.Control required type='text' placeholder='Enter Country
Name' value={country ? country: ''} onChange={(e)=> setCountry(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='phoneNumber'>
<Form.Label>Phone Number</Form.Label>
<Form.Control required type='text' placeholder='Enter Phone
Number' value={phoneNumber ? phoneNumber: ''} onChange={(e)=>
setPhoneNumber(e.target.value)}>
</Form.Control>
</Form.Group>
14. UserEditScreen.js
import React from 'react'
import { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { Form, Button, Alert } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Loader from '../Components/Loader'
import FormContainer from '../Components/FormContainer'
import { getUserDetails, updateUser } from '../actions/userActions'
import { USER_UPDATE_RESET } from '../constants/userConstants'
useEffect(()=>{
if(successUpdate){
dispatch({type:USER_UPDATE_RESET})
history.push('/admin/userlist')
}else{
if(!user.name || user._id !== Number(userId)) {
dispatch(getUserDetails(userId))
}else {
setName(user.name)
setEmail(user.email)
setIsAdmin(user.isAdmin)
}
}
}, [user, userId, successUpdate,history])
</Form.Control>
</Form.Group>
<Form.Group controlId='email'>
<Form.Label>Email Address</Form.Label>
<Form.Control type='email' placeholder='Enter Email'
value={email} onChange={(e)=> setEmail(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='isAdmin'>
<Form.Check type='checkbox' label='Is Admin' checked=
{isAdmin} onChange={(e)=> setIsAdmin(e.target.checked)}>
</Form.Check>
</Form.Group>
<Button type='submit' variant='primary'>Update Now</Button>
</Form>
)}
</FormContainer>
</div>
)
}
15. UserListScreen.js
import React from 'react'
import { useState, useEffect } from 'react'
import { LinkContainer } from 'react-router-bootstrap'
import { Table, Button, Alert } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Loader from '../Components/Loader'
import { listUsers, deleteUser } from '../actions/userActions'
function UserListScreen({history}) {
const dispatch=useDispatch()
const userList = useSelector(state => state.userList)
const {loading, error, users} = userList
useEffect(() =>{
if(userInfo && userInfo.isAdmin){
dispatch(listUsers())
} else {
history.push('/login')
}
dispatch(listUsers())
}, [dispatch, history, successDelete, userInfo])
return (
<div>
<h1>USERS</h1>
{loading
?(<Loader/>)
: error
?(<Alert variant='danger'>{error}</Alert>)
: (
<Table striped bordered hover responsive className='table-sm'>
<thead>
<tr>
<th>ID</th>
<th>NAME</th>
<th>EMAIL</th>
<th>ADMIN</th>
<th></th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr key={user._id}>
<td>{user._id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.isAdmin ? (
<i className='fas fa-check'
style={{color:'green'}}></i>
): (
<i className='fas fa-cross'
style={{color:'red'}}></i>
)}</td>
<td>
<LinkContainer to={`/admin/user/$
{user._id}/edit`}>
<Button variant='light' className='btn-
sm'>
<i className='fas fa-edit'></i>
</Button>
</LinkContainer>
<Button variant='danger' className='btn-sm'
onClick={() => deleteHandler(user._id)}>
<i className='fas fa-trash-alt'></i>
</Button>
</td>
</tr>
))}
</tbody>
</Table>
)}
</div>
)
}
APP.js
import {Container} from 'react-bootstrap'
import { BrowserRouter as Router,Route } from 'react-router-dom'
import Header from './Components/Header'
import Footer from './Components/Footer'
import Homescreen from './Screens/Homescreen'
import ProductScreen from './Screens/ProductScreen'
import CartScreen from './Screens/CartScreen'
import LoginScreen from './Screens/LoginScreen'
import RegisterScreen from './Screens/RegisterScreen'
import ProfileScreen from './Screens/ProfileScreen'
import ShippingScreen from './Screens/ShippingScreen'
import PaymentScreen from './Screens/PaymentScreen'
import PlaceOrderScreen from './Screens/PlaceOrderScreen'
import OrderScreen from './Screens/OrderScreen'
import UserListScreen from './Screens/UserListScreen'
import UserEditScreen from './Screens/UserEditScreen'
import ProductListScreen from './Screens/ProductListScreen'
import ProductEditScreen from './Screens/ProductEditScreen'
import OrderListScreen from './Screens/OrderListScreen'
function App() {
return (
<Router>
<Header />
<main className= "py-3">
<Container>
<Route path='/' component={Homescreen} exact />
<Route path='/login' component={LoginScreen} />
<Route path='/register' component={RegisterScreen} />
<Route path='/profile' component={ProfileScreen} />
<Route path='/shipping' component={ShippingScreen} />
<Route path='/placeorder' component={PlaceOrderScreen} />
<Route path='/orders/:id' component={OrderScreen} />
<Route path='/payment' component={PaymentScreen} />
<Route path='/Product/:id' component={ProductScreen}/>
<Route path='/cart/:id?' component={CartScreen}/>
</Router>
);
}
STORE.js
import {createStore, combineReducers,applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import {composeWithDevTools } from 'redux-devtools-extension'
import { productListReducer,productDetailsReducer, productDeleteReducer,
productCreateReducer, productUpdateReducer } from './reducers/productReducers'
import { cartReducer } from './reducers/cartReducers'
import { userLoginReducer, userRegisterReducer, userDetailsReducer,
userUpdateProfileReducer, userListReducer, userDeleteReducer, userUpdateReducer, }
from './reducers/userReducers'
import { orderCreateReducer, orderDetailsReducer, orderPayReducer,
orderListMyReducer, orderListReducer } from './reducers/orderReducers'
const reducer = combineReducers({
productList:productListReducer,
productDetails:productDetailsReducer,
productDelete:productDeleteReducer,
productCreate:productCreateReducer,
productUpdate:productUpdateReducer,
cart:cartReducer,
userLogin:userLoginReducer,
userRegister:userRegisterReducer,
userDetails:userDetailsReducer,
userUpdateProfile:userUpdateProfileReducer,
userList:userListReducer,
userDelete:userDeleteReducer,
userUpdate:userUpdateReducer,
orderCreate:orderCreateReducer,
orderDetails:orderDetailsReducer,
orderPay:orderPayReducer,
orderListMy:orderListMyReducer,
orderList:orderListReducer,
})
const initialState = {
cart:{ cartItems: cartItemsFromStorage,
shippingAddress: shippingAddressFromStorage,
},
userLogin:{ userInfo:userInfoFromStorage }
}
const middleware = [thunk]
const store = createStore(reducer, initialState,
composeWithDevTools(applyMiddleware(...middleware)))