TrustPilot clone – PHP, MySQL, Laravel

A clone of TrustPilot website is created in PHP and MySQL using Laravel framework version 11. For frontend rendering, I am using Vue JS 3 and on admin side I am using React JS.

Files included:

  • .php
  • .css
  • .js

Features:

  1. User can post reviews about a company.
  2. Can flag a review.
  3. Can share reviews on social media.
  4. Company owners can claim a company by verifying their email address.
  5. Automatically takes screenshot of a company home page.
  6. Admin can add companies from admin panel.
  7. Admin can view all reviews, flags and claims.

Demo:

Show loader on AJAX – VueJS

Today, you will learn, how you can show a loader in VueJS when an AJAX is called. We will be using Axios library for calling AJAX request.

If you do not want to use Axios library, you can use the default XMLHttpRequest object of Javascript. Learn how to do it from here.

Video tutorial:

Let’s say we have the following code that:

  1. Includes VueJS and Axios library.
  2. Create a div for Vue app.
  3. Mount Vue app onto the div.
  4. On mounted, calls an AJAX request.
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

<div id="app"></div>

And following javascript code will mount the Vue app.

Vue.createApp({
	async mounted() {
		const response = await axios.post(
			"https://api.github.com/users/adnanafzal565"
		)
		
		console.log(response)
	}
}).mount("#app")

Now, I will create a loading text that will be displayed only if the loading variable is true.

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

<div id="app">
	<p v-if="loading">Loading...</p>
</div>

Then I will create that variable in my Vue app and initialize it as false.

Vue.createApp({

	data() {
		return {
			loading: false
		}
	},

	async mounted() {
		const response = await axios.post(
			"https://api.github.com/users/adnanafzal565"
		)
		
		console.log(response)
	}
}).mount("#app")

Lastly, we are going to set this variable to true before calling the AJAX and false after the AJAX is finished.

Vue.createApp({

	data() {
		return {
			loading: false
		}
	},

	async mounted() {
		this.loading = true
		
		const response = await axios.post(
			"https://api.github.com/users/adnanafzal565"
		)
		
		this.loading = false
		
		console.log(response)
	}
}).mount("#app")

So that’s it. That’s how you can show a loader while AJAX is being called in VueJS.

Job Portal website in PHP and MySQL – MVC

A Job Portal website is created in PHP and MySQL using MVC architecture. MVC stands for Model-View-Controller and this architectural design is used by many websites for scalability.

Live Demo

  • ✅ Easy setup.
  • ✅ Compatible with almost every shared/dedicated/VPS hosting.
  • ✅ Free support.

New features:

  • ✅ Optimized sending bulk emails.

Files included:

  • .php
  • .css
  • .js

Tech stack:

  1. PHP +7.0
  2. MySQL +5.0
  3. Bootstrap 4
  4. Vue JS 3

Recruiter can post a job

Post job

Recruiter posted jobs

Recruiter uploaded jobs

Change status of applicant

Application status change

Edit/delete job

A recruiter can edit or delete any of his posted jobs at any time. This helps if the recruiter needs to change the requirements for a job or delete if the vacancy is already been filled.

Jobs Listing

Users will get a listing of all the jobs posted by recruiters.

Job listing

Job Detail

They can view the job details by clicking the job title.

Job detail

Filter Jobs

On the jobs listing page, users can filter jobs by the type of job they want, like developer, designer, etc. By the location to see if the job is in their city or if they can relocate to that city. Or by the nature of the job i.e. is the job part-time, full-time, or remote. Users can also search the jobs in their salary range. This way they can find jobs that pay them according to their needs.

Real-time updates on new jobs

Users will get real-time updates whenever a new job is posted by the recruiter. They do not have to refresh the page to check if there is any new job. To develop this feature, I have used sockets. You need to install Node JS in your system or server to make this feature work. Even if you do not have Node JS installed, all other features will work except for real-time job updates.

Email notifications of new jobs

Users can turn on notifications from recruiters. Whenever that recruiter posts a new job, all the users who have turned on their notifications will receive an email.

Admin can see all the stats

The admin of the website can see the total number of users registered. The total number of jobs that have been posted by recruiters. And the total number of applications that have been submitted for those jobs. The admin can see all this information on his dashboard.

