Nothing Special   »   [go: up one dir, main page]

Project Report

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 84

790.- St.

Xavier’s College, Jaipur


(Affiliated by University of Rajasthan)
Department of Computer Science

Session 2023-2024
Paper Code: 310
PROJECT

Submitted by:
Ayush Vashistha Submitted to:
Piyush Saini Dr. Arpita Banerjee
Class: BCA-III HOD
ACKNOWLEDGEMENT

I would like to express my sincere gratitude to several individuals and organization for
supporting me throughout the completion of my project.

First, I wish to express my sincere gratitude to my mentor (Ms. Alka Kumari) for her
enthusiasm patience, insightful comments, helpful information, practical advices and
unceasing ideas that have helped me tremendously at all times in my Project and writing of
these thesis. Her immense knowledge, profound experience and professional expertise in
Backend has enabled me to complete this project successfully. Without her support and
guidance, this project would not have been possible.

I am also thankful to our respected HOD Dr. Arvind Kumar Pandey and all faculty members
for loving inspiration and timely guidance. I also wish to express my sincere thanks to the
Department of Computer science & Information technology of ARKA JAIN UNIVERSITY
for accepting this project.

Thanks for all your encouragement!


ABSTRACT

The purpose of this project is to devlop and online food ordering system. It is a system that
enable customer to place their food order online at any time at any place.

The reason to devlop this system is due to the issue facing by food industry. These issue are
such as peak hour-long queue issues, increase of take away than visitors, speed major request
of food management, limited promotion and quality control of food management.

Therefore, this system enhance the speed and standardization of taking order from the
cutomer and supply it to the staff in the kitchen accordingly.

Beside that it provide user friendly web pages and effective advertising medium to the new
product of the online food ordering restaurant to the customer at reasonable price.
DECLARATION
TABLE OF CONTENTS

Chapter 1

Introduction and Objective.................................................................................................9

1.1 Introduction......................................................................................................................9

1.2 Objective.........................................................................................................................10

Chapter 2

System Analysis...............................................................................................................11-21

2.1 Software Requirement Specification (SRS).....................................................................11

2.1.1 Data Gathering..................................................................................................11

2.1.2 Feasible Study...................................................................................................12

2.1.3 Software Process Model....................................................................................12

2.2 Hardware Requirement.....................................................................................................13

2.3 Software Requirement.......................................................................................................13

2.4 Justification of Selection of Technology...........................................................................14

2.4.1 XAMPP..............................................................................................................14

2.4.2 Language............................................................................................................14

HTML

CSS

JavaScript

Bootstrap

PHP
2.4.3 MySQL...............................................................................................................15

ONLINE FOOD ORDERING SYSTEM Page No. 7


2.5 Data Flow Diagram (DFD)................................................................................................15

2.5.1 DFD 0 Level.......................................................................................................16

2.5.2 DFD 1 Level.......................................................................................................17

2.5.3 DFD 2 Level.......................................................................................................19

Chapter 3

3.1 Entity Relationship Diagram (ER- Diagram)....................................................................23

3.2 Data Dictionary.................................................................................................................24

3.3 Database Normalization....................................................................................................27

Chapter 4

Program Code and Testing...........................................................................................28-175

4.1 Coding........................................................................................................................28-173

4.2 Testing Approach......................................................................................................174-175

Chapter 5

Results and Discussion.................................................................................................176-180

5.1 Output Screen...........................................................................................................176-180

Chapter 6

Conclusion............................................................................................................................181

6.1 Limitation........................................................................................................................182

6.2 Future Scope....................................................................................................................182


Chapter 7

7.1 References.......................................................................................................................183
CHAPTER 1

INTRODUCTION

Online food ordering system is proposed here which simplifies the food ordering process. It
can be defined as a simple and convenient way for customers to order food online, without
having to go to the restaurant. The proposed system shows an customer interface and update
the menu with all available options so that it eases the customer work. Customer can choose
more than one item to make an order and can view order details..

User can order his/her favourite food from desired restaurant and enjoy them with his/her
loved ones. and through this website only the admin who has the contraption power of this
website can look up to every activities of user and can guide or help them whenever a user is
needed for help.

As you open the website RESTRO 1839 a animated page will load and it will have two
options one i.e Login and other sign-up.

If a user is new to the website then he can do sign-up first then he will get a user id and
password , through which he can then Login into the website easily .

Login into the website easily, and if he has that user id and password from previously so he
can directswitch on to login area.

After login the user will be redirected to home page where he will get to see a navbar
containing optionslike about section, menu section , order section, contact section.

Scrolling down there he will get option to explore our website. Then if he want to book order
for food thenhe will get option of verieties of foods options user have to go down the website
where the option will be available.

User can book his favourite foods and can cancel it also , after order he will get a message
that his order has been placed after that it will lead to the payment option where user has to
pay the required amount through Cash on Delivery or Online payment.

And all these activities can be controlled by admin he will get notification whenever any user
will login intothe website and place any order. Admin can add ,delete and update foods .
OBJECTIVE

It is required to keep the computerized data, as it is difficult to do manually and is also fast as
it takes less time. Purpose to computerize its data is to overcome from hazard of manual
system. This web portal is developed as to deliver food to everyone in more efficient and
effective way.
CHAPTER 2

REQUIREMENT AND

ANALYSIS

2.1 Software Requirement Specification

A software requirements specification (SRS) is a detailed description of a


software system to be developed with its functional and non-functional
requirements. The SRS is developed based the agreement between customer and
contractors. It may include the use cases of how user is going to interact with
software system. The software requirement specification document consistent of
all necessary requirements required for project development. To develop the
software system we should have clear understanding of Software system. To
achieve this we need to continuous communication with customers to gather all
requirements.

2.1.1 Data Gathering Data Gathering is the process of gathering and measuring
information on variables of interest, in an established systematic fashion that
enables one to answer stated research questions, test hypotheses, and evaluate
outcomes. The data collection component of research is common to all fields of
study including physical and social sciences, humanities, business, etc. Data
gathering techniques used in the (Software Development Lifecycle) SDLC.

