0% found this document useful (0 votes)
205 views

Code For Project Documentation

The document defines models and serializers for a Django e-commerce application. It includes models for Products, Reviews, Orders, OrderItems, and ShippingAddresses. It also includes serializers to serialize the model data. Finally, it includes API views for products and orders, including adding order items, getting user/admin orders, updating order status to paid, and getting individual products. The views use the serializers and models to get, create and update order and product data through a REST API.

Uploaded by

tester testing
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
205 views

Code For Project Documentation

The document defines models and serializers for a Django e-commerce application. It includes models for Products, Reviews, Orders, OrderItems, and ShippingAddresses. It also includes serializers to serialize the model data. Finally, it includes API views for products and orders, including adding order items, getting user/admin orders, updating order status to paid, and getting individual products. The views use the serializers and models to get, create and update order and product data through a REST API.

Uploaded by

tester testing
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 69

1.Models.

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

from rest_framework import serializers


from django.contrib.auth.models import User
from rest_framework_simplejwt.tokens import RefreshToken
from base.models import Product, Order, OrderItem, ShippingAddress

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

def get_name(self, obj):


name = obj.first_name
if name == '':
name = obj.email
return name

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__'

def get_orderItems(self, obj):


items = obj.orderitem_set.all()
serializer = OrderItemSerializer(items, many=True)
return serializer.data

def get_shippingAddress(self, obj):


try:
address = ShippingAddressSerializer(obj.shippingaddress,
many=False).data
except:
address = False
return address

def get_user(self, obj):


user = obj.user
serializer = UserSerializer(user, many=False)
return serializer.data

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

from base.serializers import ProductSerializer, OrderSerializer


from rest_framework import status
from datetime import datetime

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def addOrderItems(request):
user= request.user
data = request.data
orderItems = data['orderItems']

if orderItems and len(orderItems) == 0:


return Response({'detail': 'No Order Items'},
status=status.HTTP_400_BAD_REQUEST)
else:
order=Order.objects.create(
user=user,
paymentMethod=data['paymentMethod'],
taxPrice=data['taxPrice'],
shippingPrice=data['shippingPrice'],
totalPrice=data['totalPrice']
)

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

from base.serializers import ProductSerializer


from rest_framework import status

@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

from base.serializers import ProductSerializer, UserSerializer,


UserSerializerWithToken
# Create your views here.
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView

from django.contrib.auth.hashers import make_password


from rest_framework import status

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()

serializer = UserSerializer(user, many=False)

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"),

path('update/<str:pk>/', views.updateProduct, name="product-update"),


path('delete/<str:pk>/', views.deleteProduct, name="product-delete"),
]

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"),

path('<str:pk>/', views.getUserById, name='user'),

path('update/<str:pk>/', views.updateUser, name='user-update'),

path('delete/<str:pk>/', views.deleteUser, name='user-delete'),


]

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'

export const addToCart = (id, qty) => async(dispatch, getState) => {


const {data} = await axios.get(`/api/products/${id}`)

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))
}

export const removeFromCart = (id)=> (dispatch, getState) =>{


dispatch({
type: CART_REMOVE_ITEM,
payload: id,
})
localStorage.setItem(`cartItems`, JSON.stringify(getState().cart.cartItems))
}

export const saveShippingAddress = (data)=> (dispatch) =>{


dispatch({
type: CART_SAVE_SHIPPING_ADDRESS,
payload: data,
})
localStorage.setItem(`shippingAddress`, JSON.stringify(data))

export const savePaymentMethod = (data)=> (dispatch) =>{


dispatch({
type: CART_SAVE_PAYMENT_METHOD,
payload: data,
})
localStorage.setItem(`paymentMethod`, JSON.stringify(data))

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'

import { CART_CLEAR_ITEMS } from '../constants/cartConstants'

export const createOrder = (order) => async (dispatch, getState) => {


try{
dispatch({
type: ORDER_CREATE_REQUEST
})

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,
})
}
}

export const getOrderDetails = (id) => async (dispatch, getState) => {


try{
dispatch({
type: ORDER_DETAILS_REQUEST
})

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,
})
}
}

export const ListMyOrders = () => async (dispatch, getState) => {


try{
dispatch({
type: ORDER_LIST_MY_REQUEST
})

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,
})
}
}