Manage users

Admin will have the option to add new users to the website. While adding, he/she can select if the user be an applicant or a recruiter. Admin can also manage existing users. Admin can edit the user and can also delete the user if required. Admin can change the password of the user as well. This is helpful if the user is finding it difficult to receive the password reset email. Or if you want to prevent the user from logging in.

Deployment

This Job Portal website can be deployed on any server that supports PHP and MySQL.

Create a URL shortener app in Vue JS, Python, Mongo DB

In this tutorial, we will create a URL shortener app in Vue JS, Python and Mongo DB. We will use Vue JS as frontend, Python as backend and Mongo DB as database.

We will be creating a single page application in Vue JS 3, FastAPI for creating APIs in Python and standard Mongo DB for storing data.

User will enter a URL and the app will create a shorter URL of it. User can share that short URL on social media. Whenever someone access that short URL, we will show ads to him for 5 seconds. Then he will be able to move to the actual URL.

User can see how many people have clicked on his shorten URL and how many have accessed the real URL.

We will create the frontend in Vue JS 3, it will be a single page application (SPA). The backend will be in Python, we will be using FastAPI.

Add URL – Vue JS

The first step is to show user a form where he can enter his URL to shorten. So go ahead and create a folder anywhere in your computer (I have created on desktop). And inside that folder, create 2 more folders named “web” and “api”.

All our frontend code will go in “web” and all our backend code will go in “api”. Now open your command prompt (CMD) or terminal in your “web” folder and run the following command to install Vue JS.

> npm install -g @vue/cli

Then we will create an SPA in that folder.

> vue create .

If asked for Vue JS version, select Vue JS 3. Then run the following command to start Vue JS on localhost.

> npm run serve

You can access your app from http://localhost:8080/

Now go in your “web/src/components” and delete the “HelloWorld.vue” file. And create a file named “HomeComponent.vue”. Following will be the content of that file:

<template>
	HomeComponent
</template>

<script>
	export default {
		name: "HomeComponent"
	}
</script>

Open “src/main.js” and remove the “HelloWorld” component occurrences from there too.

In your components folder, create a folder named “layouts” and create 2 files in it: “AppHeader.vue” and “AppFooter.vue”. Following will be the content of these files:

// AppHeader.vue

<template>
	AppHeader
</template>

<script>
	export default {
		name: "AppHeader"
	}
</script>

// AppFooter.vue
<template>
	AppFooter
</template>

<script>
	export default {
		name: "AppFooter"
	}
</script>

Then run the following command to install “vue-router” that will be used for navigation, “sweetalert2” for displaying popups and “axios” for making AJAX calls.

npm install vue-router sweetalert2 axios

Then in your “main.js”, initialize the vue-router module.

import { createRouter, createWebHistory } from "vue-router"
import HomeComponent from "./components/HomeComponent.vue"

const app = createApp(App)

const routes = [
	{ path: "/", component: HomeComponent }
]

const router = createRouter({
	history: createWebHistory(),
	routes
})

app.use(router)
app.mount('#app')

Open your “web/src/App.vue” and replace the existing content with the following.

<template>
  <app-header />
    <router-view />
  <app-footer />
</template>

<script>

import AppHeader from "./components/layouts/AppHeader.vue"
import AppFooter from "./components/layouts/AppFooter.vue"

export default {
  name: 'App',
  components: {
    AppHeader,
    AppFooter
  }
}
</script>

After that, download Bootstrap 5 and paste the CSS and JS files in your “web/src/assets” folder. Then include them in your AppHeader component.

import "../../assets/css/bootstrap.css"
import "../../assets/js/jquery.js"
import "../../assets/js/bootstrap.js"

If you get any error regarding popper, just run the following commands.

> npm install @popperjs/core
> npm remove @vue/cli-plugin-eslint

Learn more about them in here.

Then open your HomeComponent and create a form inside <template> tag. The form simply have 1 field to enter the URL and a submit button.

<div class="container">
	<div class="row">
		<div class="offset-md-3 col-md-6">
			<form v-on:submit.prevent="shorten_url">
				<div class="form-group">
					<label class="form-label">Enter URL</label>
					<input type="url" name="url" placeholder="Enter URL" class="form-control" required />
				</div>

				<input type="submit" class="btn btn-primary" style="margin-top: 10px;" value="Shorten" />
			</form>

			<!-- [table goes here] -->
		</div>
	</div>