2.1.2 Feasibility Study The measure of how beneficial or practical the


development of informant system will be to an organization. along this topic
feasibility is measured. So far taking the feasibility study and feasibility analysis
during the development of the project food Ordering system we have studied on
the following four major categories of feasibility study

 Operational feasibility : Operational feasibility is the measure of how well a


proposed system solves the problems, and takes advantage of the opportunities
identified during scope definition and how it satisfies the requirements identified
in the requirements analysis phase of system development.
 Technical feasibility : A technical feasibility study assesses the details of how
you intend to deliver a product or service to customers. Think materials,
labour, transportation, where

your business will be located, and the technology that will be necessary to bring
all this together.

 Schedule Feasibility : Schedule Feasibility is defined as the probability of a


project to be completed within its scheduled time limits, by a planned due date.
If a project has a high probability to be completed on-time, then its schedule
feasibility is appraised as high.

 Economic feasibility : the degree to which the economic advantages of


something to be made, done, or achieved are greater than the economic costs:
The state commissioned a report on the economic feasibility of a single-payer
health system. During the development of food Ordering system . we have tried
to address all these feasibility analysis phases seriously . That‟s why we think ,
our project will succeed properly. Food ordering System

2.1.3 Software Process Model

A waterfall model under the software development life cycle (SDLC) is the
methodology used to produce the food ordering system and the customer self
ordering system. It is used by system developers to produce or alter information
systems or software. It divides the development process into several stages or
processes. After the completion of one stage, it will logically move to another
stage. Sometimes moving back to the previous stage is necessary due to failure
that occurs in current stage.
2.2 HARDWARE REQUIREMENTS

 Processor : 1.6GHz or Faster

 Disk space: 4GB of Available Hard Disk

 RAM: 2GB

 Graphics – Directx 9- capable Video Card

 Display – 1024 x 768 or Higher Resolution

2.3 SOFTWARE REQUIREMENT

 Operating System : Windows (Vista/7 or above)

 Web Browser: IE 10 or above, Mozilla FF 31 and above or Google Chrome

 Xampp
2.4 JUSTIFICATION OF SELECTION OF TECHNOLOGY

2.4.1 XAMPP

XAMPP is a free and open-source cross-platform web server solution stack


package developed by Apache Friends, consisting mainly of the Apache HTTP
Server, MariaDB database, and interpreters for scripts written in the PHP and
Perl programming languages.

2.4.2 LANGUAGE

 HTML: Hypertext Markup Language is the standard markup language


for documents designed to be displayed in a web browser. It can be
assisted technologies such as Cascading Style Sheets and scripting
languages such as JavaScript.
 CSS: Cascading Style Sheets (CSS) is a style sheet language used for
describing the presentation of a document written in a markup language
like HTML. CSS is a cornerstone technology of the World Wide Web,
alongside HTML and JavaScript.
 Bootstrap: Bootstrap is a free and open-source CSS framework directed
at responsive, mobile-first front-end web development. It contains CSS
and JavaScript-based design templates for typography, forms, buttons,
modals navigation, and other interface components.
 JavaScript: JavaScript is a programming language that conforms to the
ECMA Script specification. JavaScript is high-level, often just-in-time
compiled, and multi- paradigm. Curly bracket syntax, dynamic typing,
prototype-based object-orientation, and first-class functions.
 PHP: Php is a server-side scripting language. that is used to develop
Static websites or Dynamic websites or Web applications. PHP stands
for Hypertext Pre-processor, that earlier stood for Personal Home Pages.
PHP scripts can only be interpreted on a server that has PHP installed.

2.4.3 MySQL

MySQL is an open-source relational database management system. Its name is a


combination of "My", the name of co-founder Michael Widenius's daughter, and
"SQL", the abbreviation for Structured Query Language. This application is
widely used for purposes, including data warehousing, e-commerce and logging
applications. The data in MySQL databases are stored in the form of tables. It
helps the admins to collect the data in an easy way. One of the reasons MySQL
is the world's most popular open source database is that it provides
comprehensive support for every application development need. ... MySQL also
provides connectors and drivers (ODBC, JDBC, etc.) that allow all forms of
applications to make use of MySQL as a preferred data management server.

2.5 DATA FLOW DIAGRAM (DFD)

DFD is an important tool used by system analysis. A data flow diagram model, a
system using external entities from which data flows to a process which
transforms the data and create output data transforms which go to other
processes or external entities such as files. The main merit of DFD is that it can
provide an overview of what data a system would process.
SYMBOLS

 A Circle represents a process that transforms incoming data flow into


outgoing data flows.
 A Square defines a source or destination of system data.
 An Arrow identifies data flow direction. It is the pipeline
through which the information flows.
 An Open Rectangle is a data store, data at rest or a temporary repository of data.

Data flow diagram symbol

Data Flow - Data flow are pipelines through the packets of information flow.

Process - A Process or task performed by the system.

Entity - Entity are object of the system. A source or destination data of a system.

Data Store - A place where data to be stored.

CONTEXT LEVEL DFD:

The context level data flow diagram (dfd) is describe the whole system. The (0)
level dfd describe the all user module who operate the system. Below data flow
diagram of online library management site shows the two user can operate the
system Admin and Member user.
CHAP

TER 3

SYSTE

DESIG

3.1 ER Diagram
3.2 DATABASE NORMALIZATION

Normalization is a database design technique that reduces data redundancy and


eliminates undesirable characteristics like Insertion, Update and Deletion
Anomalies. Normalization rules divides larger tables into smaller tables and
links them using relationships. The purpose of Normalisation in SQL is to
eliminate redundant (repetitive) data and ensure data is stored logically.
Source Code

Database Connection
import mongoose from "mongoose";