export const ListOrders = () => async (dispatch, getState) => {


try{
dispatch({
type: ORDER_LIST_REQUEST
})

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'

export const listProducts = () => async (dispatch) =>{


try{
dispatch({ type : PRODUCT_LIST_REQUEST })
const{data} = await axios.get('/api/products/')
dispatch({ type : PRODUCT_LIST_SUCCESS,
payload: data

})
}catch(error){
dispatch({ type : PRODUCT_LIST_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})

}
}

export const listProductDetails = (_Id) => async (dispatch) =>{


try{
dispatch({ type : PRODUCT_DETAILS_REQUEST })
const{data} = await axios.get(`/api/products/${_Id}`)
dispatch({ type : PRODUCT_DETAILS_SUCCESS,
payload: data

})
}catch(error){
dispatch({ type : PRODUCT_DETAILS_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})

}
}

export const deleteProduct = (id) => async (dispatch, getState) => {


try{
dispatch({
type: PRODUCT_DELETE_REQUEST
})

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,
})
}
}

export const createProduct = () => async (dispatch, getState) => {


try{
dispatch({
type: PRODUCT_CREATE_REQUEST
})

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,
})
}
}

export const updateProduct = (product) => async (dispatch, getState) => {


try{
dispatch({
type: PRODUCT_UPDATE_REQUEST
})

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'

import { ORDER_LIST_MY_RESET } from '../constants/orderConstants'

export const login = (email, password) => async (dispatch) => {


try{
dispatch({
type: USER_LOGIN_REQUEST
})
const config = {
headers:{
'content-type': 'application/json'
}
}
const { data } = await axios.post(
'/api/users/login/',
{ 'username':email, 'password':password },
config
)

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 logout = () => (dispatch)=>{


localStorage.removeItem('userInfo')
dispatch({type:USER_LOGOUT})
dispatch({type:USER_DETAILS_RESET})
dispatch({type:ORDER_LIST_MY_RESET})
dispatch({type:USER_LIST_RESET})
}

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,
})
}
}

export const getUserDetails = (id) => async (dispatch, getState) => {


try{
dispatch({
type: USER_DETAILS_REQUEST
})

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,
})
}
}

export const updateUserProfile = (user) => async (dispatch, getState) => {


try{
dispatch({
type: USER_UPDATE_PROFILE_REQUEST
})

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,
})
}
}

export const listUsers = () => async (dispatch, getState) => {


try{
dispatch({
type: USER_LIST_REQUEST
})
const {
userLogin:{userInfo},
} =getState()
const config = {
headers:{
'content-type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.get(
`/api/users/`,
config
)

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,
})
}
}

export const deleteUser = (id) => async (dispatch, getState) => {


try{
dispatch({
type: USER_DELETE_REQUEST
})

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,
})
}
}

export const updateUser = (user) => async (dispatch, getState) => {


try{
dispatch({
type: USER_UPDATE_REQUEST
})

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'

function CheckoutProgress({step1, step2, step3, step4}) {


return (
<Nav className='justify-content-center mb-4'>
<Nav.Item>
{step1 ? (
<LinkContainer to= '/login'>
<Nav.Link>Login</Nav.Link>
</LinkContainer>
):(
<Nav.Link disabled>Login</Nav.Link>
)}
</Nav.Item>

<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>
)
}

export default CheckoutProgress

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 &copy;
Mittals</Col>
</Row>
</Container>
</footer>
)
}

export default 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

const dispatch = useDispatch()

const logoutHandler = () =>{


dispatch(logout())
}

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>
)}

{userInfo && userInfo.isAdmin && (


<NavDropdown title='Admin' id='adminmenu'>
<LinkContainer to='/admin/userlist'>
<NavDropdown.Item>Users</NavDropdown.Item>
</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>
)
}

export default 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>
)
}

export default Loader

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>

)
}

export default Product

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>
)
}

export default Rating

8. SearchBar.js
import React, {useState} from 'react'
import { Button, Form } from 'react-bootstrap'

function SearchBar() {

const [keyword, setKeyword] = useState('')

const submitHandler = (e) => {


e.preventDefault()
}
return (
<Form onSubmit={submitHandler} inline>
<Form.Control type='text' name='q' onChange={(e) =>
setKeyword(e.target.value)} className='mr-sm-2 ml-sm-5'>
</Form.Control>
<Button type='submit' variant='outline-success' className='p-
2'>Submit</Button>
</Form>
)
}