</div>

Then create a function “shorten_url” in your <script> tag in HomeComponent.

import axios from "axios"
import swal from "sweetalert2"

export default {
	name: "HomeComponent",

	methods: {
		async shorten_url() {
			const form = event.target
			const formData = new FormData(form)
			formData.append("timezone", Intl.DateTimeFormat().resolvedOptions().timeZone)

			try {
				const response = await axios.post(
					this.$api_url + "/shorten-url",
					formData
				)

				if (response.data.status == "success") {
					// [on url shortened success]
				} else {
					swal.fire("Error", response.data.message, "error")
				}
			} catch (exp) {
				console.log(exp)
			}
		}
	}
}

In your “main.js” add the following line that defines the URL of our Python API.

app.config.globalProperties.$api_url = "http://127.0.0.1:8000"

In the above function, we are sending form data to the server. We are also sending current timezone, so the server can return the time (in local timezone) when the URL was added.

Add URL – Python, Mongo DB

So the view is created, now we need to create our backend API that will handle this request.

Making sure you have installed Python 3 in your system, run the following commands in your “api” folder.

pip3 install fastapi uvicorn pymongo python-multipart

Create a file named api.py and write the following code in it:

import random, string
from fastapi import FastAPI, Form
from typing_extensions import Annotated
from fastapi.middleware.cors import CORSMiddleware
from pymongo import MongoClient
from bson.objectid import ObjectId
from datetime import datetime, timezone as timezone_module
from dateutil import tz

MONGO_CONNECTING_STRING = "mongodb://localhost:27017"
client = MongoClient(MONGO_CONNECTING_STRING)
db_name = "url_shortener"
db = client[db_name]

app = FastAPI()

app.add_middleware(
	CORSMiddleware,
	allow_origins=["*"]
)

@app.post("/shorten-url")
def shorten_url(url: Annotated[str, Form()], timezone: Annotated[str, Form()]):

	while True:
		random_characters = "".join(random.choice(string.ascii_lowercase) for _ in range(8))
		url_obj = db["urls"].find_one({
			"hash": random_characters
		})

		if (url_obj == None):
			break

	inserted_doc = {
		"_id": ObjectId(),
		"url": url,
		"hash": random_characters,
		"views": 0,
		"clicks": 0,
		"created_at": datetime.now(timezone_module.utc)
	}

	db["urls"].insert_one(inserted_doc)
	inserted_doc["_id"] = str(inserted_doc["_id"])
	inserted_doc["created_at"] = convert_utc_to_local(timezone, inserted_doc["created_at"])

	return {
		"status": "success",
		"message": "URL has been shortened.",
		"url": inserted_doc
	}

def convert_utc_to_local(timezone, utc):
	# Hardcode zones:
	from_zone = tz.gettz('UTC')
	to_zone = tz.gettz(timezone)

	# Tell the datetime object that it's in UTC time zone since 
	# datetime objects are 'naive' by default
	utc = utc.replace(tzinfo=from_zone)

	# Convert time zone
	utc = utc.astimezone(to_zone).strftime("%b %d, %Y %H:%M:%S")

	return utc

To start the API, run the following command in your “api” folder:

uvicorn api:app --reload

You can access it from here:

http://127.0.0.1:8000

You might see it blank and that’s okay. Because it will be accessed via AJAX calls.

Explanation:

First, we are making connection with Mongo DB. Then we are initializing FastAPI and setting CORS middleware to prevent CORS error.

After that, we are creating a function that will handle the request. It accepts URL and timezone.

It will generate random 8 characters and make sure they are unique in database using do-while loop.

Then it will insert the record in database. And in order to return the inserted document to the client side, we need to convert the ObjectId to string.

Date & time will be stored in UTC in database. But to return to client side, we have to convert UTC to user’s local timezone. So we have created a separate function “convert_utc_to_local” for that.

Show all added URLs – Vue JS

In your HomeComponent, write the following code in [table goes here] section.

