//here is my server.js code import express from 'express'; import data from './data.js'; const app = express(); //test api app.get('/api/products', (req , res)=>{ res.send(data.products); }) app.get('/api/products/slug/:slug', (req , res)=>{ const product = data.products.find((x)=> x.slug === req.params.slug) if(product){ res.send(product) }else{ res.status(404).send({message:'product not found'}); } res.send(data.products); }) app.get('/api/products/:id', (req , res)=>{ const product = data.products.find((x)=> x._id === req.params._id) if(product){ res.send(product) }else{ res.status(404).send({message:'product not found'}); } res.send(data.products); }) const port = process.env.PORT || 5000; app.listen(port, () => { console.log(`server is running on ${port}`) }); here is my productscreen.js code// import axios from "axios"; import React from "react"; import { useContext , useEffect, useReducer } from "react"; import { useParams } from "react-router-dom"; import Row from "react-bootstrap/Row"; import Col from "react-bootstrap/Col"; import Rating from "../components/Rating"; import ListGroup from 'react-bootstrap/ListGroup' import Card from 'react-bootstrap/Card' import Badge from 'react-bootstrap/Badge' import Button from "react-bootstrap/esm/Button"; import {Helmet} from 'react-helmet-async' import LoadingBox from "../components/LoadingBox"; import MessageBox from "../components/MessageBox"; import getError from "../Error"; import { Store } from "../Store"; const ProductScreen = () => { const reducer = (state, action) => { switch (action.type) { case "FETCH_REQUEST": return { ...state, loading: true }; case "FETCH_SUCCESS": return { ...state, product: action.payload, loading: false }; case "FETCH_FAIL": return { ...state, loading: false, error: action.payload }; default: return state; } }; const params = useParams(); const { slug } = params; const [{ loading, error, product }, dispatch] = useReducer(reducer, { product: [], loading: true, error: "", }); // const [products, setProducts] = useState([]); useEffect(() => { const fetchData = async () => { dispatch({ type: "FETCH_REQUEST" }); try { const result = await axios.get(`/api/products/slug/${slug}`); dispatch({ type: "FETCH_SUCCESS", payload: result.data }); } catch (err) { dispatch({ type: "FETCH_FAIL", payload: getError(err) }); } // setProducts(result.data) }; fetchData(); }, [slug]); const {state, dispatch: ctxDispatch} = useContext(Store); const {cart} = state; const addToCart = async () =>{ const existItem = cart.cartItems.find(x => x._id === product._id) const quantity = existItem ? existItem.quantity + 1 : 1; const { data } = await axios.get(`/api/products/${product._id}`); if(data.countInStock < quantity) { window.alert('sorry, product is out of stock'); return; } ctxDispatch({ type:'CART_ADD_ITEM', payload: {...product, quantity:1}, }) } return loading ? ( <LoadingBox /> ):error ? ( <MessageBox variant="danger">{error}</MessageBox> ): ( <div> <Row> <Col md={6}> <img className="img-large" src={product.image} alt={product.name} ></img> </Col> <Col md={3}> <ListGroup variant="flush"> <ListGroup.Item> <Helmet> <title>{product.name}</title> </Helmet> <h1>{product.name}</h1> </ListGroup.Item> <ListGroup.Item> <Rating Rating={product.rating} numReviews={product.numReviews} ></Rating> </ListGroup.Item> <ListGroup.Item>price : ${product.price}</ListGroup.Item> <ListGroup.Item> Description: <p>{product.description}</p></ListGroup.Item> </ListGroup> </Col> <Col md={3}> <Card> <Card.Body> <ListGroup variant="flush"> <ListGroup.Item> <Row> <Col>Prices:</Col> <Col>{product.price}</Col> </Row> </ListGroup.Item> <ListGroup.Item> <Row> <Col>Status:</Col> <Col>{product.countInStock>0? <Badge bg = "success">In stock</Badge>: <Badge bg = "danger">Unavailiable</Badge>}</Col> </Row> </ListGroup.Item> {product.countInStock > 0 && ( <ListGroup.Item> <div className="d-grid"> <Button onClick={addToCart} variant = "primary">Add to Cart</Button> </div> </ListGroup.Item> )} </ListGroup> </Card.Body> </Card> </Col> </Row> </div> ); }; export default ProductScreen; // here is my store.js code import { createContext, useReducer } from "react"; // Implement add to cart and store using context export const Store = createContext (); const initialState = { cart:{ cartItems:[], }, }; function reducer(state, action) { switch (action.type){ case 'CART_ADD_ITEM': //add to cart const newItem = action.payload; const existItem = state.cart.cartItems.find( (item) => item._id === newItem._id ); const cartItems = existItem ? state.cart.cartItems.map((item) => item._id === existItem._id ? newItem : item ) : [...state.cart.cartItems, newItem]; return { ...state, cart: {...state.cart, cartItems }}; default: return state; }; } export function StoreProvider(props) { const [state, dispatch] = useReducer(reducer, initialState); const value = {state, dispatch}; return <Store.Provider value={value}>{props.children}</Store.Provider> } //here is my app.js code import React from 'react' import {BrowserRouter ,Route , Routes} from 'react-router-dom' import HomeScreen from './screens/HomeScreen' import ProductScreen from './screens/ProductScreen' import Navbar from 'react-bootstrap/Navbar'; import Nav from 'react-bootstrap/Nav'; import Badge from 'react-bootstrap/Badge'; import {LinkContainer} from 'react-router-bootstrap'; import Container from 'react-bootstrap/Container'; import { Link } from 'react-router-dom'; import { useContext } from 'react'; import { Store } from './Store' const App = () => { const {state} = useContext(Store); const {cart} = state; return ( <BrowserRouter> <div className='d-flex flex-column site-container'> <header> <Navbar bg = "dark" variant="dark"> <Container> <LinkContainer to="/"> <Navbar.Brand>MOJO-Shoping</Navbar.Brand> </LinkContainer> <Nav className="me-auto"> <Link to="/cart" className='nav-link'> Cart {cart.cartItems.length > 0 && ( <Badge pill bg = "danger"> {cart.cartItems.reduce((a , c) => a + c.quantity , 0)} </Badge> )} </Link> </Nav> </Container> </Navbar> </header> <main> <Container className='mt-4'> <Routes> <Route path='/product/:slug' element = {<ProductScreen />} /> <Route path='/' element={<HomeScreen />} /> </Routes> </Container> </main> <footer> <div className='text-center'>All rights reserved</div> </footer> </div> </BrowserRouter> ) } export default App
Bassir Changed status to publish October 11, 2022