export default 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'

export const ORDER_CREATE_RESET ='ORDER_CREATE_RESET'

export const ORDER_DETAILS_REQUEST = 'ORDER_DETAILS_REQUEST'


export const ORDER_DETAILS_SUCCESS = 'ORDER_DETAILS_SUCCESS'
export const ORDER_DETAILS_FAIL = 'ORDER_DETAILS_FAIL'

export const ORDER_PAY_REQUEST = 'ORDER_PAY_REQUEST'


export const ORDER_PAY_SUCCESS = 'ORDER_PAY_SUCCESS'
export const ORDER_PAY_FAIL = 'ORDER_PAY_FAIL'
export const ORDER_PAY_RESET ='ORDER_PAY_RESET'

export const ORDER_LIST_MY_REQUEST = 'ORDER_LIST_MY_REQUEST'


export const ORDER_LIST_MY_SUCCESS = 'ORDER_LIST_MY_SUCCESS'
export const ORDER_LIST_MY_FAIL = 'ORDER_LIST_MY_FAIL'
export const ORDER_LIST_MY_RESET ='ORDER_LIST_MY_RESET'

export const ORDER_LIST_REQUEST = 'ORDER_LIST_REQUEST'


export const ORDER_LIST_SUCCESS = 'ORDER_LIST_SUCCESS'
export const ORDER_LIST_FAIL = 'ORDER_LIST_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'

export const PRODUCT_DELETE_REQUEST = 'PRODUCT_DELETE_REQUEST'


export const PRODUCT_DELETE_SUCCESS = 'PRODUCT_DELETE_SUCCESS'
export const PRODUCT_DELETE_FAIL = 'PRODUCT_DELETE_FAIL'

export const PRODUCT_CREATE_REQUEST = 'PRODUCT_CREATE_REQUEST'


export const PRODUCT_CREATE_SUCCESS = 'PRODUCT_CREATE_SUCCESS'
export const PRODUCT_CREATE_FAIL = 'PRODUCT_CREATE_FAIL'
export const PRODUCT_CREATE_RESET = 'PRODUCT_CREATE_RESET'

export const PRODUCT_UPDATE_REQUEST = 'PRODUCT_UPDATE_REQUEST'


export const PRODUCT_UPDATE_SUCCESS = 'PRODUCT_UPDATE_SUCCESS'
export const PRODUCT_UPDATE_FAIL = 'PRODUCT_UPDATE_FAIL'
export const PRODUCT_UPDATE_RESET = 'PRODUCT_UPDATE_RESET'

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'

export const USER_LOGOUT = 'USER_LOGOUT'

export const USER_REGISTER_REQUEST = 'USER_REGISTER_REQUEST'


export const USER_REGISTER_SUCCESS = 'USER_REGISTER_SUCCESS'
export const USER_REGISTER_FAIL = 'USER_REGISTER_FAIL'

export const USER_DETAILS_REQUEST = 'USER_DETAILS_REQUEST'


export const USER_DETAILS_SUCCESS = 'USER_DETAILS_SUCCESS'
export const USER_DETAILS_FAIL = 'USER_DETAILS_FAIL'
export const USER_DETAILS_RESET = 'USER_DETAILS_RESET'

export const USER_UPDATE_PROFILE_REQUEST = 'USER_UPDATE_PROFILE_REQUEST'


export const USER_UPDATE_PROFILE_SUCCESS = 'USER_UPDATE_PROFILE_SUCCESS'
export const USER_UPDATE_PROFILE_FAIL = 'USER_UPDATE_PROFILE_FAIL'
export const USER_UPDATE_PROFILE_RESET = 'USER_UPDATE_PROFILE_RESET'

export const USER_LIST_REQUEST = 'USER_LIST_REQUEST'


export const USER_LIST_SUCCESS = 'USER_LIST_SUCCESS'
export const USER_LIST_FAIL = 'USER_LIST_FAIL'
export const USER_LIST_RESET = 'USER_LIST_RESET'

export const USER_DELETE_REQUEST = 'USER_DELETE_REQUEST'


export const USER_DELETE_SUCCESS = 'USER_DELETE_SUCCESS'
export const USER_DELETE_FAIL = 'USER_DELETE_FAIL'

