├── src
├── components
│ ├── Sum.js
│ ├── __tests__
│ │ ├── Sum.test.js
│ │ └── Header.test.js
│ ├── Contact.jsx
│ ├── Instamart.jsx
│ ├── About.jsx
│ ├── Error.jsx
│ ├── NotFound.jsx
│ ├── Profile.jsx
│ ├── Cart.jsx
│ ├── Header.jsx
│ ├── Shimmer.jsx
│ ├── RestaurentCard.jsx
│ ├── Footer.jsx
│ ├── Body.jsx
│ └── RestaurentMenu.jsx
├── index.css
├── Utils
│ ├── UserContext.js
│ ├── Helper.js
│ ├── store.js
│ ├── CartSlice.js
│ ├── useRestaurant.js
│ └── useOnline.js
├── App.js
└── Config.js
├── assets
├── hiking.png
├── offer.png
└── offer2.png
├── tailwind.config.js
├── README.md
├── index.html
├── package.json
└── jest.config.js
/src/components/Sum.js:
--------------------------------------------------------------------------------
1 | export const Sum = (num1,num2)=>num1 + num2;
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
--------------------------------------------------------------------------------
/assets/hiking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chhatrapati295/FoodPanda-food-app/HEAD/assets/hiking.png
--------------------------------------------------------------------------------
/assets/offer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chhatrapati295/FoodPanda-food-app/HEAD/assets/offer.png
--------------------------------------------------------------------------------
/assets/offer2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chhatrapati295/FoodPanda-food-app/HEAD/assets/offer2.png
--------------------------------------------------------------------------------
/src/components/__tests__/Sum.test.js:
--------------------------------------------------------------------------------
1 | import { Sum } from "../Sum"
2 |
3 | test('For sum of two numbers',()=>{
4 | expect(Sum(2,3)).toBe(5);
5 | })
--------------------------------------------------------------------------------
/src/components/Contact.jsx:
--------------------------------------------------------------------------------
1 | const Contact = ()=>{
2 | return(
3 |
4 |
This is Contact Page
5 |
6 | )
7 | }
8 | export default Contact;
--------------------------------------------------------------------------------
/src/components/Instamart.jsx:
--------------------------------------------------------------------------------
1 | const Instamart = ()=>{
2 | return(
3 |
4 |
This is Instamart Page
5 |
6 | )
7 | }
8 | export default Instamart;
--------------------------------------------------------------------------------
/src/Utils/UserContext.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | const UserContext = createContext({
4 | name : 'Chhatrapati Chauhan',
5 | email : 'chhatrapati1511@gmail.com'
6 | })
7 | export default UserContext;
--------------------------------------------------------------------------------
/src/Utils/Helper.js:
--------------------------------------------------------------------------------
1 | export function filterData (searchText,allRestaurents){
2 | return (allRestaurents.filter((restaurent)=>{
3 | return restaurent?.data?.name.toLowerCase()?.includes(searchText.toLowerCase())
4 | }))
5 | }
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,js,ts,jsx,tsx}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/src/Utils/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import CartSlice from "./CartSlice";
3 |
4 | const store = configureStore({
5 | reducer : {
6 | cart : CartSlice
7 | }
8 | })
9 | export default store;
--------------------------------------------------------------------------------
/src/components/About.jsx:
--------------------------------------------------------------------------------
1 | import { Outlet } from "react-router-dom";
2 |
3 | const About = ()=>{
4 | return(
5 |
6 |
This is About Page
7 |
8 |
9 | )
10 | }
11 | export default About;
--------------------------------------------------------------------------------
/src/components/Error.jsx:
--------------------------------------------------------------------------------
1 | import { useRouteError } from "react-router-dom";
2 | const Error = ()=>{
3 | const err = useRouteError()
4 | return(
5 |
6 |
You made a mistake
7 | {err.status} : {err.statusText}
8 |
9 | )
10 | }
11 | export default Error;
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FoodPanda-food-app
2 | In this project I have used Swiggy live API to fetch all the data through CORS.
3 |
4 | 🚀 React js as a UI library.
5 | Redux toolkit for state management.
6 | Parcel for bundling.
7 | Babel as a JavaScript transpiler.
8 | React router-V6 for routing.
9 | Tailwind CSS for styling.
10 | Completely responsive.
11 | React testing library with jest for unit testing and integration testing.
12 |
--------------------------------------------------------------------------------
/src/components/NotFound.jsx:
--------------------------------------------------------------------------------
1 | const NotFound = ()=>{
2 | return(
3 |
4 |
5 |
Internet is dissconnected
6 |
7 | )
8 | }
9 | export default NotFound;
--------------------------------------------------------------------------------
/src/Utils/CartSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const CartSlice = createSlice({
4 | name : 'cart',
5 | initialState : {
6 | items : []
7 | },
8 | reducers : {
9 | addItem : (state,action)=>{
10 | state.items.push(action.payload)
11 | },
12 | removeItem : (state,action)=>{
13 | state.items.pop()
14 | },
15 | clearItem : (state,action)=>{
16 | state.items = []
17 | }
18 | }
19 | })
20 |
21 | export const{addItem , removeItem , clearItem} = CartSlice.actions;
22 | export default CartSlice.reducer;
--------------------------------------------------------------------------------
/src/Utils/useRestaurant.js:
--------------------------------------------------------------------------------
1 | import { useState , useEffect } from "react"
2 |
3 | const useRestaurant = (resId)=>{
4 | const[resMenu , setResMenu] = useState(null)
5 | useEffect(()=>{
6 | getMenu()
7 | },[])
8 | async function getMenu(){
9 | const URL = await fetch(`https://corsproxy.io/?https://www.swiggy.com/dapi/menu/pl?page-type=REGULAR_MENU&complete-menu=true&lat=19.0759837&lng=72.8776559&restaurantId=${resId}&submitAction=ENTER`)
10 | const json = await URL.json()
11 | console.log(json?.data?.cards[2]?.groupedCard?.cardGroupMap?.REGULAR?.cards[2])
12 | setResMenu(json?.data)
13 | }
14 | return resMenu;
15 | }
16 | export default useRestaurant;
--------------------------------------------------------------------------------
/src/Utils/useOnline.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react"
2 |
3 | const UseOnline = ()=>{
4 | const[isOnline,setIsOnline]= useState(true)
5 | useEffect(()=>{
6 | const handleOnline = ()=>{
7 | setIsOnline(true)
8 | }
9 | const handleOffline = ()=>{
10 | setIsOnline(false)
11 | }
12 | window.addEventListener('online',handleOnline)
13 | window.addEventListener('offline',handleOffline)
14 | return (()=>{
15 | window.removeEventListener('online',handleOnline)
16 | window.removeEventListener('offline',handleOffline)
17 | })
18 | },[])
19 | return isOnline;
20 | }
21 | export default UseOnline;
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | FoodPanda | order food from best restaurants near you
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "foodpanda-main",
3 | "version": "1.0.0",
4 | "description": "",
5 | "scripts": {
6 | "test": "jest",
7 | "start": "parcel index.html",
8 | "build": "parcel build index.html"
9 | },
10 | "author": "Chhatrapati chauhan",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@reduxjs/toolkit": "^1.9.3",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0",
16 | "react-loading-skeleton": "^3.2.0",
17 | "react-redux": "^8.0.5",
18 | "react-router-dom": "^6.10.0"
19 | },
20 | "devDependencies": {
21 | "@testing-library/react": "^14.0.0",
22 | "jest": "^29.5.0",
23 | "jest-environment-jsdom": "^29.5.0",
24 | "parcel": "^2.8.3",
25 | "postcss": "^8.4.21",
26 | "process": "^0.11.10",
27 | "tailwindcss": "^3.3.1"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/__tests__/Header.test.js:
--------------------------------------------------------------------------------
1 | import { render } from "@testing-library/react"
2 | import Header from '../Header'
3 | import { Provider } from "react-redux"
4 | import store from "../../Utils/store"
5 | import {StaticRouter} from 'react-router-dom/server'
6 |
7 | test('To load header when rendering first time',()=>{
8 | const header = render(
9 |
10 |
11 |
12 |
13 |
14 | );
15 | // console.log(header)
16 | const logo = header.getByTestId('logo')
17 | expect(logo.src).toBe("https://th.bing.com/th/id/R.f6bc2b2712b5a390fee444e60d312b69?rik=qTqjtW7Nn4UiJw&riu=http%3a%2f%2fwww.gadgetsmagazine.com.ph%2fwp-content%2fuploads%2f2017%2f09%2ffoodpanda-logo.png&ehk=Jy3z435XdWQADxTy4KoiuJvyN6HyGj9DOZIzHuitbEI%3d&risl=&pid=ImgRaw&r=0")
18 | })
19 |
20 | test('Cart item should be 0 in intital render',()=>{
21 | const header = render(
22 |
23 |
24 |
25 |
26 |
27 | )
28 | const cart = header.getByTestId('cart')
29 | expect(cart.innerHTML).toBe('0')
30 | })
--------------------------------------------------------------------------------
/src/components/Profile.jsx:
--------------------------------------------------------------------------------
1 | import { Component } from "react";
2 | // import UserContext from "../Utils/UserContext";
3 |
4 | class Profile extends Component{
5 | constructor(props){
6 | super(props)
7 | this.state = {
8 | name : 'What',
9 | loc : 'where'
10 | }
11 | }
12 | async componentDidMount(){
13 | const url = await fetch('https://api.github.com/users/chhatrapati295')
14 | const data = await url.json()
15 | console.log(data)
16 | this.setState({
17 | name : data.name,
18 | loc : data.location
19 | })
20 |
21 | }
22 | render(){
23 | console.log('render')
24 | return(
25 | <>
26 | hello
27 | {/*
28 | {
29 | ({user})=>(
30 | {user.name} : {user.email}
31 | )
32 | }
33 | */}
34 | {this.state.name}
35 | {this.state.loc}
36 | >
37 | )
38 | }
39 | }
40 | export default Profile;
--------------------------------------------------------------------------------
/src/components/Cart.jsx:
--------------------------------------------------------------------------------
1 | import { useDispatch, useSelector } from "react-redux";
2 | import { IMG_CDN } from "../Config";
3 | import { clearItem } from "../Utils/CartSlice";
4 |
5 | const Cart = ()=>{
6 | const cartItems = useSelector((store)=> store.cart.items)
7 | console.log(cartItems)
8 | const dispatch = useDispatch()
9 | function clearItemFunc (){
10 | dispatch(clearItem())
11 | }
12 | return(
13 |
14 |
15 |
Cart ({cartItems.length})
16 | clearItemFunc()}>Clear Cart
17 |
18 |
19 | {cartItems.map(item=>{
20 | return
21 | })}
22 |
23 |
24 | )
25 | }
26 | const CartItem = ({name,imageId,price,description})=>{
27 | return(
28 |
29 |
36 |
37 | {name}
38 | ₹{!price ? '250' : price/100}
39 | {description}
40 |
41 |
42 | )
43 | }
44 | export default Cart;
--------------------------------------------------------------------------------
/src/components/Header.jsx:
--------------------------------------------------------------------------------
1 | import { Link } from "react-router-dom";
2 | // import UseOnline from "../Utils/useOnline";
3 | import { useContext } from "react";
4 | import UserContext from "../Utils/UserContext";
5 | import { useSelector } from "react-redux";
6 | // import store from "../Utils/store";
7 |
8 | const Header = ()=>{
9 | // const isOnline = UseOnline()
10 | const myInfo = useContext(UserContext)
11 | const cartItems = useSelector(store => store.cart.items)
12 | return(
13 |
14 |
15 |
16 |
17 |
18 | Home
19 | About
20 | Contact
21 | {cartItems.length}
22 | {/* Instamart */}
23 |
24 | {/*
{isOnline ? '🟢' : '🔴'}
*/}
25 | {/*
{myInfo.name} */}
26 |
27 | )
28 | }
29 | export default Header;
--------------------------------------------------------------------------------
/src/components/Shimmer.jsx:
--------------------------------------------------------------------------------
1 | import Skeleton from "react-loading-skeleton";
2 | import "react-loading-skeleton/dist/skeleton.css";
3 |
4 | const Shimmer = () => {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | };
18 | const ShimmerCard = () => {
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 | );
27 | };
28 | export const ShimmerMenu = () => {
29 | return (
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | );
59 | };
60 | export default Shimmer;
61 |
--------------------------------------------------------------------------------
/src/components/RestaurentCard.jsx:
--------------------------------------------------------------------------------
1 | import { IMG_CDN } from "../Config";
2 | import offerImg from "../../assets/offer2.png";
3 | import { useContext } from "react";
4 | import UserContext from "../Utils/UserContext";
5 | const RestaurentCard = ({
6 | name,
7 | cuisines,
8 | avgRating,
9 | cloudinaryImageId,
10 | slaString,
11 | costForTwoString,
12 | aggregatedDiscountInfo,
13 | // user
14 | }) => {
15 | const myInfo= useContext(UserContext)
16 | return (
17 |
18 |
28 |
{name}
29 |
{cuisines.join(", ")}
30 |
31 |
32 |
33 |
34 | {avgRating === "--" ? "4.2" : avgRating}
35 |
36 |
37 |
38 |
{slaString}
39 |
40 |
{costForTwoString}
41 |
42 |
43 |
44 |
45 | {!aggregatedDiscountInfo?.shortDescriptionList[0]?.meta
46 | ? "40% off | Use TRYNEW"
47 | : aggregatedDiscountInfo?.shortDescriptionList[0]?.meta}
48 |
49 |
50 | {/*
{myInfo.name} */}
51 |
52 | );
53 | };
54 | export default RestaurentCard;
55 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Suspense, lazy, useState } from "react"
2 | import ReactDOM from 'react-dom/client'
3 | import Header from "./components/Header"
4 | import Body from "./components/Body"
5 | import { Outlet, RouterProvider, createBrowserRouter } from "react-router-dom"
6 | import Error from "./components/Error"
7 | import About from "./components/About"
8 | import Contact from "./components/Contact"
9 | import Footer from "./components/Footer"
10 | import RestaurentMenu from "./components/RestaurentMenu"
11 | import Profile from "./components/Profile"
12 | import Shimmer from "./components/Shimmer"
13 | import Cart from "./components/Cart"
14 | import UserContext from "./Utils/UserContext"
15 | import { Provider } from "react-redux"
16 | import store from "./Utils/store"
17 |
18 | const Instamart = lazy(()=> import("./components/Instamart"))
19 |
20 | const App = ()=>{
21 | return(
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 | )
32 | }
33 | const creatingRouter = createBrowserRouter([
34 | {
35 | path : '/',
36 | element : ,
37 | errorElement : ,
38 | children : [
39 | {
40 | path : '/',
41 | element :