<table class="table table-bordered" style="margin-top: 50px;">
	<thead>
		<tr>
			<th>URL</th>
			<th>Views</th>
			<th>Clicks</th>
			<th>Created at</th>
		</tr>
	</thead>

	<tbody>
		<tr v-for="(url, index) in urls">
			<td>
				<router-link v-bind:to="'/url/' + url.hash" v-text="url.hash"></router-link>
			</td>
			<td v-text="url.views"></td>
			<td v-text="url.clicks"></td>
			<td v-text="url.created_at"></td>
		</tr>
	</tbody>
</table>

Then in your <script> tag, initialize an empty array.

data() {
	return {
		urls: []
	}
},

And write the following code at [on url shortened success] section:

this.urls.unshift(response.data.url)

Add a “mounted” event in your Vue JS object.

mounted() {
	this.get_data()
}

After that, create the following method inside your “methods” object.

async get_data() {
	const formData = new FormData()
	formData.append("timezone", Intl.DateTimeFormat().resolvedOptions().timeZone)

	try {
		const response = await axios.post(
			this.$api_url + "/fetch-urls",
			formData
		)

		if (response.data.status == "success") {
			this.urls = response.data.urls
		} else {
			swal.fire("Error", response.data.message, "error")
		}
	} catch (exp) {
		console.log(exp)
	}
}

Fetch all URLs – Python, Mongo DB

Now we need to create an API in Python that will fetch all URLs from Mongo DB. Write the following code in your “api/api.py” file.

@app.post("/fetch-urls")
def fetch_urls(timezone: Annotated[str, Form()]):
	urls = db["urls"].find().sort("created_at", -1)

	url_arr = []
	for url in urls:
		url["_id"] = str(url["_id"])
		url["created_at"] = convert_utc_to_local(timezone, url["created_at"])

		url_arr.append(url)

	return {
		"status": "success",
		"message": "Data has been fetched.",
		"urls": url_arr
	}

Test the app now and you will see all your added URLs. Now whenever a URL is clicked, we will show a new page where user will have to wait for 5 seconds to access the real URL.

Access the URL – Vue JS

In your “web/src/components” folder, create a file named “URLComponent.vue” and write the following code in it:

<template>
	URLComponent
</template>

<script>

	export default {
		name: "URLComponent"
	}
</script>

Register it in your “main.js” file.

import URLComponent from "./components/URLComponent.vue"

And add it in “routes” array too.

{ path: "/url/:url", component: URLComponent }

Back to your URLComponent, write the following code inside <template> tag.

<div class="container">
	<div class="row">
		<div class="col-md-12">
			<div class="float-end" style="padding: 15px;
			    border-radius: 5px;
			    background-color: lightblue;
			    cursor: pointer;">
			    <span v-if="remaining_seconds > 0">
			    	Redirecting in <span v-text="remaining_seconds"></span> seconds
			    </span>
				
			    <span v-else v-on:click="goto_website">Go to website</span>
			</div>
		</div>
	</div>
</div>

This will show a text that will show the number of seconds remaining till user has to wait. When the time is over, it will show a clickable text which when clicked, should move the user to the actual URL.

import axios from "axios"
import swal from "sweetalert2"

export default {
	name: "URLComponent",

	data() {
		return {
			url: this.$route.params.url,
			remaining_seconds: 5,
			url_obj: null,
			interval: null
		}
	},

	methods: {
		async goto_website() {
			if (this.url_obj == null) {
				return
			}

			window.location.href = this.url_obj.url
		},

		async get_data() {
			const formData = new FormData()
			formData.append("url", this.url)

			try {
				const response = await axios.post(
					this.$api_url + "/get-url",
					formData
				)

				if (response.data.status == "success") {
					this.url_obj = response.data.url
				} else {
					swal.fire("Error", response.data.message, "error")
				}
			} catch (exp) {
				console.log(exp)
			}
		}
	},

	mounted() {
		const self = this
		this.get_data()

		setTimeout(function () {
			self.interval = setInterval(function () {
				self.remaining_seconds--

				if (self.remaining_seconds <= 0) {
					clearInterval(self.interval)
				}
			}, 1000)
		}, 500)
	}
}

When this component is mounted, we will call “get_data” function that will fetch the single URL data from Python API.

Also, it will start a countdown timer from 5. Once timer hits 0, you can click the button and go to your actual URL.