export const connectDB = async () =>{


await mongoose.connect('mongodb+srv://Test:test123@cluster0.f5edu4z.mongodb.net/food-
del').then(()=>console.log("DB Connected"))
}
Admin Page
Add-:
Css :
.add{
width: 70%;
margin-left: max(5vw,25px);
margin-top: 50px;
color: #6D6D6D;
font-size: 16px;
}
.add form{
gap: 20px;
}
.add-img-upload img{
width: 120px;
}
.add-product-name, .add-product-description{
width: max(40%,280px);
}
.add-product-name input ,.add-product-description textarea{
padding: 10px 10px;
}
.add-category-price{
display: flex;
gap: 30px;
}
.add-category-price select,.add-category-price input{
max-width: 120px;
padding: 10px;
}
.add-btn{
max-width: 120px;
border: none;
padding: 10px;
background-color: black;
color: white;
cursor: pointer;
}
export default Add
List-:
Css :
.list-table-format{
display: grid;
grid-template-columns: 0.5fr 2fr 1fr 1fr 0.5fr;
align-items: center;
gap: 10px;
padding: 12px 15px;
border: 1px solid #cacaca;
font-size: 13px;
}
.list-table-format.title{
background-color: #f9f9f9;
}
.list-table-format img{
width: 50px;
}
@media(max-width:600px){
.list-table-format{
grid-template-columns: 1fr 3fr 1fr;
gap: 15px;
}
.list-table-format.title{
display: none;
}
}
List.jsx :
import React, { useEffect, useState } from 'react'
import './List.css'
import { url } from '../../assets/assets'
import axios from 'axios';
import { toast } from 'react-toastify';

const List = () => {

const [list,setList] = useState([]);

const fetchList = async () => {


const response = await axios.get(`${url}/api/food/list`)
if(response.data.success)
{
setList(response.data.data);
}
else{
toast.error("Error")
}
}

const removeFood = async (foodId) => {


const response = await axios.post(`${url}/api/food/remove`,{
id:foodId
})
await fetchList();
if (response.data.success) {
toast.success(response.data.message);
}
else {
toast.error("Error")
}
}

useEffect(()=>{
fetchList();
},[])

return (
<div className='list add flex-col'>
<p>All Foods List</p>
<div className='list-table'>
<div className="list-table-format title">
<b>Image</b>
<b>Name</b>
<b>Category</b>
<b>Price</b>
<b>Action</b>
</div>
{list.map((item,index)=>{
return (
<div key={index} className='list-table-format'>
<img src={`${url}/images/`+item.image} alt="" />
<p>{item.name}</p>
<p>{item.category}</p>
<p>₹{item.price}</p>
<p className='cursor' > </div>
)
})}
</div>
</div>
)
}

export default List


Order-:
Css :
.order-item{
display: grid;
grid-template-columns: 0.5fr 2fr 1fr 1fr 1fr;
align-items: start;
gap: 30px;
border: 1px solid tomato;
padding: 20px;
margin: 30px 0px;
font-size: 14px;
color: #505050;
}
.order-item-food,.order-item-name{
font-weight: 600;
}
.order-item-name{
margin-top: 30px;
margin-bottom: 5px;
}
.order-item-address{
margin-bottom: 10px;
}
.order-item select{
background-color: #ffe8e4;
border: 1px solid tomato;
width: max(10vw,120px);
padding: 10px;
outline:none;
}
@media(max-width:1000px){
.order-item{
font-size: 12px;
grid-template-columns: 0.5fr 2fr 1fr;
padding: 15px 8px;
}
.order-item select{
padding: 5px;
font-size: 12px;
}
.order-item img{
width: 40px;
}
}
Order.jsx -:
import React, { useEffect, useState } from 'react'
import './Orders.css'
import { toast } from 'react-toastify';
import axios from 'axios';
import { assets, url } from '../../assets/assets';

const Order = () => {

const [orders, setOrders] = useState([]);

const fetchAllOrders = async () => {


const response = await axios.get(`${url}/api/order/list`)
if (response.data.success) {
setOrders(response.data.data.reverse());
console.log(response.data.data);
}
else {
toast.error("Error")
}
}

const statusHandler = async (event,orderId) => {


console.log(event,orderId);
const response = await axios.post(`${url}/api/order/status`,{
orderId,
status:event.target.value
})
if(response.data.success)
{
await fetchAllOrders();
}
}

useEffect(() => {
fetchAllOrders();
}, [])

return (
<div className='order add'>
<h3>Order Page</h3>
<div className="order-list">
{orders.map((order, index) => (
<div key={index} className='order-item'>
<img src={assets.parcel_icon} alt="" />
<div>
<p className='order-item-food'>
{order.items.map((item, index) => {
if (index === order.items.length - 1) {
return item.name + " x " + item.quantity
}
else {
return item.name + " x " + item.quantity + ", "
}
})}
</p>
<p className='order-item-name'>{order.address.firstName+" "+order.address.lastName}</p>
<div className='order-item-address'>
<p>{order.address.street+","}</p>
<p>{order.address.city+", "+order.address.state+", "+order.address.country+",
"+order.address.zipcode}</p>
</div>
<p className='order-item-phone'>{order.address.phone}</p>
</div>
<p>Items : {order.items.length}</p>
<p>₹{order.amount}</p>
<select value={order.status} name="" id="">
<option value="Food Processing">Food Processing</option>
<option value="Out for delivery">Out for delivery</option>
<option value="Delivered">Delivered</option>
</select>
</div>
))}
</div>
</div>
)
}

export default Order

App.jsx -:
import React from 'react'
import Navbar from './components/Navbar/Navbar'
import Sidebar from './components/Sidebar/Sidebar'
import { Route, Routes } from 'react-router-dom'
import Add from './pages/Add/Add'
import List from './pages/List/List'
import Orders from './pages/Orders/Orders'
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const App = () => {


return (
<div className='app'>
<ToastContainer/>
<Navbar/>
<hr />
<div className="app-content">
<Sidebar/>
<Routes>
<Route path="/add" element={<Add/>}/>
<Route path="/list" element={<List/>}/>
<Route path="/orders" element={<Orders/>}/>
</Routes>
</div>
</div>
)
}

export default App

Index.css-:

@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap');
*{
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: Outfit;
}
body{
min-height: 100vh;
background-color: #FCFCFC;
}
a{
text-decoration: none;
color: inherit;
}
hr{
border: none;
height: 1px;
background-color: #A9A9A9;
}
.app-content{
display: flex;
}
.flex-col{
display: flex;
flex-direction: column;
gap: 10px;
}
.cursor{
cursor: pointer;
}
Main.jsx -:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import { BrowserRouter } from 'react-router-dom'
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<App />
</BrowserRouter>

)
Index.html -:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Food Del Admin Panel</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

Backend
CartContoller.js -:
import userModel from "../models/userModel.js"

// add to user cart


const addToCart = async (req, res) => {
try {
let userData = await userModel.findOne({_id:req.body.userId});
let cartData = await userData.cartData;
if (!cartData[req.body.itemId]) {
cartData[req.body.itemId] = 1;
}
else {
cartData[req.body.itemId] += 1;
}
await userModel.findByIdAndUpdate(req.body.userId, {cartData});
res.json({ success: true, message: "Added To Cart" });
} catch (error) {
console.log(error);
res.json({ success: false, message: "Error" })
}
}

// remove food from user cart


const removeFromCart = async (req, res) => {
try {
let userData = await userModel.findById(req.body.userId);
let cartData = await userData.cartData;
if (cartData[req.body.itemId] > 0) {
cartData[req.body.itemId] -= 1;
}
await userModel.findByIdAndUpdate(req.body.userId, {cartData});
res.json({ success: true, message: "Removed From Cart" });
} catch (error) {
console.log(error);
res.json({ success: false, message: "Error" })
}

// get user cart


const getCart = async (req, res) => {
try {
let userData = await userModel.findById(req.body.userId);
let cartData = await userData.cartData;
res.json({ success: true, cartData:cartData });
} catch (error) {
console.log(error);
res.json({ success: false, message: "Error" })
}
}

export { addToCart, removeFromCart, getCart }


FoodController.js -:
import foodModel from "../models/foodModel.js";
import fs from 'fs'

// all food list


const listFood = async (req, res) => {
try {
const foods = await foodModel.find({})
res.json({ success: true, data: foods })
} catch (error) {
console.log(error);
res.json({ success: false, message: "Error" })
}

// add food
const addFood = async (req, res) => {

let image_filename = `${req.file.filename}`

const food = new foodModel({


name: req.body.name,
description: req.body.description,
price: req.body.price,
category:req.body.category,
image: image_filename,
})
try {
await food.save();
res.json({ success: true, message: "Food Added" })
} catch (error) {
console.log(error);
res.json({ success: false, message: "Error" })
}
}

// delete food
const removeFood = async (req, res) => {
try {

const food = await foodModel.findById(req.body.id);


fs.unlink(`uploads/${food.image}`, () => { })

await foodModel.findByIdAndDelete(req.body.id)
res.json({ success: true, message: "Food Removed" })

} catch (error) {
console.log(error);
res.json({ success: false, message: "Error" })
}

export { listFood, addFood, removeFood }


OrderController.js -:
import orderModel from "../models/orderModel.js";
import userModel from "../models/userModel.js"
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
// Placing User Order for Frontend
const placeOrder = async (req, res) => {

try {
const newOrder = new orderModel({
userId: req.body.userId,
items: req.body.items,
amount: req.body.amount,
address: req.body.address,
})
await newOrder.save();
await userModel.findByIdAndUpdate(req.body.userId, { cartData: {} });

const line_items = req.body.items.map((item) => ({


price_data: {
currency: "inr",
product_data: {
name: item.name
},
unit_amount: item.price*100
},
quantity: item.quantity
}))

line_items.push({
price_data:{
currency:"inr",
product_data:{
name:"Delivery Charge"
},
unit_amount: 10*50
},
quantity:1
})
const session = await stripe.checkout.sessions.create({
success_url: `http://localhost:5173/verify?success=true&orderId=${newOrder._id}`,
cancel_url: `http://localhost:5173/verify?success=false&orderId=${newOrder._id}`,
line_items: line_items,
mode: 'payment',
});

res.json({success:true,session_url:session.url});

} catch (error) {
console.log(error);
res.json({ success: false, message: "Error" })
}
}

// Listing Order for Admin panel


const listOrders = async (req, res) => {
try {
const orders = await orderModel.find({});
res.json({ success: true, data: orders })
} catch (error) {
console.log(error);
res.json({ success: false, message: "Error" })
}
}

// User Orders for Frontend


const userOrders = async (req, res) => {
try {
const orders = await orderModel.find({ userId: req.body.userId });
res.json({ success: true, data: orders })
} catch (error) {
console.log(error);
res.json({ success: false, message: "Error" })
}
}

const updateStatus = async (req, res) => {


console.log(req.body);
try {
await orderModel.findByIdAndUpdate(req.body.orderId, { status: req.body.status });
res.json({ success: true, message: "Status Updated" })
} catch (error) {
res.json({ success: false, message: "Error" })
}

const verifyOrder = async (req, res) => {


const {orderId , success} = req.body;
try {
if (success==="true") {
await orderModel.findByIdAndUpdate(orderId, { payment: true });
res.json({ success: true, message: "Paid" })
}
else{
await orderModel.findByIdAndDelete(orderId)
res.json({ success: false, message: "Not Paid" })
}
} catch (error) {
res.json({ success: false, message: "Not Verified" })
}

export { placeOrder, listOrders, userOrders, updateStatus ,verifyOrder }


UserController.js -:
import jwt from "jsonwebtoken";
import bcrypt from "bcrypt";
import validator from "validator";
import userModel from "../models/userModel.js";

//create token
const createToken = (id) => {
return jwt.sign({id}, process.env.JWT_SECRET);
}

//login user
const loginUser = async (req,res) => {
const {email, password} = req.body;
try{
const user = await userModel.findOne({email})

if(!user){
return res.json({success:false,message: "User does not exist"})
}

const isMatch = await bcrypt.compare(password, user.password)

if(!isMatch){
return res.json({success:false,message: "Invalid credentials"})
}

const token = createToken(user._id)


res.json({success:true,token})
} catch (error) {
console.log(error);
res.json({success:false,message:"Error"})
}
}
//register user
const registerUser = async (req,res) => {
const {name, email, password} = req.body;
try{
//check if user already exists
const exists = await userModel.findOne({email})
if(exists){
return res.json({success:false,message: "User already exists"})
}

// validating email format & strong password


if(!validator.isEmail(email)){
return res.json({success:false,message: "Please enter a valid email"})
}
if(password.length<8){
return res.json({success:false,message: "Please enter a strong password"})
}

// hashing user password


const salt = await bcrypt.genSalt(10); // the more no. round the more time it will take
const hashedPassword = await bcrypt.hash(password, salt)

const newUser = new userModel({name, email, password: hashedPassword})


const user = await newUser.save()
const token = createToken(user._id)
res.json({success:true,token})

} catch(error){
console.log(error);
res.json({success:false,message:"Error"})
}
}

export {loginUser, registerUser}


auth.js -:
import jwt from 'jsonwebtoken';

const authMiddleware = async (req, res, next) => {


const { token } = req.headers;
if (!token) {
return res.json({success:false,message:'Not Authorized Login Again'});
}
try {
const token_decode = jwt.verify(token, process.env.JWT_SECRET);
req.body.userId = token_decode.id;
next();
} catch (error) {
return res.json({success:false,message:error.message});
}
}

export default authMiddleware;


Models -:
FoodModel.js -:
import mongoose from "mongoose";

const foodSchema = new mongoose.Schema({


name: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true},
image: { type: String, required: true },
category:{ type:String, required:true}
})

const foodModel = mongoose.models.food || mongoose.model("food", foodSchema);


export default foodModel;
OrderModel.js -:
import mongoose from "mongoose";
const orderSchema = new mongoose.Schema({
userId: {type:String,required:true},
items: { type: Array, required:true},
amount: { type: Number, required: true},
address:{type:Object,required:true},
status: {type:String,default:"Food Processing"},
date: {type:Date,default:Date.now()},
payment:{type:Boolean,default:false}
})

const orderModel = mongoose.models.order || mongoose.model("order", orderSchema);


export default orderModel;
UserModel.js -:
import mongoose from "mongoose";

const userSchema = new mongoose.Schema({


name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
cartData:{type:Object,default:{}}
}, { minimize: false })

const userModel = mongoose.models.user || mongoose.model("user", userSchema);


export default userModel;

Server.js -:
import express from "express"
import cors from 'cors'
import { connectDB } from "./config/db.js"
import userRouter from "./routes/userRoute.js"
import foodRouter from "./routes/foodRoute.js"
import 'dotenv/config'
import cartRouter from "./routes/cartRoute.js"
import orderRouter from "./routes/orderRoute.js"

// app config
const app = express()
const port = 4000

// middlewares
app.use(express.json())
app.use(cors())

// db connection
connectDB()

// api endpoints
app.use("/api/user", userRouter)
app.use("/api/food", foodRouter)
app.use("/images",express.static('uploads'))
app.use("/api/cart", cartRouter)
app.use("/api/order",orderRouter)

app.get("/", (req, res) => {


res.send("API Working")
});

app.listen(port, () => console.log(`Server started on http://localhost:${port}`))

Frontend -:
Explore Menu -:
.explore-menu{
display: flex;
flex-direction: column;
gap: 20px;
}
.explore-menu h1{
color: #262626;
font-weight: 500;
}
.explore-menu-text{
max-width: 60%;
color: #808080;
}
.explore-menu-list{
display: flex;
justify-content: space-between;
align-items: center;
gap: 30px;
text-align: center;
margin: 20px 0px;
overflow-x: scroll;
}
.explore-menu-list::-webkit-scrollbar{
display: none;
}
.explore-menu-list-item img{
width: 7.5vw;
min-width: 80px;
cursor: pointer;
border-radius: 50%;
transition: 0.2s;
}
.explore-menu-list-item .active{
border: 4px solid tomato;
padding: 2px;
}
.explore-menu-list-item p{
margin-top: 10px;
color: #747474;
font-size: max(1.4vw,16px);
cursor: pointer;
}
.explore-menu hr{
margin: 10px 0px;
height: 2px;
background-color: #E2E2E2;
border: none;
}
@media (max-width:1050px) {
.explore-menu-text{
max-width: 100%;
font-size: 14px;
}
}
import React, { useContext } from 'react'
import './ExploreMenu.css'
import { StoreContext } from '../../Context/StoreContext'

const ExploreMenu = ({category,setCategory}) => {

const {menu_list} = useContext(StoreContext);

return (
<div className='explore-menu' id='explore-menu'>
<h1>Explore our menu</h1>
<p className='explore-menu-text'>Choose from a diverse menu featuring a delectable array of
dishes. Our mission is to satisfy your cravings and elevate your dining experience, one delicious meal at
a time.</p>
<div className="explore-menu-list">
{menu_list.map((item,index)=>{
return (
<div >key={index} className='explore-menu-list-item'>
<img src={item.menu_image} className={category===item.menu_name?"active":""}
alt="" />
<p>{item.menu_name}</p>
</div>
)
})}
</div>
<hr />
</div>
)
}

export default ExploreMenu

FoodDisplay -:
.food-display{
margin-top: 30px;
}
.food-display h2{
font-size: max(2vw,24px);
font-weight: 600;
}
.food-display-list{
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
margin-top: 30px;
gap: 30px;
row-gap: 50px;
}
import React, { useContext } from 'react'
import './FoodDisplay.css'
import FoodItem from '../FoodItem/FoodItem'
import { StoreContext } from '../../Context/StoreContext'
const FoodDisplay = ({category}) => {

const {food_list} = useContext(StoreContext);

return (
<div className='food-display' id='food-display'>
<h2>Top dishes near you</h2>
<div className='food-display-list'>
{food_list.map((item)=>{
if (category==="All" || category===item.category) {
return <FoodItem key={item._id} image={item.image} name={item.name}
desc={item.description} price={item.price} id={item._id}/>
}
})}
</div>
</div>
)
}

export default FoodDisplay


FoodItem -:
.food-item{
width: 100%;
margin: auto;
border-radius: 15px;
box-shadow: 0px 0px 10px #00000015;
transition: 0.3s;
animation: fadeIn 1s;
}
.food-item:hover{
transform: scale(1.02);
}
.food-item-img-container{
position: relative;
}
.food-item-img-container .add{
width: 35px;
position: absolute;
bottom: 15px;
right: 15px;
cursor: pointer;
border-radius: 50%;
}
.food-item-img-container .add:hover{
border: 2px solid #FF4C24;
}
.food-item-image{
width: 100%;
border-radius: 15px 15px 0px 0px;
}
.food-item-counter{
position: absolute;
bottom: 15px;
right: 15px;
display: flex;
align-items: center;
gap: 10px;
padding: 6px;
border-radius: 50px;
background-color: white;
}
.food-item-counter img{
width: 30px;
}
.food-item-info{
padding: 20px;
}
.food-item-name-rating{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.food-item-name-rating p{
font-size: 20px;
font-weight: 500;
}
.food-item-name-rating img{
width: 70px;
}
.food-item-desc{
color: #676767;
font-size: 12px;
}
.food-item-price{
color: #FF4C24;
font-size: 22px;
font-weight: 500;
margin: 10px 0px;
}
import React, { useContext, useState } from 'react'
import './FoodItem.css'
import { assets } from '../../assets/assets'
import { StoreContext } from '../../Context/StoreContext';

const FoodItem = ({ image, name, price, desc , id }) => {

const [itemCount, setItemCount] = useState(0);


const {cartItems,addToCart,removeFromCart,url} = useContext(StoreContext);

return (
<div className='food-item'>
<div className='food-item-img-container'>
<img className='food-item-image' src={url+"/images/"+image} alt="" />
{!cartItems[id]
?<img className='add' => addToCart(id)} src={assets.add_icon_white}
alt="" />
:<div className="food-item-counter">
<img src={assets.remove_icon_red} alt="" />
<p>{cartItems[id]}</p>
<img src={assets.add_icon_green} alt="" />
</div>
}
</div>
<div className="food-item-info">
<div className="food-item-name-rating">
<p>{name}</p> <img src={assets.rating_starts} alt="" />
</div>
<p className="food-item-desc">{desc}</p>
<p className="food-item-price">₹{price}</p>
</div>
</div>
)
}

export default FoodItem

Footer -:
.footer{
color: #D9D9D9;
background-color: #323232;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 20px 8vw;
padding-top: 80px;
}
.footer-content{
width: 100%;
display: grid;
grid-template-columns: 2fr 1fr 1fr;
gap: 80px;
}
.footer-content-left , .footer-content-center , .footer-content-right {
display: flex;
flex-direction: column;
align-items: start;
gap: 20px;
}
.footer-content-left ul li, .footer-content-center ul li, .footer-content-right ul li{
margin-bottom: 10px;
list-style: none;
}
.footer-content-left h2, .footer-content-center h2, .footer-content-right h2{
color: white;
}
.footer-social-icons img{
width: 40px;
}
.footer-social-icons{
display: flex;
gap: 15px;
}
.footer li{
cursor: pointer;
}
.footer hr{
width: 100%;
height: 2px;
margin: 20px 0px;
}
@media (max-width:750px) {
.footer-content{
display: flex;
flex-direction: column;
gap: 35px;
}
.footer-copyright{
text-align: center;
}
}
import React from 'react'
import './Footer.css'
import { assets } from '../../assets/assets'

const Footer = () => {


return (
<div className='footer' id='footer'>
<div className="footer-content">
<div className="footer-content-left">
<img src={assets.logo} alt="" />
<p>Delightfully bringing culinary convenience to your doorstep. Enjoy every bite with
Tomato.</p>
<div className="footer-social-icons">
<img src={assets.facebook_icon} alt="" />
<img src={assets.twitter_icon} alt="" />
<img src={assets.linkedin_icon} alt="" />
</div>
</div>
<div className="footer-content-center">
<h2>COMPANY</h2>
<ul>
<li>Home</li>
<li>About us</li>
<li>Delivery</li>
<li>Privacy policy</li>
</ul>
</div>
<div className="footer-content-right">
<h2>GET IN TOUCH</h2>
<ul>
<li>+1-212-456-7890</li>
<li>contact@tomato.com</li>
</ul>
</div>
</div>
<hr />
<p className="footer-copyright">Copyright 2024 © Tomato.com - All Right Reserved.</p>
</div>
)
}

export default Footer

Header -:
.header{
height: 34vw;
margin: 30px auto;
background: url('/header_img.png') no-repeat;
background-size:contain;
position: relative;
}
.header-contents{
position: absolute;
display: flex;
flex-direction: column;
align-items: start;
gap: 1.5vw;
max-width: 50%;
bottom: 10%;
left: 6vw;
animation: fadeIn 3s;
}
.header-contents h2{
font-weight:500;
color: white;
font-size: max(4.5vw,22px);
}
.header-contents p{
color: white;
font-size: 1vw;
}
.header-contents button{
border: none;
color: #747474;
font-weight: 500;
padding: 1vw 2.3vw;
background: white;
font-size: max(1vw,13px);
border-radius: 50px;
}
@media (max-width:1050px) {
.header{
height: 38vw;
}
.header-contents{
max-width: 45%;
}
}
@media(max-width:750px){
.header-contents{
max-width: 55%;
}
.header-contents p{
display: none;
}
.header-contents button{
padding: 2vw 4vw;
}
}
import React from 'react'
import './Header.css'

const Header = () => {


return (
<div className='header'>
<div className='header-contents'>
<h2>Order your favourite food here</h2>
<p>Choose from a diverse menu featuring a delectable array of dishes crafted with the finest
ingredients and culinary expertise. Our mission is to satisfy your cravings and elevate your dining
experience, one delicious meal at a time.</p>
<button>View Menu</button>
</div>
</div>
)
}

export default Header

LoginPopup-:
.login-popup{
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
background-color: #00000090;
display: grid;
}
.login-popup-container{
place-self: center;
width: max(23vw,330px);
color: #808080;
background-color: white;
display: flex;
flex-direction: column;
gap: 25px;
padding: 25px 30px;
border-radius: 8px;
font-size: 14px;
animation: fadeIn 0.5s;
}
.login-popup-title{
display: flex;
justify-content: space-between;
align-items: center;
color: black;
}
.login-popup-title img{
width: 16px;
cursor: pointer;
}
.login-popup-inputs{
display: flex;
flex-direction: column;
gap: 20px;
}
.login-popup-inputs input{
outline: none;
border: 1px solid #C9C9C9;
padding: 10px;
border-radius: 4px;
}
.login-popup-container button{
border: none;
padding: 10px;
border-radius: 4px;
color: white;
background-color: #FF4C24;
font-size: 15px;
cursor: pointer;
}
.login-popup-condition{
display: flex;
align-items: start;
gap: 8px;
margin-top: -15px;
}

.login-popup-condition input{
margin-top: 5px;
}

.login-popup p span{
color: #FF4C24;
font-weight: 500;
cursor: pointer;
}
import React, { useContext, useState } from 'react'
import './LoginPopup.css'
import { assets } from '../../assets/assets'
import { StoreContext } from '../../Context/StoreContext'
import axios from 'axios'
import { toast } from 'react-toastify'

const LoginPopup = ({ setShowLogin }) => {

const { setToken, url,loadCartData } = useContext(StoreContext)


const [currState, setCurrState] = useState("Sign Up");

const [data, setData] = useState({


name: "",
email: "",
password: ""
})

const => {


const name = event.target.name
const value = event.target.value
setData(data => ({ ...data, [name]: value }))
}

const (e) => {


e.preventDefault()

let new_url = url;


if (currState === "Login") {
new_url += "/api/user/login";
}
else {
new_url += "/api/user/register"
}
const response = await axios.post(new_url, data);
if (response.data.success) {
setToken(response.data.token)
localStorage.setItem("token", response.data.token)
loadCartData({token:response.data.token})
setShowLogin(false)
}
else {
toast.error(response.data.message)
}
}

return (
<div className='login-popup'>
<form className="login-popup-container">
<div className="login-popup-title">
<h2>{currState}</h2> <img => setShowLogin(false)}
src={assets.cross_icon} alt="" />
</div>
<div className="login-popup-inputs">
{currState === "Sign Up" ? <input name='name' >value={data.name} type="text" placeholder='Your name' required /> : <></>}
<input name='email' value={data.email} type="email"
placeholder='Your email' />
<input name='password' value={data.password}
type="password" placeholder='Password' required />
</div>
<button>{currState === "Login" ? "Login" : "Create account"}</button>
<div className="login-popup-condition">
<input type="checkbox" name="" id="" required/>
<p>By continuing, i agree to the terms of use & privacy policy.</p>
</div>
{currState === "Login"
? <p>Create a new account? <span => setCurrState('Sign Up')}>Click
here</span></p>
: <p>Already have an account? <span => setCurrState('Login')}>Login
here</span></p>
}
</form>
</div>
)
}

export default LoginPopup

NavBar-:
.navbar {
padding: 20px 0px;
display: flex;
justify-content: space-between;
align-items: center;
}

.navbar .logo {
width: 150px;
}

.navbar-menu {
display: flex;
list-style: none;
gap: 20px;
color: #49557E;
font-size: 18px;
}

.navbar-menu .active {
padding-bottom: 2px;
border-bottom: 2px solid #49557E;
}
.navbar-right {
display: flex;
align-items: center;
gap: 40px;
}

.navbar-search-icon{
position: relative;
}

.navbar-search-icon .dot{
position: absolute;
min-width: 10px;
min-height: 10px;
background-color: #FF4C24;
border-radius: 5px;
top: -8px;
right: -8px;
}

.navbar-right button {
background: transparent;
font-size: 16px;
color: #49557E;
border: 1px solid #FF4C24;
padding: 10px 30px;
border-radius: 50px;
cursor: pointer;
transition: 0.3s;
}

.navbar-right button:hover {
background: #fff4f2;
}

.navbar-profile{
position: relative;

}
.navbar-profile-dropdown{
position: absolute;
display: none;
right: 0;
z-index: 1;
}
.navbar-profile-dropdown li{
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
}
.navbar-profile-dropdown img{
width: 20px;
}
.navbar-profile-dropdown li:hover{
color: #FF4C24;
}
.navbar-profile:hover .navbar-profile-dropdown{
display: flex;
flex-direction: column;
gap: 10px;
background-color: #fff2ef;
padding: 12px 25px;
border-radius: 4px;
border: 1px solid tomato;
outline: 2px solid white;
list-style: none;
}
.navbar-profile hr{
background-color: gray;
height: 1px;
border: none;
}
@media (max-width:1050px) {
.navbar .logo {
width: 140px;
}

.navbar-menu {
gap: 20px;
font-size: 17px;
}

.navbar-right {
gap: 30px;
}

.navbar-right img {
width: 22px;
}

.navbar-right button {
padding: 8px 25px;
}
}

@media (max-width:900px) {
.navbar .logo {
width: 120px;
}
.navbar-menu {
gap: 15px;
font-size: 16px;
}

.navbar-right {
gap: 20px;
}

.navbar-right img {
width: 20px;
}

.navbar-right button {
font-size: 15px;
padding: 7px 20px;
}
}

@media (max-width:750px) {
.navbar-menu {
display: none;
}
}

StoreContent-:
import { createContext, useEffect, useState } from "react";
import { food_list, menu_list } from "../assets/assets";
import axios from "axios";
export const StoreContext = createContext(null);

const StoreContextProvider = (props) => {

const url = "http://localhost:4000"


const [food_list, setFoodList] = useState([]);
const [cartItems, setCartItems] = useState({});
const [token, setToken] = useState("")

const addToCart = async (itemId) => {


if (!cartItems[itemId]) {
setCartItems((prev) => ({ ...prev, [itemId]: 1 }));
}
else {
setCartItems((prev) => ({ ...prev, [itemId]: prev[itemId] + 1 }));
}
if (token) {
await axios.post(url + "/api/cart/add", { itemId }, { headers: { token } });
}
}

const removeFromCart = async (itemId) => {


setCartItems((prev) => ({ ...prev, [itemId]: prev[itemId] - 1 }))
if (token) {
await axios.post(url + "/api/cart/remove", { itemId }, { headers: { token } });
}
}

const getTotalCartAmount = () => {


let totalAmount = 0;
for (const item in cartItems) {
if (cartItems[item] > 0) {
let itemInfo = food_list.find((product) => product._id === item);
totalAmount += itemInfo.price * cartItems[item];
}
}
return totalAmount;
}
const fetchFoodList = async () => {
const response = await axios.get(url + "/api/food/list");
setFoodList(response.data.data)
}

const loadCartData = async (token) => {


const response = await axios.post(url + "/api/cart/get", {}, { headers: token });
setCartItems(response.data.cartData);
}

useEffect(() => {
async function loadData() {
await fetchFoodList();
if (localStorage.getItem("token")) {
setToken(localStorage.getItem("token"))
await loadCartData({ token: localStorage.getItem("token") })
}
}
loadData()
}, [])

const contextValue = {
url,
food_list,
menu_list,
cartItems,
addToCart,
removeFromCart,
getTotalCartAmount,
token,
setToken,
loadCartData,
setCartItems
};

return (
<StoreContext.Provider value={contextValue}>
{props.children}
</StoreContext.Provider>
)

export default StoreContextProvider;

Cart-:
.cart {
margin: 100px 0px;
}

.cart hr {
height: 1px;
background-color: #E2E2E2;
border: none;
}

.cart-items-title {
display: grid;
grid-template-columns: 1fr 1.5fr 1fr 1fr 1fr 0.5fr;
align-items: center;
color: grey;
font-size: max(1vw, 12px);
}

.cart-items-item {
margin: 10px 0px;
color: black;
}

.cart-items-item img {
width: 50px;
}

.cart-items-item div {
max-width: 40px;
text-align: center;
border: 1px solid #EBEBEB;
padding: 8px 8px;
font-size: 12px;
}
.cart-items-remove-icon{
cursor: pointer;
}
.cart-bottom {
margin-top: 80px;
display: flex;
justify-content: space-between;
gap: max(12vw,20px);
}

.cart-total {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
}

.cart-total-details {
display: flex;
justify-content: space-between;
color: #555555;
}

.cart-total hr {
margin: 10px 0px;
}

.cart-total button {
border: none;
color: white;
background-color: #FF4C24;
width: max(15vw,200px);
padding: 12px 0px;
border-radius: 4px;
cursor: pointer;
}

.cart-promocode {
flex: 1;
}
.cart-promocode p{
color: #555555;
}
.cart-promocode-input{
margin-top: 10px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #eaeaea;
border-radius: 4px;
}
.cart-promocode-input input{
background: transparent;
border: none;
outline: none;
padding-left: 10px;
}
.cart-promocode-input button{
width: max(10vw,150px);
padding: 12px 5px;
background-color: black;
border: none;
color: white;
border-radius: 4px;
}

@media(max-width:750px) {
.cart-bottom {
flex-direction: column-reverse;
}
.cart-promocode{
justify-content: start;
}
}

Home-:
import React, { useState } from 'react'
import Header from '../../components/Header/Header'
import ExploreMenu from '../../components/ExploreMenu/ExploreMenu'
import FoodDisplay from '../../components/FoodDisplay/FoodDisplay'
import AppDownload from '../../components/AppDownload/AppDownload'

const Home = () => {

const [category,setCategory] = useState("All")

return (
<>
<Header/>
<ExploreMenu setCategory={setCategory} category={category}/>
<FoodDisplay category={category}/>
<AppDownload/>
</>
)
}

export default Home

App.jsx-:
import React, { useState } from 'react'
import Home from './pages/Home/Home'
import Footer from './components/Footer/Footer'
import Navbar from './components/Navbar/Navbar'
import { Route, Routes } from 'react-router-dom'
import Cart from './pages/Cart/Cart'
import LoginPopup from './components/LoginPopup/LoginPopup'
import PlaceOrder from './pages/PlaceOrder/PlaceOrder'
import MyOrders from './pages/MyOrders/MyOrders'
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import Verify from './pages/Verify/Verify'

const App = () => {

const [showLogin,setShowLogin] = useState(false);

return (
<>
<ToastContainer/>
{showLogin?<LoginPopup setShowLogin={setShowLogin}/>:<></>}
<div className='app'>
<Navbar setShowLogin={setShowLogin}/>
<Routes>
<Route path='/' element={<Home />}/>
<Route path='/cart' element={<Cart />}/>
<Route path='/order' element={<PlaceOrder />}/>
<Route path='/myorders' element={<MyOrders />}/>
<Route path='/verify' element={<Verify />}/>
</Routes>
</div>
<Footer />
</>
)
}

export default App

index.css-:
@import url('https://fonts.googleapis.com/css2?
family=Outfit:wght@300;400;500;600;700&display=swap');

*{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Outfit', sans-serif;
scroll-behavior: smooth;
}

body {
min-height: 100vh;
}

a{
text-decoration: none;
color: inherit;
}

.app {
width: 80%;
margin: auto;
}

@keyframes fadeIn {
0% {
opacity: 0;
}

100% {
opacity: 1;
}
}

@media (max-width:1050px) {
.app {
width: 90%;
}
}

main.jsx-:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import { BrowserRouter } from 'react-router-dom'
import StoreContextProvider from './Context/StoreContext'

ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<StoreContextProvider>
<App />
</StoreContextProvider>
</BrowserRouter>,
)

index.html-:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tomato</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
Screenshots-:
1. Home Page-:

2. Sign Up-:

3. Log In-:
4. Admin Dashboard-:

5. List Items-:
6. Orders-:

7. Explore Menu-:
8. Cart-:

9. Checkout-:

10. Payment Page-:


CHAPTER 7

REFERENCES

 HTML & CSS, and JavaScript


Book by Jon Duckett

 Microsoft SQL Server : A beginner’s guide,seventh


EditionBook by Dusan Petkovic

 Microsoft® SQL Server® Notes for Professionals book


https://books.goalkicker.com/MicrosoftSQLServerBook/

 W3 Schools https://www.w3schools.com/

You might also like