export const USER_UPDATE_REQUEST = 'USER_UPDATE_REQUEST'


export const USER_UPDATE_SUCCESS = 'USER_UPDATE_SUCCESS'
export const USER_UPDATE_FAIL = 'USER_UPDATE_FAIL'
export const USER_UPDATE_RESET = 'USER_UPDATE_RESET'

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'

export const cartReducer = (state ={cartItems:[], shippingAddress:{}}, action) => {


switch(action.type){
case CART_ADD_ITEM:
const item = action.payload
const existItem = state.cartItems.find(x => x.product === item.product)

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'

export const orderCreateReducer =(state={}, action) =>{


switch(action.type){
case ORDER_CREATE_REQUEST:
return {
loading: true
}

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
}
}

export const orderDetailsReducer =(state={loading:true, orderItems:[],


shippingAddress:{}}, action) =>{
switch(action.type){
case ORDER_DETAILS_REQUEST:
return {
...state,
loading: true
}

case ORDER_DETAILS_SUCCESS:
return {
loading: false,
order: action.payload
}

case ORDER_DETAILS_FAIL:
return {
loading: false,
error: action.payload
}

default:
return state
}
}

export const orderPayReducer =(state={}, action) =>{


switch(action.type){
case ORDER_PAY_REQUEST:
return {
loading: true
}

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
}
}

export const orderListMyReducer =(state={orders:[]}, action) =>{


switch(action.type){
case ORDER_LIST_MY_REQUEST:
return {
loading: true
}

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
}
}

export const orderListReducer =(state={orders:[]}, action) =>{


switch(action.type){
case ORDER_LIST_REQUEST:
return {
loading: true
}

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'

export const productListReducer = (state = {products:[]}, action)=> {


switch(action.type){
case PRODUCT_LIST_REQUEST:
return {loading:true, products:[]}

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

}
}

export const productDeleteReducer = (state = {}, action)=> {


switch(action.type){
case PRODUCT_DELETE_REQUEST:
return {loading:true}

case PRODUCT_DELETE_SUCCESS:
return {loading:false, success:true}

case PRODUCT_DELETE_FAIL:
return {loading:false, error: action.payload}
default:
return state

}
}

export const productCreateReducer = (state = {}, action)=> {


switch(action.type){
case PRODUCT_CREATE_REQUEST:
return {loading:true}

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

}
}

export const productUpdateReducer = (state = {product:{}},


action)=> {
switch(action.type){
case PRODUCT_UPDATE_REQUEST:
return {loading:true}

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'

export const userLoginReducer = (state = {}, action)=> {


switch(action.type){
case USER_LOGIN_REQUEST:
return {loading:true}

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

}
}

export const userRegisterReducer = (state = {}, action)=> {


switch(action.type){
case USER_REGISTER_REQUEST:
return {loading:true}

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

}
}

export const userDetailsReducer = (state = {user:{}}, action)=> {


switch(action.type){
case USER_DETAILS_REQUEST:
return {...state, loading:true}

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

}
}

export const userUpdateProfileReducer = (state = {}, action)=> {


switch(action.type){
case USER_UPDATE_PROFILE_REQUEST:
return {loading:true}

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

}
}

export const userListReducer = (state = {users:[]}, action)=> {


switch(action.type){
case USER_LIST_REQUEST:
return {loading:true}

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

}
}

export const userUpdateReducer = (state = {user:{}}, action)=> {


switch(action.type){
case USER_UPDATE_REQUEST:
return {loading:true}

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'

function CartScreen({ match, Location, history }) {


const productId = match.params.id
const qty = Location && Location.search ? Number(Location.search &&
Location.search.split('=')[1]) : 1
console.log('qty:', qty)
const dispatch = useDispatch()
const cart = useSelector(state => state.cart)
const {cartItems} = cart

useEffect(() =>{
if(productId){
dispatch(addToCart(productId, qty))
}
}, [dispatch, productId, qty])

const removeFromCartHandler = (id) => {


dispatch(removeFromCart(id))
}
const checkoutHandler =() =>{
history.push('/shipping')
}

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>
)
}

export default CartScreen

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>
)
}

export default Homescreen

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'

function LoginScreen({Location, history}) {


const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const dispatch = useDispatch()

const redirect = Location && Location.search ? Location.search.split('=')[1] :


'/'

const userLogin = useSelector(state => state.userLogin)


const {error, loading, userInfo} = userLogin
useEffect(()=>{
if(userInfo){
history.push(redirect)
}
}, [history, userInfo, redirect])

const submitHandler = (e) => {


e.preventDefault()
dispatch(login(email, password))
}

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>

<Button type='submit' variant='primary'>Sign In</Button>


</Form>
<Row className='py-3'>
<Col>
New Customer? <Link to={redirect ? `/register?redirect=$
{redirect}` : '/register'}>Register</Link>
</Col>

</Row>
</FormContainer>
)
}

export default LoginScreen

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

const userLogin = useSelector(state => state.userLogin)


const {userInfo} = userLogin

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>
)
}

export default OrderListScreen


5. OrderScreen.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 Loader from '../Components/Loader'
import { useDispatch, useSelector } from 'react-redux'
import { PayPalButton } from 'react-paypal-button-v2'
import { getOrderDetails, payOrder } from '../actions/orderActions'
import { ORDER_PAY_RESET } from '../constants/orderConstants'

function OrderScreen({match}) {

const orderId = match.params.id


const dispatch=useDispatch()

const [sdkReady ,setSdkReady] =useState(false)

const orderDetails = useSelector(state => state.orderDetails)


const {order, error, loading} = orderDetails

const orderPay = useSelector(state => state.orderPay)


const {loading:loadingPay, success:successPay} = orderPay

if(!loading && !error){


order.itemsPrice = order.orderItems.reduce((acc, item) => acc +
item.Price*item.qty, 0)
}

const addPayPalScript = () =>{


const script = document.createElement('script')
script.type ='text/javascript'
script.src = 'https://www.paypal.com/sdk/js?client-id=AWMr2auluYq36kyQt-
dC2AcDZerUQIVlttkNzH0Kji7TeUI2LDdFWiZf3u7OmNCn_ll45AQNxCGuMTkS'
script.async = true
script.onload= ()=> {
setSdkReady(true)
}
document.body.appendChild(script)
}

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)
}
}

},[dispatch, order, orderId, successPay])

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>
)
}