Fetch single URL – Python, Mongo DB

Create the following API in your “api/api.py” file.

@app.post("/get-url")
def get_url(url: Annotated[str, Form()]):

	url = db["urls"].find_one({
		"hash": url
	})

	if (url == None):
		return {
			"status": "error",
			"message": "URL not found."
		}

	url["_id"] = str(url["_id"])

	return {
		"status": "success",
		"message": "Data has been fetched.",
		"url": url
	}

This will fetch the single URL from Python API.

Number of clicks on Shorten URL

When you share the shorten URL with your friends, you might want to know how many have clicked the shorten URL and how many clicked the actual URL.

To increment number of clicks on shorten URL, we will simply go to “api.py” function “get_url” and add the following code before converting ObjectId “_id” to string.

db["urls"].find_one_and_update({
	"_id": url["_id"]
}, {
	"$inc": {
		"views": 1
	}
})

Test now and you will see whenever someone access your shorten URL page, your “views” gets incremented in HomeComponent.

Number of clicks on actual URL

In order to see how many has clicked on your actual URL, you need to open your “URLComponent.vue” file. Add the following lines in your “goto_website” function before the “window.location.href” line.

const formData = new FormData()
formData.append("url", this.url)
window.navigator.sendBeacon((this.$api_url + "/url-clicked"), formData)

Then create its API in Python that will handle this request.

@app.post("/url-clicked")
def url_clicked(url: Annotated[str, Form()]):
	db["urls"].find_one_and_update({
		"hash": url
	}, {
		"$inc": {
			"clicks": 1
		}
	})

Now whenever someone visit the actual URL, the “clicks” counter gets incremented.

Header and Footer

Write the following code insde <template> tag of your AppHeader component.

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container-fluid">
    <router-link class="navbar-brand" to="/">URL Shortener</router-link>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <router-link class="nav-link active" aria-current="page" to="/">Home</router-link>
        </li>
      </ul>
    </div>
  </div>
</nav>

And change your AppFooter component to the following.

<template>
	<footer class="container-fluid" style="margin-top: 50px; background-color: #e9e9e9; padding: 25px;">
		<p class="text-center" style="margin-bottom: 0px;">
			&copy;<span v-text="year"></span>&nbsp;
			adnan-tech.com
		</p>
	</footer>
</template>

<script>
	export default {
		name: "AppFooter",

		data() {
			return {
				year: new Date().getFullYear()
			}
		}
	}
</script>

So this is how you can create a URL shortener app using Vue JS as frontend, Python as backend and Mongo DB as database. If you face any problem in following this, kindly do let me know.

A guide to MEVN

MEVN stands for Mongo DB, Express JS, Vue JS, and Node JS. It is a technology stack used by developers to create full-fledged web applications. Most of the applications created in the MEVN stack are single-page applications. But it is up to you if you want to single page or multi-page web application.

Table of content

  1. What is MEVN ?
  2. Why MEVN ?
    • Same language for frontend and backend
    • Easy deployment
    • Seamless user experience
    • APIs for mobile apps
    • Mongo DB is scaled horizontally
    • Short learning curve
    • Better support for sockets
  3. Future of MEVN
  4. Projects developed in MEVN
  5. Where to learn MEVN ?
    • Official documentation
    • YouTube
    • Blogs
  6. Issues you will face in the development

Let’s get started.

1. What is MEVN ?

MEVN is a technology stack used to develop full-fledged web applications. You can easily create scalable web applications either single-page or multi-page applications. It is a new yet quickly evolving technology stack that has been adopted by a lot of developers already. Learning this will not only make you a frontend developer but a backend developer as well. Thus increasing your demand and reputation in the community.

Hiring a developer in this stack is easy for companies as well. Hiring individual developers for the backend and frontend is costly, especially for startups. So they end up looking for someone who knows both the backend and frontend.

2. Why MEVN ?

If you learn this technology stack, your demand is automatically increased since companies would love to have a developer that can handle both frontend and backend tasks. Even if you didn’t get a job as a full-stack developer, you can still get a job as either a frontend or backend developer since you can work in both.

Same language for frontend and backend

