diff --git a/src/App.scss b/src/App.scss index aba1d539..eaa7d9b0 100644 --- a/src/App.scss +++ b/src/App.scss @@ -22,18 +22,20 @@ @import './assets/styles/ImageSlider.scss'; @import './assets/styles/Queries.scss'; @import './assets/styles/ViewCart.scss'; -@import "./assets/styles/Notifications.scss"; -@import "./assets/styles/Search.scss"; -@import "./assets/styles/CustomSelect.scss"; -@import "./assets/styles/SellerProduct.scss"; -@import "./assets/styles/SellerCollection.scss"; -@import "./assets/styles/SellerLayout.scss"; -@import "./assets/styles/tables.scss"; -@import "./assets/styles/adminDashboard.scss"; -@import "./assets/styles/users.scss"; -@import "./assets/styles/liveChat.scss"; -@import "./assets//styles/UserProfile.scss"; -@import "./assets/styles/SellerSideProduct.scss"; +@import './assets/styles/Notifications.scss'; +@import './assets/styles/Search.scss'; +@import './assets/styles/CustomSelect.scss'; +@import './assets/styles/SellerProduct.scss'; +@import './assets/styles/SellerCollection.scss'; +@import './assets/styles/SellerLayout.scss'; +@import './assets/styles/tables.scss'; +@import './assets/styles/adminDashboard.scss'; +@import './assets/styles/users.scss'; +@import './assets/styles/liveChat.scss'; +@import './assets//styles/UserProfile.scss'; +@import './assets/styles/SellerSideProduct.scss'; +@import './assets/styles/myOrders.scss'; @import "./assets/styles/tables.scss"; @import "./assets/styles/cards.scss"; @import "./assets/styles/trackOrder.scss"; +@import './assets/styles/trackOrder.scss'; diff --git a/src/assets/styles/Colors.scss b/src/assets/styles/Colors.scss index be501a2e..6aba0de3 100644 --- a/src/assets/styles/Colors.scss +++ b/src/assets/styles/Colors.scss @@ -1,5 +1,6 @@ @import url('https://fonts.googleapis.com/css2?family=Averia+Serif+Libre:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&display=swap'); $primary-color: #ff6d18; +$primary-color-opacity: #ff6d184d; $primary-color-light: #ffe2d1; $primary-color-dark: #ff8a46; $secondary-color: #777777; diff --git a/src/assets/styles/myOrders.scss b/src/assets/styles/myOrders.scss new file mode 100644 index 00000000..61aa7192 --- /dev/null +++ b/src/assets/styles/myOrders.scss @@ -0,0 +1,118 @@ +.my-orders-section { + h1 { + color: $primary-color; + text-align: center; + font-size: 22px; + padding: 10px; + } + .order { + width: 90%; + margin: auto; + font-size: 14px; + margin-top: 20px; + margin-bottom: 20px; + + .head { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 10px 0; + background: $border-color; + text-transform: uppercase; + font-size: 12px; + + div { + flex: 1; + color: $black; + font-weight: bold; + font-size: 12px; + padding-left: 5px; + } + + .or { + flex: 2; + } + } + + .order-body { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + background: $white; + + div { + flex: 1; + color: $black; + padding: 5px; + border: 1px solid $border-color; + min-height: 100px; + margin: -1px 0 0 -1px; // Adjust to remove gaps between borders + } + + .order-product { + display: flex; + flex-direction: row; + font-size: 12px; + + img { + width: 48%; + height: 80px; + object-fit: cover; + } + + p { + padding-left: 10px; + + h3 { + margin-top: 5px; + font-size: 12px; + } + + span { + font-weight: bold; + } + + .o-price { + margin-left: 20px; + } + } + } + + .order-details { + a { + top: 20px; + position: relative; + text-transform: uppercase; + text-decoration: underline; + font-size: 12px; + } + } + + .date-placed { + span { + top: 20px; + position: relative; + } + } + + .track { + button { + padding: 5px; + border: 2px solid $primary-color; + color: $primary-color; + border-radius: 5px; + margin-top: 20px; + cursor: pointer; + } + + .disabled { + cursor: default; + color: $primary-color-opacity; + border: 2px solid $primary-color-opacity; + } + } + } + } +} diff --git a/src/assets/styles/trackOrder.scss b/src/assets/styles/trackOrder.scss index 957ede6a..37fabb1b 100644 --- a/src/assets/styles/trackOrder.scss +++ b/src/assets/styles/trackOrder.scss @@ -35,7 +35,7 @@ $text-family: 'Averia Serif Libre'; p { margin: 30px 0; - + } img { @@ -64,7 +64,7 @@ $text-family: 'Averia Serif Libre'; padding: 0; position: relative; margin-left: 20px; - + &::before { content: ''; @@ -91,7 +91,7 @@ $text-family: 'Averia Serif Libre'; border-radius: 50%; margin-right: 10px; z-index: 1; - + } p { @@ -120,4 +120,4 @@ $text-family: 'Averia Serif Libre'; border-bottom: 2px solid #ccc; padding-bottom: 5px; } -} +} \ No newline at end of file diff --git a/src/pages/UserViewCart.tsx b/src/pages/UserViewCart.tsx index ff423333..3002642d 100644 --- a/src/pages/UserViewCart.tsx +++ b/src/pages/UserViewCart.tsx @@ -1,9 +1,9 @@ /* eslint-disable */ -import React, { useEffect, useState } from "react"; -import { Meta } from "../components/Meta"; -import { useAppDispatch, useAppSelector } from "../store/store"; -import { PuffLoader, PulseLoader } from "react-spinners"; -import { toast } from "react-toastify"; +import React, { useEffect, useState } from 'react'; +import { Meta } from '../components/Meta'; +import { useAppDispatch, useAppSelector } from '../store/store'; +import { PuffLoader, PulseLoader } from 'react-spinners'; +import { toast } from 'react-toastify'; import { checkout, getUserCarts, @@ -15,7 +15,7 @@ import { createSessionStripe, updateCartStatus, userSaveOrder, -} from "../store/features/carts/cartSlice"; +} from '../store/features/carts/cartSlice'; import { FaCheckSquare, FaMinus, @@ -24,20 +24,20 @@ import { FaTrash, FaGift, FaShippingFast, -} from "react-icons/fa"; -import { GiBroom } from "react-icons/gi"; -import { useNavigate } from "react-router-dom"; -import Dialog from "@mui/material/Dialog"; -import DialogActions from "@mui/material/DialogActions"; -import DialogContent from "@mui/material/DialogContent"; -import DialogContentText from "@mui/material/DialogContentText"; -import DialogTitle from "@mui/material/DialogTitle"; -import Product from "../components/product/Product"; -import { Box, LinearProgress } from "@mui/material"; -import Button from "@mui/material/Button"; -import Dispatch from "react"; -import { fetchUserProfile } from "../store/features/user/userSlice"; -import { useLocation } from "react-router-dom"; +} from 'react-icons/fa'; +import { GiBroom } from 'react-icons/gi'; +import { useNavigate } from 'react-router-dom'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import Product from '../components/product/Product'; +import { Box, LinearProgress } from '@mui/material'; +import Button from '@mui/material/Button'; +import Dispatch from 'react'; +import { fetchUserProfile } from '../store/features/user/userSlice'; +import { useLocation } from 'react-router-dom'; const UserViewCart: React.FC = () => { const dispatch = useAppDispatch(); @@ -56,8 +56,8 @@ const UserViewCart: React.FC = () => { const [open, setOpen] = useState(false); const [cartToPay, setCartToPay] = useState(null); const [amountToPay, setAmountToPay] = useState(null); - const [stripePrice, setStripePrice] = useState(""); - const [currentEndpoint, setCurrentEndpoint] = useState(""); + const [stripePrice, setStripePrice] = useState(''); + const [currentEndpoint, setCurrentEndpoint] = useState(''); const navigate = useNavigate(); const location = useLocation(); @@ -73,20 +73,20 @@ const UserViewCart: React.FC = () => { setIsLoading(true); const response = await dispatch(getUserCarts()); const response1 = await dispatch(getUserCarts()).unwrap(); - if (response.payload === "Not authorized") { + if (response.payload === 'Not authorized') { setIsLoggedOut(true); - toast.error("Please login first"); - navigate("/login"); + toast.error('Please login first'); + navigate('/login'); } setCartResponseData(response1.data); setIsLoading(false); } catch (error: any) { - if (error === "Not authorized") { + if (error === 'Not authorized') { setIsLoggedOut(true); - toast.error("Please login first"); - navigate("/login"); + toast.error('Please login first'); + navigate('/login'); } - console.error("Error fetching carts:", error); + console.error('Error fetching carts:', error); setIsLoading(false); setIsError(true); toast.error(error.message); @@ -108,12 +108,12 @@ const UserViewCart: React.FC = () => { const response = await dispatch(checkout(cartId)); if (!response.payload) { throw new Error( - "Checkout failed, Check your internet connection or try again later" + 'Checkout failed, Check your internet connection or try again later' ); } - localStorage.setItem("cartToPay", cartId); + localStorage.setItem('cartToPay', cartId); - localStorage.setItem("productsToSave", JSON.stringify(productsArr)); + localStorage.setItem('productsToSave', JSON.stringify(productsArr)); const totalCartAmount = response.payload.data.totalAmount; const array = cartResponseData.carts[index]; @@ -126,14 +126,14 @@ const UserViewCart: React.FC = () => { ); setTotalProductPrice(totalProductPrice); - const names = productsArr.map((product) => product.name).join(", "); + const names = productsArr.map((product) => product.name).join(', '); const descriptions = productsArr .map((product) => product.description) - .join(", "); + .join(', '); const image1 = productsArr[0]?.image; const image2 = productsArr[1]?.image; const shopidToSave: any = productsArr[0]?.shopId; - localStorage.setItem("shopIdToSave", shopidToSave); + localStorage.setItem('shopIdToSave', shopidToSave); const unit_amount = Math.round(totalCartAmount * 100); @@ -149,16 +149,16 @@ const UserViewCart: React.FC = () => { ); console.log(stripeProduct); localStorage.setItem( - "stripePrice", + 'stripePrice', stripeProduct.payload.data.product.default_price ); setCheckoutSuccess(true); - toast.success("Checkout is done Successfully"); + toast.success('Checkout is done Successfully'); } catch (error) { - console.error("Checkout failed", error); - toast.error("Checkout failed"); + console.error('Checkout failed', error); + toast.error('Checkout failed'); } finally { setIsPreloader(false); } @@ -169,19 +169,17 @@ const UserViewCart: React.FC = () => { setIsPreloader(true); const profile: any = await dispatch(fetchUserProfile()); const data = { - successUrl: - "https://e-commerce-ninja-fn-staging.netlify.app/shopping-cart?success", - cancelUrl: - "https://e-commerce-ninja-fn-staging.netlify.app/shopping-cart?cancel", + successUrl: 'https://e-commerce-ninja-fn-staging.netlify.app/shopping-cart?success', + cancelUrl: 'https://e-commerce-ninja-fn-staging.netlify.app/shopping-cart?cancel', customerEmail: profile.payload.email, - price: localStorage.getItem("stripePrice"), + price: localStorage.getItem('stripePrice'), }; const response = await dispatch(createSessionStripe(data)); const url = response.payload.data.session.url; window.location.href = url; } catch (error) { - console.error("Checkout failed", error); - toast.error("Payment initialization failed, try again later"); + console.error('Checkout failed', error); + toast.error('Payment initialization failed, try again later'); } finally { setIsPreloader(false); } @@ -189,38 +187,42 @@ const UserViewCart: React.FC = () => { const checkPayFailOrSuccess = async () => { const params = window.location.search.slice(1); - if (params === "success") { + if (params === 'success') { setIsPreloader(true); - const cartId = localStorage.getItem("cartToPay"); - const products = localStorage.getItem("productsToSave"); - const shopId = localStorage.getItem("shopIdToSave"); + const cartId = localStorage.getItem('cartToPay'); + const products = localStorage.getItem('productsToSave'); + const shopId = localStorage.getItem('shopIdToSave'); if (!cartId || !products || !shopId) { - navigate("/shopping-cart"); - toast.error("Unknown error occurred saving order"); + navigate('/shopping-cart'); + toast.error('Unknown error occurred saving order'); return; } const data = { cartId: cartId, - status: "Paid", + status: 'Paid', }; + + const response = await dispatch(getUserCarts()); + const response1 = await dispatch(getUserCarts()).unwrap(); + setCartResponseData(response1.data); const cartStatus = await dispatch(updateCartStatus(data)); const order = await dispatch( userSaveOrder({ cartId: cartId, - paymentMethodId: "Stripe", + paymentMethodId: 'Stripe', products: products, shopId: shopId, }) ); - toast.success("Cart Payment successful"); - localStorage.removeItem("cartToPay"); - localStorage.removeItem("productsToSave"); - localStorage.removeItem("shopIdToSave"); - navigate("/shopping-cart"); + toast.success('Cart Payment successful'); + localStorage.removeItem('cartToPay'); + localStorage.removeItem('productsToSave'); + localStorage.removeItem('shopIdToSave'); + navigate('/my-orders'); setIsPreloader(false); - } else if (params === "cancel") { - toast.error("Payment cancelled successfully"); - navigate("/shopping-cart"); + } else if (params === 'cancel') { + toast.error('Payment cancelled successfully'); + navigate('/shopping-cart'); setIsPreloader(false); } }; @@ -278,12 +280,12 @@ const UserViewCart: React.FC = () => { toast.error(response.message); } } catch (error: any) { - if (error === "Not authorized") { - localStorage.setItem("pendingCartProduct", productId); - toast.error("Please login first"); - navigate("/login"); + if (error === 'Not authorized') { + localStorage.setItem('pendingCartProduct', productId); + toast.error('Please login first'); + navigate('/login'); } else { - toast.error("Something went wrong. Please try again later."); + toast.error('Something went wrong. Please try again later.'); } } finally { setIsLoading(false); @@ -306,8 +308,8 @@ const UserViewCart: React.FC = () => { await dispatch(clearCarts()).unwrap(); setIsPreloader(false); await fetchCarts(); - toast.success("Cart cleared successfully"); - navigate("/shopping-cart"); + toast.success('Cart cleared successfully'); + navigate('/shopping-cart'); handleClose(); }; @@ -323,10 +325,10 @@ const UserViewCart: React.FC = () => { ); setCartResponseData({ ...cartResponseData, carts: remainingCarts }); setIsPreloader(false); - toast.success("Cart cleared successfully"); + toast.success('Cart cleared successfully'); } catch (error) { - console.error("Error clearing cart:", error); - toast.error("Failed to clear the cart"); + console.error('Error clearing cart:', error); + toast.error('Failed to clear the cart'); } finally { setIsPreloader(false); } @@ -346,9 +348,9 @@ const UserViewCart: React.FC = () => { const response = await dispatch(clearCartProduct({ cartId, productId })); const response1 = await dispatch(getUserCarts()).unwrap(); setCartResponseData(response1.data); - toast.success("product cleared successfully"); + toast.success('product cleared successfully'); } catch (error) { - toast.error("Failed to clear the product "); + toast.error('Failed to clear the product '); throw error; } finally { setIsPreloader(false); @@ -365,12 +367,12 @@ const UserViewCart: React.FC = () => { {isPreloader && (
- + @@ -396,7 +398,7 @@ const UserViewCart: React.FC = () => {

Shopping Cart

- {cart.status === "Paid" ? ( + {cart.status === 'Paid' ? ( @@ -407,7 +409,7 @@ const UserViewCart: React.FC = () => { } className={`checkout-btn`} > - {"Checkout"} + {'Checkout'} )} @@ -439,9 +441,11 @@ const UserViewCart: React.FC = () => { {product.discount}
${product.price}
-
{product.description}
+
+ {product.description} +
- {cart.status !== "Paid" && ( + {cart.status !== 'Paid' && (
+
+
+
+ ))} + + ))} + + + + ); +}; + +export default UserVIewOrders; diff --git a/src/pages/trackOrder.tsx b/src/pages/trackOrder.tsx new file mode 100644 index 00000000..610c73c7 --- /dev/null +++ b/src/pages/trackOrder.tsx @@ -0,0 +1,167 @@ +/* eslint-disable */ +import React, { useState, useEffect } from 'react'; +import { useAppDispatch } from '../store/store'; +import { userTrackOrderStatus } from '../store/features/carts/cartSlice'; +import { useNavigate, useParams } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import { PuffLoader } from 'react-spinners'; +import { fetchUserProfile } from '../store/features/user/userSlice'; + +const TrackOrder = () => { + const dispatch = useAppDispatch(); + const [orderResponseData, setOrderResponseData] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [isLoggedOut, setIsLoggedOut] = useState(false); + const [isError, setIsError] = useState(false); + const [shippingAddress, setShippingAddress] = useState(null); + + const { orderId, productId } = useParams<{ + orderId: string; + productId: string; + }>(); + const navigate = useNavigate(); + + useEffect(() => { + fetchTrackOrderStatus(orderId); + }, [dispatch, orderId]); + + const fetchTrackOrderStatus = async (orderId) => { + try { + setIsLoading(true); + const response = await dispatch(userTrackOrderStatus(orderId)); + const profile: any = await dispatch(fetchUserProfile()); + setShippingAddress(profile.payload.addresses); + + if (response.payload === 'Not authorized') { + setIsLoggedOut(true); + toast.error('Please login first'); + navigate('/login'); + return; + } + + setOrderResponseData(response.payload.data); + setIsLoading(false); + } catch (error: any) { + if (error.message === 'Not authorized') { + setIsLoggedOut(true); + toast.error('Please login first'); + navigate('/login'); + return; + } + console.error('Error fetching orders:', error); + setIsLoading(false); + setIsError(true); + toast.error('Error getting orders, check your internet connection'); + } finally { + setIsLoading(false); + } + }; + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (isError) { + return ( +
+

No orders found.

+
+ ); + } + + if (isLoggedOut) { + return ( +
+

Please login or create an account first.

+
+ ); + } + + const productsJSON = orderResponseData?.order?.products; + let products = []; + + if (productsJSON) { + try { + products = JSON.parse(productsJSON); + } catch (error) { + console.error('Failed to parse products JSON', error); + } + } + + const product = products.find((product) => product.id === productId); + + if (!product) { + return ( +
+

Product not found.

+
+ ); + } + + return ( +
+
+

Order Details

+

+ ORDER ID: {orderResponseData?.order.id.split('-')[0]} +

+
+

Your order status: {orderResponseData?.order.status}

+ {shippingAddress ? ( +

+ Shipping Address: {shippingAddress.province},{' '} + {shippingAddress.district}, {shippingAddress.sector},{' '} + {shippingAddress.cell} +

+ ) : ( +

+ Shipping Address: Not provided +

+ )} +
+

+ + Total +
+
+
+ ${product.quantity * product.price} +

+

+ + Tracking Number +
+
+
+ {orderResponseData?.order.id.split('-')[0]} +

+
+
+ {product.name} +

{product.name}

+
+
+
+

Delivery Timeline

+
+
    +
  • +
    +
    +

    {orderResponseData?.order.shippingProcess}

    + + {new Date(orderResponseData?.order.updatedAt).toDateString()} + +
    +
  • +
+
+
+ ); +}; + +export default TrackOrder; diff --git a/src/pages/trackerOrder.tsx b/src/pages/trackerOrder.tsx deleted file mode 100644 index 7319b860..00000000 --- a/src/pages/trackerOrder.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* eslint-disable */ -import React from "react"; -const TrackerOrder = () => { - return ( -
-
-

Order Details

-

- ORDER ID: 7001860211 -

- -
-

Your order was delivered on June 22, 2024

-

- Shipping Address: Musanze, Byangabo -

-
-

- - Total -
-
-
- 800,000 Rwf -

- -

- - Tracking Number -
-
-
- 1Z999AA12345678 -

-
-
- - Product - -

Flat TV

-
- -
-
-

Delivery Timeline

-
-
    -
  • -
    -
    -

    Order Placed

    - June 21, 2024 - 11:55 p.m -
    -
  • -
  • -
    -
    -

    Shipped

    - June 22, 2024 - 8:55 a.m -
    -
  • -
  • -
    -
    -

    Delivered

    - June 22, 2024 - 10:25 a.m -
    -
  • -
-
-
- ); -}; - -export default TrackerOrder; diff --git a/src/router.tsx b/src/router.tsx index da616b26..70eb2253 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -28,8 +28,8 @@ import Users from './pages/admin/Users'; import Logout from './components/layout/Logout'; import UserProfile from './pages/UserEditProfile'; import ProductsPage from './pages/Products'; -import UserCartPaymentSuccess from './pages/UserCartPaymentSuccess'; -import TrackerOrder from "../src/pages/trackerOrder" +import UserVIewOrders from './pages/UserViewOrders'; +import TrackOrder from './pages/trackOrder'; const AppRouter: React.FC = () => { return (
@@ -50,6 +50,14 @@ const AppRouter: React.FC = () => { path="/api/auth/google/callback" element={} /> + } + /> + } + /> } /> { } /> } /> } /> - }/> + } /> + } /> + + + + } + /> + } /> + } /> + } /> + } /> } /> } /> - } /> } /> } /> - } /> }> } /> @@ -98,4 +117,4 @@ const AppRouter: React.FC = () => { ); }; -export default AppRouter; \ No newline at end of file +export default AppRouter; diff --git a/src/store/features/carts/cartService.tsx b/src/store/features/carts/cartService.tsx index 913abf99..1cf30490 100644 --- a/src/store/features/carts/cartService.tsx +++ b/src/store/features/carts/cartService.tsx @@ -74,49 +74,13 @@ const createStripeProduct = async (data) => { currency: 'usd', }, }, - }); - + }) return response.data; }; const createStripeSession = async (data) => { - const customer_email = data.email; - console.log('Cuatomer email', customer_email); const response = await axiosInstance.post( '/api/cart/checkout-stripe-session', - // { - // sessionInfo: { - // success_url: data.successUrl, - // cancel_url: data.cancelUrl, - // customer_email: data.customerEmail, - // mode: 'payment', - // ui_mode: 'hosted', - // payment_method_types: ['card'], - // line_items: [ - // { - // quantity: 1, - // price: data.price, - // }, - // ], - // }, - - // sessionInfo: { - // success_url: - // 'http://localhost:3000/api-gateway/stripe/checkout-payment-succeeded', - // cancel_url: - // 'http://localhost:3000/api-gateway/stripe/checkout-payment-cancelled', - // customer_email: 'k.joshua800@gmail.com', - // mode: 'payment', - // ui_mode: 'hosted', - // payment_method_types: ['card'], - // line_items: [ - // { - // quantity: 1, - // price: 'price_1PjIQRP2sfrKqqIOWUYjolbZ', - // }, - // ], - // }, - // } { sessionInfo: { success_url: data.successUrl, @@ -155,6 +119,20 @@ const saveOrder = async (data) => { }); return response.data; }; + +const getUserOrders = async () => { + const response = await axiosInstance.get( + '/api/cart/buyer-get-orders-history' + ); + return response.data; +}; +const userTrackOrderStatus = async (id) => { + const reponse = await await axiosInstance.get( + `/api/cart/user-get-order-status/${id}` + ); + return reponse.data; +}; + const cartService = { createCart, getUserCarts, @@ -166,5 +144,7 @@ const cartService = { createStripeSession, updateCartStatus, saveOrder, + getUserOrders, + userTrackOrderStatus }; export default cartService; diff --git a/src/store/features/carts/cartSlice.tsx b/src/store/features/carts/cartSlice.tsx index b643bc63..dc85dcf8 100644 --- a/src/store/features/carts/cartSlice.tsx +++ b/src/store/features/carts/cartSlice.tsx @@ -14,6 +14,7 @@ const initialState: iCartInitialResource = { cartCounter: 0, cartTotalMoney: 0, cartProductslist: [], + orders: null, }; interface CreateCartParams { @@ -145,14 +146,41 @@ export const updateCartStatus = createAsyncThunk( } ); -export const userSaveOrder = createAsyncThunk('cart/saveOrder', async(data:any,thunkApi)=> { - try { - const response = await cartService.saveOrder(data); - return response; - } catch (error) { - return thunkApi.rejectWithValue(getErrorMessage(error)); +export const userSaveOrder = createAsyncThunk( + 'cart/saveOrder', + async (data: any, thunkApi) => { + try { + const response = await cartService.saveOrder(data); + return response; + } catch (error) { + return thunkApi.rejectWithValue(getErrorMessage(error)); + } } -}) +); + +export const getUserOrders = createAsyncThunk( + 'cart/GetOrders', + async (_, thunkApi) => { + try { + const response = await cartService.getUserOrders(); + return response; + } catch (error) { + return thunkApi.rejectWithValue(getErrorMessage(error)); + } + } +); + +export const userTrackOrderStatus = createAsyncThunk( + 'cart/userTrackOrderStatus', + async (id: any, thunkApi) => { + try { + const response = await cartService.userTrackOrderStatus(id); + return response; + } catch (error) { + return thunkApi.rejectWithValue(getErrorMessage(error)); + } + } +); const cartSlice = createSlice({ name: 'cart', @@ -179,6 +207,9 @@ const cartSlice = createSlice({ }); state.cartTotalMoney = calculateTotalPrice(state.carts); }, + userGetOrders: (state, action) => { + state.orders = action.payload; + }, }, extraReducers: (builder) => { builder @@ -212,7 +243,7 @@ const cartSlice = createSlice({ state.isError = false; state.isSuccess = true; state.carts = action.payload.data.carts; - console.log(state.carts) + console.log(state.carts); let cartProductsTotal = 0; let cartTotalAmount = 0; let cartsProductsList = []; @@ -315,6 +346,41 @@ const cartSlice = createSlice({ state.isError = true; state.isSuccess = false; state.message = action.payload; + }) + .addCase(getUserOrders.pending, (state) => { + state.isLoading = true; + state.isError = false; + state.isSuccess = false; + }) + .addCase(getUserOrders.fulfilled, (state, action) => { + state.isLoading = false; + state.isError = false; + state.isSuccess = true; + state.orders = action.payload; + state.message = 'Orders retrieved successfully'; + }) + .addCase(getUserOrders.rejected, (state, action) => { + state.isLoading = false; + state.isError = true; + state.isSuccess = false; + state.message = ''; + }) + .addCase(userTrackOrderStatus.pending, (state) => { + state.isLoading = true; + state.isError = false; + state.isSuccess = false; + }) + .addCase(userTrackOrderStatus.fulfilled, (state, action) => { + state.isLoading = false; + state.isError = false; + state.isSuccess = true; + state.message = 'Order status updated successfully'; + }) + .addCase(userTrackOrderStatus.rejected, (state, action) => { + state.isLoading = false; + state.isError = true; + state.isSuccess = false; + state.message = ''; }); }, }); diff --git a/src/utils/types/store.d.ts b/src/utils/types/store.d.ts index d9344ce7..34f38da8 100644 --- a/src/utils/types/store.d.ts +++ b/src/utils/types/store.d.ts @@ -125,8 +125,9 @@ export interface iCartInitialResource { message: string | null; isLoggedOut: boolean; cartCounter: number; - cartTotalMoney:number; + cartTotalMoney: number; cartProductslist: any[]; + orders: any } export interface IProfile { id: string, @@ -148,9 +149,9 @@ export interface IProfile { } }; -export interface IPassword{ +export interface IPassword { oldPassword: string, - newPassword:string, + newPassword: string, confirmNewPassword: string } @@ -161,18 +162,18 @@ export interface ILocation { sector: string; } -export interface UserService{ +export interface UserService { user: IProfile | null, isLoading: boolean, - isError: string, - isSuccess: boolean, - message: string + isError: string, + isSuccess: boolean, + message: string } export interface AdminReponse { message?: string; - data?: {user:IUser}; + data?: { user: IUser }; error?: string; status?: number; }