├── .env.template
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── favicon.ico
├── favicon.png
├── index.html
├── logo.png
├── logo192.png
├── manifest.json
└── robots.txt
├── src
├── App.test.tsx
├── App.tsx
├── Firebase
│ └── index.js
├── Pages
│ ├── About
│ │ └── index.tsx
│ ├── Admin
│ │ ├── Dashboard.tsx
│ │ └── index.tsx
│ ├── Auth
│ │ ├── Login.tsx
│ │ ├── Register.tsx
│ │ └── index.tsx
│ ├── Home
│ │ └── index.tsx
│ ├── Menu
│ │ └── index.tsx
│ ├── Profile
│ │ └── index.tsx
│ ├── Services
│ │ └── index.tsx
│ └── index.tsx
├── components
│ ├── Admin
│ │ ├── AddFood
│ │ │ ├── CategoriesSelector.tsx
│ │ │ └── index.tsx
│ │ ├── Content.tsx
│ │ ├── Dashboard
│ │ │ ├── CategoryCards.tsx
│ │ │ └── index.tsx
│ │ ├── Menu
│ │ │ └── index.tsx
│ │ ├── Sidenav.tsx
│ │ ├── SidenavMenu.tsx
│ │ └── Users
│ │ │ ├── index.tsx
│ │ │ └── user.tsx
│ ├── Assets
│ │ └── index.tsx
│ ├── Cart
│ │ ├── Body.tsx
│ │ ├── CartTotal.tsx
│ │ ├── Header.tsx
│ │ ├── Item.tsx
│ │ └── index.tsx
│ ├── Checkout
│ │ ├── Header.tsx
│ │ ├── Selector.tsx
│ │ ├── body.tsx
│ │ ├── footer.tsx
│ │ ├── forms
│ │ │ ├── Card.tsx
│ │ │ └── Momo.tsx
│ │ └── index.tsx
│ ├── Contact
│ │ ├── form.tsx
│ │ ├── header.tsx
│ │ └── index.tsx
│ ├── Container
│ │ └── index.tsx
│ ├── EmptyCart
│ │ └── index.tsx
│ ├── Filters
│ │ ├── Button.tsx
│ │ └── index.tsx
│ ├── FoodItem
│ │ ├── action.tsx
│ │ └── index.tsx
│ ├── Footer
│ │ └── index.tsx
│ ├── Header
│ │ ├── DropDown.tsx
│ │ ├── LoginAction.tsx
│ │ ├── Navigations.tsx
│ │ ├── index.tsx
│ │ └── mobile-nav.tsx
│ ├── Loader
│ │ └── index.tsx
│ ├── NotFound
│ │ └── index.tsx
│ ├── Sections
│ │ ├── Fruits
│ │ │ └── index.tsx
│ │ ├── Menu
│ │ │ └── index.tsx
│ │ └── index.tsx
│ ├── Showcase
│ │ ├── Statics.tsx
│ │ ├── index.tsx
│ │ ├── left.tsx
│ │ └── right.tsx
│ ├── Upload
│ │ └── index.tsx
│ └── index.tsx
├── context
│ ├── StateProvider.js
│ ├── initialState.js
│ └── reducer.js
├── firebase.config.js
├── img
│ ├── NotFound.svg
│ ├── avatar.png
│ ├── c1.png
│ ├── c2.png
│ ├── c3.png
│ ├── c4.png
│ ├── c6.png
│ ├── c7.png
│ ├── chef1.png
│ ├── cheff.png
│ ├── cu1.png
│ ├── cu2.png
│ ├── cu3.png
│ ├── cu4.png
│ ├── cu5.png
│ ├── cu6.png
│ ├── d1.png
│ ├── d2.png
│ ├── d3.png
│ ├── d4.png
│ ├── d5.png
│ ├── d6.png
│ ├── d7.png
│ ├── d8.png
│ ├── delivery.png
│ ├── emptyCart.svg
│ ├── f1.png
│ ├── f10.png
│ ├── f2.png
│ ├── f3.png
│ ├── f4.png
│ ├── f5.png
│ ├── f6.png
│ ├── f7.png
│ ├── f8.png
│ ├── f9.png
│ ├── fi1.png
│ ├── fi2.png
│ ├── fi3.png
│ ├── fi4.png
│ ├── fi5.png
│ ├── hero-bg.png
│ ├── i1.png
│ ├── i2.png
│ ├── i3.png
│ ├── i4.png
│ ├── i5.png
│ ├── i6.png
│ ├── i7.png
│ ├── logo.png
│ ├── momo.png
│ ├── r1.png
│ ├── r2.png
│ ├── r3.png
│ ├── r4.png
│ ├── r5.png
│ └── visa.png
├── index.css
├── index.tsx
├── logo.svg
├── react-app-env.d.ts
├── reportWebVitals.ts
├── setupTests.ts
└── utils
│ ├── categories.tsx
│ ├── fetchSessionData.js
│ ├── filters.tsx
│ ├── functions.tsx
│ └── showcaseStatic.tsx
├── tailwind.config.js
├── tsconfig.json
└── types.tsx
/.env.template:
--------------------------------------------------------------------------------
1 | REACT_APP_FIREBASE_API_KEY=[YOUR_KEY]
2 | REACT_APP_FIREBASE_AUTH_DOMAIN=[YOUR_AUTH_DOMIAN]
3 | REACT_APP_FIREBASE_DB_URL=[YOUR_DB_URL]
4 | REACT_APP_FIREBASE_PROJECT_ID=[YOUR_PROJECT_ID]
5 | REACT_APP_FIREBASE_STORAGE_BUCKET=[YOUR_STORAGE_BUCKET]
6 | REACT_APP_FIREBASE_MESSAGING_ID=[YOUR_MESSAGING_ID]
7 | REACT_APP_FIREBASE_APP_ID=[YOUR_APP_ID]
8 | REACT_APP_FIREBASE_MEASUREMENT_ID=[YOUR_MEASUREMENT_ID]
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .env
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 |
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Smart Online Restaurant App
2 |
3 | ## STACK USED
4 | - ReactJS (Typescript)
5 | - Redux
6 | - TailwindCSS
7 | - Firebase
8 | ## You Can See
9 | DEMO HERE!
10 | ## Deployment Status
11 | [](https://app.netlify.com/sites/bzone-restaurant/deploys)
12 |
13 | ## UI Desktop View
14 | 
15 | 
16 | 
17 | 
18 | 
19 | 
20 | 
21 | 
22 | 
23 |
24 |
25 | ## UI Mobile View
26 | 
27 | 
28 | 
29 | 
30 | 
31 | 
32 |
33 | ## Thank You!
34 |
35 | Thanks to Kevin Inoue for sharing this freebie!
36 |
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bentilzone-restaurant",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.4",
7 | "@testing-library/react": "^13.3.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "@types/jest": "^27.5.2",
10 | "@types/node": "^16.11.38",
11 | "@types/react": "^18.0.12",
12 | "@types/react-dom": "^18.0.5",
13 | "firebase": "^9.8.2",
14 | "framer-motion": "^6.3.10",
15 | "react": "^18.1.0",
16 | "react-dom": "^18.1.0",
17 | "react-icons": "^4.4.0",
18 | "react-router-dom": "^6.3.0",
19 | "react-scripts": "5.0.1",
20 | "react-toastify": "^9.0.3",
21 | "typescript": "^4.7.3",
22 | "web-vitals": "^2.1.4"
23 | },
24 | "scripts": {
25 | "start": "react-scripts start",
26 | "build": "react-scripts build",
27 | "test": "react-scripts test",
28 | "eject": "react-scripts eject"
29 | },
30 | "eslintConfig": {
31 | "extends": [
32 | "react-app",
33 | "react-app/jest"
34 | ]
35 | },
36 | "browserslist": {
37 | "production": [
38 | ">0.2%",
39 | "not dead",
40 | "not op_mini all"
41 | ],
42 | "development": [
43 | "last 1 chrome version",
44 | "last 1 firefox version",
45 | "last 1 safari version"
46 | ]
47 | },
48 | "devDependencies": {
49 | "autoprefixer": "^10.4.7",
50 | "postcss": "^8.4.14",
51 | "tailwindcss": "^3.1.2"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/public/favicon.ico
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/public/favicon.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
18 | Bentilzone Restaurant
19 |
20 |
39 |
40 |
41 | You need to enable JavaScript to run this app.
42 |
43 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/public/logo.png
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/public/logo192.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | render( );
7 | const linkElement = screen.getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import "react-toastify/dist/ReactToastify.css";
2 |
3 | import {
4 | About,
5 | Admin,
6 | Home,
7 | Login,
8 | Menu,
9 | Profile,
10 | Services,
11 | Signup,
12 | } from "./Pages";
13 | import { Cart, Footer, Header } from "./components";
14 | import { Route, Routes } from "react-router-dom";
15 | import {
16 | calculateCartTotal,
17 | dispatchUsers,
18 | fetchFoodData,
19 | fetchUserCartData,
20 | isAdmin,
21 | } from "./utils/functions";
22 |
23 | import { AnimatePresence } from "framer-motion";
24 | import Contact from "./components/Contact";
25 | import { ToastContainer } from "react-toastify";
26 | import { useEffect } from "react";
27 | import { useStateValue } from "./context/StateProvider";
28 |
29 | function App() {
30 | const [{ showCart,showContactForm, user, foodItems, cartItems, adminMode }, dispatch] =
31 | useStateValue();
32 |
33 | useEffect(() => {
34 | fetchFoodData(dispatch);
35 | dispatchUsers(dispatch);
36 | user && fetchUserCartData(user, dispatch);
37 | }, []);
38 |
39 | useEffect(() => {
40 | foodItems &&
41 | cartItems.length > 0 &&
42 | calculateCartTotal(cartItems, foodItems, dispatch);
43 | }, [cartItems, foodItems, dispatch]);
44 | return (
45 |
46 |
47 |
48 | {showCart && }
49 | {showContactForm && }
50 | {!(adminMode && isAdmin(user)) && }
51 | {}}
57 | >
58 | {/* Routes */}
59 |
60 | } />
61 | } />
62 | } />
63 | } />
64 | } />
65 | } />
66 | } />
67 | } />
68 |
69 |
70 | {!(adminMode && isAdmin(user)) && }
71 |
72 |
73 |
74 | );
75 | }
76 |
77 | export default App;
78 |
--------------------------------------------------------------------------------
/src/Firebase/index.js:
--------------------------------------------------------------------------------
1 | import { app, firestore, storage } from "../firebase.config";
2 | import { collection, deleteDoc, doc, getDocs, orderBy, query, setDoc } from "firebase/firestore";
3 | import { createUserWithEmailAndPassword, getAuth, signInWithEmailAndPassword, signInWithPopup } from "firebase/auth";
4 | import {
5 | deleteObject,
6 | getDownloadURL,
7 | ref,
8 | uploadBytesResumable,
9 | } from "firebase/storage";
10 |
11 | import { MdOutlineCloudUpload } from "react-icons/md";
12 | import { toast } from "react-toastify";
13 | import { shuffleItems } from "../utils/functions";
14 |
15 | export const firebaseUploadImage = (
16 | imageFile,
17 | promise,
18 | progressHandler,
19 | action,
20 | to
21 | ) => {
22 | promise(true);
23 | // progressHandler(0)
24 | toast.info(`Upload started.....`, {
25 | icon: ,
26 | });
27 | const storageRef = ref(
28 | storage,
29 | `Images/${to}/${Date.now()}-${imageFile.name}`
30 | );
31 | const uploadPhoto = uploadBytesResumable(storageRef, imageFile);
32 | uploadPhoto.on(
33 | "state_changed",
34 | (snapshot) => {
35 | progressHandler(
36 | `Upload status: ${Math.round(
37 | (snapshot.bytesTransferred / snapshot.totalBytes) * 100
38 | )}%`
39 | );
40 | },
41 | (error) => {
42 | console.log(error);
43 | toast.error("Error while uploading, Try again🤗");
44 | action(null);
45 | setTimeout(() => {
46 | promise(false);
47 | }, 3000);
48 | },
49 | () => {
50 | getDownloadURL(uploadPhoto.snapshot.ref).then((downloadUrl) => {
51 | action(downloadUrl);
52 | promise(false);
53 | toast.success("Photo Uploaded Successfully😊");
54 | });
55 | }
56 | );
57 | };
58 |
59 | export const firebaseRemoveUploadedImage = (
60 | ImageFile,
61 | imageHandler,
62 | promise
63 | ) => {
64 | const dummy = "https://firebasestorage.googleapis.com/v0/b/bentilzone-restaurant.appspot.com/o/Images"
65 | promise(true);
66 | toast.info(`Removing Image.....`, {
67 | icon: ,
68 | autoClose: 1500,
69 | toastId: "remove-image",
70 | });
71 | if(ImageFile.includes(dummy))
72 | {
73 | const deleteRef = ref(storage, ImageFile);
74 | deleteObject(deleteRef).then(() => {
75 | imageHandler(null);
76 | promise(false);
77 | toast.success("Photo removed Successfully😊", { autoClose: 2000, toastId: "remove-image" });
78 | });
79 | }else{
80 | imageHandler(null);
81 | promise(false);
82 | toast.success("Photo removed Successfully😊", { autoClose: 2000, toastId: "remove-image" });
83 | }
84 | };
85 | export const silentRemoveUploadedImage = (ImageFile) => {
86 | const deleteRef = ref(storage, ImageFile);
87 | deleteObject(deleteRef).then(() => {});
88 | };
89 |
90 | export const firebaseSaveProduct = async (data) => {
91 | await setDoc(doc(firestore, "Food", `${Date.now()}`), data, {
92 | merge: true,
93 | });
94 | };
95 |
96 |
97 | // Authenticate user using PROVIDER
98 | export const AUTHPROVIDER = async (provider) => {
99 | const firebaseAuth = getAuth(app);
100 | const {
101 | user: { refreshToken, providerData },
102 | } = await signInWithPopup(firebaseAuth, provider);
103 | // add provider data to user
104 | await firebaseAddUser(providerData[0]);
105 | let userData = await firebaseGetUser(providerData[0].uid);
106 | return { refreshToken, userData };
107 | };
108 |
109 | // Signup with email and password
110 | export const EMAILSIGNUP = async (email, password) => {
111 | const firebaseAuth = getAuth(app);
112 | return createUserWithEmailAndPassword(firebaseAuth, email, password)
113 | };
114 |
115 | // Signin with email and password
116 | export const EMAILSIGNIN = async (email, password) => {
117 | const firebaseAuth = getAuth(app);
118 | const result = await signInWithEmailAndPassword(firebaseAuth, email, password)
119 | let user = result.user.providerData[0];
120 |
121 |
122 | return await firebaseGetUser(user.uid)
123 | };
124 |
125 |
126 | // Fetch All Food Products from Firestore
127 | export const firebaseFetchFoodItems = async () => {
128 | const items = await getDocs(
129 | query(collection(firestore, "Food"), orderBy("id", "desc"))
130 | );
131 |
132 | return shuffleItems(items.docs.map((doc) => doc.data()));
133 | }
134 |
135 |
136 | // cart operation
137 | export const firebaseAddToCart = async (data) => {
138 | await setDoc(doc(firestore, "CartItems", `${data.id}`), data, {
139 | merge: true,
140 | });
141 | };
142 |
143 |
144 |
145 | // Fetch All Cart Items from Firestore
146 | export const firebaseFetchAllCartItems = async () => {
147 | const items = await getDocs(
148 | query(collection(firestore, "CartItems"), orderBy("id", "desc"))
149 | );
150 |
151 | return shuffleItems(items.docs.map((doc) => doc.data()));
152 | }
153 |
154 | // Update Cart Items
155 | export const firebaseUpdateCartItem = async (data) => {
156 | await setDoc(doc(firestore, "CartItems", `${data.id}`), data, {
157 | merge: true,
158 | });
159 | }
160 |
161 | // Delete Cart from Firestore
162 | export const firebaseDeleteCartItem = async (item) => {
163 | await deleteDoc(doc(firestore, "CartItems", `${item.id}`));
164 | }
165 |
166 | // Delete Cart from Firestore
167 | export const firebaseEmptyCart = async () => {
168 | await deleteDoc(doc(firestore, "CartItems"));
169 | }
170 |
171 | // Empty user cart from firestore
172 | export const firebaseEmptyUserCart = async (cartItems) => {
173 | cartItems.forEach((item) => {
174 | firebaseDeleteCartItem(item);
175 | })
176 | }
177 |
178 | // Logout user
179 | export const firebaseLogout = async () => {
180 | await getAuth(app).signOut();
181 | }
182 |
183 | // ADMIN USER MANAGEMENT
184 |
185 | // firestore add to users collection
186 | export const firebaseAddUser = async (data) => {
187 | // check if user already exists
188 | const user = await firebaseGetUser(data.uid);
189 | if (user.length === 0) {
190 | await setDoc(doc(firestore, "Users", `${data.uid}`), data, {
191 | merge: true,
192 | });
193 | }
194 | }
195 |
196 | // get user
197 | export const firebaseGetUser = async (uid) => {
198 | const user = await getDocs(
199 | query(collection(firestore, "Users"))
200 | );
201 | let users = user.docs.map((doc) => doc.data());
202 | return users.filter((user) => user.uid === uid)
203 | }
204 |
205 | // update user
206 | export const firebaseUpdateUser = async (data) => {
207 | await setDoc(doc(firestore, "Users", `${data.uid}`), data, {
208 | merge: true,
209 | });
210 | }
211 |
212 | // firebase get all users
213 | export const firebaseGetAllUsers = async () => {
214 | const users = await getDocs(
215 | query(collection(firestore, "Users"))
216 | );
217 | let usersData = users.docs.map((doc) => doc.data());
218 | return usersData
219 | }
220 |
221 | // delete food
222 | export const firebaseDeleteFood = async (id) => {
223 | await deleteDoc(doc(firestore, "Food", `${id}`));
224 | }
--------------------------------------------------------------------------------
/src/Pages/About/index.tsx:
--------------------------------------------------------------------------------
1 | const About = () => {
2 | return (
3 |
4 |
About Page Cominig Up soon!!
5 |
6 | );
7 | }
8 |
9 | export default About;
--------------------------------------------------------------------------------
/src/Pages/Admin/Dashboard.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { Content, Sidenav, Stats } from '../../components';
3 |
4 |
5 | const Dashboard = () => {
6 | const [activePage, setActivePage] = useState("Dashboard");
7 | const [element, setElement] = useState( );
8 | return (
9 |
10 |
11 |
12 |
13 | );
14 | }
15 |
16 |
17 | export default Dashboard;
--------------------------------------------------------------------------------
/src/Pages/Admin/index.tsx:
--------------------------------------------------------------------------------
1 | import AddFood from "../../components/Admin/AddFood";
2 | import Dashboard from "./Dashboard";
3 | import Home from "../Home";
4 | import { useStateValue } from "../../context/StateProvider";
5 | import { isAdmin } from "../../utils/functions";
6 |
7 | const Admin = () => {
8 | const [{user}] = useStateValue()
9 | return (
10 | <>
11 | {isAdmin(user) ? : }
12 | >
13 | );
14 | };
15 |
16 | export default Admin;
17 |
--------------------------------------------------------------------------------
/src/Pages/Auth/Login.tsx:
--------------------------------------------------------------------------------
1 | import { Link, useNavigate } from "react-router-dom";
2 | import ProviderAuth, { ImageBox } from ".";
3 | import { toast } from "react-toastify";
4 |
5 | import { motion } from "framer-motion";
6 | import { useState } from "react";
7 | import { useStateValue } from "../../context/StateProvider";
8 | import { EMAILSIGNIN } from "../../Firebase";
9 |
10 | const Login = () => {
11 | const navigate = useNavigate();
12 | const [{ user }, dispatch] = useStateValue();
13 | const [email, setEmail] = useState("");
14 | const [password, setPassword] = useState("");
15 |
16 | const EmailAuth = () => {
17 | if (!user) {
18 | if (email.length > 0 && password.length > 0) {
19 | toast.promise(
20 | EMAILSIGNIN(email, password),
21 | {
22 | pending: "Signing in...",
23 | success: "Signin successful: WELCOME!",
24 | error: "Error signing account, Please try again🤗",
25 | }
26 | ).then((userData) => {
27 | // Signed in
28 | const user = userData[0];
29 | dispatch({
30 | type: "SET_USER",
31 | user: user,
32 | });
33 | localStorage.setItem("user", JSON.stringify(user));
34 | navigate("/");
35 | }
36 | ).catch((error) => {
37 | // const errorCode = error.code;
38 | const errorMessage = error.message;
39 | toast.error(errorMessage, { autoClose: 15000 });
40 | }
41 | );
42 |
43 | } else {
44 | toast.warn("Please fill all the fields", { autoClose: 15000 });
45 | }
46 | }
47 | };
48 |
49 | return (
50 |
115 | );
116 | };
117 |
118 | export default Login;
119 |
--------------------------------------------------------------------------------
/src/Pages/Auth/Register.tsx:
--------------------------------------------------------------------------------
1 |
2 | import { Link, useNavigate } from "react-router-dom";
3 | import ProviderAuth, { ImageBox } from ".";
4 | import { toast } from "react-toastify";
5 |
6 | // import { motion } from "framer-motion";
7 | import { useState } from "react";
8 | import { useStateValue } from "../../context/StateProvider";
9 | import { EMAILSIGNUP, firebaseAddUser } from "../../Firebase";
10 |
11 | // toast.configure()
12 |
13 | const Login = () => {
14 | const navigate = useNavigate();
15 | const [{ user }, dispatch] = useStateValue();
16 | const [email, setEmail] = useState('');
17 | const [password, setPassword] = useState('');
18 |
19 | const EmailAuth = () => {
20 | if (!user) {
21 | if (email.length > 0 && password.length > 0) {
22 | toast.promise(
23 | EMAILSIGNUP(email, password),
24 | {
25 | pending: "Creating Account...",
26 | success: "Signup successful: WELCOME!",
27 | error: "Error Creating account, Please try again🤗",
28 | }
29 | ).then((userCredential) => {
30 | // Signed in
31 | const user = userCredential.user.providerData[0];
32 | firebaseAddUser(user);
33 | dispatch({
34 | type: "SET_USER",
35 | user: user,
36 | });
37 | localStorage.setItem("user", JSON.stringify(user));
38 | navigate("/");
39 | }
40 | ).catch((error) => {
41 | // const errorCode = error.code;
42 | const errorMessage = error.message;
43 | toast.error(errorMessage, { autoClose: 15000 });
44 | }
45 | );
46 |
47 | } else {
48 | toast.warn("Please fill all the fields", { autoClose: 15000 });
49 | }
50 | }
51 | };
52 |
53 | return (
54 |
109 | );
110 | };
111 |
112 | export default Login;
113 |
--------------------------------------------------------------------------------
/src/Pages/Auth/index.tsx:
--------------------------------------------------------------------------------
1 | import "react-toastify/dist/ReactToastify.css";
2 |
3 | import { Cheff1 } from "../../components/Assets";
4 | import {
5 | // GithubAuthProvider,
6 | GoogleAuthProvider,
7 | } from "firebase/auth";
8 | import { useNavigate } from "react-router-dom";
9 | import { toast } from "react-toastify";
10 | import { FcGoogle } from "react-icons/fc";
11 | import { BsGithub } from "react-icons/bs";
12 |
13 | import { motion } from "framer-motion";
14 | import { useStateValue } from "../../context/StateProvider";
15 | import { AUTHPROVIDER } from "../../Firebase";
16 | import { MdOutlineNotificationsActive } from "react-icons/md";
17 | import { fetchUserCartData } from "../../utils/functions";
18 |
19 | const ProviderAuth = () => {
20 | const GOOGLE_PROVIDER = new GoogleAuthProvider();
21 | // const GITHUB_PROVIDER = new GithubAuthProvider();
22 | const [{ user }, dispatch] = useStateValue();
23 | const navigate = useNavigate();
24 |
25 | const AUTH = async ({ provider }: { provider: any }) => {
26 | if (!user) {
27 | toast
28 | .promise(AUTHPROVIDER(provider), {
29 | pending: "Signing in...",
30 | success: "Signin successful",
31 | error: "Error Signing in, Please try again🤗",
32 | })
33 | .then(({ refreshToken, userData }) => {
34 | // Signed in
35 | const user = userData[0];
36 | // const userData = getUserData(user);
37 | dispatch({
38 | type: "SET_USER",
39 | user: user,
40 | });
41 | fetchUserCartData(user, dispatch);
42 | localStorage.setItem("user", JSON.stringify(user));
43 | navigate("/");
44 | })
45 | .catch((error) => {
46 | // const errorCode = error.code;
47 | const errorMessage = error.message;
48 | toast.error(errorMessage, { autoClose: 15000 });
49 | });
50 | }
51 | };
52 | return (
53 |
54 |
58 | toast.warn("GitHub Signin is not available yet", {
59 | autoClose: 2000,
60 | icon: (
61 |
62 | ),
63 | toastId: "github",
64 | })
65 | }
66 | >
67 |
68 | Github
69 |
70 | AUTH({ provider: GOOGLE_PROVIDER })}
74 | >
75 |
76 | Google
77 |
78 |
79 | );
80 | };
81 |
82 | export const ImageBox = () => {
83 | return (
84 |
85 |
96 |
97 | );
98 | };
99 |
100 | export default ProviderAuth;
101 |
--------------------------------------------------------------------------------
/src/Pages/Home/index.tsx:
--------------------------------------------------------------------------------
1 | import { FruitsSection, MenuSection, ShowcaseBanner, } from "../../components"
2 |
3 | const Home = () => {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
15 | export default Home
--------------------------------------------------------------------------------
/src/Pages/Menu/index.tsx:
--------------------------------------------------------------------------------
1 | import { MenuSection } from "../../components";
2 |
3 | const Menu = () => {
4 | return (
5 |
6 |
7 |
8 |
9 | );
10 | }
11 |
12 | export default Menu;
--------------------------------------------------------------------------------
/src/Pages/Profile/index.tsx:
--------------------------------------------------------------------------------
1 | import { BiUser } from "react-icons/bi";
2 | import { BsPhone } from "react-icons/bs";
3 | import {
4 | MdOutlineDataSaverOn,
5 | MdDeleteOutline,
6 | } from "react-icons/md";
7 |
8 | import { motion } from "framer-motion";
9 | import { toast } from "react-toastify";
10 | import { useState } from "react";
11 | import { useStateValue } from "../../context/StateProvider";
12 | import { AssetUploader, Loader } from "../../components";
13 | import { updateUserData } from "../../utils/functions";
14 | import { firebaseRemoveUploadedImage } from "../../Firebase";
15 |
16 |
17 | const UpdateProfile = () => {
18 | const [{ user }, dispatch] = useStateValue();
19 | const [displayName, setDisplayName] = useState(user.displayName)
20 | // const [email, setEmail] = useState(user.email)
21 | const [photoURL, setPhotoURL] = useState(user.photoURL)
22 | const [loading, setLoading] = useState(false)
23 | const [phoneNumber, setPhoneNumber] = useState(user.phoneNumber)
24 | const [btnText, setBtnText] = useState("Save")
25 | const [loaderMessage, setLoadermessage] = useState("");
26 |
27 | const deleteImage = async () => {
28 | setLoadermessage("Removing Photo......");
29 | firebaseRemoveUploadedImage(photoURL, setPhotoURL, setLoading);
30 | const data = { ...user, photoURL: null };
31 | await updateUserData(data, dispatch, false);
32 | };
33 | const saveChanges = async () => {
34 | setBtnText("Saving....");
35 | if(displayName.lenth < 0 || phoneNumber.length !== 10)
36 | {
37 | toast.error("Fill out fields correctly")
38 | setBtnText("Save")
39 | }else{
40 | const data = {
41 | ...user,
42 | displayName,
43 | phoneNumber,
44 | photoURL,
45 | }
46 | await updateUserData(data, dispatch, true);
47 | setBtnText("Save");
48 | }
49 |
50 | };
51 |
52 | const updatePhotoUrl = async (newUrl: string) => {
53 | setPhotoURL(newUrl);
54 | const data = { ...user, photoURL: newUrl };
55 | await updateUserData(data, dispatch, false)
56 | }
57 |
58 | const validateNumber = (value: any) => {
59 | if (isNaN(value)) {
60 | toast.error("Please enter a valid phone number", { toastId: 123 });
61 | return "";
62 | }
63 | return value;
64 | };
65 |
66 |
67 |
68 | return (
69 |
70 |
71 |
72 |
73 | setDisplayName(e.target.value)}
81 | />
82 |
83 |
84 |
85 |
86 |
87 | setPhoneNumber(validateNumber(e.target.value))}
94 | />
95 |
96 |
97 |
98 | {
99 | loading ? (
100 |
101 | ):(
102 | <>
103 | {photoURL ? (
104 | <>
105 |
106 |
111 |
deleteImage()}
117 | >
118 |
119 |
120 |
121 | >
122 | ) : (
123 |
128 | )}
129 | >
130 | )
131 | }
132 |
133 |
134 |
135 | saveChanges()}
139 | >
140 | {btnText}
141 |
142 |
143 |
144 |
145 | );
146 | };
147 |
148 | export default UpdateProfile;
149 |
--------------------------------------------------------------------------------
/src/Pages/Services/index.tsx:
--------------------------------------------------------------------------------
1 | const Services = () => {
2 | return (
3 |
4 |
Services Page Cominig Up soon!!
5 |
6 | );
7 | }
8 |
9 | export default Services;
--------------------------------------------------------------------------------
/src/Pages/index.tsx:
--------------------------------------------------------------------------------
1 |
2 | export {default as Home } from './Home';
3 | export {default as Admin} from './Admin';
4 | export {default as Login} from './Auth/Login';
5 | export {default as Signup} from './Auth/Register';
6 | export {default as Profile} from './Profile'
7 | export {default as About} from './About';
8 | export {default as Services} from './Services';
9 | export {default as Menu} from './Menu';
--------------------------------------------------------------------------------
/src/components/Admin/AddFood/CategoriesSelector.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | export type FoodCategory = {
3 | id: number;
4 | name: string;
5 | urlParam: string;
6 | };
7 |
8 | export type FoodCategories = FoodCategory[];
9 |
10 | interface Props {
11 | categories: FoodCategories;
12 | action: any;
13 | selected: string;
14 | }
15 | const CategoriesSelector: React.FC = ({
16 | categories,
17 | action,
18 | selected,
19 | }) => {
20 | return (
21 | action(e.target.value)}>
22 |
23 | {selected? selected: "Select category"}
24 |
25 | {categories
26 | // .filter((cat) => cat.urlParam !== selected)
27 | .map((category, index) => (
28 |
29 | {category.name}
30 |
31 | ))}
32 |
33 | );
34 | };
35 |
36 | export default CategoriesSelector;
37 |
--------------------------------------------------------------------------------
/src/components/Admin/AddFood/index.tsx:
--------------------------------------------------------------------------------
1 | import { AssetUploader, Loader } from "../..";
2 | import { BiCategory, BiFoodMenu } from "react-icons/bi";
3 | import {
4 | MdDeleteOutline,
5 | MdOutlineDataSaverOn,
6 | MdOutlineFastfood,
7 | MdOutlineFoodBank,
8 | MdOutlineProductionQuantityLimits,
9 | } from "react-icons/md";
10 | import {
11 | firebaseFetchFoodItems,
12 | firebaseRemoveUploadedImage,
13 | firebaseSaveProduct,
14 | } from "../../../Firebase";
15 |
16 | import { Categories } from "../../../utils/categories";
17 | import CategoriesSelector from "./CategoriesSelector";
18 | import { GiTakeMyMoney } from "react-icons/gi";
19 | import { motion } from "framer-motion";
20 | import { toast } from "react-toastify";
21 | import { useState } from "react";
22 | import { useStateValue } from "../../../context/StateProvider";
23 | import { fetchFoodData } from "../../../utils/functions";
24 |
25 | const AddFood = () => {
26 | const [title, setTitle] = useState("");
27 | const [calories, setCalories] = useState("");
28 | const [price, setPrice] = useState("");
29 | const [image, setImage] = useState(null);
30 | const [category, setCategory] = useState("");
31 | const [loading, setLoading] = useState(false);
32 | const [quantity, setQuantity] = useState("");
33 | const [description, setDescription] = useState("");
34 | const [loaderMessage, setLoadermessage] = useState("");
35 | const [{ foodItems }, dispatch] = useStateValue();
36 |
37 | const deleteImage = () => {
38 | setLoadermessage("Removing Photo......");
39 | firebaseRemoveUploadedImage(image, setImage, setLoading);
40 | };
41 | const saveItem = () => {
42 | setLoadermessage(`Saving Product ${title}.`);
43 | setLoading(true);
44 | try {
45 | if (!title || !calories || !price || !image || !category) {
46 | toast.error("Please fill all fields before saving product 🤗");
47 | setLoading(false);
48 | return;
49 | } else {
50 | const data = {
51 | id: Date.now(),
52 | title: title,
53 | calories: calories,
54 | category: category,
55 | description: description,
56 | price: price,
57 | imageURL: image,
58 | qty: quantity,
59 | };
60 | toast
61 | .promise(firebaseSaveProduct(data), {
62 | pending: "Saving Product...",
63 | success: "Product saved successfully",
64 | error: "Error saving product, Please try again🤗",
65 | })
66 | .then(() => {
67 | clearForm();
68 | setLoading(false);
69 | fetchFoodData(dispatch);
70 | })
71 | .catch((error) => {
72 | console.log(error);
73 | });
74 | setLoadermessage("");
75 | setLoading(false);
76 | }
77 | } catch (error) {
78 | console.log(error);
79 | toast.error("Error whilesaving product");
80 | }
81 | };
82 | const clearForm = () => {
83 | setTitle("");
84 | setCalories("");
85 | setPrice("");
86 | setImage(null);
87 | // setCategory("");
88 | setQuantity("");
89 | setDescription("");
90 | };
91 |
92 | const validateNumber = (value: any) => {
93 | if (isNaN(value)) {
94 | toast.error("Please enter a valid number", { toastId: 123 });
95 | return "";
96 | }
97 | return value;
98 | };
99 |
100 |
101 |
102 | return (
103 |
104 |
105 |
106 |
107 | setTitle(e.target.value)}
115 | />
116 |
117 |
118 |
119 |
120 |
121 |
126 |
127 |
128 |
129 | setQuantity(validateNumber(e.target.value))}
137 | />
138 |
139 |
140 |
141 | {loading ? (
142 |
143 | ) : (
144 | <>
145 | {image ? (
146 | <>
147 |
148 |
153 |
deleteImage()}
159 | >
160 |
161 |
162 |
163 | >
164 | ) : (
165 |
170 | )}
171 | >
172 | )}
173 |
174 |
200 |
201 |
202 | setDescription(e.target.value)}
210 | />
211 |
212 |
213 |
214 | saveItem()}
218 | >
219 | Save
220 |
221 |
222 |
223 |
224 | );
225 | };
226 |
227 | export default AddFood;
228 |
--------------------------------------------------------------------------------
/src/components/Admin/Content.tsx:
--------------------------------------------------------------------------------
1 | import { FaShopify } from "react-icons/fa";
2 | import { Link } from "react-router-dom";
3 | import { useStateValue } from "../../context/StateProvider";
4 | import { ToggleAdminMode } from "../../utils/functions";
5 |
6 | const Content = ({ pageTitle, Element }: { pageTitle: string, Element:JSX.Element }) => {
7 | const [{}, dispatch] = useStateValue();
8 | return (
9 |
10 |
11 | {pageTitle}
12 |
13 | {/* home button */}
14 | ToggleAdminMode(dispatch, false)}>
15 |
16 |
17 | store
18 |
19 |
20 |
21 |
{Element}
22 |
23 |
24 | );
25 | };
26 | export default Content;
--------------------------------------------------------------------------------
/src/components/Admin/Dashboard/CategoryCards.tsx:
--------------------------------------------------------------------------------
1 | import { Categories } from "../../../utils/categories"
2 | const CategoryCards = () => {
3 | let category = Categories[Math.floor(Math.random() * Categories.length)];
4 | return (
5 |
6 | {/* Catgory card */}
7 |
8 |
9 | )
10 | }
11 |
12 | export default CategoryCards
--------------------------------------------------------------------------------
/src/components/Admin/Dashboard/index.tsx:
--------------------------------------------------------------------------------
1 | import CategoryCards from "./CategoryCards";
2 |
3 | const Dashboard = () => {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | );
14 | };
15 |
16 | export default Dashboard;
17 |
--------------------------------------------------------------------------------
/src/components/Admin/Menu/index.tsx:
--------------------------------------------------------------------------------
1 | import { FaSearch } from "react-icons/fa";
2 | import { FoodItem } from "../../../../types";
3 | import { SingleFoodItem } from "../../FoodItem";
4 | import React, { useState } from "react";
5 | import { useStateValue } from "../../../context/StateProvider";
6 |
7 | const Menu = () => {
8 | const [{ foodItems }, dispatch] = useStateValue();
9 | const [query, setQuery] = useState("");
10 | const [filteredFoodItems, setFilteredFoodItems] = useState(foodItems);
11 |
12 | const filterFood = () => {
13 | if(query.length === 0) {
14 | setFilteredFoodItems(foodItems);
15 | }else{
16 | const filteredFoodItems = foodItems.filter((foodItem:FoodItem) => foodItem.title.toLowerCase().includes(query.toLowerCase()));
17 | setFilteredFoodItems(filteredFoodItems);
18 | }
19 | }
20 | const searchFood = (e: React.ChangeEvent) => {
21 | setQuery(e.target.value);
22 | filterFood();
23 | }
24 | return (
25 |
26 | {/* search bar */}
27 |
28 | searchFood(e)}
34 | />
35 | {/* search button */}
36 |
37 |
38 |
39 |
40 |
41 | {
42 | filteredFoodItems.map((item: FoodItem) => (
43 |
44 | ))
45 | }
46 |
47 |
48 | );
49 | };
50 |
51 | export default Menu;
52 |
--------------------------------------------------------------------------------
/src/components/Admin/Sidenav.tsx:
--------------------------------------------------------------------------------
1 | import { Logo } from "../Assets";
2 | import SidenavMenu from "./SidenavMenu";
3 | import { Link, useNavigate } from "react-router-dom";
4 | import { AiFillLock } from "react-icons/ai";
5 | import { useStateValue } from "../../context/StateProvider";
6 | import { logout, ToggleAdminMode } from "../../utils/functions";
7 | import { motion } from "framer-motion";
8 | const Sidenav = ({
9 | activePage,
10 | setActivePage,
11 | setPageContent,
12 | }: {
13 | activePage: string;
14 | setActivePage: any;
15 | setPageContent: any;
16 | }) => {
17 | return (
18 |
19 |
20 |
25 |
26 |
27 | );
28 | };
29 |
30 | const SidenavHeader = () => {
31 | const [{ adminMode }, dispatch] = useStateValue();
32 | return (
33 |
40 | ToggleAdminMode(dispatch, false)}
42 | to={"/"}
43 | className="flex items-center ml-1 pb-8 w-full justify-center"
44 | >
45 |
46 |
47 | Bentilzone
48 |
49 |
50 |
51 | );
52 | };
53 |
54 | const SidenavFooter = () => {
55 | const [{ user }, dispatch] = useStateValue();
56 | const navigate = useNavigate();
57 | return (
58 | logout(user, dispatch, navigate)}
64 | className="flex items-center justify-center mt-auto px-3 gap-3 text-orange-50 cursor-pointer opacity-70 hover:opacity-100"
65 | >
66 |
67 | Logout
68 |
69 | );
70 | };
71 |
72 | export default Sidenav;
73 |
--------------------------------------------------------------------------------
/src/components/Admin/SidenavMenu.tsx:
--------------------------------------------------------------------------------
1 | import { AiFillDashboard } from "react-icons/ai";
2 | import { FiUsers } from "react-icons/fi";
3 | import {
4 | MdAddModerator,
5 | MdOutlineFavoriteBorder,
6 | MdRestaurantMenu,
7 | } from "react-icons/md";
8 | import { motion } from "framer-motion";
9 | import { FaCogs } from "react-icons/fa";
10 | import AddFood from "./AddFood";
11 | import Dashboard from "./Dashboard";
12 | import Users from "./Users";
13 | import Menu from "./Menu";
14 | import { useStateValue } from "../../context/StateProvider";
15 |
16 | const SidenavMenu = ({
17 | activePage,
18 | setActivePage,
19 | setPageContent,
20 | }: {
21 | activePage: string;
22 | setActivePage: any;
23 | setPageContent: any;
24 | }) => (
25 |
31 | }
34 | title="Dashboard"
35 | setActivePage={setActivePage}
36 | setPageContent={setPageContent}
37 | pageContent={ }
38 | />
39 | }
42 | title="Add Food"
43 | setActivePage={setActivePage}
44 | setPageContent={setPageContent}
45 | pageContent={ }
46 | />
47 | }
50 | title="Menu"
51 | setActivePage={setActivePage}
52 | setPageContent={setPageContent}
53 | pageContent={ }
54 | />
55 | }
58 | title="Orders"
59 | setActivePage={setActivePage}
60 | setPageContent={setPageContent}
61 | pageContent={
62 | Orders
63 | }
64 | />
65 | }
68 | title="Users"
69 | setActivePage={setActivePage}
70 | setPageContent={setPageContent}
71 | pageContent={ }
72 | />
73 | }
76 | title="Settings"
77 | setActivePage={setActivePage}
78 | setPageContent={setPageContent}
79 | pageContent={
80 | Settings
81 | }
82 | />
83 |
84 | );
85 |
86 | const NavItem = ({
87 | activePage,
88 | svgIcon,
89 | title,
90 | setActivePage,
91 | setPageContent,
92 | pageContent,
93 | }: {
94 | activePage: string;
95 | setActivePage: any;
96 | svgIcon: any;
97 | title: string;
98 | setPageContent: any;
99 | pageContent: JSX.Element;
100 | }) => {
101 | const handleClick = () => {
102 | setActivePage(title);
103 | setPageContent(pageContent);
104 | };
105 | const [{users, foodItems}, dispatch] = useStateValue()
106 | return (
107 |
114 | {svgIcon}
115 | {title}
116 | {
117 | (title === "Menu" || title === "Users") && (
118 |
119 |
120 | {
121 | title === "Menu"? foodItems.length:users.length
122 | }
123 |
124 |
125 | )
126 | }
127 |
128 |
129 | );
130 | };
131 | export default SidenavMenu;
132 |
--------------------------------------------------------------------------------
/src/components/Admin/Users/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { FaSearch } from "react-icons/fa";
3 | import { useStateValue } from "../../../context/StateProvider";
4 | import User from "./user";
5 |
6 |
7 | const Users = () => {
8 | const [{ users }, dispatch] = useStateValue();
9 | const [query, setQuery] = useState("");
10 | const [filteredUsers, setFilteredUsers] = useState(users);
11 |
12 | const filterUsers = () => {
13 | if(query.length === 0) {
14 | setFilteredUsers(users);
15 | }else{
16 | const filter = users.filter((item:any) => item.displayName.toLowerCase().includes(query.toLowerCase()));
17 | setFilteredUsers(filter);
18 | }
19 | }
20 | const searchUsers = (e: React.ChangeEvent) => {
21 | setQuery(e.target.value);
22 | filterUsers();
23 | }
24 | return (
25 |
26 | {/* search bar */}
27 |
28 | searchUsers(e)}
34 | />
35 | {/* search button */}
36 |
37 |
38 |
39 |
40 |
41 | {/* dasboard statistics and counts */}
42 |
43 | {
44 | filteredUsers.map((user:any) => (
45 |
46 | ))
47 | }
48 |
49 |
50 | );
51 | };
52 |
53 | export default Users;
54 |
55 |
56 |
--------------------------------------------------------------------------------
/src/components/Admin/Users/user.tsx:
--------------------------------------------------------------------------------
1 | import { MdDeleteForever, MdEmail } from "react-icons/md";
2 | import { GiShieldDisabled } from "react-icons/gi";
3 | import { Avatar } from "../../Assets";
4 | import { FcGoogle } from "react-icons/fc";
5 | import {motion} from "framer-motion";
6 | const User = ({item}: {item:any}) => {
7 | return (
8 |
9 |
10 |
16 |
17 |
18 | {item?.displayName || 'User'}
19 |
20 | {item?.email}
21 | {item?.phoneNumber}
22 |
23 |
24 | {
25 | item?.providerId !== 'google.com' ? :
26 | } {item.providerId}
27 |
28 |
29 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 | )
45 | }
46 |
47 | export default User
--------------------------------------------------------------------------------
/src/components/Assets/index.tsx:
--------------------------------------------------------------------------------
1 | import AvatarI from "../../img/avatar.png";
2 | import Cheff1I from "../../img/chef1.png";
3 | import CheffI from "../../img/cheff.png";
4 | import LogoI from "../../img/chef1.png";
5 | import BikeDeliveryI from "../../img/delivery.png";
6 | import HeroBgI from "../../img/hero-bg.png";
7 | import EmptyCartI from "../../img/emptyCart.svg";
8 | import NotFoundI from "../../img/NotFound.svg";
9 | import Visa from "../../img/visa.png";
10 | import Momo from "../../img/momo.png";
11 | // Showcase Banner Static Assets
12 | import IcreamI from "../../img/i1.png";
13 | import StrawberryI from "../../img/f5.png";
14 | import ChickenI from "../../img/c3.png";
15 | import FishI from "../../img/fi3.png";
16 |
17 |
18 |
19 | // Exports
20 | export const Logo = LogoI
21 | export const Avatar = AvatarI
22 | export const Cheff = CheffI
23 | export const Cheff1 = Cheff1I
24 | export const BikeDelivery = BikeDeliveryI
25 | export const HeroBg = HeroBgI
26 | export const Icecream = IcreamI
27 | export const Strawberry = StrawberryI
28 | export const Chicken = ChickenI
29 | export const Fish = FishI
30 | export const EmptyCartImg = EmptyCartI
31 | export const NotFoundImg = NotFoundI
32 | export const CreditCard = Visa
33 | export const MOMO = Momo
--------------------------------------------------------------------------------
/src/components/Cart/Body.tsx:
--------------------------------------------------------------------------------
1 | import CartItem from './Item'
2 | import CartTotal from './CartTotal'
3 | import { useStateValue } from '../../context/StateProvider';
4 |
5 | const CartBody = ({action}:{action:any}) => {
6 | const [{cartItems}] = useStateValue();
7 | return (
8 |
9 |
10 | {
11 | cartItems && cartItems.length > 0 && cartItems.map((item:any, index:number) => {
12 | return
13 | } )
14 | }
15 |
16 |
17 |
18 | )
19 | }
20 |
21 | export default CartBody
--------------------------------------------------------------------------------
/src/components/Cart/CartTotal.tsx:
--------------------------------------------------------------------------------
1 | import {motion} from 'framer-motion'
2 | import { useStateValue } from '../../context/StateProvider';
3 |
4 | const CartTotal = ({checkoutState}: {checkoutState:any}) => {
5 | const [{cartTotal}] = useStateValue();
6 | return (
7 |
8 |
9 |
Sub Total
10 |
-
11 |
₵ {cartTotal}
12 |
13 |
14 |
Delivery
15 |
-
16 |
₵ {0.00}
17 |
18 |
19 |
20 |
Total
21 |
-
22 |
₵ {cartTotal}
23 |
24 |
checkoutState(true)} whileTap={{scale:0.8}} className='w-full p-2 rounded-full bg-gradient-to-tr from-orange-400 to-orange-600 text-gray-50 text-lg my-2 hover:shadow-lg'>
25 | Checkout ₵{cartTotal}
26 |
27 |
28 |
29 | )
30 | }
31 |
32 | export default CartTotal
--------------------------------------------------------------------------------
/src/components/Cart/Header.tsx:
--------------------------------------------------------------------------------
1 | import { BiRefresh } from "react-icons/bi";
2 | import { MdLogin, MdOutlineKeyboardBackspace } from "react-icons/md";
3 | import { motion } from "framer-motion";
4 | import { MdShoppingBasket } from "react-icons/md";
5 | import { useStateValue } from "../../context/StateProvider";
6 | import { emptyCart, hideCart } from "../../utils/functions";
7 | import { Link } from "react-router-dom";
8 | const CartHeader = () => {
9 | const [{ user, cartItems, foodItems }, dispatch] = useStateValue();
10 |
11 | return (
12 |
13 |
hideCart(dispatch)}>
14 |
15 |
16 |
17 |
18 | Cart
19 |
20 |
21 |
22 | {user ? (
23 |
emptyCart(cartItems, foodItems, dispatch)}
27 | className="flex items-center justify-center gap-2 p-1 px-2 my-2 bg-cardOverlay rounded-md hover:shadow-sm text-textColor text-base"
28 | >
29 | clear
30 |
31 | ) : (
32 |
hideCart(dispatch)}>
33 |
38 | Login to cart
39 |
40 |
41 | )}
42 |
43 | );
44 | };
45 |
46 | export default CartHeader;
47 |
--------------------------------------------------------------------------------
/src/components/Cart/Item.tsx:
--------------------------------------------------------------------------------
1 | import { BiMinus, BiPlus } from "react-icons/bi";
2 |
3 | import { MdDelete } from "react-icons/md";
4 | import { motion } from "framer-motion";
5 | import { cartItem } from "../../../types";
6 | import { deleteCartItem, getFoodyById, updateCartItemQty } from "../../utils/functions";
7 | import { useStateValue } from "../../context/StateProvider";
8 |
9 | const CartItem = ({ item }: { item: cartItem }) => {
10 | const [{ foodItems, cartItems }, dispatch] = useStateValue();
11 | const { id, fid, qty } = item;
12 | const foodItem = getFoodyById(foodItems, fid);
13 |
14 | return (
15 |
16 |
17 |
22 |
23 |
24 |
{foodItem?.title}
25 |
26 | ₵ {foodItem?.price}
27 |
28 |
29 |
30 |
31 |
32 |
1 ? () => updateCartItemQty(cartItems, foodItems, item, dispatch, -1) : () => {}}
36 | >
37 |
38 |
39 |
40 | {qty}
41 |
42 |
updateCartItemQty(cartItems, foodItems, item, dispatch, 1)}
46 | >
47 |
48 |
49 |
50 |
51 |
deleteCartItem(cartItems, foodItems, item, dispatch)}
55 | >
56 |
57 |
58 |
59 | );
60 | };
61 |
62 | export default CartItem;
63 |
--------------------------------------------------------------------------------
/src/components/Cart/index.tsx:
--------------------------------------------------------------------------------
1 | import { useStateValue } from "../../context/StateProvider";
2 | import CartBody from "./Body";
3 | import CarttHeader from "./Header";
4 | import { motion } from "framer-motion";
5 | import EmptyCart from "../EmptyCart";
6 | import NotFound from "../NotFound";
7 | import Checkout from "../Checkout";
8 | import { useState } from "react";
9 | const Cart = () => {
10 | const [{ cartItems }] = useStateValue();
11 | const [checkoutOpen, setCheckoutOpen] = useState(false);
12 | return (
13 | <>
14 | {checkoutOpen ? (
15 |
16 | ) : (
17 | <>
18 |
24 |
25 | {cartItems && cartItems.length > 0 ? (
26 |
27 | ) : (
28 |
29 |
30 |
31 | )}
32 |
33 | {!cartItems && }
34 | >
35 | )}
36 | >
37 | );
38 | };
39 |
40 | export default Cart;
41 |
--------------------------------------------------------------------------------
/src/components/Checkout/Header.tsx:
--------------------------------------------------------------------------------
1 | import { MdOutlineKeyboardBackspace } from "react-icons/md";
2 | import { motion } from "framer-motion";
3 | import { RiSecurePaymentLine } from "react-icons/ri";
4 | import { BsShieldLock } from "react-icons/bs";
5 |
6 | const Header = ({ action }: { action: any }) => {
7 | return (
8 |
9 |
action(false)}>
10 |
11 |
12 |
17 | Secured Payment
18 |
19 |
24 |
25 |
26 |
27 |
28 | );
29 | };
30 |
31 | export default Header;
32 |
--------------------------------------------------------------------------------
/src/components/Checkout/Selector.tsx:
--------------------------------------------------------------------------------
1 | import { useStateValue } from "../../context/StateProvider";
2 | import { CreditCard, MOMO } from "../Assets";
3 | const Selector = () => {
4 | const [{paymentMethod}, dispatch] = useStateValue();
5 | const setPaymentMethod = (method:string) => {
6 | dispatch({
7 | type: "SET_PAYMENT_METHOD",
8 | paymentMethod: method,
9 | });
10 | }
11 | return (
12 |
54 | );
55 | };
56 |
57 | export default Selector;
58 |
--------------------------------------------------------------------------------
/src/components/Checkout/body.tsx:
--------------------------------------------------------------------------------
1 | import { BiLock } from "react-icons/bi";
2 | import CardForm from "./forms/Card";
3 | import CheckoutFooter from "./footer";
4 | import MomoForm from "./forms/Momo";
5 | import Selector from "./Selector";
6 | import { motion } from "framer-motion";
7 | import { useStateValue } from "../../context/StateProvider";
8 | import { emptyCart } from "../../utils/functions";
9 | import { useState } from "react";
10 | import { ImSpinner3 } from "react-icons/im";
11 | import { toast } from "react-toastify";
12 |
13 | const Body = ({ action }: { action: any }) => {
14 | const [{ checkoutData, cartTotal, paymentMethod, cartItems, foodItems }, dispatch] =
15 | useStateValue();
16 | const [loading, setLoading] = useState(false);
17 |
18 | const completePayment = () => {
19 | if(!checkoutData) return toast.error("Complete payment info")
20 | setLoading(true);
21 | setTimeout(async () => {
22 | setLoading(false);
23 | await emptyCart(cartItems, foodItems, dispatch);
24 | action(false);
25 | toast.success("Order completed successfuly with payment. Thank you for your patronage.", {
26 | position: "top-center",
27 | autoClose: 6000
28 | });
29 | }, 3000);
30 | };
31 | return (
32 |
33 | {/* Payment Selectors */}
34 |
35 | {/* payment form */}
36 |
37 | {paymentMethod === "mobile_money" ?
:
}
38 |
39 |
40 | Amount Due:{" "}
41 | {`GH₵${cartTotal}`} {" "}
42 |
43 |
44 | {/* pay now button */}
45 |
46 |
47 |
52 | {!loading && }
53 | {!loading ? (
54 | "PAY NOW"
55 | ) : (
56 |
57 | )}
58 |
59 |
60 |
61 |
62 |
63 | );
64 | };
65 |
66 | export default Body;
67 |
--------------------------------------------------------------------------------
/src/components/Checkout/footer.tsx:
--------------------------------------------------------------------------------
1 | import { BsShieldLock } from "react-icons/bs";
2 |
3 | const CheckoutFooter = () => {
4 | return (
5 |
6 |
7 |
8 |
9 | Secured by BENSTACK
10 |
11 |
12 |
13 | );
14 | };
15 |
16 | export default CheckoutFooter;
17 |
--------------------------------------------------------------------------------
/src/components/Checkout/forms/Card.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const CardForm = () => {
4 | return (
5 |
6 |
7 |
11 | Name on Card
12 |
13 |
20 |
21 |
22 |
26 | Card Number
27 |
28 |
35 |
36 |
68 |
69 | )
70 | }
71 |
72 | export default CardForm
--------------------------------------------------------------------------------
/src/components/Checkout/forms/Momo.tsx:
--------------------------------------------------------------------------------
1 | import { useStateValue } from "../../../context/StateProvider";
2 |
3 | const MomoForm = () => {
4 | const [{checkoutData}, dispatch] = useStateValue();
5 | const updateCheckoutData = (key:string, val:string) => {
6 | dispatch({
7 | type: "UPDATE_CHECKOUT_DATA",
8 | checkoutData: {
9 | ...checkoutData,
10 | [key]:val
11 | }
12 | });
13 | }
14 | return (
15 |
16 |
17 |
21 | Select Provider
22 |
23 | updateCheckoutData("provider", e.target.value)}
27 | >
28 | Select Provider
29 | MTN Mobile Money
30 | Airtel Tigo Money
31 | Vodafone Cash
32 |
33 |
34 |
35 |
36 |
40 | Account Name
41 |
42 |
49 |
50 |
51 |
55 | MOMO Number
56 |
57 | updateCheckoutData("phone", e.target.value)}
64 | />
65 |
66 |
67 | )
68 | }
69 |
70 | export default MomoForm
--------------------------------------------------------------------------------
/src/components/Checkout/index.tsx:
--------------------------------------------------------------------------------
1 | import { motion } from "framer-motion";
2 | import Body from "./body";
3 | import Header from "./Header";
4 | const Checkout = ({handler}: {handler: any}) => {
5 | return (
6 |
12 |
13 |
14 |
15 | );
16 | };
17 |
18 | export default Checkout;
19 |
--------------------------------------------------------------------------------
/src/components/Contact/form.tsx:
--------------------------------------------------------------------------------
1 | import {EmptyCartImg} from '../Assets'
2 | import { toast } from 'react-toastify';
3 | import { useState } from 'react';
4 |
5 | const Form = () => {
6 | const [name, setName] = useState('')
7 | const [email, setEmail] = useState('')
8 | const [message, setMessage] = useState('')
9 | const [subject, setSubject] = useState('')
10 |
11 | const submitForm = (e:any) => {
12 | e.preventDefault()
13 | return toast.info(`${name} Form handling is not implemented yet`, {
14 | position: 'top-left',
15 | autoClose: 3000,
16 | toastId: 'form'
17 | })
18 | }
19 | return (
20 |
77 | );
78 | };
79 |
80 | export default Form;
81 |
--------------------------------------------------------------------------------
/src/components/Contact/header.tsx:
--------------------------------------------------------------------------------
1 | import { MdOutlineKeyboardBackspace, MdOutlineMessage } from "react-icons/md";
2 |
3 | import { hideContactform } from "../../utils/functions";
4 | import { motion } from "framer-motion";
5 | import { useStateValue } from "../../context/StateProvider";
6 |
7 | const ContactHeader = () => {
8 | const [{}, dispatch] = useStateValue();
9 | return (
10 |
11 | hideContactform(dispatch)}
14 | >
15 |
16 |
17 |
18 |
23 |
24 | CONTACT US
25 |
26 |
27 | );
28 | };
29 |
30 | export default ContactHeader;
31 |
--------------------------------------------------------------------------------
/src/components/Contact/index.tsx:
--------------------------------------------------------------------------------
1 | import ContactHeader from "./header";
2 | import Form from "./form";
3 | import { motion } from "framer-motion";
4 | const Contact = () => {
5 | return (
6 |
12 |
13 |
14 |
15 | );
16 | };
17 |
18 | export default Contact;
19 |
--------------------------------------------------------------------------------
/src/components/Container/index.tsx:
--------------------------------------------------------------------------------
1 | import { useLayoutEffect, useRef } from "react";
2 |
3 | import { FoodItem } from "../../../types";
4 | import Loader from "../Loader";
5 | import { SingleFoodItem } from "../FoodItem";
6 | import { motion } from "framer-motion";
7 | import NotFound from "../NotFound";
8 | import { isAdmin } from "../../utils/functions";
9 | import { useStateValue } from "../../context/StateProvider";
10 |
11 | const Container = ({scrollOffset, col, items, className }: {scrollOffset:number, col?: boolean; items: FoodItem[], className?:string }) => {
12 | const containerRef = useRef(null);
13 | useLayoutEffect(() => {
14 | if(null !== containerRef.current){
15 | containerRef.current.scrollLeft += scrollOffset
16 | }
17 | }, [scrollOffset]);
18 | const [{user}, dispatch] = useStateValue();
19 | return (
20 |
29 | {items && items.map((item: FoodItem) => (
30 |
31 | ))}
32 | {
33 | !items && (!col ? ( ): ( ))
34 | }
35 | {
36 | items && items.length <= 0 && ( )
37 | }
38 |
39 | );
40 | };
41 |
42 | export default Container;
43 |
--------------------------------------------------------------------------------
/src/components/EmptyCart/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { EmptyCartImg } from '../Assets'
3 |
4 | const EmptyCart = () => {
5 | return (
6 |
7 |
8 |
Cart is empty
9 |
10 | )
11 | }
12 |
13 | export default EmptyCart
--------------------------------------------------------------------------------
/src/components/Filters/Button.tsx:
--------------------------------------------------------------------------------
1 | import { motion } from "framer-motion";
2 | import { MdOutlineFastfood } from "react-icons/md";
3 | import { FoodCategory } from "../../../types";
4 | const Button = ({
5 | category,
6 | filter,
7 | setFilter,
8 | }: {
9 | category: FoodCategory;
10 | filter: string;
11 | setFilter: any;
12 | }) => {
13 | return (
14 | setFilter(category.urlParam)}
16 | // whileHover={{ scale: 1.1 }}
17 | whileTap={{ scale: 1.1 }}
18 | className={`group ${
19 | category.urlParam === filter
20 | ? "hover:bg-btnOverlay bg-cartNumBg"
21 | : "bg-btnOverlay hover:bg-cartNumBg"
22 | } w-24 min-w-[6rem] h-28 cursor-pointer rounded-lg drop-shadow-xl flex flex-col gap-3 items-center justify-center duration-150 transition-all ease-out`}
23 | >
24 |
31 | {/* */}
34 |
41 | {category.icon || }
42 |
43 |
44 |
51 | {category.name}
52 |
53 |
54 | );
55 | };
56 |
57 | export default Button;
58 |
--------------------------------------------------------------------------------
/src/components/Filters/index.tsx:
--------------------------------------------------------------------------------
1 | import { motion } from "framer-motion";
2 | import Button from "./Button";
3 | import { Categories } from "../../utils/categories";
4 | import { FoodCategory } from "../../../types";
5 | import { BiRestaurant } from "react-icons/bi";
6 |
7 | const Filters = ({filter, setFilter}: {filter:string, setFilter: any}) => {
8 |
9 | return (
10 |
16 | }} filter = {filter} setFilter = {setFilter} />
17 | {
18 | Categories.map((category: FoodCategory) =>{
19 | return
20 | })
21 | }
22 |
23 |
24 | );
25 | };
26 |
27 | export default Filters;
28 |
--------------------------------------------------------------------------------
/src/components/FoodItem/action.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useStateValue } from "../../context/StateProvider";
3 | import { motion } from "framer-motion";
4 | import { addToCart, deleteFood } from "../../utils/functions";
5 | import { MdAddShoppingCart, MdDeleteForever } from "react-icons/md";
6 | import { BiEditAlt } from "react-icons/bi";
7 | import { FoodItem } from "../../../types";
8 | const Action = ({ food, admin }: { food: FoodItem; admin?: boolean }) => {
9 | const [{ cartItems, foodItems, user }, dispatch] = useStateValue();
10 | return (
11 |
12 | {admin ? (
13 | <>
14 |
20 |
21 |
22 | deleteFood(food, foodItems, dispatch)}
27 | title="Delete"
28 | >
29 |
30 |
31 | >
32 | ) : (
33 | addToCart(cartItems, foodItems, user, food.id, dispatch)}
38 | title="Add to cart"
39 | >
40 |
41 |
42 | )}
43 |
44 | );
45 | };
46 |
47 | export default Action;
48 |
--------------------------------------------------------------------------------
/src/components/FoodItem/index.tsx:
--------------------------------------------------------------------------------
1 | import { FoodItem } from "../../../types";
2 | import { motion } from "framer-motion";
3 | import Action from "./action";
4 | export const SingleFoodItem = ({
5 | item,
6 | col,
7 | admin
8 | }: {
9 | item: FoodItem;
10 | col?: boolean;
11 | admin?:boolean
12 | }) => {
13 | const { id, title, price, calories, imageURL, description } = item;
14 |
15 | return (
16 |
24 |
34 |
35 |
{title}
36 |
{description}
37 | {admin && (
{calories} calories
)}
38 |
39 |
40 | ₵ {price}
41 |
42 |
43 |
44 |
45 | );
46 | };
47 |
--------------------------------------------------------------------------------
/src/components/Footer/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import { Logo } from "../Assets";
4 | import {
5 | BsGithub,
6 | BsLinkedin,
7 | BsTwitter,
8 | BsInstagram,
9 | BsFacebook,
10 | BsDribbble,
11 | } from "react-icons/bs";
12 | import { motion } from "framer-motion";
13 | const Footer = () => {
14 | return (
15 |
94 | );
95 | };
96 |
97 | export default Footer;
98 |
--------------------------------------------------------------------------------
/src/components/Header/DropDown.tsx:
--------------------------------------------------------------------------------
1 | import { motion } from "framer-motion";
2 | import { FaUserCog } from "react-icons/fa";
3 | import { MdLogout } from "react-icons/md";
4 | import { RiAdminLine } from "react-icons/ri";
5 | import { Link, useNavigate } from "react-router-dom";
6 | import { useStateValue } from "../../context/StateProvider";
7 | import { isAdmin, logout, ToggleAdminMode } from "../../utils/functions";
8 |
9 | const DropDown = ({ user }: { user: any;}) => {
10 | const navigate = useNavigate();
11 | const [{}, dispatch] = useStateValue();
12 |
13 | return (
14 |
20 |
21 | {user?.displayName || user?.email}
22 |
23 | {isAdmin(user) && (
24 | ToggleAdminMode(dispatch, true)}
28 | >
29 | Administrator
30 |
31 |
32 | )}
33 |
34 | Profile
35 |
36 | logout(user, dispatch, navigate)}
39 | >
40 | Logout
41 |
42 |
43 |
44 | );
45 | };
46 |
47 | export default DropDown;
48 |
--------------------------------------------------------------------------------
/src/components/Header/LoginAction.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from "react-router-dom"
2 | import { MdLogin } from "react-icons/md"
3 | import { motion } from "framer-motion"
4 |
5 | const LoginAction = ({text, mobile}:{text?:string, mobile?:boolean}) => {
6 | return (
7 |
8 |
14 |
15 | {text && {text}
}
16 |
17 |
18 | )
19 | }
20 |
21 | export default LoginAction
--------------------------------------------------------------------------------
/src/components/Header/Navigations.tsx:
--------------------------------------------------------------------------------
1 | // import React from 'react'
2 | import { Link } from "react-router-dom";
3 | import { MdShoppingBasket } from "react-icons/md";
4 | import { motion } from "framer-motion";
5 | import { useStateValue } from "../../context/StateProvider";
6 |
7 | const Navigations = ({ direction }: { direction?: string }) => {
8 | const [{ showContactForm, cartItems }, dispatch] = useStateValue();
9 | const handleToggleCart = () => {
10 | dispatch({
11 | type: "TOGGLE_CART",
12 | showCart: true,
13 | });
14 | };
15 | const handleToggleContact = () => {
16 | dispatch({
17 | type: "TOGGLE_CONTACT_FORM",
18 | showContactForm: !showContactForm,
19 | });
20 | }
21 | return (
22 |
23 |
29 |
33 | Home
34 |
35 |
39 | Menu
40 |
41 |
45 | Services
46 |
47 |
51 | About us
52 |
53 |
58 | Contact us
59 |
60 |
61 |
62 |
68 |
69 | {cartItems && (
70 |
71 |
72 | {cartItems.length}
73 |
74 |
75 | )}
76 |
77 |
78 | );
79 | };
80 |
81 | export default Navigations;
82 |
--------------------------------------------------------------------------------
/src/components/Header/index.tsx:
--------------------------------------------------------------------------------
1 | import { Avatar, Logo } from "../Assets";
2 | import { Link } from "react-router-dom";
3 |
4 | import DropDown from "./DropDown";
5 | import { HiOutlineMenuAlt2 } from "react-icons/hi";
6 | import LoginAction from "./LoginAction";
7 | import MobileNav from "./mobile-nav";
8 | import Navigations from "./Navigations";
9 | import { RiArrowDropDownLine } from "react-icons/ri";
10 | import { motion } from "framer-motion";
11 | import { useState } from "react";
12 | import { useStateValue } from "../../context/StateProvider";
13 | const Header = () => {
14 | //
15 | // const firebaseAuth = getAuth(app);
16 | const [{ user }, dispatch] = useStateValue();
17 | const [isOpen, setIsOpen] = useState(false);
18 | const [isOpenMobileNav, setIsOpenMobileNav] = useState(false);
19 |
20 |
21 | return (
22 |
120 | );
121 | };
122 |
123 | export default Header;
124 |
--------------------------------------------------------------------------------
/src/components/Header/mobile-nav.tsx:
--------------------------------------------------------------------------------
1 | // import React from 'react'
2 |
3 | import { MdOutlineRestaurantMenu, MdShoppingBasket } from "react-icons/md";
4 |
5 | import { Link } from "react-router-dom";
6 | import { Logo } from "../Assets";
7 | import { motion } from "framer-motion";
8 | import { useStateValue } from "../../context/StateProvider";
9 |
10 | const MobileNav = ({
11 | isOpen,
12 | setIsOpen,
13 | }: {
14 | isOpen: boolean;
15 | setIsOpen: any;
16 | }) => {
17 | const [{ showContactForm, showCart, cartItems }, dispatch] = useStateValue();
18 | const handleToggleCart = () => {
19 | dispatch({
20 | type: "TOGGLE_CART",
21 | showCart: !showCart,
22 | });
23 | };
24 | const handleToggleContact = () => {
25 | dispatch({
26 | type: "TOGGLE_CONTACT_FORM",
27 | showContactForm: !showContactForm,
28 | });
29 | }
30 | return (
31 |
32 |
33 |
42 |
43 | {cartItems && (
44 |
45 |
46 | {cartItems.length}
47 |
48 |
49 | )}
50 |
51 | setIsOpen(!isOpen)}
58 | >
59 |
60 |
61 |
62 |
65 |
setIsOpen(!isOpen)} to={'/menu'} className="text-base text-textColor cursor-pointer hover:text-headingColor duration-100 transition-all ease-in-out px-10">
66 | Menu
67 |
68 |
setIsOpen(!isOpen)} to={'services'} className="text-base text-textColor cursor-pointer hover:text-headingColor duration-100 transition-all ease-in-out px-10">
69 | Services
70 |
71 |
setIsOpen(!isOpen)} to={'/about'} className="text-base text-textColor cursor-pointer hover:text-headingColor duration-100 transition-all ease-in-out px-10">
72 | About
73 |
74 |
75 | Contact
76 |
77 |
78 |
79 |
setIsOpen(!isOpen)}
82 | className="flex items-center justify-center w-full"
83 | >
84 |
89 |
90 | Bentilzone
91 |
92 |
93 |
94 | );
95 | };
96 |
97 | export default MobileNav;
98 |
--------------------------------------------------------------------------------
/src/components/Loader/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { motion } from "framer-motion";
3 |
4 | const Loader = ({progress, className}:{progress:string, className?:string}) => {
5 | return (
6 | <>
7 |
13 |
20 |
24 |
28 |
29 | {progress}
30 |
31 | >
32 | );
33 | };
34 |
35 | export const Loader2 = () => {
36 | return (
37 | <>
38 |
45 |
49 |
53 |
54 | >
55 | );
56 | };
57 |
58 | export default Loader;
59 |
--------------------------------------------------------------------------------
/src/components/NotFound/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { NotFoundImg } from '../Assets'
3 |
4 | const NotFound = ({text}: {text:string}) => {
5 | return (
6 |
7 |
8 |
{text}
9 |
10 | )
11 | }
12 |
13 | export default NotFound
--------------------------------------------------------------------------------
/src/components/Sections/Fruits/index.tsx:
--------------------------------------------------------------------------------
1 | import { PrevNext as PrevNextButtons, Title } from ".."
2 |
3 | import Container from "../../Container"
4 | import { FilterFood } from "../../../utils/filters"
5 | import { useState } from "react"
6 |
7 | const Fruits = () => {
8 | const fruits = FilterFood("fruits")
9 | const [scrollValue, setScrollValue] = useState(0)
10 |
11 |
12 | return (
13 |
14 |
15 |
16 |
setScrollValue(10000)} onPrev = {() => setScrollValue(-10000)} />
17 |
18 |
19 |
20 | )
21 | }
22 |
23 | export default Fruits
--------------------------------------------------------------------------------
/src/components/Sections/Menu/index.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | import Container from "../../Container";
4 | import { FilterFood } from "../../../utils/filters";
5 | import Filters from "../../Filters";
6 | import { Title } from "..";
7 | import { useStateValue } from "../../../context/StateProvider";
8 |
9 | const Menu = ({title}:{title?:string}) => {
10 |
11 | const [scrollValue, setScrollValue] = useState(0);
12 | const [{ foodItems }, dispatch] = useStateValue();
13 | const [filter, setFilter] = useState("all");
14 |
15 | return (
16 |
28 | );
29 | };
30 |
31 | export default Menu;
32 |
--------------------------------------------------------------------------------
/src/components/Sections/index.tsx:
--------------------------------------------------------------------------------
1 | import { MdChevronLeft, MdChevronRight } from 'react-icons/md';
2 |
3 | import {motion} from 'framer-motion';
4 |
5 | export const Title = ({ title, center }: { title: string, center?:boolean }) => {
6 | return (
7 |
8 | {title}
9 |
10 | );
11 | };
12 |
13 | export const Pagination = ({
14 | currentPage,
15 | totalPages,
16 | onPageChange,
17 | }: {
18 | currentPage: number;
19 | totalPages: number;
20 | onPageChange: (page: number) => void;
21 | }) => {
22 | const pages = [];
23 | for (let i = 1; i <= totalPages; i++) {
24 | pages.push(i);
25 | }
26 | return (
27 |
28 |
29 | {pages.map((page) => {
30 | return (
31 |
37 | onPageChange(page)}>
38 | {page}
39 |
40 |
41 | );
42 | })}
43 |
44 |
45 | );
46 | };
47 |
48 | export const PrevNext = ({
49 | onPrev,
50 | onNext,
51 | }: {
52 | onPrev: () => void;
53 | onNext: () => void;
54 | }) => {
55 | return (
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | );
65 | };
66 |
67 |
--------------------------------------------------------------------------------
/src/components/Showcase/Statics.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { motion } from "framer-motion";
3 | import { foodItemsStatic } from "../../../types";
4 |
5 | const StaticsImages: React.FC = ({ items }) => {
6 | return (
7 |
8 | {items.map((item, index) => (
9 |
13 |
20 |
{item.title}
21 |
22 | {item.desc}
23 |
24 |
25 | ₵ {item.price}
26 |
27 |
28 | ))}
29 |
30 | );
31 | };
32 |
33 | export default StaticsImages;
34 |
--------------------------------------------------------------------------------
/src/components/Showcase/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Left from './left'
3 | import Right from './right'
4 |
5 |
6 | const Showcase = () => {
7 | return (
8 |
12 | )
13 | }
14 |
15 | export default Showcase
--------------------------------------------------------------------------------
/src/components/Showcase/left.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { BikeDelivery } from "../Assets";
3 | import { motion } from "framer-motion";
4 | const Left = () => {
5 | return (
6 |
7 |
8 |
Bike Delivery
9 |
10 |
15 |
16 |
17 |
18 | The Fastest Food Delivery in
19 | Accra
20 |
21 |
22 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus nam
23 | delectus sed, vel quaerat, libero nesciunt debitis, architecto
24 | repudiandae accusamus aut exercitationem nisi non doloribus! Temporibus
25 | officia architecto reiciendis blanditiis.
26 |
27 |
31 | Order Now
32 |
33 |
34 | );
35 | };
36 |
37 | export default Left;
38 |
--------------------------------------------------------------------------------
/src/components/Showcase/right.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { HeroBg } from '../Assets'
3 | import StaticsImages from './Statics'
4 | import { data } from '../../utils/showcaseStatic'
5 | const Right = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default Right
--------------------------------------------------------------------------------
/src/components/Upload/index.tsx:
--------------------------------------------------------------------------------
1 | import { MdCloudUpload } from 'react-icons/md'
2 | import { firebaseUploadImage } from '../../Firebase';
3 |
4 | const Upload = ({action, promise, progressHandler, to = "Products"}:{action:any, promise:any, progressHandler:any, to?:string}) => {
5 | const uploadImage = (e:any) => {
6 | const imageFIle = e.target.files[0]
7 | firebaseUploadImage(imageFIle, promise, progressHandler, action, to)
8 | }
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
Click here to upload
16 |
PNG, JPG or GIF (MAX. 800x400px)
17 |
18 | uploadImage(e)} />
19 |
20 |
21 | )
22 | }
23 |
24 | export default Upload
--------------------------------------------------------------------------------
/src/components/index.tsx:
--------------------------------------------------------------------------------
1 | export {default as Header} from './Header';
2 | export {default as ShowcaseBanner} from './Showcase';
3 | export {default as Loader} from './Loader';
4 | export {Loader2 as LoaderAlt} from './Loader';
5 | export {default as AssetUploader} from './Upload';
6 | export {default as FruitsSection} from './Sections/Fruits';
7 | export {default as MenuSection} from './Sections/Menu';
8 | export {default as EmptyCart} from './EmptyCart';
9 | export {default as Cart} from './Cart';
10 | export {default as Footer} from './Footer';
11 | export {default as Sidenav} from './Admin/Sidenav';
12 | export {default as Content} from './Admin/Content';
13 | export {default as AddFood} from './Admin/AddFood';
14 | export {default as Stats} from './Admin/Dashboard';
--------------------------------------------------------------------------------
/src/context/StateProvider.js:
--------------------------------------------------------------------------------
1 | import React, {createContext, useContext, useReducer} from "react";
2 |
3 | export const StateContext = createContext();
4 |
5 | export const StateProvider = ({reducer, initialState, children}) => (
6 |
7 | {children}
8 |
9 | );
10 |
11 | export const useStateValue = () => useContext(StateContext);
--------------------------------------------------------------------------------
/src/context/initialState.js:
--------------------------------------------------------------------------------
1 | import { fetchSessionUser, fetchSessionUserMode } from "../utils/fetchSessionData";
2 |
3 | const sessionUser = fetchSessionUser();
4 | const sessionUserMode = fetchSessionUserMode();
5 | export const initialState = {
6 | user: sessionUser,
7 | foodItems: null,
8 | showCart: false,
9 | showContactForm: false,
10 | cartItems: [],
11 | cartTotal: 0,
12 | adminMode: sessionUserMode,
13 | users: [],
14 | paymentMethod: 'mobile_money',
15 | checkoutData: {},
16 | }
--------------------------------------------------------------------------------
/src/context/reducer.js:
--------------------------------------------------------------------------------
1 | export const actionTypes = {
2 | SET_USER: 'SET_USER',
3 | SET_FOOD_ITEMS: 'SET_FOOD_ITEMS',
4 | TOGGLE_CART: 'TOGGLE_CART',
5 | SET_CARTITEMS: 'SET_CARTITEMS',
6 | SET_CART_TOTAL: 'SET_CART_TOTAL',
7 | SET_ADMIN_MODE: 'SET_ADMIN_MODE',
8 | SET_USERS: 'SET_USERS',
9 | UPDATE_USER: 'UPDATE_USER',
10 | SET_PAYMENT_METHOD: 'SET_PAYMENT_METHOD',
11 | UPDATE_CHECKOUT_DATA: 'UPDATE_CHECKOUT_DATA',
12 | TOGGLE_CONTACT_FORM: 'TOGGLE_CONTACT_FORM'
13 | }
14 |
15 | const reducer = (state, action) => {
16 | // console.log(action)
17 | switch (action.type) {
18 | case actionTypes.SET_USER:
19 | return {
20 | ...state,
21 | user: action.user,
22 | };
23 | case actionTypes.SET_FOOD_ITEMS:
24 | return {
25 | ...state,
26 | foodItems: action.foodItems,
27 | };
28 | case actionTypes.TOGGLE_CART:
29 | return {
30 | ...state,
31 | showCart: action.showCart,
32 | };
33 | case actionTypes.SET_CARTITEMS:
34 | return {
35 | ...state,
36 | cartItems: action.cartItems,
37 | };
38 | case actionTypes.SET_CART_TOTAL:
39 | return {
40 | ...state,
41 | cartTotal: action.cartTotal,
42 | };
43 | case actionTypes.SET_ADMIN_MODE:
44 | return {
45 | ...state,
46 | adminMode: action.adminMode,
47 | };
48 | case actionTypes.SET_USERS:
49 | return {
50 | ...state,
51 | users: action.users,
52 | };
53 | case actionTypes.UPDATE_USER:
54 | return {
55 | ...state,
56 | user: action.user
57 | };
58 | case actionTypes.SET_PAYMENT_METHOD:
59 | return {
60 | ...state,
61 | paymentMethod: action.paymentMethod
62 | };
63 | case actionTypes.UPDATE_CHECKOUT_DATA:
64 | return {
65 | ...state,
66 | checkoutData: action.checkoutData
67 | };
68 | case actionTypes.TOGGLE_CONTACT_FORM:
69 | return {
70 | ...state,
71 | showContactForm: action.showContactForm
72 | };
73 | default:
74 | return state;
75 | }
76 | }
77 |
78 | export default reducer;
--------------------------------------------------------------------------------
/src/firebase.config.js:
--------------------------------------------------------------------------------
1 | import { getApp, getApps, initializeApp } from "firebase/app";
2 |
3 | import { getFirestore } from "firebase/firestore";
4 | import { getStorage } from "firebase/storage";
5 |
6 | const firebaseConfig = {
7 | apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
8 | authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
9 | databaseURL: process.env.REACT_APP_FIREBASE_DB_URL,
10 | projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
11 | storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
12 | messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_ID,
13 | appId: process.env.REACT_APP_FIREBASE_APP_ID,
14 | measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID,
15 | };
16 |
17 | const app = getApps.length > 0 ? getApp() : initializeApp(firebaseConfig);
18 | const firestore = getFirestore(app);
19 | const storage = getStorage(app);
20 |
21 | export { app, firestore, storage };
22 |
--------------------------------------------------------------------------------
/src/img/NotFound.svg:
--------------------------------------------------------------------------------
1 | not found
--------------------------------------------------------------------------------
/src/img/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/avatar.png
--------------------------------------------------------------------------------
/src/img/c1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/c1.png
--------------------------------------------------------------------------------
/src/img/c2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/c2.png
--------------------------------------------------------------------------------
/src/img/c3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/c3.png
--------------------------------------------------------------------------------
/src/img/c4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/c4.png
--------------------------------------------------------------------------------
/src/img/c6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/c6.png
--------------------------------------------------------------------------------
/src/img/c7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/c7.png
--------------------------------------------------------------------------------
/src/img/chef1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/chef1.png
--------------------------------------------------------------------------------
/src/img/cheff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/cheff.png
--------------------------------------------------------------------------------
/src/img/cu1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/cu1.png
--------------------------------------------------------------------------------
/src/img/cu2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/cu2.png
--------------------------------------------------------------------------------
/src/img/cu3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/cu3.png
--------------------------------------------------------------------------------
/src/img/cu4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/cu4.png
--------------------------------------------------------------------------------
/src/img/cu5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/cu5.png
--------------------------------------------------------------------------------
/src/img/cu6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/cu6.png
--------------------------------------------------------------------------------
/src/img/d1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/d1.png
--------------------------------------------------------------------------------
/src/img/d2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/d2.png
--------------------------------------------------------------------------------
/src/img/d3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/d3.png
--------------------------------------------------------------------------------
/src/img/d4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/d4.png
--------------------------------------------------------------------------------
/src/img/d5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/d5.png
--------------------------------------------------------------------------------
/src/img/d6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/d6.png
--------------------------------------------------------------------------------
/src/img/d7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/d7.png
--------------------------------------------------------------------------------
/src/img/d8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/d8.png
--------------------------------------------------------------------------------
/src/img/delivery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/delivery.png
--------------------------------------------------------------------------------
/src/img/emptyCart.svg:
--------------------------------------------------------------------------------
1 | empty_cart
--------------------------------------------------------------------------------
/src/img/f1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/f1.png
--------------------------------------------------------------------------------
/src/img/f10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/f10.png
--------------------------------------------------------------------------------
/src/img/f2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/f2.png
--------------------------------------------------------------------------------
/src/img/f3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/f3.png
--------------------------------------------------------------------------------
/src/img/f4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/f4.png
--------------------------------------------------------------------------------
/src/img/f5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/f5.png
--------------------------------------------------------------------------------
/src/img/f6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/f6.png
--------------------------------------------------------------------------------
/src/img/f7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/f7.png
--------------------------------------------------------------------------------
/src/img/f8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/f8.png
--------------------------------------------------------------------------------
/src/img/f9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/f9.png
--------------------------------------------------------------------------------
/src/img/fi1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/fi1.png
--------------------------------------------------------------------------------
/src/img/fi2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/fi2.png
--------------------------------------------------------------------------------
/src/img/fi3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/fi3.png
--------------------------------------------------------------------------------
/src/img/fi4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/fi4.png
--------------------------------------------------------------------------------
/src/img/fi5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/fi5.png
--------------------------------------------------------------------------------
/src/img/hero-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/hero-bg.png
--------------------------------------------------------------------------------
/src/img/i1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/i1.png
--------------------------------------------------------------------------------
/src/img/i2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/i2.png
--------------------------------------------------------------------------------
/src/img/i3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/i3.png
--------------------------------------------------------------------------------
/src/img/i4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/i4.png
--------------------------------------------------------------------------------
/src/img/i5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/i5.png
--------------------------------------------------------------------------------
/src/img/i6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/i6.png
--------------------------------------------------------------------------------
/src/img/i7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/i7.png
--------------------------------------------------------------------------------
/src/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/logo.png
--------------------------------------------------------------------------------
/src/img/momo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/momo.png
--------------------------------------------------------------------------------
/src/img/r1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/r1.png
--------------------------------------------------------------------------------
/src/img/r2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/r2.png
--------------------------------------------------------------------------------
/src/img/r3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/r3.png
--------------------------------------------------------------------------------
/src/img/r4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/r4.png
--------------------------------------------------------------------------------
/src/img/r5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/r5.png
--------------------------------------------------------------------------------
/src/img/visa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartCoolDev/Smart-Restaurant-react/d465a3f3ddd180d5c3b32df0d46dfb15c2ea477f/src/img/visa.png
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css?family=Poppins:100,100i,200,200i,300,300i,400,400i,500,500i,600,600i,700,700i,800,800i,900,900i);
2 |
3 |
4 | * {
5 | box-sizing: border-box;
6 | padding: 0;
7 | margin: 0;
8 | }
9 |
10 | body {
11 | font-family: 'Poppins', sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
12 | overflow-x: hidden;
13 | overflow-y: auto;
14 |
15 | }
16 |
17 | html,
18 | body {
19 | scroll-behavior: smooth;
20 | }
21 |
22 | body::-webkit-scrollbar {
23 | width: 0.4em;
24 | border-radius: 50vh;
25 | cursor: pointer;
26 | }
27 |
28 | body::-webkit-scrollbar-track {
29 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
30 | }
31 |
32 | body::-webkit-scrollbar-thumb {
33 | background-color: rgb(249, 115, 22);
34 | outline: none;
35 | }
36 |
37 | /* Hide scrollbar for Chrome, Safari and Opera */
38 | .scrollbar-hidden::-webkit-scrollbar {
39 | display: none;
40 | }
41 |
42 | /* Hide scrollbar for IE, Edge and Firefox */
43 | .scrollbar-hidden {
44 | -ms-overflow-style: none;
45 | /* IE and Edge */
46 | scrollbar-width: none;
47 | /* Firefox */
48 | }
49 |
50 | @tailwind base;
51 | @tailwind components;
52 | @tailwind utilities;
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 | import {BrowserRouter as Router} from 'react-router-dom';
7 | import { StateProvider } from './context/StateProvider';
8 | import { initialState } from './context/initialState';
9 | import reducer from './context/reducer';
10 | const root = ReactDOM.createRoot(
11 | document.getElementById('root') as HTMLElement
12 | );
13 | root.render(
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | );
22 |
23 | // If you want to start measuring performance in your app, pass a function
24 | // to log results (for example: reportWebVitals(console.log))
25 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
26 | reportWebVitals();
27 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/reportWebVitals.ts:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from 'web-vitals';
2 |
3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4 | if (onPerfEntry && onPerfEntry instanceof Function) {
5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6 | getCLS(onPerfEntry);
7 | getFID(onPerfEntry);
8 | getFCP(onPerfEntry);
9 | getLCP(onPerfEntry);
10 | getTTFB(onPerfEntry);
11 | });
12 | }
13 | };
14 |
15 | export default reportWebVitals;
16 |
--------------------------------------------------------------------------------
/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/utils/categories.tsx:
--------------------------------------------------------------------------------
1 | import { GiFruitTree, GiChickenOven, GiBeerBottle, GiBowlOfRice } from "react-icons/gi";
2 | import { MdOutlineIcecream } from "react-icons/md";
3 | import {FaFish} from "react-icons/fa";
4 |
5 | export const Categories = [
6 | {
7 | id: 1,
8 | name: "Chicken",
9 | urlParam: 'chicken',
10 | icon: ,
11 | },
12 | {
13 | id: 2,
14 | name: "Fruits",
15 | urlParam: 'fruits',
16 | icon: ,
17 | },
18 | {
19 | id: 3,
20 | name: "Soft Drinks",
21 | urlParam: 'drinks',
22 | icon: ,
23 | },
24 | {
25 | id: 4,
26 | name: "Desserts",
27 | urlParam: 'desserts',
28 |
29 | },
30 | {
31 | id: 5,
32 | name: "Icecreams",
33 | urlParam: 'icecreams',
34 | icon: ,
35 | },
36 | {
37 | id: 6,
38 | name: "Fish",
39 | urlParam: 'fish',
40 | icon: ,
41 | },
42 | {
43 | id: 7,
44 | name: "Rice",
45 | urlParam: 'rice',
46 | icon: ,
47 | },
48 | {
49 | id: 8,
50 | name: "Curry",
51 | urlParam: 'curry',
52 |
53 | }
54 | ]
--------------------------------------------------------------------------------
/src/utils/fetchSessionData.js:
--------------------------------------------------------------------------------
1 | import { firebaseGetAllUsers } from "../Firebase";
2 |
3 | export const fetchSessionUser = () => {
4 | const user =
5 | localStorage.getItem("user") !== "undefined"
6 | ? JSON.parse(localStorage.getItem("user"))
7 | : localStorage.clear();
8 |
9 | return user;
10 | // return null
11 | };
12 | export const fetchSessionCart = () => {
13 | const cartInfo =
14 | localStorage.getItem("cartItems") !== "undefined"
15 | ? JSON.parse(localStorage.getItem("cartItems"))
16 | : localStorage.clear();
17 |
18 | return cartInfo ? cartInfo : [];
19 | };
20 |
21 | // session usermode
22 | export const fetchSessionUserMode = () => {
23 | const adminMode =
24 | localStorage.getItem("userMode") !== "undefined"
25 | ? JSON.parse(localStorage.getItem("adminMode"))
26 | : localStorage.clear();
27 |
28 | return adminMode ? adminMode : false;
29 | }
30 |
--------------------------------------------------------------------------------
/src/utils/filters.tsx:
--------------------------------------------------------------------------------
1 | import { FoodItem } from "../../types"
2 | import { useStateValue } from "../context/StateProvider"
3 |
4 | export const FilterFood = (category:string) => {
5 | const [{foodItems}, dispatch] = useStateValue()
6 | return foodItems?.filter((item:FoodItem) => item.category.toLowerCase() === category.toLowerCase())
7 | }
8 |
9 | export const GetFoodById = (id: number) => {
10 | const [{foodItems}, dispatch] = useStateValue()
11 | return foodItems?.find((item:FoodItem) => item.id === id)
12 | }
--------------------------------------------------------------------------------
/src/utils/functions.tsx:
--------------------------------------------------------------------------------
1 | import { FoodItem, cartItem } from "../../types";
2 | import {
3 | firebaseAddToCart,
4 | firebaseDeleteCartItem,
5 | firebaseDeleteFood,
6 | firebaseEmptyUserCart,
7 | firebaseFetchAllCartItems,
8 | firebaseFetchFoodItems,
9 | firebaseGetAllUsers,
10 | firebaseGetUser,
11 | firebaseLogout,
12 | firebaseUpdateCartItem,
13 | firebaseUpdateUser,
14 | } from "../Firebase";
15 |
16 | import { MdShoppingBasket } from "react-icons/md";
17 | import { toast } from "react-toastify";
18 |
19 | export const addToCart = async (
20 | cartItems: cartItem[],
21 | foodItems: FoodItem[],
22 | user: any,
23 | fid: number,
24 | dispatch: any
25 | ) => {
26 | if (!user) {
27 | toast.error("Please login to add items to cart", {
28 | icon: ,
29 | toastId: "unauthorizedAddToCart",
30 | });
31 | } else {
32 | if (cartItems.some((item: cartItem) => item["fid"] === fid)) {
33 | toast.error("Item already in cart", {
34 | icon: ,
35 | toastId: "itemAlreadyInCart",
36 | });
37 | } else {
38 | const data: cartItem = {
39 | id: Date.now(),
40 | fid: fid,
41 | uid: user.uid,
42 | qty: 1,
43 | };
44 | dispatch({
45 | type: "SET_CARTITEMS",
46 | cartItems: [...cartItems, data],
47 | });
48 | calculateCartTotal(cartItems, foodItems, dispatch);
49 | await firebaseAddToCart(data);
50 | }
51 | }
52 | };
53 | export const dispatchtUserCartItems = (
54 | uid: string,
55 | items: cartItem[],
56 | dispatch: any
57 | ) => {
58 | const cartItems = items.filter((item: cartItem) => item.uid === uid);
59 | dispatch({
60 | type: "SET_CARTITEMS",
61 | cartItems: cartItems,
62 | });
63 |
64 | return cartItems;
65 | };
66 |
67 | export const fetchUserCartData = async (user: any, dispatch: any) => {
68 | if (user) {
69 | await firebaseFetchAllCartItems()
70 | .then((data) => {
71 | const userCart = dispatchtUserCartItems(user.uid, data, dispatch);
72 | localStorage.setItem("cartItems", JSON.stringify(userCart));
73 | })
74 | .then(() => {})
75 | .catch((e) => {
76 | console.log(e);
77 | });
78 | } else {
79 | localStorage.setItem("cartItems", "undefined");
80 | }
81 | };
82 |
83 | export const fetchFoodData = async (dispatch: any) => {
84 | await firebaseFetchFoodItems()
85 | .then((data) => {
86 | dispatch({
87 | type: "SET_FOOD_ITEMS",
88 | foodItems: data,
89 | });
90 | })
91 | .then(() => {})
92 | .catch((e) => {
93 | console.log(e);
94 | });
95 | };
96 |
97 | export const getFoodyById = (menu: FoodItem[], fid: number) => {
98 | return menu.find((item: FoodItem) => item.id === fid);
99 | };
100 |
101 | // Update cart item State
102 | export const updateCartItemState = async (
103 | cartItems: cartItem[],
104 | item: cartItem,
105 | dispatch: any
106 | ) => {
107 | const index = cartItems.findIndex(
108 | (cartItem: cartItem) => cartItem.id === item.id
109 | );
110 | if (index !== -1) {
111 | cartItems[index] = item;
112 | }
113 | dispatch({
114 | type: "SET_CARTITEMS",
115 | cartItems: cartItems,
116 | });
117 | await firebaseUpdateCartItem(item)
118 | .then(() => {})
119 | .catch((e) => {
120 | console.log(e);
121 | });
122 | };
123 |
124 | // Update Cart Item Quantity
125 | export const updateCartItemQty = async (
126 | cartItems: cartItem[],
127 | foodItems: FoodItem[],
128 | item: cartItem,
129 | dispatch: any,
130 | val: number
131 | ) => {
132 | const index = cartItems.findIndex(
133 | (cartItem: cartItem) => cartItem.id === item.id
134 | );
135 | if (index !== -1) {
136 | cartItems[index].qty += val;
137 | dispatch({
138 | type: "SET_CARTITEMS",
139 | cartItems: cartItems,
140 | });
141 | calculateCartTotal(cartItems, foodItems, dispatch);
142 | await firebaseUpdateCartItem(cartItems[index])
143 | .then(() => {})
144 | .catch((e) => {
145 | console.log(e);
146 | });
147 | }
148 | };
149 |
150 | // Delete Cart Item
151 | export const deleteCartItem = async (
152 | cartItems: cartItem[],
153 | foodItems: FoodItem[],
154 | item: cartItem,
155 | dispatch: any
156 | ) => {
157 | const index = cartItems.findIndex(
158 | (cartItem: cartItem) => cartItem.id === item.id
159 | );
160 | if (index !== -1) {
161 | cartItems.splice(index, 1);
162 | dispatch({
163 | type: "SET_CARTITEMS",
164 | cartItems: cartItems,
165 | });
166 | calculateCartTotal(cartItems, foodItems, dispatch);
167 | await firebaseDeleteCartItem(item)
168 | .then(() => {})
169 | .catch((e) => {
170 | console.log(e);
171 | });
172 | }
173 | };
174 |
175 | // Calculate Total Price Round to 2 decimal places
176 | export const calculateCartTotal = (
177 | cartItems: cartItem[],
178 | foodItems: FoodItem[],
179 | dispatch: any
180 | ) => {
181 | let total = 0;
182 | cartItems.forEach((item: cartItem) => {
183 | const foodItem = getFoodyById(foodItems, item.fid);
184 | total += item.qty * parseFloat(foodItem?.price || "0");
185 | });
186 | dispatch({
187 | type: "SET_CART_TOTAL",
188 | cartTotal: total.toFixed(2),
189 | });
190 | };
191 |
192 | // Empty Cart
193 | export const emptyCart = async (
194 | cartItems: cartItem[],
195 | foodItems: FoodItem[],
196 | dispatch: any
197 | ) => {
198 | if (cartItems.length > 0) {
199 | dispatch({
200 | type: "SET_CARTITEMS",
201 | cartItems: [],
202 | });
203 | calculateCartTotal(cartItems, foodItems, dispatch);
204 | await firebaseEmptyUserCart(cartItems)
205 | .then(() => {})
206 | .catch((e) => {
207 | console.log(e);
208 | });
209 | } else {
210 | toast.warn("Cart is already empty");
211 | }
212 | };
213 |
214 | // Hide Cart
215 | export const hideCart = (dispatch: any) => {
216 | dispatch({
217 | type: "TOGGLE_CART",
218 | showCart: !true,
219 | });
220 | };
221 |
222 | // Hide Cart
223 | export const hideContactform = (dispatch: any) => {
224 | dispatch({
225 | type: "TOGGLE_CONTACT_FORM",
226 | showContactForm: !true,
227 | });
228 | };
229 |
230 | export const shuffleItems = (items: any) => {
231 | let currentIndex = items.length,
232 | randomIndex;
233 |
234 | // While there remain elements to shuffle.
235 | while (currentIndex !== 0) {
236 | // Pick a remaining element.
237 | randomIndex = Math.floor(Math.random() * currentIndex);
238 | currentIndex--;
239 |
240 | // And swap it with the current element.
241 | [items[currentIndex], items[randomIndex]] = [
242 | items[randomIndex],
243 | items[currentIndex],
244 | ];
245 | }
246 |
247 | return items;
248 | };
249 |
250 | export const logout = async (user: any, dispatch: any, navigate: any) => {
251 | if (user) {
252 | await firebaseLogout()
253 | .then(() => {
254 | dispatch({
255 | type: "SET_USER",
256 | user: null,
257 | });
258 | dispatch({
259 | type: "SET_CARTITEMS",
260 | cartItems: [],
261 | });
262 | // turn off adminMode
263 | dispatch({
264 | type: "SET_ADMIN_MODE",
265 | adminMode: false,
266 | });
267 |
268 | localStorage.setItem("user", "undefined");
269 | localStorage.setItem("adminMode", "undefined");
270 | localStorage.removeItem("cartItems");
271 | navigate("/");
272 | })
273 | .catch((e: any) => {
274 | console.log(e);
275 | });
276 | } else {
277 | console.log("You are not logged in");
278 | }
279 | };
280 |
281 | export const ToggleAdminMode = (dispatch: any, state: boolean) => {
282 | dispatch({
283 | type: "SET_ADMIN_MODE",
284 | adminMode: state,
285 | });
286 | localStorage.setItem("adminMode", JSON.stringify(state));
287 | console.log(state);
288 | };
289 |
290 | export const isAdmin = (user: any) => {
291 | let isAdmin =user?.email == "bentilshadrack72@gmail.com" || user?.email == "admin@test.com"
292 | return isAdmin
293 | };
294 |
295 | // get user
296 | export const getUserData = async (user: any) => {
297 | return await firebaseGetUser(user.uid);
298 | };
299 |
300 | // update currentUser
301 | export const updateUserData = async (
302 | user: any,
303 | dispatch: any,
304 | alert: boolean
305 | ) => {
306 | await firebaseUpdateUser(user)
307 | .then(() => {
308 | dispatch({
309 | type: "SET_USER",
310 | user: user,
311 | });
312 | })
313 | .catch((e: any) => {
314 | console.log(e);
315 | })
316 | .then(() => {
317 | localStorage.setItem("user", JSON.stringify(user));
318 | alert && toast.success("User data updated successfully");
319 | });
320 | };
321 |
322 | // get all users
323 | export const dispatchUsers = async (dispatch: any) => {
324 | await firebaseGetAllUsers()
325 | .then((users: any) => {
326 | dispatch({
327 | type: "SET_USERS",
328 | users: users,
329 | });
330 | })
331 | .catch((e: any) => {
332 | console.log(e);
333 | });
334 | }
335 | export const getAllUser = async() => {
336 | await firebaseGetAllUsers().then((users: any) => {
337 | return users
338 | }).catch((e:any) => {
339 | console.log(e)
340 | })
341 | }
342 | // delete food
343 | export const deleteFood = async (
344 | food: FoodItem,
345 | foodItems: FoodItem[],
346 | dispatch: any
347 | ) => {
348 | await firebaseDeleteFood(food.id);
349 | // remove food from foodItems
350 | const foodIndex = foodItems.indexOf(food);
351 | if(foodIndex !== -1)
352 | {
353 | foodItems.splice(foodIndex, 1)
354 | }
355 | dispatch ({
356 | type: "SET_FOOD_ITEMS",
357 | foodItems
358 | })
359 | toast.success("Food deleted successfully");
360 | };
361 |
362 |
--------------------------------------------------------------------------------
/src/utils/showcaseStatic.tsx:
--------------------------------------------------------------------------------
1 | import {Chicken, Fish, Icecream, Strawberry} from "../components/Assets";
2 |
3 | export const data = [
4 |
5 | {
6 | id: 2,
7 | title: 'Strawberries',
8 | desc: "Fresh Strawberries",
9 | price: '7.25',
10 | imgSrc: Strawberry
11 | },
12 | {
13 | id: 3,
14 | title: 'Chicken',
15 | desc: "Mixed Kebab",
16 | price: '15.65',
17 | imgSrc: Chicken
18 | },
19 | {
20 | id: 4,
21 | title: 'Tilapia',
22 | desc: "Roasted Tilapia",
23 | price: '10.25',
24 | imgSrc: Fish
25 | },{
26 | id: 1,
27 | title: 'Icream',
28 | desc: "Chocolate & Vanila",
29 | price: '5.25',
30 | imgSrc: Icecream
31 | },
32 |
33 | ]
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | content: ["./src/**/*.{js,jsx,ts,tsx}"],
3 | theme: {
4 | extend: {
5 | colors: {
6 | primary: "#f5f3f3",
7 | headingColor: "#2e2e2e",
8 | cartNumBg: "#e80013",
9 | textColor: "#515151",
10 | cardOverlay: "rgba(256, 256, 256, 0.4)",
11 | btnOverlay: "rgba(255, 255, 255, 0.8)",
12 | lightGray: "#9ca0ab",
13 | containerbg: "rgba(255, 131, 0, 0.04)",
14 | cartBg: "#282a2c",
15 | cartItem: "#2e3033",
16 | cartTotal: "#343739",
17 | },
18 | display: ["group-hover"]
19 | },
20 | plugins: [],
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react-jsx"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/types.tsx:
--------------------------------------------------------------------------------
1 | export type foodItemStatic = {
2 | id: number;
3 | title: string;
4 | desc: string;
5 | price: string;
6 | imgSrc: string;
7 | }
8 | export type foodItemsStatic = {
9 | items: foodItemStatic[];
10 | }
11 | export type FoodItem = {
12 | id: number;
13 | title: string;
14 | description?: string;
15 | price: string;
16 | imageURL: string;
17 | calories: string;
18 | qty: string;
19 | category: string;
20 | };
21 |
22 | export type FoodItems = {
23 | items: FoodItem[];
24 | }
25 |
26 | export type FoodCategory = {
27 | id: number;
28 | name: string;
29 | urlParam: string;
30 | icon?: JSX.Element
31 | }
32 |
33 | export type cartItem = {
34 | id: number;
35 | fid: number;
36 | uid: string;
37 | qty: number;
38 | }
39 |
40 | export type cartItems = {
41 | items: cartItem[]
42 | }
43 |
44 | export type User = {
45 | uid: string;
46 | email?: string;
47 | displayName?:string;
48 | phoneNumber?: string;
49 | providerId: string;
50 | photoURL?: string;
51 |
52 | }
53 | export type FoodCategories = FoodCategory[];
--------------------------------------------------------------------------------