export default OrderScreen

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}) {

const cart = useSelector(state => state.cart)


const {shippingAddress} = cart

const dispatch = useDispatch()

const [paymentMethod, setPaymentMethod] = useState('PayPal')

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>

<Button type='submit' variant='primary'>Continue</Button>

</Form>

</FormContainer>
)
}

export default PaymentScreen

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 orderCreate = useSelector(state => state.orderCreate)


const {order, error, success} = orderCreate

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])

const placeOrder = () => {


dispatch(createOrder({
orderItems:cart.cartItems,
shippingAddress:cart.shippingAddress,
paymentMethod:cart.paymentMethod,
itemsPrice:cart.itemsPrice,
shippingPrice:cart.shippingPrice,
taxPrice:cart.taxPrice,
totalPrice:cart.totalPrice,

}))
}
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>
)
}

export default PlaceOrderScreen

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'

function ProductEditScreen({match, history}) {


const productId = match.params.id

const [Name, setName] = useState('')


const [Price, setPrice] = useState(0)
const [Brand, setBrand] = useState('')
const [Category, setCategory] = useState('')
const [InStock, setInStock] = useState(0)
const [image, setImage] = useState('')
const [Description, setDescription] = useState('')
const [uploading, setUploading] = useState(false)
const dispatch = useDispatch()

const productDetails = useSelector(state => state.productDetails)


const {error, loading, product} = productDetails

const productUpdate = useSelector(state => state.productUpdate)


const {error:errorUpdate, loading:loadingUpdate, success:successUpdate} =
productUpdate

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])

const submitHandler = (e) => {


e.preventDefault()
dispatch(updateProduct({
_Id:productId,
Name,
Price,
image,
Brand,
Category,
InStock,
Description
}))
}