In this stack, the primary language is Javascript. Node JS is a Javascript runtime environment, Vue JS is a Javascript frontend framework and Express JS is a framework of Node JS for creating APIs. Mongo DB syntax is also very similar to Javascript. So you do not need to learn Javascript for the frontend and PHP or Python for the backend. One language i.e. Javascript is used for both sides (frontend and backend).

Easy deployment

Vue JS builds are minified code of HTML, CSS, and Javascript. So they can easily be deployed on most servers. You do not need to worry if your hosting supports PHP, Java, Python, or any other language. If your hosting supports HTML (which almost every hosting does) then you are good to go.

Node JS can also be easily deployed on Virtual Private Servers (VPS) or dedicated servers. You can check our detailed guide on how to deploy Node JS on VPS or dedicated servers.

Mongo DB can also be deployed on VPS or dedicated servers. But it can also be deployed on Mongo DB’s official site. You can check our tutorial for Mongo DB deployment.

Seamless user experience

Most of the apps created in this stack are single-page applications. They provide a better user experience since there is no page reload on any link. Only the required section of the page changes dynamically. Some of the websites that are single-paged are Gmail, Facebook, and Twitter.

APIs for mobile apps

Most of the rendering is done on the client side. This means you have to create APIs for each request. This helps you in the future when you want to develop mobile apps for your website. Android and iOS apps can easily communicate with APIs developed in Node JS.

Mongo DB is scaled horizontally

Horizontal scaling is performed by adding more nodes to the servers. Horizontal scaling is best for a non-relational database like Mongo DB since all the data is stored in a single document.

Moreover, if you have to add one more attribute to a single entity, you can easily add it to that document only. Unless in MySQL, where either you have to create a column that will result in assigning the value to all rows. Or you have to create a separate table and join them in each query which will slow down your application.

In Mongo DB, all data required for an entity is stored in a single document. No relationships are made. So data can be saved on different servers without being dependent on each other.

Short learning curve

If you know Javascript, you already know Vue JS. Unlike in React where you have to use JSX syntax, in Vue JS you can use legacy HTML and CSS code and use Javascript with it. If you know the basics of Javascript, spend a few hours on Vue JS official documentation and you will become a Vue JS developer.

Better support for sockets

Sockets are used for real-time communication. Like on Facebook, you do not have to refresh the page to check new notifications. Whenever a new notification is received, it automatically displays an alert. If you develop your web application in the MEVN stack, you will be able to add real-time features like alerts, notifications, chat messages, real-time collaborations, etc.

3. Future of MEVN

MEVN proving itself a bright future. A lot of developers are moving to this stack. It is in the race with MEAN and MERN stacks. It has solved a lot of issues that developers faced in web development. For example, during infinite scroll, the web page hangs due to too much data. Vue JS solved this by using the useVirtualList component. Node JS has solved real-time communication problems via sockets. And Mongo DB has solved the scalability problems and also the problems that came with tightly-coupled databases.

4. Projects developed in MEVN

To show you how easy it is to develop websites in this technology stack, we developed some projects in it. We have developed a chat app, a customer support ticketing system, and more.

5. Where to learn MEVN

You can learn this technology stack from many sources.

Official documentation

To stay updated with the latest versions and features, check out the official documentation of Vue JS. Node JS can also be learned from their official documentation. Mongo DB also came with outstanding documentation.

YouTube

Check this playlist to find a lot of tutorials on the MEVN stack.

Blogs

We have created many text-based tutorials on this stack.

6. Issues you will face in the development

You need to spend a lot of time to make the application up and running. The first version of your product might take more time and effort because you need to set up the APIs and basic functionality. However, we have created a boilerplate for authentication that will save you 100% time on rewriting the authentication code.

Mixed spaces and tabs issue fixed in Vue JS

If you ever encounter an error in Vue JS that says “mixed spaces and tabs”. You can fix it by simply running the following command:

npm remove @vue/cli-plugin-eslint

Removing the ESLint will fix this issue in your Vue JS app. Check out our more projects and tutorials on Vue JS here.

Video tutorial:

Ecommerce website in MEVN stack

It is a single-page ecommerce website developed in Vue JS. Vue JS is an open-source Javascript framework specifically built to design user interfaces and is widely used for creating single-page applications.