const uploadFileHandler = async (e) => {


const file = e.target.files[0]
const formData = new FormData()

formData.append('image', file)
formData.append('product_Id', productId)
setUploading(true)

try{
const config = {
headers:{
'Content-Type':'multipart/form-data'
}
}

const {data} = await axios.post('/api/products/upload/', formData,


config)

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>}

{loading ? <Loader/> : error ? <Alert


variant='danger'>{error}</Alert>
: (
<Form onSubmit={submitHandler}>
<Form.Group controlId='name'>
<Form.Label>Name</Form.Label>
<Form.Control type='name' placeholder='Enter Name'
value={Name} onChange={(e)=> setName(e.target.value)}>
</Form.Control>
</Form.Group>

<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>

<Button type='submit' variant='primary'>Update Now</Button>


</Form>
)}

</FormContainer>
</div>
)
}

export default ProductEditScreen

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 }) {

const dispatch = useDispatch()

const productList = useSelector(state => state.productList)


const { loading, error, products} = productList

const productDelete = useSelector(state => state.productDelete)


const {loading:loadingDelete, error:errorDelete, success:successDelete} =
productDelete

const productCreate = useSelector(state => state.productCreate)


const {loading:loadingCreate, error:errorCreate, success:successCreate,
product: createdProduct} = productCreate

const userLogin = useSelector(state => state.userLogin)


const { userInfo } = userLogin

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])

const deleteHandler = (id) => {

if (window.confirm('Do You Want To Delete This Product?')) {


dispatch(deleteProduct(id))
}
}
const createProductHandler =() => {
dispatch(createProduct())
}

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>

{loadingDelete && <Loader/>}


{errorDelete && <Alert variant='danger'>{errorDelete}</Alert>}

{loadingCreate && <Loader/>}


{errorCreate && <Alert variant='danger'>{errorCreate}</Alert>}

{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>
)
}

export default ProductListScreen

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'

function ProductScreen({match, history}) {


const [qty, setQty] = useState(1)

const dispatch = useDispatch()


const productDetails = useSelector(state =>state.productDetails)
const {loading,error, product} = productDetails

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>
)
}

export default ProductScreen


11. ProfileScreen.js
import React from 'react'
import { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { Form, Button, Row, Col, Alert, Table } from 'react-bootstrap'
import { LinkContainer } from 'react-router-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Loader from '../Components/Loader'
import Message from '../Components/Message'
import { getUserDetails, updateUserProfile } from '../actions/userActions'
import { USER_UPDATE_PROFILE_RESET } from '../constants/userConstants'
import { ListMyOrders } from '../actions/orderActions'

function ProfileScreen({history}) {

const [name, setName] = useState('')


const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [message, setMessage] = useState('')
const dispatch = useDispatch()

const userDetails = useSelector(state => state.userDetails)


const {error, loading, user} = userDetails

const userLogin = useSelector(state => state.userLogin)


const {userInfo} = userLogin

const userUpdateProfile = useSelector(state => state.userUpdateProfile)


const {success} = userUpdateProfile

const orderListMy = useSelector(state => state.orderListMy)


const {loading:loadingOrders, error:errorOrders, orders} = orderListMy
useEffect(()=>{
if(!userInfo){
history.push('/login')
}else{
if(!user || !user.name || success || userInfo._id !== user._id){
dispatch({type: USER_UPDATE_PROFILE_RESET})
dispatch(getUserDetails('profile'))
dispatch(ListMyOrders())

}else{
setName(user.name)
setEmail(user.email)
}
}
}, [dispatch, history, userInfo, user, success])

const submitHandler = (e) => {


e.preventDefault()

if(password !== confirmPassword){


setMessage('Password does not match. Please Try Again')
}else{
dispatch(updateUserProfile({
'id':user._Id,
'name':name,
'email':email,
'password':password

}))
setMessage('')
}

}
return (
<Row>
<Col md={3}>
<h2>DashBoard</h2>

{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 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>

<Button type='submit' variant='primary'>Update Your Profile


Now</Button>
</Form>
</Col>

<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>
)
}

export default ProfileScreen

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'

function RegisterScreen({Location, history}) {


const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [message, setMessage] = useState('')
const dispatch = useDispatch()

const redirect = Location && Location.search ? Location.search.split('=')[1] :


'/'

const userRegister = useSelector(state => state.userRegister)


const {error, loading, userInfo} = userRegister
useEffect(()=>{
if(userInfo){
history.push(redirect)
}
}, [history, userInfo, redirect])

const submitHandler = (e) => {


e.preventDefault()

if(password !== confirmPassword){


setMessage('Password does not match. Please Try Again')
}else{
dispatch(register(name, email, password))
}

}
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>

<Button type='submit' variant='primary'>Register Now</Button>


</Form>

<Row className='py-3'>
<Col>
Already Registered? <Link to={redirect ? `/login?redirect=$
{redirect}` : '/login'}>Sign In</Link>
</Col>

</Row>

</FormContainer>
)
}

export default RegisterScreen

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}) {

const cart = useSelector(state => state.cart)


const {shippingAddress} = cart

const dispatch = useDispatch()

const [name, setName] = useState(shippingAddress.name)


const [address, setAddress] = useState(shippingAddress.address)
const [city, setCity] = useState(shippingAddress.city)
const [pinCode, setPinCode] = useState(shippingAddress.pinCode)
const [country, setCountry] = useState(shippingAddress.country)
const [phoneNumber, setPhoneNumber] = useState(shippingAddress.phoneNumber)

const submitHandler =(e) => {


e.preventDefault()
dispatch(saveShippingAddress({name, address, city, pinCode, country,
phoneNumber}))
history.push('/payment')
}
return (
<FormContainer>
<CheckoutProgress step1 step2/>
<h1>Enter Destination</h1>
<Form onSubmit={submitHandler}>

<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>

<Button type='submit' variant='primary'>Proceed</Button>


</Form>
</FormContainer>
)
}