Node JS is a Javascript run-time environment developed for creating the backend of applications. Its framework Express is widely used for creating APIs. It is built to create scalable applications.

Mongo DB is a no-SQL database. It is a non-relational database system. It is easily scalable because the data is loosely coupled.

FeaturesFreePremium $100
Product management (admin panel)YesYes
Product listingYesYes
Product detailYesYes
Shopping cartYesYes
Checkout (PayPal & Stripe)YesYes
Order management (admin panel)YesYes
Order detailYesYes
Product specificationsYesYes
Stock managementYesYes
Search and sortYesYes
New order emailYesYes
Product reviewsNoYes
Shipping charges by countryNoYes
Product image compressionNoYes
Realtime chat between users and adminNoYes

Following is the feature list of this project:

  • Product management (admin panel)
  • Product listing
  • Product detail
  • Shopping cart
  • Checkout (PayPal & Stripe)
  • Order management (admin panel)
  • Order detail
  • Product specifications
  • Stock management
  • Product reviews
  • Search and sort
  • Shipping charges by country
  • Email to admin whenever a new order is placed
  • Product image compression
  • Realtime chat between users and admin

Add product

Admin will be able to add products. He will enter the name of the product. Add a little description of the product. And set the price of the product. The price will be in dollars. Along with them, the admin can upload one or more images of the product.

Product listing

Users will see the products added by the admin on their home page. The latest products are displayed first. Along with each product, a button will be displayed to view the detail of the product.

Product detail

Users can view the detail of the product. If the product contains more than one image, then it will be displayed as a beautiful slider. From this page, users will also be able to add products to the cart. If the product is already added to the cart, then he will be able to remove it from the cart.

Shopping cart

Users can add the product to the cart. From the cart’s page, he will be able to adjust the quantity of the product. There will be multiple products in the cart and you can set the quantity of each product separately. You will also see your total bill as soon as you change the quantity of any product added to the cart.

Checkout (Stripe & PayPal)

After adding the products to the cart and setting each product’s quantity, the user can go to the checkout page. Here, he can either pay via Stripe or PayPal. Both payment methods accept debit and master cards securely. When the user made the payment, his payment is verified from the server. If verified, then a new order will be created in the database.

Order management

Whenever a user made a payment via Stripe or PayPal, an order will be created. All orders will be displayed on the admin panel ordered by latest to oldest. By default, the status of the order is “Processing”. But admin can change the status of the order to “Completed” when the product is delivered to the customer.

Admin will also be able to view the total amount of the order, the payment method customer has used, and the user’s shipping details.

Order detail

Admin can view all the products that were included in each order. He can manually verify the payment by clicking the payment method. If he clicks “Stripe”, he will be redirected to the Stripe payments page. If he clicks “PayPal”, then he will be redirected to the PayPal business page. Admin can check the name, email, and phone of the user and also his shipping address.

Product specifications

Admin can add the specifications of each product and the user will be able to see it on the product detail page.

Stock management

Admin can set the number of units in stock for each product. When the user makes an order, then the number of units he has selected will be subtracted.

Product reviews

User can give reviews on a product and it will be displayed to all users who visit that product. Admin will have the ability to remove any review, for example, spamming, etc.

Search and sort

Users can search by product by its name, description, category, or specifications. Users can also sort the products by date or by price.

Shipping charges by country

Admin can set the shipping charges by each country because, in a global eCommerce website, users place orders from all over the world. For example, if your store is located in USA and someone places an order from the UK. Then you charge the shipping fee differently than other countries.

Email to admin whenever a new order is placed

Admin will receive an email whenever a new order has been placed by the user.

Product image compression

Now you can compress the product images from the admin panel. The 3 MB image can be reduced to just 182 KB and the image will still be of great quality.

Realtime chat between users and admin

Users will be able to have a chat with the admin to know more about a product before placing an order. I believe every eCommerce website should have this feature.

We are constantly updating this project and adding more features and enhancements to it. Following are all the builds that are released till today.

  • In the very first release, we build the basic E-commerce version where the admin can add products and users can see them. Add them to carts and order them. We also added Stripe and PayPal payment methods.
  • In the second release, we added more features. Allowing users to give reviews about a product. Allowing admin to charge a different shipping fee for each country and many more.
  • In the third release, we added functionality to compress product images and to have real-time chat between users and admin.