export default ShippingScreen

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'

function UserEditScreen({match, history}) {


const userId = match.params.id

const [name, setName] = useState('')


const [email, setEmail] = useState('')
const [isAdmin, setIsAdmin] = useState(false)
const dispatch = useDispatch()

const userDetails = useSelector(state => state.userDetails)


const {error, loading, user} = userDetails

const userUpdate = useSelector(state => state.userUpdate)


const {error:errorUpdate, loading:loadingUpdate, success:successUpdate} =
userUpdate

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])

const submitHandler = (e) => {


e.preventDefault()
dispatch(updateUser({_id:user._id, name, email, isAdmin}))
}
return (
<div>
<Link to='/admin/userlist'>Go Back</Link>
<FormContainer>
<h1>EDIT USER</h1>
{loadingUpdate && <Loader/>}
{errorUpdate && <Alert variant='danger'>{errorUpdate}</Alert> }

{loading ? <Loader/> : error ? <Alert


variant='danger'>{error}</Alert>
: (
<Form onSubmit={submitHandler}>
<Form.Group controlId='name'>
<Form.Label>Name</Form.Label>
<Form.Control 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 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>
)
}

export default UserEditScreen

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

const userLogin = useSelector(state => state.userLogin)


const {userInfo} = userLogin

const userDelete = useSelector(state => state.userDelete)


const {success:successDelete} = userDelete

useEffect(() =>{
if(userInfo && userInfo.isAdmin){
dispatch(listUsers())
} else {
history.push('/login')
}
dispatch(listUsers())
}, [dispatch, history, successDelete, userInfo])

const deleteHandler = (id) => {


if(window.confirm('Do You really want to delete this user')){
dispatch(deleteUser(id))
}
}

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>
)
}

export default UserListScreen

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}/>

<Route path='/admin/userlist' component={UserListScreen} />


<Route path='/admin/user/:id/edit' component={UserEditScreen} />

<Route path='/admin/productlist' component={ProductListScreen} />


<Route path='/admin/product/:id/edit' component={ProductEditScreen} />

<Route path='/admin/orderlist' component={OrderListScreen} />


</Container>
</main>
<Footer />

</Router>
);
}

export default App;

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 cartItemsFromStorage = localStorage.getItem('cartItems') ?


JSON.parse(localStorage.getItem('cartItems')) : []

const userInfoFromStorage = localStorage.getItem('userInfo') ?


JSON.parse(localStorage.getItem('userInfo')) : null

const shippingAddressFromStorage = localStorage.getItem('shippingAddress') ?


JSON.parse(localStorage.getItem('shippingAddress')) : {}

const initialState = {
cart:{ cartItems: cartItemsFromStorage,
shippingAddress: shippingAddressFromStorage,
},
userLogin:{ userInfo:userInfoFromStorage }
}
const middleware = [thunk]
const store = createStore(reducer, initialState,
composeWithDevTools(applyMiddleware(...middleware)))

export default store

You might also like