Free version

https://github.com/adnanafzal565/ecommerce-mevn-stack

Dynamic constra template – Vue JS & Laravel

“Constra” is an HTML static template in HTML & CSS. It is an HTML template designed for the construction website. The businesses that allow construction-related services. We have converted to a dynamic website using Vue JS and Laravel.

You can check out the following tutorials. In these tutorials, we have shown you, how to convert a static HTML template into a dynamic construction website.

Part 1:

You will learn in this part:

  • How to convert an HTML template into a Vue JS app
  • Create single-page applications in Vue JS
  • Use the vue-router module
  • Use internal CSS, JS, and image files from the “assets” folder
  • How to fix the “Mixed spaces and tabs” error
  • Remove ESLint from the Vue JS app
  • Use Bootstrap, jQuery, and other JS libraries in the Vue JS app
  • How to fix “Can’t resolve popper.js”
  • Use the “background-image” property in Vue JS
  • Use slider library (Shuffle) in Vue JS

Part 2:

In this part, you will learn:

  • How to pass parameters in URL in Vue JS
  • How to fetch a single record in Laravel eloquent
  • How to call AJAX using Axios in Vue JS
  • Using “slick” JS library in Vue JS
  • Create a foreign key in Laravel migration
  • Create a has-many relationship in Laravel
  • Upload file in Laravel storage

You can download the complete source code from Github as well.

You can also check out our chat website developed in Vue JS, Node JS, and Mongo DB.

Pass value between components – Vue JS

In this article, we will teach you how to pass value between 2 components in Vue JS. We will be using Vuex for this.

Video tutorial

Create a store

First, you need to create a store. To do this, install a module named vuex. Run the following command in your terminal:

npm install vuex

After that, you must create a folder named “vuex” in your “src” folder. Then, create a file named “store.js” inside “vuex” folder. Following will be the content of store.js file:

import { createStore } from "vuex"

export default createStore({
	state() {
		return {
			variable: 123
		}
	},

	// [mutations goes here]

	// [getters goes here]
})

“variable” will be the variable that you need to pass between components. You can set its default value here.

Pass value to component 1

Let’s say you want to display the value in component 1. So I am going to create a simple paragraph tag to display a value.

<p v-text="variable"></p>

And we need to make this variable a computed property. So we will write the following Javascript code in component 1.

import store from "../vuex/store"

export default {
	computed: {
		variable: function () {
			return store.getters.getVariable
		}
	}
}

First, we are including the store file that we created in the previous step. Our component is in “src/components” folder, and store file is in “src/vuex”, so we have to move a step back using “../”.

Then we are created a computed property “variable”, and it returns the “getVariable” value from the store getters object. The getters is the built-in property in Vuex store. And “getVariable” will be a function that we need to create in our store file.

So write the following code in the [getters goes here] section of store.js file:

getters: {
	getVariable: function (state) {
		return state.variable
	}
}

It accepts a state object as an argument. And with this object, you can call the variables in the state() function create in the first step. Run the component 1 now and you will see the value “123” in your paragraph.

Pass value from component 2

Now support in your component 2, you want to change its value and it should reflect in component 1 as well. First, write the following code in the [mutations goes here] section of store.js file:

mutations: {
	setVariable: function (state, newValue) {
		state.variable = newValue
	}
}

It accepts state and newValue as arguments. With the state object, you can change the values. And newValue is simply the new value that will be passed to it.

To call this function, we are going to create a simple button in our component 2.

<button type="button" v-on:click="updateVariable">Update variable</button>

Then we are going to create this method in our Javascript and call the setVariable function from our store file.

import store from "../vuex/store"

export default {
	methods: {
		updateVariable: function () {
			store.commit("setVariable", 567)
		}
	}
}

commit function from Vuex store will call the function created in mutations object. Second parameter will be the new value. Run the app now and click on the button. As soon as you press the button, you will notice that the variable value in 1st component will automatically get updated.

Source code

[wpdm_package id=’1733′]

Conclusion

So you have learned how to create a Vuex store in Vue JS, and how to pass value between components in Vue JS. If you face any problems in following this, kindly do let me know. We also created a chat application where we implemented this technique, so you will know how it is used practically in projects.