Menu

Full Stack Daily Morning 16-01-2023

Full Stack Daily Morning 16-01-2023

Download HTML-CSS ZIP File

Scratchpad #2

// let age = 30;

// if (age >= 21) {
// 	console.log('You are allowed to enter');
// }

// console.log('Program ends');

// let num = 21;

// if (num % 2 === 0) {
// 	console.log('EVEN');
// }

// let age = 2;

// if (age >= 65) {
// 	console.log('Drinks are free');
// } else if (age >= 21) {
// 	console.log('You are allowed to enter and drink');
// } else if (age >= 18) {
// 	console.log("You can enter but you can't drink");
// } else {
// 	console.log("You aren't allowed");
// }

// let password = 'helloworld@123';

// if (password.length >= 6) {
// 	if (password.indexOf(' ') !== -1) {
// 		console.log('Password cannot contain spaces');
// 	} else {
// 		console.log('Valid password');
// 	}
// } else {
// 	console.log('Password is too short');
// }

// let loggedInUser = null;

// if (loggedInUser) {
// 	console.log('Welcome. This is your dashboard.');
// } else {
// 	console.log('Please login to access dashboard');
// }

// let age = 35;

// if (age >= 18 && age < 21) {
// 	console.log("You can enter but you can't drink");
// } else if (age >= 21 && age < 65) {
// 	console.log('You are allowed to enter and drink');
// } else if (age >= 65) {
// 	console.log('Drinks are free');
// } else {
// 	console.log("You aren't allowed");
// }

// let day = 100;

// switch (day) {
// 	case 1:
// 		console.log('Monday');
// 		break;
// 	case 2:
// 		console.log('Tuesday');
// 		break;
// 	case 3:
// 		console.log('Wednesday');
// 		break;
// 	case 4:
// 		console.log('Thursday');
// 		break;
// 	case 5:
// 		console.log('Friday');
// 		break;
// 	case 6:
// 		console.log('Saturday');
// 		break;
// 	case 7:
// 		console.log('Sunday');
// 		break;
// 	default:
// 		console.log('Invalid day code');
// }

// if (day === 1) {
// 	console.log('Monday');
// } else if (day === 2) {
// 	console.log('Tuesday');
// } else if (day === 3) {
// 	console.log('Wednesday');
// } else if (day === 4) {
// 	console.log('Thursday');
// }

// let num = 32;

// num === 7 ? console.log('LUCKY') : console.log('UNLUCKY');

// if (num === 7) {
// 	console.log('LUCKY');
// } else {
// 	console.log('UNLUCKY');
// }

let currentStatus = 'idle';
// let color;
let color =
	currentStatus === 'offline'
		? 'red'
		: currentStatus === 'online'
		? 'green'
		: 'yellow';

// if (currentStatus === 'offline') {
// 	color = 'red';
// } else if (currentStatus === 'online') {
// 	color = 'green';
// } else {
// 	color = 'yellow';
// }

console.log(color);

Scratchpad #3

// // // const product = {
// // // 	imageUrl: 'https:.//.',
// // // 	brand: 'Apple',
// // // 	description: 'Some desc....',
// // // 	price: 100000,
// // // 	inStock: 500,
// // // 	discounted: true,
// // // 	name: 'iPhone 14',
// // // 	'hello world': true,
// // // 	1000: false,
// // // };

// // // const product2 = [
// // // 	'iPhone 14',
// // // 	'Apple',
// // // 	'Some description...',
// // // 	100000,
// // // 	500,
// // // 	true,
// // // 	'https://....png',
// // // ];

// // // const names = ['john', 'jane', 'jack', 'jill'];

// // // const names = {0: 'john', 1: 'jane', 2: 'jack', 3: 'jill', length: 4}

// // const pallette = {
// // 	red: '#eb4d4b',
// // 	yellow: '#f9ca24',
// // 	blue: '#30336b',
// // };

// // let color = 'yellow';

// // console.log(pallette[color]);

// // for (let i = 10; i >= 0; i--) {
// // 	console.log(i, 'Hello World');
// // }

// // const nums = [12, 34, 56, 34, 78, 54, 23, 12];

// // for (let i = 0; i < nums.length; i++) {
// // 	console.log(nums[i]);
// // }

// // const movies = [
// // 	{ movieName: 'Inception', rating: 3.8 },
// // 	{ movieName: 'Avengers', rating: 3.4 },
// // 	{ movieName: 'Iron Man', rating: 2.9 },
// // ];

// // for (let i = 0; i < movies.length; i++) {
// // 	const movie = movies[i];
// // 	console.log(`${movie.movieName} has a rating of ${movie.rating}`);
// // }

// // const word = 'hello world';

// // let reveredWord = '';
// // for (let i = word.length - 1; i >= 0; i--) {
// // 	reveredWord += word[i];
// // }

// // console.log(reveredWord);

// // for (let i = 0; i < 5; i++) {
// // 	console.log(`Outer Loop: ${i}`);

// // 	for (let j = 0; j < 5; j++) {
// // 		console.log(`		Inner loop: ${j}`);
// // 	}
// // }

// // const gameBoard = [
// // 	[4, 64, 8, 4],
// // 	[128, 32, 4, 16],
// // 	[16, 4, 4, 32],
// // 	[2, 16, 16, 2],
// // ];

// // let total = 0;

// // for (let i = 0; i < gameBoard.length; i++) {
// // 	for (let j = 0; j < gameBoard[i].length; j++) {
// // 		total += gameBoard[i][j];
// // 	}
// // }

// // console.log(total);

// const gameBoard = [
// 	[
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4, 123, 3],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 	],
// 	[
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 	],
// 	[
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 	],
// 	[
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 		[4, 64, 8, 4],
// 	],
// ];

// // loop over and print all the numbers
// // total
// // total even numbers
// // total evens and odds

// let evens = 0;
// let odds = 0;

// // -------------------------------

// // -------------------------------

// for (let i = 0; i < 10; i++) {
// 	console.log(i);
// }

// let i = 0;

// while (i < 10) {
// 	console.log(i);
// 	i++;
// }

// let target = Math.floor(Math.random() * 10) + 1;
// let guess = Math.floor(Math.random() * 10) + 1;

// while (guess !== target) {
// 	console.log(`Target: ${target} | Guess: ${guess}`);
// 	if (guess === 1) {
// 		break;
// 	}
// 	guess = Math.floor(Math.random() * 10) + 1;
// }

// console.log(`Game over. Target: ${target} | Guess: ${guess}`);

let target = Math.floor(Math.random() * 10) + 1;
let guess = Math.floor(Math.random() * 10) + 1;

while (true) {
	console.log(`Target: ${target} | Guess: ${guess}`);
	if (target === guess) {
		break;
	}
	guess = Math.floor(Math.random() * 10) + 1;
}

console.log(`Game over. Target: ${target} | Guess: ${guess}`);

Scratchpad #4

let categories = [
	'fashion',
	'electronics',
	'mobiles',
	'books',
	'toys',
	'groceries',
];

// for (let i = 0; i < categories.length; i++) {
// 	console.log(categories[i]);
// }

// for (let category of categories) {
// 	console.log(category);
// }

// for (let char of 'hello') {
// 	console.log(char);
// }

// const matrix = [
// 	[1, 4, 7],
// 	[9, 7, 2],
// 	[9, 4, 6],
// ];

// for (let row of matrix) {
// 	for (let col of row) {
// 		console.log(col);
// 	}
// }

// const cats = ['fashion', 'mobiles', 'books'];
// const prods = ['tshirt', 'samsung', '1984'];

// for (let i = 0; i < cats.length; i++) {
// 	console.log(cats[i], prods[i]);
// }

const productPrices = {
	Apple: 80000,
	OnePlus: 50000,
	Samsung: 90000,
};

// for (let item of Object.keys(productPrices)) {
// 	console.log(item);
// }

// for (let item of Object.values(productPrices)) {
// 	console.log(item);
// }

// for (let key of Object.keys(productPrices)) {
// 	console.log(key, productPrices[key]);
// }

// for (let key in productPrices) {
// 	console.log(key, productPrices[key]);
// }

// const movieRating = {
// 	pursuitOfHappiness: 4.8,
// 	satya: 4.8,
// 	gangsOfWasepur: 4,
// 	robot: -3,
// };

// for (let movie in movieRating) {
// 	// console.log(movie)
// 	console.log(`${movie} has a rating of ${movieRating[movie]}`);
// }

// function greet() {
// 	console.log('Hello');
// 	console.log('World');
// 	console.log('Universe');
// }

// for (let i = 0; i < 10; i++) {
// 	greet();
// }

// function rollDie() {
// 	let roll = Math.floor(Math.random() * 6) + 1;
// 	console.log(`Rolled: ${roll}`);
// }

// function throwDice() {
// 	rollDie();
// 	rollDie();
// 	rollDie();
// }

// throwDice();

// function greet(name) {
// 	console.log(`Hello, ${name}`);
// }

// greet('John');
// greet('Jane');

// function rollDie() {
// 	let roll = Math.floor(Math.random() * 6) + 1;
// 	console.log(`Rolled: ${roll}`);
// }

// function throwDice(count) {
// 	for (let i = 0; i < count; i++) {
// 		rollDie();
// 	}
// }

// throwDice(5);

// function greet(firstName, lastName) {
// 	return `Hello, ${firstName} ${lastName}`;
// }

// console.log(greet('jill', 'smith'));

// // const result = greet('John', 'Doe');

// // console.log('Result =>', result);

// function greet(firstName, lastName) {
// 	console.log('Test');
// 	return `Hello, ${firstName} ${lastName}`;
// }

// console.log(greet('Jane', 'Doe'));

// let fullName = 'John Doe';

// function greet() {
// 	let fullName = 'Jane Smith';
// 	console.log(fullName);
// }

// console.log(fullName);

// greet();

// let fullName = 'John Doe';

// if (true) {
// 	var fullName = 'Jane Smith';
// 	console.log(fullName);
// }

// console.log(fullName);

// for (var i = 0; i < 10; i++) {
// 	console.log(i);
// }

// console.log(i);

// function outer() {
// 	function inner() {
// 		let movie = 'Iron Man';
// 		console.log(movie);
// 	}

// 	inner();
// }

// outer();

// function greet() {
// 	console.log('hello world');
// }

// const test1 = 100;

// const test = greet;

// test();

// const testFunc = function () {
// 	console.log('hello world');
// };

// testFunc();

// const arr = [
// 	10,
// 	'hello',
// 	function () {
// 		return 'hello world';
// 	},
// ];

// console.log(arr[2]());

// const arr = [
// 	function (a, b) {
// 		return a + b;
// 	},
// 	function (a, b) {
// 		return a - b;
// 	},
// 	function (a, b) {
// 		return a * b;
// 	},
// 	function (a, b) {
// 		return a / b;
// 	},
// ];

// console.log(arr[3](10, 5));

const math = {
	add: function (a, b) {
		return a + b;
	},
	sub: function (a, b) {
		return a - b;
	},
	PI: 3.14,
	mul: function (a, b) {
		return a * b;
	},
};

console.log(math.mul(10, 5));
console.log(Math.PI);

// [email protected]

Scratchpad #4

let categories = [
	'fashion',
	'electronics',
	'mobiles',
	'books',
	'toys',
	'groceries',
];

// for (let i = 0; i < categories.length; i++) {
// 	console.log(categories[i]);
// }

// for (let category of categories) {
// 	console.log(category);
// }

// for (let char of 'hello') {
// 	console.log(char);
// }

// const matrix = [
// 	[1, 4, 7],
// 	[9, 7, 2],
// 	[9, 4, 6],
// ];

// for (let row of matrix) {
// 	for (let col of row) {
// 		console.log(col);
// 	}
// }

// const cats = ['fashion', 'mobiles', 'books'];
// const prods = ['tshirt', 'samsung', '1984'];

// for (let i = 0; i < cats.length; i++) {
// 	console.log(cats[i], prods[i]);
// }

const productPrices = {
	Apple: 80000,
	OnePlus: 50000,
	Samsung: 90000,
};

// for (let item of Object.keys(productPrices)) {
// 	console.log(item);
// }

// for (let item of Object.values(productPrices)) {
// 	console.log(item);
// }

// for (let key of Object.keys(productPrices)) {
// 	console.log(key, productPrices[key]);
// }

// for (let key in productPrices) {
// 	console.log(key, productPrices[key]);
// }

// const movieRating = {
// 	pursuitOfHappiness: 4.8,
// 	satya: 4.8,
// 	gangsOfWasepur: 4,
// 	robot: -3,
// };

// for (let movie in movieRating) {
// 	// console.log(movie)
// 	console.log(`${movie} has a rating of ${movieRating[movie]}`);
// }

// function greet() {
// 	console.log('Hello');
// 	console.log('World');
// 	console.log('Universe');
// }

// for (let i = 0; i < 10; i++) {
// 	greet();
// }

// function rollDie() {
// 	let roll = Math.floor(Math.random() * 6) + 1;
// 	console.log(`Rolled: ${roll}`);
// }

// function throwDice() {
// 	rollDie();
// 	rollDie();
// 	rollDie();
// }

// throwDice();

// function greet(name) {
// 	console.log(`Hello, ${name}`);
// }

// greet('John');
// greet('Jane');

// function rollDie() {
// 	let roll = Math.floor(Math.random() * 6) + 1;
// 	console.log(`Rolled: ${roll}`);
// }

// function throwDice(count) {
// 	for (let i = 0; i < count; i++) {
// 		rollDie();
// 	}
// }

// throwDice(5);

// function greet(firstName, lastName) {
// 	return `Hello, ${firstName} ${lastName}`;
// }

// console.log(greet('jill', 'smith'));

// // const result = greet('John', 'Doe');

// // console.log('Result =>', result);

// function greet(firstName, lastName) {
// 	console.log('Test');
// 	return `Hello, ${firstName} ${lastName}`;
// }

// console.log(greet('Jane', 'Doe'));

// let fullName = 'John Doe';

// function greet() {
// 	let fullName = 'Jane Smith';
// 	console.log(fullName);
// }

// console.log(fullName);

// greet();

// let fullName = 'John Doe';

// if (true) {
// 	var fullName = 'Jane Smith';
// 	console.log(fullName);
// }

// console.log(fullName);

// for (var i = 0; i < 10; i++) {
// 	console.log(i);
// }

// console.log(i);

// function outer() {
// 	function inner() {
// 		let movie = 'Iron Man';
// 		console.log(movie);
// 	}

// 	inner();
// }

// outer();

// function greet() {
// 	console.log('hello world');
// }

// const test1 = 100;

// const test = greet;

// test();

// const testFunc = function () {
// 	console.log('hello world');
// };

// testFunc();

// const arr = [
// 	10,
// 	'hello',
// 	function () {
// 		return 'hello world';
// 	},
// ];

// console.log(arr[2]());

// const arr = [
// 	function (a, b) {
// 		return a + b;
// 	},
// 	function (a, b) {
// 		return a - b;
// 	},
// 	function (a, b) {
// 		return a * b;
// 	},
// 	function (a, b) {
// 		return a / b;
// 	},
// ];

// console.log(arr[3](10, 5));

const math = {
	add: function (a, b) {
		return a + b;
	},
	sub: function (a, b) {
		return a - b;
	},
	PI: 3.14,
	mul: function (a, b) {
		return a * b;
	},
};

console.log(math.mul(10, 5));
console.log(Math.PI);

// [email protected]

Scratchpad #5

// // function math(a, b, fn) {
// // 	return fn(a, b);
// // }

// // function add(a, b) {
// // 	return a + b;
// // }

// // console.log(math(10, 5, add));

// // function repeat(func, num) {
// //   for (let i = 0; i < num; i++) {
// //     func()
// //   }
// // }

// // function sayHello() {
// //   console.log('Hello World!')
// // }
// // function sayGoodbye() {
// //   console.log('Bye World!')
// // }

// // repeat(sayHello, 10)
// // repeat(sayGoodbye, 5)

// // function randomPick(f1, f2) {
// //   let randNum = Math.random()
// //   if (randNum < 0.5) {
// //     f1()
// //   } else {
// //     f2()
// //   }
// // }

// // randomPick(sayHello, sayGoodbye)

// // function raiseBy(num) {
// // 	return function (x) {
// // 		return x ** num;
// // 	};
// // }

// // const square = raiseBy(2);
// // const cube = raiseBy(3);

// // console.log(cube(10));

// function isBetween(x, y) {
// 	return function (num) {
// 		return num >= x && num < y;
// 	};
// }

// const isUnderAge = isBetween(0, 18);
// const isLegalAge = isBetween(18, 21);

// // console.log(isUnderAge(35));
// console.log(isLegalAge(35));

// function isBetween(x, y) {
//   return function (num) {
//     return num >= x && num <= y
//   }
// }

// const isUnderAge = isBetween(0, 18)
// const canEnterButNotDrink = isBetween(18, 21)
// const canDrink = isBetween(21, 65)
// const isSenior = isBetween(65, 100)

// console.log(isUnderAge(5))
// console.log(canEnterButNotDrink(20))
// console.log(canDrink(30))
// console.log(isSenior(70))

// function math(a, b, fn) {
// 	return fn(a, b);
// }

// function add(a, b) {
// 	return a + b;
// }

// console.log(math(10, 5, add));

// setTimeout(function () {
// 	console.log('Hello World');
// }, 3000);

// function add(a, b) {
// 	return a + b;
// }

// console.log(add(10, 5));

// var hello;

// console.log(hello);
// var hello = 'world';

// const nums = [9, 2, 4, 6, 2, 3, 7, 6];

// // for (let num of nums) {
// // 	console.log(num);
// // }

// nums.forEach(function (num) {
// 	console.log(num);
// });

// const movies = [
// 	{
// 		title: 'Avengers',
// 		rating: 3.8,
// 	},
// 	{
// 		title: 'Dr. Strange',
// 		rating: 3.9,
// 	},
// 	{
// 		title: 'Tenet',
// 		rating: 4.3,
// 	},
// 	{
// 		title: 'Joker',
// 		rating: 4.7,
// 	},
// ];

// movies.forEach(function (movie, i) {
// 	console.log(`${i} - ${movie.title} has a rating of ${movie.rating}.`);
// });

// const names = ['john', 'jack', 'jane', 'james'];

// const upperNames = names.map(function (name) {
// 	// ['JOHN', 'JACK', 'JANE', 'JAMES']
// 	return name.toUpperCase();
// });

// const upperNames = [];

// for (let name of names) {
// 	upperNames.push(name.toUpperCase());
// }

// console.log(upperNames);

// const nums = [2, 3, 4, 7, 6, 8, 13, 10, 19, 12, 14, 22, 21, 16];

// const doubles = nums.map(function (num) {
// 	return num * 2;
// });

// console.log(doubles);

// const numDetails = nums.map(function (num) {
// 	return { number: num, isEven: num % 2 === 0 };
// });

// console.log(numDetails);

// function square(num) {
// 	return num ** 2;
// }

// const square = n => n ** 2;

// console.log(square(10));

// const nums = [2, 3, 4, 7, 6, 8, 13, 10, 19, 12, 14, 22, 21, 16];

// const doubles = nums.map(function (num) {
// 	return num * 2;
// });

// const doubles2 = nums.map(num => num * 2);

// const nums = [1,2,3,4,5,6]

// // using regular function expressions
// const doubles1 = nums.map(function (n) {
//   return n * 2
// })

// // using arrow functions
// const doubles2 = nums.map(n => {
//   return n * 2
// })

// // using arrow function's one-liner implicit return
// const doubles3 = nums.map(n => n * 2)
// const parityList = nums.map(n => n % 2 === 0 ? 'Even' : 'Odd')

// let movies = ['The Terminator', 'The Avengers', 'Jurassic Park', 'Titanic'];

// // const result = movies.find((movie) => movie.includes('Park'));
// // const result = movies.find((movie) => movie[0] === 'T');
// const result = movies.find((movie) => movie.indexOf('Hello') === 0);
// console.log(result);

// const books = [
// 	{
// 		title: 'The Shining',
// 		author: 'Stephen King',
// 		rating: 4.1,
// 	},
// 	{
// 		title: 'Sacred Games',
// 		author: 'Vikram Chandra',
// 		rating: 4.5,
// 	},
// 	{
// 		title: '1984',
// 		author: 'George Orwell',
// 		rating: 4.9,
// 	},
// 	{
// 		title: 'The Alchemist',
// 		author: 'Paulo Coelho',
// 		rating: 3.5,
// 	},
// 	{
// 		title: 'The Great Gatsby',
// 		author: 'F. Scott Fitzgerald',
// 		rating: 3.8,
// 	},
// ];

// // const result = books.find((book) => book.author.includes('King'));
// // const result = books.find((book) => book.rating >= 4);
// const result = books.filter((book) => book.rating >= 4);
// console.log(result);

// const goodBook = books.filter(b => b.rating >= 4.3)

// const georgeBooks = books.filter(b => (
//   b.author.includes('George')
// ))

// const lowRated = books.filter(book => {
//   return book.rating < 4
// })

// let query = 'the'
// const filteredBooks = books.filter(book => {
//   const title = book.title.toLowerCase()
//   return title.includes(query)
// })

// console.log(goodBook)
// console.log(georgeBooks)
// console.log(lowRated)
// console.log(booksWithThe)

// const names = ['jack', 'james', 'john', 'jane', 'josh', 'jrad'];

// const result = names.every((name) => name[0] === 'j');
// console.log(result);

// const bestBooks = books.every((book) => book.rating >= 4);

// const notAuthor = books.every(
// 	(book) => book.author.toLowerCase() !== 'chetan bhagat'
// );

// console.log(bestBooks);
// console.log(notAuthor);

// const names = ['jack', 'james', 'john', 'jane', 'josh', 'jrad'];

// const result = names.some((name) => name[0] === 'b');
// console.log(result);

const prices = [500.4, 211, 23, 5, 4, 22.2, -23.2, 9233];

prices.sort((a, b) => b - a);
console.log(prices);

Scratchpad #6

// // const nums = [3, 2, 4, 6, 9];

// // acc   	currVal
// // 3			2
// // 5			4
// // 9			6
// // 15			9
// // 24

// // let total = nums.reduce((acc, currVal) => acc - currVal);
// // console.log(total);

// // let total = 0;
// // for (let num of nums) {
// // 	total += num;
// // }

// // console.log(total);

// // let nums = [21, 221, 2, 1, 34, 123, 4342, 56, 4];

// // acc     currVal
// // 21				221
// // 221			2
// // 221			1
// // 221			34
// // 221

// // const result = nums.reduce((acc, currVal) => {
// // 	if (currVal > acc) {
// // 		return currVal;
// // 	}
// // 	return acc;
// // });

// // console.log(result);

// // const nums = [3, 2, 4, 6, 9];

// // let total = nums.reduce((acc, currVal) => acc + currVal, 100);
// // console.log(total);

// // function multiply(a, b) {
// // 	if (typeof b === 'undefined') {
// // 		b = 1;
// // 	}
// // 	return a * b;
// // }

// // function multiply(a, b = 3) {
// // 	return a * b;
// // }

// // console.log(multiply(12));

// function printNames(a, b, c) {
// 	console.log(a);
// 	console.log(b);
// 	console.log(c);
// }

// // const names = ['john', 'jack', 'jane'];

// // // printNames(names[0], names[1], names[2]);
// // // printNames(...names);
// printNames(...'hello');

// // // printNames('john', 'jack', 'jane');

// // const nums = [5, 10, 11, 2, 1];

// // console.log(Math.max(...nums));

// const user = {
// 	firstName: 'John',
// 	lastName: 'Doe',
// 	age: 20,
// };

// const users = [user, user, user, user];

// // console.log(users[1].age);

// users[1].firstName = 'Abhishek';

// console.log(users[0].firstName);

// function add(...nums) {
// 	return nums.reduce((acc, currVal) => acc + currVal);
// }

// console.log(add(10, 5, 56, 23, 100));

// function add(a, b, ...nums) {
// 	console.log(a, b, nums);
// }

// add(10, 20, 30, 40, 50, 60);

// const users = ['john', 'jane', 'jack'];

// const admin = users[0];
// const mod = users[1];
// const user = users[2];

// const [admin, mod, user] = users;
// console.log(admin, mod, user);

// const [admin, , user] = users;
// console.log(admin, user);

// const [admin, ...others] = users;
// console.log(admin, others);

// const user = {
// 	firstName: 'John',
// 	lastName: 'Doe',
// 	email: '[email protected]',
// 	phone: 99982234567,
// };

// const { firstName, lastName, ...others } = user;

// console.log(firstName, lastName, others);

function printProfile({ firstName, lastName, age, company }) {
	console.log(
		`Hello, my name is ${firstName} ${lastName} and I am ${age} years old. I work for ${company}.`
	);
}

printProfile({ firstName: 'Jane', lastName: 'Doe', age: 20, company: 'Apple' });

Scratchpad #7

// // // const movieReviews = [4.5, 5.0, 3.2, 2.1, 4.7, 3.8, 3.1, 3.9, 4.4];
// // // const highest = Math.max(...movieReviews);
// // // const lowest = Math.min(...movieReviews);

// // // let total = 0;
// // // movieReviews.forEach((rating) => (total += rating));
// // // const average = total / movieReviews.length;

// // // const info = { highest, lowest, average, hello: 'world' };

// // // console.log(info);

// // // const getReviewDetails = (arr) => {
// // // 	const highest = Math.max(...arr);
// // // 	const lowest = Math.min(...arr);
// // // 	const total = arr.reduce((accumulator, nextVal) => accumulator + nextVal);
// // // 	const average = total / arr.length;

// // // 	return {
// // // 		highest,
// // // 		lowest,
// // // 		total,
// // // 		average,
// // // 	};
// // // };

// // // const reviewList = [4.5, 5.0, 3.2, 2.1, 4.7, 3.8, 3.1, 3.9, 4.4];

// // // const statistics = getReviewDetails(reviewList);
// // // console.log(statistics);

// // // const username = 'janedoe';
// // // const role = 'admin';

// // // const user1 = {
// // // 	[role]: username,
// // // };

// // // console.log(user1);

// // // const addProperty = (obj, k, v) => {
// // // 	return { ...obj, [k]: v };
// // // };

// // // console.log(addProperty({ firstName: 'John' }, 'age', 20));

// // // const math = {
// // // 	add(a, b) {
// // // 		return a + b;
// // // 	},
// // // 	sub(a, b) {
// // // 		return a - b;
// // // 	},
// // // };

// // // console.log(math.add(10, 4));

// // // function helloworld() {
// // // 	console.log('Hello World');
// // // 	console.log(this);
// // // }

// // // helloworld();

// // function func() {
// // 	console.log(`Hello my name is ${this.firstName} ${this.lastName}`);
// // }

// // const user1 = {
// // 	firstName: 'John',
// // 	lastName: 'Doe',
// // 	age: 20,
// // 	func,
// // };

// // const user2 = {
// // 	firstName: 'Jane',
// // 	lastName: 'Doe',
// // 	age: 20,
// // 	func,
// // };

// // user1.func();
// // user2.func();

// // // // const user = {
// // // // 	firstName: 'John',
// // // // 	lastName: 'Doe',
// // // // 	age: 20,
// // // // 	greet() {
// // // // 		console.log(this);
// // // // 	},
// // // // };

// // // user.greet();

// // // let helloworld = 'hello world';
// // console.log(this);

// // const user = {
// // 	firstName: 'John',
// // 	lastName: 'Doe',
// // 	role: 'admin',
// // 	fullName() {
// // 		return `${this.firstName} ${this.lastName} is an ${this.role}`;
// // 	},
// // 	logDetails() {
// // 		console.log(`${this.fullName()} and is cool!`);
// // 	},
// // };

// // user.logDetails();

// // const log = user.logDetails;
// // log();

const hellos = {
	messages: [
		'hello world',
		'hello universe',
		'hello darkness',
		'hello hello',
		'heylo',
	],
	pickMsg() {
		const index = Math.floor(Math.random() * this.messages.length);
		return this.messages[index];
	},
	start() {
		setInterval(() => {
			// this -> hellos
			console.log(this.pickMsg());
		}, 1000);
	},
};

// hellos.start();

// const user = {
// 	firstName: 'John',
// 	lastName: 'Doe',
// 	role: 'admin',
// 	fullName: function () {
// 		return `${this.firstName} ${this.lastName} is an ${this.role}`;
// 	},
// 	logDetails: () => {
// 		console.log(`${this.fullName()} and is cool!`);
// 	},
// };

// console.log(user.logDetails());

Task test.js

const products = [
	{
		id: 1,
		title: 'iPhone 9',
		description: 'An apple mobile which is nothing like apple',
		price: 549,
		discountPercentage: 12.96,
		rating: 4.69,
		stock: 94,
		brand: 'Apple',
		category: 'smartphones',
		thumbnail: 'https://i.dummyjson.com/data/products/1/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/1/1.jpg',
			'https://i.dummyjson.com/data/products/1/2.jpg',
			'https://i.dummyjson.com/data/products/1/3.jpg',
			'https://i.dummyjson.com/data/products/1/4.jpg',
			'https://i.dummyjson.com/data/products/1/thumbnail.jpg',
		],
	},
	{
		id: 2,
		title: 'iPhone X',
		description:
			'SIM-Free, Model A19211 6.5-inch Super Retina HD display with OLED technology A12 Bionic chip with ...',
		price: 899,
		discountPercentage: 17.94,
		rating: 4.44,
		stock: 34,
		brand: 'Apple',
		category: 'smartphones',
		thumbnail: 'https://i.dummyjson.com/data/products/2/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/2/1.jpg',
			'https://i.dummyjson.com/data/products/2/2.jpg',
			'https://i.dummyjson.com/data/products/2/3.jpg',
			'https://i.dummyjson.com/data/products/2/thumbnail.jpg',
		],
	},
	{
		id: 3,
		title: 'Samsung Universe 9',
		description:
			"Samsung's new variant which goes beyond Galaxy to the Universe",
		price: 1249,
		discountPercentage: 15.46,
		rating: 4.09,
		stock: 36,
		brand: 'Samsung',
		category: 'smartphones',
		thumbnail: 'https://i.dummyjson.com/data/products/3/thumbnail.jpg',
		images: ['https://i.dummyjson.com/data/products/3/1.jpg'],
	},
	{
		id: 4,
		title: 'OPPOF19',
		description: 'OPPO F19 is officially announced on April 2021.',
		price: 280,
		discountPercentage: 17.91,
		rating: 4.3,
		stock: 123,
		brand: 'OPPO',
		category: 'smartphones',
		thumbnail: 'https://i.dummyjson.com/data/products/4/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/4/1.jpg',
			'https://i.dummyjson.com/data/products/4/2.jpg',
			'https://i.dummyjson.com/data/products/4/3.jpg',
			'https://i.dummyjson.com/data/products/4/4.jpg',
			'https://i.dummyjson.com/data/products/4/thumbnail.jpg',
		],
	},
	{
		id: 5,
		title: 'Huawei P30',
		description:
			'Huawei’s re-badged P30 Pro New Edition was officially unveiled yesterday in Germany and now the device has made its way to the UK.',
		price: 499,
		discountPercentage: 10.58,
		rating: 4.09,
		stock: 32,
		brand: 'Huawei',
		category: 'smartphones',
		thumbnail: 'https://i.dummyjson.com/data/products/5/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/5/1.jpg',
			'https://i.dummyjson.com/data/products/5/2.jpg',
			'https://i.dummyjson.com/data/products/5/3.jpg',
		],
	},
	{
		id: 6,
		title: 'MacBook Pro',
		description:
			'MacBook Pro 2021 with mini-LED display may launch between September, November',
		price: 1749,
		discountPercentage: 11.02,
		rating: 4.57,
		stock: 83,
		brand: 'Apple',
		category: 'laptops',
		thumbnail: 'https://i.dummyjson.com/data/products/6/thumbnail.png',
		images: [
			'https://i.dummyjson.com/data/products/6/1.png',
			'https://i.dummyjson.com/data/products/6/2.jpg',
			'https://i.dummyjson.com/data/products/6/3.png',
			'https://i.dummyjson.com/data/products/6/4.jpg',
		],
	},
	{
		id: 7,
		title: 'Samsung Galaxy Book',
		description:
			'Samsung Galaxy Book S (2020) Laptop With Intel Lakefield Chip, 8GB of RAM Launched',
		price: 1499,
		discountPercentage: 4.15,
		rating: 4.25,
		stock: 50,
		brand: 'Samsung',
		category: 'laptops',
		thumbnail: 'https://i.dummyjson.com/data/products/7/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/7/1.jpg',
			'https://i.dummyjson.com/data/products/7/2.jpg',
			'https://i.dummyjson.com/data/products/7/3.jpg',
			'https://i.dummyjson.com/data/products/7/thumbnail.jpg',
		],
	},
	{
		id: 8,
		title: 'Microsoft Surface Laptop 4',
		description:
			'Style and speed. Stand out on HD video calls backed by Studio Mics. Capture ideas on the vibrant touchscreen.',
		price: 1499,
		discountPercentage: 10.23,
		rating: 4.43,
		stock: 68,
		brand: 'Microsoft Surface',
		category: 'laptops',
		thumbnail: 'https://i.dummyjson.com/data/products/8/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/8/1.jpg',
			'https://i.dummyjson.com/data/products/8/2.jpg',
			'https://i.dummyjson.com/data/products/8/3.jpg',
			'https://i.dummyjson.com/data/products/8/4.jpg',
			'https://i.dummyjson.com/data/products/8/thumbnail.jpg',
		],
	},
	{
		id: 9,
		title: 'Infinix INBOOK',
		description:
			'Infinix Inbook X1 Ci3 10th 8GB 256GB 14 Win10 Grey – 1 Year Warranty',
		price: 1099,
		discountPercentage: 11.83,
		rating: 4.54,
		stock: 96,
		brand: 'Infinix',
		category: 'laptops',
		thumbnail: 'https://i.dummyjson.com/data/products/9/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/9/1.jpg',
			'https://i.dummyjson.com/data/products/9/2.png',
			'https://i.dummyjson.com/data/products/9/3.png',
			'https://i.dummyjson.com/data/products/9/4.jpg',
			'https://i.dummyjson.com/data/products/9/thumbnail.jpg',
		],
	},
	{
		id: 10,
		title: 'HP Pavilion 15-DK1056WM',
		description:
			'HP Pavilion 15-DK1056WM Gaming Laptop 10th Gen Core i5, 8GB, 256GB SSD, GTX 1650 4GB, Windows 10',
		price: 1099,
		discountPercentage: 6.18,
		rating: 4.43,
		stock: 89,
		brand: 'HP Pavilion',
		category: 'laptops',
		thumbnail: 'https://i.dummyjson.com/data/products/10/thumbnail.jpeg',
		images: [
			'https://i.dummyjson.com/data/products/10/1.jpg',
			'https://i.dummyjson.com/data/products/10/2.jpg',
			'https://i.dummyjson.com/data/products/10/3.jpg',
			'https://i.dummyjson.com/data/products/10/thumbnail.jpeg',
		],
	},
	{
		id: 11,
		title: 'perfume Oil',
		description:
			'Mega Discount, Impression of Acqua Di Gio by GiorgioArmani concentrated attar perfume Oil',
		price: 13,
		discountPercentage: 8.4,
		rating: 4.26,
		stock: 65,
		brand: 'Impression of Acqua Di Gio',
		category: 'fragrances',
		thumbnail: 'https://i.dummyjson.com/data/products/11/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/11/1.jpg',
			'https://i.dummyjson.com/data/products/11/2.jpg',
			'https://i.dummyjson.com/data/products/11/3.jpg',
			'https://i.dummyjson.com/data/products/11/thumbnail.jpg',
		],
	},
	{
		id: 12,
		title: 'Brown Perfume',
		description: 'Royal_Mirage Sport Brown Perfume for Men & Women - 120ml',
		price: 40,
		discountPercentage: 15.66,
		rating: 4,
		stock: 52,
		brand: 'Royal_Mirage',
		category: 'fragrances',
		thumbnail: 'https://i.dummyjson.com/data/products/12/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/12/1.jpg',
			'https://i.dummyjson.com/data/products/12/2.jpg',
			'https://i.dummyjson.com/data/products/12/3.png',
			'https://i.dummyjson.com/data/products/12/4.jpg',
			'https://i.dummyjson.com/data/products/12/thumbnail.jpg',
		],
	},
	{
		id: 13,
		title: 'Fog Scent Xpressio Perfume',
		description:
			'Product details of Best Fog Scent Xpressio Perfume 100ml For Men cool long lasting perfumes for Men',
		price: 13,
		discountPercentage: 8.14,
		rating: 4.59,
		stock: 61,
		brand: 'Fog Scent Xpressio',
		category: 'fragrances',
		thumbnail: 'https://i.dummyjson.com/data/products/13/thumbnail.webp',
		images: [
			'https://i.dummyjson.com/data/products/13/1.jpg',
			'https://i.dummyjson.com/data/products/13/2.png',
			'https://i.dummyjson.com/data/products/13/3.jpg',
			'https://i.dummyjson.com/data/products/13/4.jpg',
			'https://i.dummyjson.com/data/products/13/thumbnail.webp',
		],
	},
	{
		id: 14,
		title: 'Non-Alcoholic Concentrated Perfume Oil',
		description:
			'Original Al Munakh® by Mahal Al Musk | Our Impression of Climate | 6ml Non-Alcoholic Concentrated Perfume Oil',
		price: 120,
		discountPercentage: 15.6,
		rating: 4.21,
		stock: 114,
		brand: 'Al Munakh',
		category: 'fragrances',
		thumbnail: 'https://i.dummyjson.com/data/products/14/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/14/1.jpg',
			'https://i.dummyjson.com/data/products/14/2.jpg',
			'https://i.dummyjson.com/data/products/14/3.jpg',
			'https://i.dummyjson.com/data/products/14/thumbnail.jpg',
		],
	},
	{
		id: 15,
		title: 'Eau De Perfume Spray',
		description:
			'Genuine  Al-Rehab spray perfume from UAE/Saudi Arabia/Yemen High Quality',
		price: 30,
		discountPercentage: 10.99,
		rating: 4.7,
		stock: 105,
		brand: 'Lord - Al-Rehab',
		category: 'fragrances',
		thumbnail: 'https://i.dummyjson.com/data/products/15/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/15/1.jpg',
			'https://i.dummyjson.com/data/products/15/2.jpg',
			'https://i.dummyjson.com/data/products/15/3.jpg',
			'https://i.dummyjson.com/data/products/15/4.jpg',
			'https://i.dummyjson.com/data/products/15/thumbnail.jpg',
		],
	},
	{
		id: 16,
		title: 'Hyaluronic Acid Serum',
		description:
			"L'Oréal Paris introduces Hyaluron Expert Replumping Serum formulated with 1.5% Hyaluronic Acid",
		price: 19,
		discountPercentage: 13.31,
		rating: 4.83,
		stock: 110,
		brand: "L'Oreal Paris",
		category: 'skincare',
		thumbnail: 'https://i.dummyjson.com/data/products/16/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/16/1.png',
			'https://i.dummyjson.com/data/products/16/2.webp',
			'https://i.dummyjson.com/data/products/16/3.jpg',
			'https://i.dummyjson.com/data/products/16/4.jpg',
			'https://i.dummyjson.com/data/products/16/thumbnail.jpg',
		],
	},
	{
		id: 17,
		title: 'Tree Oil 30ml',
		description:
			'Tea tree oil contains a number of compounds, including terpinen-4-ol, that have been shown to kill certain bacteria,',
		price: 12,
		discountPercentage: 4.09,
		rating: 4.52,
		stock: 78,
		brand: 'Hemani Tea',
		category: 'skincare',
		thumbnail: 'https://i.dummyjson.com/data/products/17/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/17/1.jpg',
			'https://i.dummyjson.com/data/products/17/2.jpg',
			'https://i.dummyjson.com/data/products/17/3.jpg',
			'https://i.dummyjson.com/data/products/17/thumbnail.jpg',
		],
	},
	{
		id: 18,
		title: 'Oil Free Moisturizer 100ml',
		description:
			'Dermive Oil Free Moisturizer with SPF 20 is specifically formulated with ceramides, hyaluronic acid & sunscreen.',
		price: 40,
		discountPercentage: 13.1,
		rating: 4.56,
		stock: 88,
		brand: 'Dermive',
		category: 'skincare',
		thumbnail: 'https://i.dummyjson.com/data/products/18/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/18/1.jpg',
			'https://i.dummyjson.com/data/products/18/2.jpg',
			'https://i.dummyjson.com/data/products/18/3.jpg',
			'https://i.dummyjson.com/data/products/18/4.jpg',
			'https://i.dummyjson.com/data/products/18/thumbnail.jpg',
		],
	},
	{
		id: 19,
		title: 'Skin Beauty Serum.',
		description:
			'Product name: rorec collagen hyaluronic acid white face serum riceNet weight: 15 m',
		price: 46,
		discountPercentage: 10.68,
		rating: 4.42,
		stock: 54,
		brand: 'ROREC White Rice',
		category: 'skincare',
		thumbnail: 'https://i.dummyjson.com/data/products/19/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/19/1.jpg',
			'https://i.dummyjson.com/data/products/19/2.jpg',
			'https://i.dummyjson.com/data/products/19/3.png',
			'https://i.dummyjson.com/data/products/19/thumbnail.jpg',
		],
	},
	{
		id: 20,
		title: 'Freckle Treatment Cream- 15gm',
		description:
			"Fair & Clear is Pakistan's only pure Freckle cream which helpsfade Freckles, Darkspots and pigments. Mercury level is 0%, so there are no side effects.",
		price: 70,
		discountPercentage: 16.99,
		rating: 4.06,
		stock: 140,
		brand: 'Fair & Clear',
		category: 'skincare',
		thumbnail: 'https://i.dummyjson.com/data/products/20/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/20/1.jpg',
			'https://i.dummyjson.com/data/products/20/2.jpg',
			'https://i.dummyjson.com/data/products/20/3.jpg',
			'https://i.dummyjson.com/data/products/20/4.jpg',
			'https://i.dummyjson.com/data/products/20/thumbnail.jpg',
		],
	},
	{
		id: 21,
		title: '- Daal Masoor 500 grams',
		description: 'Fine quality Branded Product Keep in a cool and dry place',
		price: 20,
		discountPercentage: 4.81,
		rating: 4.44,
		stock: 133,
		brand: 'Saaf & Khaas',
		category: 'groceries',
		thumbnail: 'https://i.dummyjson.com/data/products/21/thumbnail.png',
		images: [
			'https://i.dummyjson.com/data/products/21/1.png',
			'https://i.dummyjson.com/data/products/21/2.jpg',
			'https://i.dummyjson.com/data/products/21/3.jpg',
		],
	},
	{
		id: 22,
		title: 'Elbow Macaroni - 400 gm',
		description: 'Product details of Bake Parlor Big Elbow Macaroni - 400 gm',
		price: 14,
		discountPercentage: 15.58,
		rating: 4.57,
		stock: 146,
		brand: 'Bake Parlor Big',
		category: 'groceries',
		thumbnail: 'https://i.dummyjson.com/data/products/22/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/22/1.jpg',
			'https://i.dummyjson.com/data/products/22/2.jpg',
			'https://i.dummyjson.com/data/products/22/3.jpg',
		],
	},
	{
		id: 23,
		title: 'Orange Essence Food Flavou',
		description:
			'Specifications of Orange Essence Food Flavour For Cakes and Baking Food Item',
		price: 14,
		discountPercentage: 8.04,
		rating: 4.85,
		stock: 26,
		brand: 'Baking Food Items',
		category: 'groceries',
		thumbnail: 'https://i.dummyjson.com/data/products/23/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/23/1.jpg',
			'https://i.dummyjson.com/data/products/23/2.jpg',
			'https://i.dummyjson.com/data/products/23/3.jpg',
			'https://i.dummyjson.com/data/products/23/4.jpg',
			'https://i.dummyjson.com/data/products/23/thumbnail.jpg',
		],
	},
	{
		id: 24,
		title: 'cereals muesli fruit nuts',
		description:
			'original fauji cereal muesli 250gm box pack original fauji cereals muesli fruit nuts flakes breakfast cereal break fast faujicereals cerels cerel foji fouji',
		price: 46,
		discountPercentage: 16.8,
		rating: 4.94,
		stock: 113,
		brand: 'fauji',
		category: 'groceries',
		thumbnail: 'https://i.dummyjson.com/data/products/24/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/24/1.jpg',
			'https://i.dummyjson.com/data/products/24/2.jpg',
			'https://i.dummyjson.com/data/products/24/3.jpg',
			'https://i.dummyjson.com/data/products/24/4.jpg',
			'https://i.dummyjson.com/data/products/24/thumbnail.jpg',
		],
	},
	{
		id: 25,
		title: 'Gulab Powder 50 Gram',
		description: 'Dry Rose Flower Powder Gulab Powder 50 Gram • Treats Wounds',
		price: 70,
		discountPercentage: 13.58,
		rating: 4.87,
		stock: 47,
		brand: 'Dry Rose',
		category: 'groceries',
		thumbnail: 'https://i.dummyjson.com/data/products/25/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/25/1.png',
			'https://i.dummyjson.com/data/products/25/2.jpg',
			'https://i.dummyjson.com/data/products/25/3.png',
			'https://i.dummyjson.com/data/products/25/4.jpg',
			'https://i.dummyjson.com/data/products/25/thumbnail.jpg',
		],
	},
	{
		id: 26,
		title: 'Plant Hanger For Home',
		description:
			'Boho Decor Plant Hanger For Home Wall Decoration Macrame Wall Hanging Shelf',
		price: 41,
		discountPercentage: 17.86,
		rating: 4.08,
		stock: 131,
		brand: 'Boho Decor',
		category: 'home-decoration',
		thumbnail: 'https://i.dummyjson.com/data/products/26/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/26/1.jpg',
			'https://i.dummyjson.com/data/products/26/2.jpg',
			'https://i.dummyjson.com/data/products/26/3.jpg',
			'https://i.dummyjson.com/data/products/26/4.jpg',
			'https://i.dummyjson.com/data/products/26/5.jpg',
			'https://i.dummyjson.com/data/products/26/thumbnail.jpg',
		],
	},
	{
		id: 27,
		title: 'Flying Wooden Bird',
		description:
			'Package Include 6 Birds with Adhesive Tape Shape: 3D Shaped Wooden Birds Material: Wooden MDF, Laminated 3.5mm',
		price: 51,
		discountPercentage: 15.58,
		rating: 4.41,
		stock: 17,
		brand: 'Flying Wooden',
		category: 'home-decoration',
		thumbnail: 'https://i.dummyjson.com/data/products/27/thumbnail.webp',
		images: [
			'https://i.dummyjson.com/data/products/27/1.jpg',
			'https://i.dummyjson.com/data/products/27/2.jpg',
			'https://i.dummyjson.com/data/products/27/3.jpg',
			'https://i.dummyjson.com/data/products/27/4.jpg',
			'https://i.dummyjson.com/data/products/27/thumbnail.webp',
		],
	},
	{
		id: 28,
		title: '3D Embellishment Art Lamp',
		description:
			'3D led lamp sticker Wall sticker 3d wall art light on/off button  cell operated (included)',
		price: 20,
		discountPercentage: 16.49,
		rating: 4.82,
		stock: 54,
		brand: 'LED Lights',
		category: 'home-decoration',
		thumbnail: 'https://i.dummyjson.com/data/products/28/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/28/1.jpg',
			'https://i.dummyjson.com/data/products/28/2.jpg',
			'https://i.dummyjson.com/data/products/28/3.png',
			'https://i.dummyjson.com/data/products/28/4.jpg',
			'https://i.dummyjson.com/data/products/28/thumbnail.jpg',
		],
	},
	{
		id: 29,
		title: 'Handcraft Chinese style',
		description:
			'Handcraft Chinese style art luxury palace hotel villa mansion home decor ceramic vase with brass fruit plate',
		price: 60,
		discountPercentage: 15.34,
		rating: 4.44,
		stock: 7,
		brand: 'luxury palace',
		category: 'home-decoration',
		thumbnail: 'https://i.dummyjson.com/data/products/29/thumbnail.webp',
		images: [
			'https://i.dummyjson.com/data/products/29/1.jpg',
			'https://i.dummyjson.com/data/products/29/2.jpg',
			'https://i.dummyjson.com/data/products/29/3.webp',
			'https://i.dummyjson.com/data/products/29/4.webp',
			'https://i.dummyjson.com/data/products/29/thumbnail.webp',
		],
	},
	{
		id: 30,
		title: 'Key Holder',
		description:
			'Attractive DesignMetallic materialFour key hooksReliable & DurablePremium Quality',
		price: 30,
		discountPercentage: 2.92,
		rating: 4.92,
		stock: 54,
		brand: 'Golden',
		category: 'home-decoration',
		thumbnail: 'https://i.dummyjson.com/data/products/30/thumbnail.jpg',
		images: [
			'https://i.dummyjson.com/data/products/30/1.jpg',
			'https://i.dummyjson.com/data/products/30/2.jpg',
			'https://i.dummyjson.com/data/products/30/3.jpg',
			'https://i.dummyjson.com/data/products/30/thumbnail.jpg',
		],
	},
];

const users = [
	{
		id: 1,
		firstName: 'Terry',
		lastName: 'Medhurst',
		maidenName: 'Smitham',
		age: 50,
		gender: 'male',
		email: '[email protected]',
		phone: '+63 791 675 8914',
		username: 'atuny0',
		password: '9uQFF1Lh',
		birthDate: '2000-12-25',
		image: 'https://robohash.org/hicveldicta.png',
		bloodGroup: 'A−',
		height: 189,
		weight: 75.4,
		eyeColor: 'Green',
		hair: {
			color: 'Black',
			type: 'Strands',
		},
		domain: 'slashdot.org',
		ip: '117.29.86.254',
		address: {
			address: '1745 T Street Southeast',
			city: 'Washington',
			coordinates: {
				lat: 38.867033,
				lng: -76.979235,
			},
			postalCode: '20020',
			state: 'DC',
		},
		macAddress: '13:69:BA:56:A3:74',
		university: 'Capitol University',
		bank: {
			cardExpire: '06/22',
			cardNumber: '50380955204220685',
			cardType: 'maestro',
			currency: 'Peso',
			iban: 'NO17 0695 2754 967',
		},
		company: {
			address: {
				address: '629 Debbie Drive',
				city: 'Nashville',
				coordinates: {
					lat: 36.208114,
					lng: -86.58621199999999,
				},
				postalCode: '37076',
				state: 'TN',
			},
			department: 'Marketing',
			name: "Blanda-O'Keefe",
			title: 'Help Desk Operator',
		},
		ein: '20-9487066',
		ssn: '661-64-2976',
		userAgent:
			'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/12.0.702.0 Safari/534.24',
	},
	{
		id: 2,
		firstName: 'Sheldon',
		lastName: 'Quigley',
		maidenName: 'Cole',
		age: 28,
		gender: 'male',
		email: '[email protected]',
		phone: '+7 813 117 7139',
		username: 'hbingley1',
		password: 'CQutx25i8r',
		birthDate: '2003-08-02',
		image: 'https://robohash.org/doloremquesintcorrupti.png',
		bloodGroup: 'O+',
		height: 187,
		weight: 74,
		eyeColor: 'Brown',
		hair: {
			color: 'Blond',
			type: 'Curly',
		},
		domain: '51.la',
		ip: '253.240.20.181',
		address: {
			address: '6007 Applegate Lane',
			city: 'Louisville',
			coordinates: {
				lat: 38.1343013,
				lng: -85.6498512,
			},
			postalCode: '40219',
			state: 'KY',
		},
		macAddress: '13:F1:00:DA:A4:12',
		university: 'Stavropol State Technical University',
		bank: {
			cardExpire: '10/23',
			cardNumber: '5355920631952404',
			cardType: 'mastercard',
			currency: 'Ruble',
			iban: 'MD63 L6YC 8YH4 QVQB XHIK MTML',
		},
		company: {
			address: {
				address: '8821 West Myrtle Avenue',
				city: 'Glendale',
				coordinates: {
					lat: 33.5404296,
					lng: -112.2488391,
				},
				postalCode: '85305',
				state: 'AZ',
			},
			department: 'Services',
			name: 'Aufderhar-Cronin',
			title: 'Senior Cost Accountant',
		},
		ein: '52-5262907',
		ssn: '447-08-9217',
		userAgent:
			'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/11.04 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30',
	},
	{
		id: 3,
		firstName: 'Terrill',
		lastName: 'Hills',
		maidenName: 'Hoeger',
		age: 38,
		gender: 'male',
		email: '[email protected]',
		phone: '+63 739 292 7942',
		username: 'rshawe2',
		password: 'OWsTbMUgFc',
		birthDate: '1992-12-30',
		image: 'https://robohash.org/consequunturautconsequatur.png',
		bloodGroup: 'A−',
		height: 200,
		weight: 105.3,
		eyeColor: 'Gray',
		hair: {
			color: 'Blond',
			type: 'Very curly',
		},
		domain: 'earthlink.net',
		ip: '205.226.160.3',
		address: {
			address: '560 Penstock Drive',
			city: 'Grass Valley',
			coordinates: {
				lat: 39.213076,
				lng: -121.077583,
			},
			postalCode: '95945',
			state: 'CA',
		},
		macAddress: 'F2:88:58:64:F7:76',
		university: 'University of Cagayan Valley',
		bank: {
			cardExpire: '10/23',
			cardNumber: '3586082982526703',
			cardType: 'jcb',
			currency: 'Peso',
			iban: 'AT24 1095 9625 1434 9703',
		},
		company: {
			address: {
				address: '18 Densmore Drive',
				city: 'Essex',
				coordinates: {
					lat: 44.492953,
					lng: -73.101883,
				},
				postalCode: '05452',
				state: 'VT',
			},
			department: 'Marketing',
			name: 'Lindgren LLC',
			title: 'Mechanical Systems Engineer',
		},
		ein: '48-3951994',
		ssn: '633-89-1926',
		userAgent:
			'Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:21.0.0) Gecko/20121011 Firefox/21.0.0',
	},
	{
		id: 4,
		firstName: 'Miles',
		lastName: 'Cummerata',
		maidenName: 'Maggio',
		age: 49,
		gender: 'male',
		email: '[email protected]',
		phone: '+86 461 145 4186',
		username: 'yraigatt3',
		password: 'sRQxjPfdS',
		birthDate: '1969-01-16',
		image: 'https://robohash.org/facilisdignissimosdolore.png',
		bloodGroup: 'B+',
		height: 157,
		weight: 95.9,
		eyeColor: 'Gray',
		hair: {
			color: 'Blond',
			type: 'Very curly',
		},
		domain: 'homestead.com',
		ip: '243.20.78.113',
		address: {
			address: '150 Carter Street',
			city: 'Manchester',
			coordinates: {
				lat: 41.76556000000001,
				lng: -72.473091,
			},
			postalCode: '06040',
			state: 'CT',
		},
		macAddress: '03:45:58:59:5A:7B',
		university: 'Shenyang Pharmaceutical University',
		bank: {
			cardExpire: '07/24',
			cardNumber: '3580047879369323',
			cardType: 'jcb',
			currency: 'Yuan Renminbi',
			iban: 'KZ43 658B M6VS TZOU OXSO',
		},
		company: {
			address: {
				address: '210 Green Road',
				city: 'Manchester',
				coordinates: {
					lat: 41.7909099,
					lng: -72.51195129999999,
				},
				postalCode: '06042',
				state: 'CT',
			},
			department: 'Business Development',
			name: 'Wolff and Sons',
			title: 'Paralegal',
		},
		ein: '71-3644334',
		ssn: '487-28-6642',
		userAgent:
			'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.17 Safari/537.11',
	},
	{
		id: 5,
		firstName: 'Mavis',
		lastName: 'Schultz',
		maidenName: 'Yundt',
		age: 38,
		gender: 'male',
		email: '[email protected]',
		phone: '+372 285 771 1911',
		username: 'kmeus4',
		password: 'aUTdmmmbH',
		birthDate: '1968-11-03',
		image: 'https://robohash.org/adverovelit.png',
		bloodGroup: 'O+',
		height: 188,
		weight: 106.3,
		eyeColor: 'Brown',
		hair: {
			color: 'Brown',
			type: 'Curly',
		},
		domain: 'columbia.edu',
		ip: '103.72.86.183',
		address: {
			address: '2721 Lindsay Avenue',
			city: 'Louisville',
			coordinates: {
				lat: 38.263793,
				lng: -85.700243,
			},
			postalCode: '40206',
			state: 'KY',
		},
		macAddress: 'F8:04:9E:ED:C0:68',
		university: 'Estonian University of Life Sciences',
		bank: {
			cardExpire: '01/24',
			cardNumber: '4917245076693618',
			cardType: 'visa-electron',
			currency: 'Euro',
			iban: 'IT41 T114 5127 716J RGYB ZRUX DSJ',
		},
		company: {
			address: {
				address: '8398 West Denton Lane',
				city: 'Glendale',
				coordinates: {
					lat: 33.515353,
					lng: -112.240812,
				},
				postalCode: '85305',
				state: 'AZ',
			},
			department: 'Support',
			name: 'Adams Inc',
			title: 'Web Developer I',
		},
		ein: '18-7178563',
		ssn: '667-98-5357',
		userAgent:
			'Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.1 Safari/535.1',
	},
	{
		id: 6,
		firstName: 'Alison',
		lastName: 'Reichert',
		maidenName: 'Franecki',
		age: 21,
		gender: 'female',
		email: '[email protected]',
		phone: '+351 527 735 3642',
		username: 'jtreleven5',
		password: 'zY1nE46Zm',
		birthDate: '1969-07-21',
		image: 'https://robohash.org/laboriosamfacilisrem.png',
		bloodGroup: 'A+',
		height: 149,
		weight: 105.7,
		eyeColor: 'Amber',
		hair: {
			color: 'Blond',
			type: 'Straight',
		},
		domain: 'bandcamp.com',
		ip: '49.201.206.36',
		address: {
			address: '18 Densmore Drive',
			city: 'Essex',
			coordinates: {
				lat: 44.492953,
				lng: -73.101883,
			},
			postalCode: '05452',
			state: 'VT',
		},
		macAddress: '6C:34:D0:4B:4E:81',
		university: 'Universidade da Beira Interior',
		bank: {
			cardExpire: '03/22',
			cardNumber: '345675888286047',
			cardType: 'americanexpress',
			currency: 'Euro',
			iban: 'LB69 1062 QCY5 XS5T VOKU KJFG XP4S',
		},
		company: {
			address: {
				address: '6231 North 67th Avenue',
				city: 'Glendale',
				coordinates: {
					lat: 33.5279666,
					lng: -112.2022551,
				},
				postalCode: '85301',
				state: 'AZ',
			},
			department: 'Accounting',
			name: "D'Amore and Sons",
			title: 'Civil Engineer',
		},
		ein: '78-3192791',
		ssn: '158-68-0184',
		userAgent:
			'Mozilla/5.0 (Windows; U; Windows NT 6.0; nb-NO) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5',
	},
	{
		id: 7,
		firstName: 'Oleta',
		lastName: 'Abbott',
		maidenName: 'Wyman',
		age: 31,
		gender: 'female',
		email: '[email protected]',
		phone: '+62 640 802 7111',
		username: 'dpettegre6',
		password: 'YVmhktgYVS',
		birthDate: '1982-02-21',
		image: 'https://robohash.org/cupiditatererumquos.png',
		bloodGroup: 'B−',
		height: 172,
		weight: 78.1,
		eyeColor: 'Blue',
		hair: {
			color: 'Chestnut',
			type: 'Wavy',
		},
		domain: 'ovh.net',
		ip: '25.207.107.146',
		address: {
			address: '637 Britannia Drive',
			city: 'Vallejo',
			coordinates: {
				lat: 38.10476999999999,
				lng: -122.193849,
			},
			postalCode: '94591',
			state: 'CA',
		},
		macAddress: '48:2D:A0:67:19:E0',
		university: 'Institut Sains dan Teknologi Al Kamal',
		bank: {
			cardExpire: '10/23',
			cardNumber: '3589640949470047',
			cardType: 'jcb',
			currency: 'Rupiah',
			iban: 'GI97 IKPF 9DUO X25M FG8D UXY',
		},
		company: {
			address: {
				address: '1407 Walden Court',
				city: 'Crofton',
				coordinates: {
					lat: 39.019306,
					lng: -76.660653,
				},
				postalCode: '21114',
				state: 'MD',
			},
			department: 'Product Management',
			name: 'Schimmel, Wilderman and Orn',
			title: 'Sales Associate',
		},
		ein: '29-1568401',
		ssn: '478-11-2206',
		userAgent:
			'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5',
	},
	{
		id: 8,
		firstName: 'Ewell',
		lastName: 'Mueller',
		maidenName: 'Durgan',
		age: 29,
		gender: 'male',
		email: '[email protected]',
		phone: '+86 946 297 2275',
		username: 'ggude7',
		password: 'MWwlaeWcOoF6',
		birthDate: '1964-08-24',
		image: 'https://robohash.org/quiaharumsapiente.png',
		bloodGroup: 'A−',
		height: 146,
		weight: 52.1,
		eyeColor: 'Blue',
		hair: {
			color: 'Chestnut',
			type: 'Wavy',
		},
		domain: 'homestead.com',
		ip: '91.200.56.127',
		address: {
			address: '5601 West Crocus Drive',
			city: 'Glendale',
			coordinates: {
				lat: 33.6152469,
				lng: -112.179737,
			},
			postalCode: '85306',
			state: 'AZ',
		},
		macAddress: '72:DA:1B:D7:30:E9',
		university: 'Wenzhou Medical College',
		bank: {
			cardExpire: '09/23',
			cardNumber: '30549925358905',
			cardType: 'diners-club-carte-blanche',
			currency: 'Yuan Renminbi',
			iban: 'CY02 9914 5346 0PMT G6XW TP0R AWRZ',
		},
		company: {
			address: {
				address: '81 Seaton Place Northwest',
				city: 'Washington',
				coordinates: {
					lat: 38.9149499,
					lng: -77.01170259999999,
				},
				postalCode: '20001',
				state: 'DC',
			},
			department: 'Services',
			name: 'Corkery, Reichert and Hodkiewicz',
			title: 'Clinical Specialist',
		},
		ein: '88-4396827',
		ssn: '238-41-5528',
		userAgent:
			'Mozilla/5.0 (X11; Linux amd64) AppleWebKit/534.36 (KHTML, like Gecko) Chrome/13.0.766.0 Safari/534.36',
	},
	{
		id: 9,
		firstName: 'Demetrius',
		lastName: 'Corkery',
		maidenName: 'Gleason',
		age: 22,
		gender: 'male',
		email: '[email protected]',
		phone: '+86 356 590 9727',
		username: 'nloiterton8',
		password: 'HTQxxXV9Bq4',
		birthDate: '1971-03-11',
		image: 'https://robohash.org/excepturiiuremolestiae.png',
		bloodGroup: 'A+',
		height: 170,
		weight: 97.1,
		eyeColor: 'Green',
		hair: {
			color: 'Brown',
			type: 'Strands',
		},
		domain: 'goodreads.com',
		ip: '78.170.185.120',
		address: {
			address: '5403 Illinois Avenue',
			city: 'Nashville',
			coordinates: {
				lat: 36.157077,
				lng: -86.853827,
			},
			postalCode: '37209',
			state: 'TN',
		},
		macAddress: '98:EE:94:A2:91:C4',
		university: 'Nanjing University of Economics',
		bank: {
			cardExpire: '02/24',
			cardNumber: '5372664789004621',
			cardType: 'mastercard',
			currency: 'Yuan Renminbi',
			iban: 'BR68 9829 0581 3669 5088 5533 025N V',
		},
		company: {
			address: {
				address: '12245 West 71st Place',
				city: 'Arvada',
				coordinates: {
					lat: 39.8267078,
					lng: -105.1366798,
				},
				postalCode: '80004',
				state: 'CO',
			},
			department: 'Human Resources',
			name: 'Gorczany Group',
			title: 'Community Outreach Specialist',
		},
		ein: '14-1066382',
		ssn: '717-26-3759',
		userAgent:
			'Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; de) AppleWebKit/528.4+ (KHTML, like Gecko) Version/4.0dp1 Safari/526.11.2',
	},
	{
		id: 10,
		firstName: 'Eleanora',
		lastName: 'Price',
		maidenName: 'Cummings',
		age: 37,
		gender: 'female',
		email: '[email protected]',
		phone: '+60 184 408 0824',
		username: 'umcgourty9',
		password: 'i0xzpX',
		birthDate: '1958-08-11',
		image: 'https://robohash.org/aliquamcumqueiure.png',
		bloodGroup: 'O+',
		height: 198,
		weight: 48,
		eyeColor: 'Blue',
		hair: {
			color: 'Chestnut',
			type: 'Wavy',
		},
		domain: 'alibaba.com',
		ip: '73.15.179.178',
		address: {
			address: '8821 West Myrtle Avenue',
			city: 'Glendale',
			coordinates: {
				lat: 33.5404296,
				lng: -112.2488391,
			},
			postalCode: '85305',
			state: 'AZ',
		},
		macAddress: 'BC:A9:D8:98:CB:0B',
		university: 'Melaka City Polytechnic',
		bank: {
			cardExpire: '01/24',
			cardNumber: '3557806620295254',
			cardType: 'jcb',
			currency: 'Ringgit',
			iban: 'GT40 DWAD 9UHA VEOZ ZF4J 2Y0F OOFD',
		},
		company: {
			address: {
				address: '1649 Timberridge Court',
				city: 'Fayetteville',
				coordinates: {
					lat: 36.084563,
					lng: -94.206082,
				},
				postalCode: '72704',
				state: 'AR',
			},
			department: 'Marketing',
			name: 'Bins Group',
			title: 'Senior Sales Associate',
		},
		ein: '21-5278484',
		ssn: '544-66-0745',
		userAgent:
			'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.6 Safari/537.11',
	},
	{
		id: 11,
		firstName: 'Marcel',
		lastName: 'Jones',
		maidenName: 'Smith',
		age: 39,
		gender: 'male',
		email: '[email protected]',
		phone: '+967 253 210 0344',
		username: 'acharlota',
		password: 'M9lbMdydMN',
		birthDate: '1961-09-12',
		image: 'https://robohash.org/impeditautest.png',
		bloodGroup: 'B−',
		height: 203,
		weight: 63.7,
		eyeColor: 'Amber',
		hair: {
			color: 'Black',
			type: 'Straight',
		},
		domain: 'feedburner.com',
		ip: '137.235.164.173',
		address: {
			address: '2203 7th Street Road',
			city: 'Louisville',
			coordinates: {
				lat: 38.218107,
				lng: -85.779006,
			},
			postalCode: '40208',
			state: 'KY',
		},
		macAddress: '59:E8:70:5A:E5:D6',
		university: 'Hodeidah University',
		bank: {
			cardExpire: '05/24',
			cardNumber: '5893925889459720',
			cardType: 'maestro',
			currency: 'Rial',
			iban: 'NL97 UWMY 2503 2999 43',
		},
		company: {
			address: {
				address: '308 Woodleaf Court',
				city: 'Glen Burnie',
				coordinates: {
					lat: 39.1425931,
					lng: -76.6238441,
				},
				postalCode: '21061',
				state: 'MD',
			},
			department: 'Business Development',
			name: 'Kuhn-Harber',
			title: 'Account Executive',
		},
		ein: '09-3791007',
		ssn: '342-54-8422',
		userAgent:
			'Mozilla/5.0 (Windows NT 5.2) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.792.0 Safari/535.1',
	},
	{
		id: 12,
		firstName: 'Assunta',
		lastName: 'Rath',
		maidenName: 'Heller',
		age: 42,
		gender: 'female',
		email: '[email protected]',
		phone: '+380 962 542 6549',
		username: 'rhallawellb',
		password: 'esTkitT1r',
		birthDate: '1990-12-14',
		image: 'https://robohash.org/namquaerataut.png',
		bloodGroup: 'O−',
		height: 168,
		weight: 96.8,
		eyeColor: 'Gray',
		hair: {
			color: 'Black',
			type: 'Very curly',
		},
		domain: '123-reg.co.uk',
		ip: '74.80.53.208',
		address: {
			address: '6463 Vrain Street',
			city: 'Arvada',
			coordinates: {
				lat: 39.814056,
				lng: -105.046913,
			},
			postalCode: '80003',
			state: 'CO',
		},
		macAddress: '9B:DC:21:C2:30:A3',
		university: 'Kiev Slavonic University',
		bank: {
			cardExpire: '09/22',
			cardNumber: '5602230671060360',
			cardType: 'bankcard',
			currency: 'Hryvnia',
			iban: 'KW76 VNLA LX0Y DMDE PFS8 FVKP VMDF AV',
		},
		company: {
			address: {
				address: '388 East Main Street',
				coordinates: {
					lat: 43.9727945,
					lng: -73.1023187,
				},
				postalCode: '05753',
				state: 'VT',
			},
			department: 'Product Management',
			name: 'Goodwin-Skiles',
			title: 'Developer II',
		},
		ein: '14-1242349',
		ssn: '116-51-6131',
		userAgent:
			'Mozilla/5.0 (X11; CrOS i686 4319.74.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36',
	},
	{
		id: 13,
		firstName: 'Trace',
		lastName: 'Douglas',
		maidenName: 'Lemke',
		age: 26,
		gender: 'male',
		email: 'lgribbin[email protected]',
		phone: '+1 609 937 3468',
		username: 'lgribbinc',
		password: 'ftGj8LZTtv9g',
		birthDate: '1967-07-23',
		image: 'https://robohash.org/voluptatemsintnulla.png',
		bloodGroup: 'O+',
		height: 181,
		weight: 56.5,
		eyeColor: 'Amber',
		hair: {
			color: 'Auburn',
			type: 'Straight',
		},
		domain: 'histats.com',
		ip: '163.245.232.27',
		address: {
			address: '87 Horseshoe Drive',
			city: 'West Windsor',
			coordinates: {
				lat: 43.4731793,
				lng: -72.4967532,
			},
			postalCode: '05037',
			state: 'VT',
		},
		macAddress: 'B9:21:ED:9F:B8:9E',
		university: 'Dallas Christian College',
		bank: {
			cardExpire: '01/23',
			cardNumber: '3556299106119514',
			cardType: 'jcb',
			currency: 'Dollar',
			iban: 'AE47 4194 4544 3401 3419 286',
		},
		company: {
			address: {
				address: '310 Timrod Road',
				city: 'Manchester',
				coordinates: {
					lat: 41.756758,
					lng: -72.493501,
				},
				postalCode: '06040',
				state: 'CT',
			},
			department: 'Research and Development',
			name: 'Casper Inc',
			title: 'Sales Associate',
		},
		ein: '94-0648182',
		ssn: '217-05-3082',
		userAgent:
			'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4',
	},
	{
		id: 14,
		firstName: 'Enoch',
		lastName: 'Lynch',
		maidenName: 'Heidenreich',
		age: 21,
		gender: 'male',
		email: '[email protected]',
		phone: '+94 912 100 5118',
		username: 'mturleyd',
		password: 'GyLnCB8gNIp',
		birthDate: '1979-08-25',
		image: 'https://robohash.org/quisequienim.png',
		bloodGroup: 'O+',
		height: 150,
		weight: 100.3,
		eyeColor: 'Green',
		hair: {
			color: 'Auburn',
			type: 'Strands',
		},
		domain: 'icio.us',
		ip: '174.238.43.126',
		address: {
			address: '60 Desousa Drive',
			city: 'Manchester',
			coordinates: {
				lat: 41.7409259,
				lng: -72.5619104,
			},
			postalCode: '06040',
			state: 'CT',
		},
		macAddress: '52:11:E1:31:35:C1',
		university: 'University of Sri Jayawardenapura',
		bank: {
			cardExpire: '11/23',
			cardNumber: '5339467937996728',
			cardType: 'mastercard',
			currency: 'Rupee',
			iban: 'SI28 0812 7967 0952 944',
		},
		company: {
			address: {
				address: '21950 Arnold Center Road',
				city: 'Carson',
				coordinates: {
					lat: 33.8272706,
					lng: -118.2302826,
				},
				postalCode: '90810',
				state: 'CA',
			},
			department: 'Sales',
			name: 'Schoen Inc',
			title: 'Professor',
		},
		ein: '61-8316825',
		ssn: '742-81-1714',
		userAgent:
			'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-en) AppleWebKit/533.16 (KHTML, like Gecko) Version/4.1 Safari/533.16',
	},
	{
		id: 15,
		firstName: 'Jeanne',
		lastName: 'Halvorson',
		maidenName: 'Cummerata',
		age: 26,
		gender: 'female',
		email: '[email protected]',
		phone: '+86 581 108 7855',
		username: 'kminchelle',
		password: '0lelplR',
		birthDate: '1996-02-02',
		image: 'https://robohash.org/autquiaut.png',
		bloodGroup: 'A+',
		height: 176,
		weight: 45.7,
		eyeColor: 'Amber',
		hair: {
			color: 'Blond',
			type: 'Straight',
		},
		domain: 'google.co.uk',
		ip: '78.43.74.226',
		address: {
			address: '4 Old Colony Way',
			city: 'Yarmouth',
			coordinates: {
				lat: 41.697168,
				lng: -70.189992,
			},
			postalCode: '02664',
			state: 'MA',
		},
		macAddress: 'D9:DB:D9:5A:01:09',
		university: 'Donghua University, Shanghai',
		bank: {
			cardExpire: '10/23',
			cardNumber: '3588859507772914',
			cardType: 'jcb',
			currency: 'Yuan Renminbi',
			iban: 'FO12 1440 0396 8902 56',
		},
		company: {
			address: {
				address: '22572 Toreador Drive',
				city: 'Salinas',
				coordinates: {
					lat: 36.602449,
					lng: -121.699071,
				},
				postalCode: '93908',
				state: 'CA',
			},
			department: 'Marketing',
			name: 'Hahn-MacGyver',
			title: 'Software Test Engineer IV',
		},
		ein: '62-0561095',
		ssn: '855-43-8639',
		userAgent:
			'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.14 Safari/534.24',
	},
	{
		id: 16,
		firstName: 'Trycia',
		lastName: 'Fadel',
		maidenName: 'Rosenbaum',
		age: 41,
		gender: 'female',
		email: '[email protected]',
		phone: '+420 833 708 0340',
		username: 'dpierrof',
		password: 'Vru55Y4tufI4',
		birthDate: '1963-07-03',
		image: 'https://robohash.org/porronumquamid.png',
		bloodGroup: 'B+',
		height: 166,
		weight: 87.2,
		eyeColor: 'Gray',
		hair: {
			color: 'Black',
			type: 'Very curly',
		},
		domain: 'tamu.edu',
		ip: '82.170.69.15',
		address: {
			address: '314 South 17th Street',
			city: 'Nashville',
			coordinates: {
				lat: 36.1719075,
				lng: -86.740228,
			},
			postalCode: '37206',
			state: 'TN',
		},
		macAddress: '3D:21:5B:9F:76:FF',
		university: 'Technical University of Mining and Metallurgy Ostrava',
		bank: {
			cardExpire: '07/23',
			cardNumber: '6378941710246212',
			cardType: 'instapayment',
			currency: 'Koruna',
			iban: 'CH94 4961 5QY1 VPV1 NGIP P',
		},
		company: {
			address: {
				address: '1407 Walden Court',
				city: 'Crofton',
				coordinates: {
					lat: 39.019306,
					lng: -76.660653,
				},
				postalCode: '21114',
				state: 'MD',
			},
			department: 'Research and Development',
			name: 'Steuber, Considine and Padberg',
			title: 'Geological Engineer',
		},
		ein: '75-1816504',
		ssn: '677-73-1525',
		userAgent:
			'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.872.0 Safari/535.2',
	},
	{
		id: 17,
		firstName: 'Bradford',
		lastName: 'Prohaska',
		maidenName: 'Bins',
		age: 43,
		gender: 'male',
		email: '[email protected]',
		phone: '+420 874 628 3710',
		username: 'vcholdcroftg',
		password: 'mSPzYZfR',
		birthDate: '1975-10-20',
		image: 'https://robohash.org/accusantiumvoluptateseos.png',
		bloodGroup: 'O−',
		height: 199,
		weight: 94.3,
		eyeColor: 'Brown',
		hair: {
			color: 'Black',
			type: 'Curly',
		},
		domain: 'wix.com',
		ip: '75.75.234.243',
		address: {
			address: '1649 Timberridge Court',
			city: 'Fayetteville',
			coordinates: {
				lat: 36.084563,
				lng: -94.206082,
			},
			postalCode: '72704',
			state: 'AR',
		},
		macAddress: '47:FA:F7:94:7B:5D',
		university: 'Technical University of Mining and Metallurgy Ostrava',
		bank: {
			cardExpire: '05/24',
			cardNumber: '3574627048005672',
			cardType: 'jcb',
			currency: 'Koruna',
			iban: 'SI81 7221 0344 9088 864',
		},
		company: {
			address: {
				address: '20930 Todd Valley Road',
				city: 'Foresthill',
				coordinates: {
					lat: 38.989466,
					lng: -120.883108,
				},
				postalCode: '95631',
				state: 'CA',
			},
			department: 'Sales',
			name: 'Bogisich and Sons',
			title: 'Operator',
		},
		ein: '92-8837697',
		ssn: '795-36-7752',
		userAgent:
			'Mozilla/5.0 (Windows NT 5.2) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.813.0 Safari/535.1',
	},
	{
		id: 18,
		firstName: 'Arely',
		lastName: 'Skiles',
		maidenName: 'Monahan',
		age: 42,
		gender: 'male',
		email: '[email protected]',
		phone: '+55 886 766 8617',
		username: 'sberminghamh',
		password: 'cAjfb8vg',
		birthDate: '1958-02-05',
		image: 'https://robohash.org/nihilharumqui.png',
		bloodGroup: 'AB−',
		height: 192,
		weight: 97,
		eyeColor: 'Amber',
		hair: {
			color: 'Brown',
			type: 'Straight',
		},
		domain: 'seesaa.net',
		ip: '29.82.54.30',
		address: {
			address: '5461 West Shades Valley Drive',
			city: 'Montgomery',
			coordinates: {
				lat: 32.296422,
				lng: -86.34280299999999,
			},
			postalCode: '36108',
			state: 'AL',
		},
		macAddress: '61:0C:8F:92:48:D5',
		university: 'Universidade Estadual do Ceará',
		bank: {
			cardExpire: '09/24',
			cardNumber: '3578078357052002',
			cardType: 'jcb',
			currency: 'Real',
			iban: 'FR79 7925 2903 77HF 2ZY6 TU4M T84',
		},
		company: {
			address: {
				address: '3162 Martin Luther King Junior Boulevard',
				city: 'Fayetteville',
				coordinates: {
					lat: 36.05233310000001,
					lng: -94.2056987,
				},
				postalCode: '72704',
				state: 'AR',
			},
			department: 'Support',
			name: 'Metz Group',
			title: 'VP Accounting',
		},
		ein: '55-4062919',
		ssn: '551-74-1349',
		userAgent:
			'Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0',
	},
	{
		id: 19,
		firstName: 'Gust',
		lastName: 'Purdy',
		maidenName: 'Abshire',
		age: 46,
		gender: 'male',
		email: '[email protected]',
		phone: '+86 886 889 0258',
		username: 'bleveragei',
		password: 'UZGAiqPqWQHQ',
		birthDate: '1989-10-15',
		image: 'https://robohash.org/delenitipraesentiumvoluptatum.png',
		bloodGroup: 'A−',
		height: 167,
		weight: 65.3,
		eyeColor: 'Amber',
		hair: {
			color: 'Black',
			type: 'Straight',
		},
		domain: 'homestead.com',
		ip: '90.202.216.39',
		address: {
			address: '629 Debbie Drive',
			city: 'Nashville',
			coordinates: {
				lat: 36.208114,
				lng: -86.58621199999999,
			},
			postalCode: '37076',
			state: 'TN',
		},
		macAddress: '22:98:8D:97:2D:AE',
		university: 'Xinjiang University',
		bank: {
			cardExpire: '05/22',
			cardNumber: '5602214306858976',
			cardType: 'bankcard',
			currency: 'Yuan Renminbi',
			iban: 'GB94 MOIU 1274 8449 9733 05',
		},
		company: {
			address: {
				address: '6463 Vrain Street',
				city: 'Arvada',
				coordinates: {
					lat: 39.814056,
					lng: -105.046913,
				},
				postalCode: '80003',
				state: 'CO',
			},
			department: 'Sales',
			name: 'Bahringer, Auer and Wehner',
			title: 'Financial Analyst',
		},
		ein: '53-7190545',
		ssn: '809-93-2422',
		userAgent:
			'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.3 Safari/534.24',
	},
	{
		id: 20,
		firstName: 'Lenna',
		lastName: 'Renner',
		maidenName: 'Schumm',
		age: 41,
		gender: 'female',
		email: '[email protected]',
		phone: '+1 904 601 7177',
		username: 'aeatockj',
		password: 'szWAG6hc',
		birthDate: '1980-01-19',
		image: 'https://robohash.org/ipsumutofficiis.png',
		bloodGroup: 'O−',
		height: 175,
		weight: 68,
		eyeColor: 'Green',
		hair: {
			color: 'Black',
			type: 'Strands',
		},
		domain: 'sourceforge.net',
		ip: '59.43.194.22',
		address: {
			address: '22572 Toreador Drive',
			city: 'Salinas',
			coordinates: {
				lat: 36.602449,
				lng: -121.699071,
			},
			postalCode: '93908',
			state: 'CA',
		},
		macAddress: 'ED:64:AE:91:49:C9',
		university: 'Moraine Valley Community College',
		bank: {
			cardExpire: '07/22',
			cardNumber: '3565173055875732',
			cardType: 'jcb',
			currency: 'Dollar',
			iban: 'GT39 KL9Z CZYV XF26 UPYW SFPT H74U',
		},
		company: {
			address: {
				address: '491 Arabian Way',
				city: 'Grand Junction',
				coordinates: {
					lat: 39.07548999999999,
					lng: -108.474785,
				},
				postalCode: '81504',
				state: 'CO',
			},
			department: 'Support',
			name: 'Hoppe Group',
			title: 'Geologist III',
		},
		ein: '88-6715551',
		ssn: '389-03-0381',
		userAgent:
			'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.702.0 Chrome/12.0.702.0 Safari/534.24',
	},
	{
		id: 21,
		firstName: 'Doyle',
		lastName: 'Ernser',
		maidenName: 'Feeney',
		age: 23,
		gender: 'male',
		email: '[email protected]',
		phone: '+86 634 419 6839',
		username: 'ckensleyk',
		password: 'tq7kPXyf',
		birthDate: '1983-01-22',
		image: 'https://robohash.org/providenttemporadelectus.png',
		bloodGroup: 'A−',
		height: 173,
		weight: 69.9,
		eyeColor: 'Brown',
		hair: {
			color: 'Black',
			type: 'Curly',
		},
		domain: 'free.fr',
		ip: '87.213.156.73',
		address: {
			address: '3034 Mica Street',
			city: 'Fayetteville',
			coordinates: {
				lat: 36.0807929,
				lng: -94.2066449,
			},
			postalCode: '72704',
			state: 'AR',
		},
		macAddress: 'E2:5A:A5:85:9B:6D',
		university: 'Nanjing University of Traditional Chinese Medicine',
		bank: {
			cardExpire: '06/24',
			cardNumber: '30464640811198',
			cardType: 'diners-club-carte-blanche',
			currency: 'Yuan Renminbi',
			iban: 'BE41 7150 0766 2980',
		},
		company: {
			address: {
				address: '5906 Milton Avenue',
				city: 'Deale',
				coordinates: {
					lat: 38.784451,
					lng: -76.54125499999999,
				},
				postalCode: '20751',
				state: 'MD',
			},
			department: 'Product Management',
			name: 'Brekke Group',
			title: 'Programmer Analyst I',
		},
		ein: '23-4116115',
		ssn: '562-46-9709',
		userAgent:
			'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3',
	},
	{
		id: 22,
		firstName: 'Tressa',
		lastName: 'Weber',
		maidenName: 'Williamson',
		age: 41,
		gender: 'female',
		email: '[email protected]',
		phone: '+34 517 104 6248',
		username: 'froachel',
		password: 'rfVSKImC',
		birthDate: '1987-11-11',
		image: 'https://robohash.org/temporarecusandaeest.png',
		bloodGroup: 'B−',
		height: 164,
		weight: 87.1,
		eyeColor: 'Green',
		hair: {
			color: 'Black',
			type: 'Strands',
		},
		domain: 'indiatimes.com',
		ip: '71.57.235.192',
		address: {
			address: '3729 East Mission Boulevard',
			city: 'Fayetteville',
			coordinates: {
				lat: 36.0919353,
				lng: -94.10654219999999,
			},
			postalCode: '72703',
			state: 'AR',
		},
		macAddress: 'A4:8B:56:BC:ED:98',
		university: 'Universitat Rámon Llull',
		bank: {
			cardExpire: '12/21',
			cardNumber: '342220243660686',
			cardType: 'americanexpress',
			currency: 'Euro',
			iban: 'CY09 2675 2653 QNEJ JNSA 0E2V ONMM',
		},
		company: {
			address: {
				address: '8800 Cordell Circle',
				city: 'Anchorage',
				coordinates: {
					lat: 61.1409305,
					lng: -149.9437822,
				},
				postalCode: '99502',
				state: 'AK',
			},
			department: 'Research and Development',
			name: 'Durgan Group',
			title: 'VP Quality Control',
		},
		ein: '78-2846180',
		ssn: '155-87-0243',
		userAgent:
			'Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; de-de) AppleWebKit/533.16 (KHTML, like Gecko) Version/4.1 Safari/533.16',
	},
	{
		id: 23,
		firstName: 'Felicity',
		lastName: "O'Reilly",
		maidenName: 'Rosenbaum',
		age: 46,
		gender: 'female',
		email: '[email protected]',
		phone: '+63 919 564 1690',
		username: 'beykelhofm',
		password: 'zQwaHTHbuZyr',
		birthDate: '1967-10-05',
		image: 'https://robohash.org/odioquivero.png',
		bloodGroup: 'O−',
		height: 151,
		weight: 96.7,
		eyeColor: 'Brown',
		hair: {
			color: 'Brown',
			type: 'Curly',
		},
		domain: 'tamu.edu',
		ip: '141.14.53.176',
		address: {
			address: '5114 Greentree Drive',
			city: 'Nashville',
			coordinates: {
				lat: 36.0618539,
				lng: -86.738508,
			},
			postalCode: '37211',
			state: 'TN',
		},
		macAddress: '4D:AB:8D:9A:E5:02',
		university: 'University of lloilo',
		bank: {
			cardExpire: '06/22',
			cardNumber: '6333837222395642',
			cardType: 'switch',
			currency: 'Peso',
			iban: 'FR40 3929 7903 26S5 QL9A HUSV Z09',
		},
		company: {
			address: {
				address: '1770 Colony Way',
				city: 'Fayetteville',
				coordinates: {
					lat: 36.0867,
					lng: -94.229754,
				},
				postalCode: '72704',
				state: 'AR',
			},
			department: 'Legal',
			name: 'Romaguera, Williamson and Kessler',
			title: 'Assistant Manager',
		},
		ein: '92-4814248',
		ssn: '441-72-1229',
		userAgent:
			'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.872.0 Safari/535.2',
	},
	{
		id: 24,
		firstName: 'Jocelyn',
		lastName: 'Schuster',
		maidenName: 'Dooley',
		age: 19,
		gender: 'male',
		email: '[email protected]',
		phone: '+7 968 462 1292',
		username: 'brickeardn',
		password: 'bMQnPttV',
		birthDate: '1966-06-02',
		image: 'https://robohash.org/odiomolestiaealias.png',
		bloodGroup: 'O+',
		height: 166,
		weight: 93.3,
		eyeColor: 'Brown',
		hair: {
			color: 'Brown',
			type: 'Curly',
		},
		domain: 'pen.io',
		ip: '116.92.198.102',
		address: {
			address: '3466 Southview Avenue',
			city: 'Montgomery',
			coordinates: {
				lat: 32.341227,
				lng: -86.2846859,
			},
			postalCode: '36111',
			state: 'AL',
		},
		macAddress: 'AF:AA:20:8E:CA:CD',
		university: 'Bashkir State Medical University',
		bank: {
			cardExpire: '11/21',
			cardNumber: '5007666357943463',
			cardType: 'mastercard',
			currency: 'Ruble',
			iban: 'NL22 YBPM 0101 6695 08',
		},
		company: {
			address: {
				address: '80 North East Street',
				city: 'Holyoke',
				coordinates: {
					lat: 42.2041219,
					lng: -72.5977704,
				},
				postalCode: '01040',
				state: 'MA',
			},
			department: 'Product Management',
			name: 'Wintheiser-Boehm',
			title: 'Research Nurse',
		},
		ein: '77-6259466',
		ssn: '291-72-5526',
		userAgent:
			'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; ja-jp) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27',
	},
	{
		id: 25,
		firstName: 'Edwina',
		lastName: 'Ernser',
		maidenName: 'Kiehn',
		age: 21,
		gender: 'female',
		email: '[email protected]',
		phone: '+86 376 986 8945',
		username: 'dfundello',
		password: 'k9zgV68UKw8m',
		birthDate: '2000-09-28',
		image: 'https://robohash.org/doloremautdolores.png',
		bloodGroup: 'O+',
		height: 180,
		weight: 102.1,
		eyeColor: 'Blue',
		hair: {
			color: 'Brown',
			type: 'Wavy',
		},
		domain: 'apple.com',
		ip: '48.30.193.203',
		address: {
			address: '1513 Cathy Street',
			city: 'Savannah',
			coordinates: {
				lat: 32.067416,
				lng: -81.125331,
			},
			postalCode: '31415',
			state: 'GA',
		},
		macAddress: 'EC:59:D3:FC:65:92',
		university: 'Wuhan University of Technology',
		bank: {
			cardExpire: '10/23',
			cardNumber: '3558628665594956',
			cardType: 'jcb',
			currency: 'Yuan Renminbi',
			iban: 'RS85 6347 5884 2820 5764 23',
		},
		company: {
			address: {
				address: '125 John Street',
				city: 'Santa Cruz',
				coordinates: {
					lat: 36.950901,
					lng: -122.046881,
				},
				postalCode: '95060',
				state: 'CA',
			},
			department: 'Marketing',
			name: 'Volkman Group',
			title: 'Cost Accountant',
		},
		ein: '14-6307509',
		ssn: '266-43-5297',
		userAgent:
			'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3',
	},
	{
		id: 26,
		firstName: 'Griffin',
		lastName: 'Braun',
		maidenName: 'Deckow',
		age: 35,
		gender: 'male',
		email: '[email protected]',
		phone: '+62 511 790 0161',
		username: 'lgronaverp',
		password: '4a1dAKDv9KB9',
		birthDate: '1965-09-06',
		image: 'https://robohash.org/laboriosammollitiaut.png',
		bloodGroup: 'O−',
		height: 146,
		weight: 65.5,
		eyeColor: 'Blue',
		hair: {
			color: 'Blond',
			type: 'Wavy',
		},
		domain: 'foxnews.com',
		ip: '93.246.47.59',
		address: {
			address: '600 West 19th Avenue',
			city: 'Anchorage',
			coordinates: {
				lat: 61.203115,
				lng: -149.894107,
			},
			postalCode: '99503',
			state: 'AK',
		},
		macAddress: '34:06:26:95:37:D6',
		university: 'Universitas Bojonegoro',
		bank: {
			cardExpire: '07/24',
			cardNumber: '3587188969123346',
			cardType: 'jcb',
			currency: 'Rupiah',
			iban: 'AD24 9240 6903 OD2X OW1Y WD1K',
		},
		company: {
			address: {
				address: '1508 Massachusetts Avenue Southeast',
				city: 'Washington',
				coordinates: {
					lat: 38.887255,
					lng: -76.98318499999999,
				},
				postalCode: '20003',
				state: 'DC',
			},
			department: 'Engineering',
			name: 'Boyle, Boyer and Lang',
			title: 'Senior Cost Accountant',
		},
		ein: '38-0997138',
		ssn: '407-02-8915',
		userAgent:
			'Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25',
	},
	{
		id: 27,
		firstName: 'Piper',
		lastName: 'Schowalter',
		maidenName: 'Wuckert',
		age: 47,
		gender: 'female',
		email: '[email protected]',
		phone: '+60 785 960 7918',
		username: 'fokillq',
		password: 'xZnWSWnqH',
		birthDate: '1983-06-07',
		image: 'https://robohash.org/nequeodiosapiente.png',
		bloodGroup: 'A−',
		height: 197,
		weight: 71.5,
		eyeColor: 'Brown',
		hair: {
			color: 'Black',
			type: 'Curly',
		},
		domain: 'toplist.cz',
		ip: '100.159.51.104',
		address: {
			address: '1208 Elkader Court North',
			city: 'Nashville',
			coordinates: {
				lat: 36.080049,
				lng: -86.60116099999999,
			},
			postalCode: '37013',
			state: 'TN',
		},
		macAddress: '1F:42:5D:8C:66:3D',
		university: 'Sultanah Bahiyah Polytechnic',
		bank: {
			cardExpire: '09/22',
			cardNumber: '6762169351744592',
			cardType: 'maestro',
			currency: 'Ringgit',
			iban: 'BH05 STDW HECU HD4S L8U1 C6',
		},
		company: {
			address: {
				address: '600 West 19th Avenue',
				city: 'Anchorage',
				coordinates: {
					lat: 61.203115,
					lng: -149.894107,
				},
				postalCode: '99503',
				state: 'AK',
			},
			department: 'Human Resources',
			name: "O'Hara and Sons",
			title: 'Sales Representative',
		},
		ein: '11-3129153',
		ssn: '408-90-5986',
		userAgent:
			'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36',
	},
	{
		id: 28,
		firstName: 'Kody',
		lastName: 'Terry',
		maidenName: 'Larkin',
		age: 28,
		gender: 'male',
		email: '[email protected]',
		phone: '+81 859 545 8951',
		username: 'xisherwoodr',
		password: 'HLDqN5vCF',
		birthDate: '1979-01-09',
		image: 'https://robohash.org/consequunturabnon.png',
		bloodGroup: 'B−',
		height: 172,
		weight: 90.2,
		eyeColor: 'Blue',
		hair: {
			color: 'Brown',
			type: 'Wavy',
		},
		domain: 'elpais.com',
		ip: '51.102.180.216',
		address: {
			address: '210 Green Road',
			city: 'Manchester',
			coordinates: {
				lat: 41.7909099,
				lng: -72.51195129999999,
			},
			postalCode: '06042',
			state: 'CT',
		},
		macAddress: 'B4:B6:17:3C:41:E5',
		university: 'Science University of Tokyo',
		bank: {
			cardExpire: '05/23',
			cardNumber: '201443655632569',
			cardType: 'diners-club-enroute',
			currency: 'Yen',
			iban: 'GT70 4NNE RDSR 0AJV 6AQI 4XH1 RWOC',
		},
		company: {
			address: {
				address: '109 Summit Street',
				city: 'Burlington',
				coordinates: {
					lat: 44.4729749,
					lng: -73.2026566,
				},
				postalCode: '05401',
				state: 'VT',
			},
			department: 'Support',
			name: 'Leffler, Beatty and Kilback',
			title: 'Recruiting Manager',
		},
		ein: '09-1129306',
		ssn: '389-74-9456',
		userAgent:
			'Mozilla/6.0 (Macintosh; I; Intel Mac OS X 11_7_9; de-LI; rv:1.9b4) Gecko/2012010317 Firefox/10.0a4',
	},
	{
		id: 29,
		firstName: 'Macy',
		lastName: 'Greenfelder',
		maidenName: 'Koepp',
		age: 45,
		gender: 'female',
		email: '[email protected]',
		phone: '+81 915 649 2384',
		username: 'jissetts',
		password: 'ePawWgrnZR8L',
		birthDate: '1976-09-07',
		image: 'https://robohash.org/amettemporeea.png',
		bloodGroup: 'A−',
		height: 166,
		weight: 93.7,
		eyeColor: 'Amber',
		hair: {
			color: 'Black',
			type: 'Straight',
		},
		domain: 'ibm.com',
		ip: '197.37.13.163',
		address: {
			address: '49548 Road 200',
			city: "O'Neals",
			coordinates: {
				lat: 37.153463,
				lng: -119.648192,
			},
			postalCode: '93645',
			state: 'CA',
		},
		macAddress: 'D7:14:C5:45:69:C1',
		university: "Fuji Women's College",
		bank: {
			cardExpire: '04/24',
			cardNumber: '633413352570887921',
			cardType: 'solo',
			currency: 'Yen',
			iban: 'IS23 8410 4605 1294 9479 5900 11',
		},
		company: {
			address: {
				address: '5403 Illinois Avenue',
				city: 'Nashville',
				coordinates: {
					lat: 36.157077,
					lng: -86.853827,
				},
				postalCode: '37209',
				state: 'TN',
			},
			department: 'Product Management',
			name: 'Bruen and Sons',
			title: 'Structural Analysis Engineer',
		},
		ein: '31-6688179',
		ssn: '391-33-1550',
		userAgent:
			'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19',
	},
	{
		id: 30,
		firstName: 'Maurine',
		lastName: 'Stracke',
		maidenName: 'Abshire',
		age: 31,
		gender: 'female',
		email: '[email protected]',
		phone: '+48 143 590 6847',
		username: 'kdulyt',
		password: '5t6q4KC7O',
		birthDate: '1964-12-18',
		image: 'https://robohash.org/perferendisideveniet.png',
		bloodGroup: 'O−',
		height: 170,
		weight: 107.2,
		eyeColor: 'Blue',
		hair: {
			color: 'Blond',
			type: 'Wavy',
		},
		domain: 'ow.ly',
		ip: '97.11.116.84',
		address: {
			address: '81 Seaton Place Northwest',
			city: 'Washington',
			coordinates: {
				lat: 38.9149499,
				lng: -77.01170259999999,
			},
			postalCode: '20001',
			state: 'DC',
		},
		macAddress: '42:87:72:A1:4D:9A',
		university: 'Poznan School of Banking',
		bank: {
			cardExpire: '02/24',
			cardNumber: '6331108070510590026',
			cardType: 'switch',
			currency: 'Zloty',
			iban: 'MT70 MKRC 8244 59Z4 9UG1 1HY7 TKM6 1YX',
		},
		company: {
			address: {
				address: '816 West 19th Avenue',
				city: 'Anchorage',
				coordinates: {
					lat: 61.203221,
					lng: -149.898655,
				},
				postalCode: '99503',
				state: 'AK',
			},
			department: 'Support',
			name: 'Balistreri-Kshlerin',
			title: 'Quality Engineer',
		},
		ein: '51-7727524',
		ssn: '534-76-0952',
		userAgent:
			'Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11',
	},
];

const countryListAlpha2 = {
	AF: 'Afghanistan',
	AL: 'Albania',
	DZ: 'Algeria',
	AS: 'American Samoa',
	AD: 'Andorra',
	AO: 'Angola',
	AI: 'Anguilla',
	AQ: 'Antarctica',
	AG: 'Antigua and Barbuda',
	AR: 'Argentina',
	AM: 'Armenia',
	AW: 'Aruba',
	AU: 'Australia',
	AT: 'Austria',
	AZ: 'Azerbaijan',
	BS: 'Bahamas (the)',
	BH: 'Bahrain',
	BD: 'Bangladesh',
	BB: 'Barbados',
	BY: 'Belarus',
	BE: 'Belgium',
	BZ: 'Belize',
	BJ: 'Benin',
	BM: 'Bermuda',
	BT: 'Bhutan',
	BO: 'Bolivia (Plurinational State of)',
	BQ: 'Bonaire, Sint Eustatius and Saba',
	BA: 'Bosnia and Herzegovina',
	BW: 'Botswana',
	BV: 'Bouvet Island',
	BR: 'Brazil',
	IO: 'British Indian Ocean Territory (the)',
	BN: 'Brunei Darussalam',
	BG: 'Bulgaria',
	BF: 'Burkina Faso',
	BI: 'Burundi',
	CV: 'Cabo Verde',
	KH: 'Cambodia',
	CM: 'Cameroon',
	CA: 'Canada',
	KY: 'Cayman Islands (the)',
	CF: 'Central African Republic (the)',
	TD: 'Chad',
	CL: 'Chile',
	CN: 'China',
	CX: 'Christmas Island',
	CC: 'Cocos (Keeling) Islands (the)',
	CO: 'Colombia',
	KM: 'Comoros (the)',
	CD: 'Congo (the Democratic Republic of the)',
	CG: 'Congo (the)',
	CK: 'Cook Islands (the)',
	CR: 'Costa Rica',
	HR: 'Croatia',
	CU: 'Cuba',
	CW: 'Curaçao',
	CY: 'Cyprus',
	CZ: 'Czechia',
	CI: "Côte d'Ivoire",
	DK: 'Denmark',
	DJ: 'Djibouti',
	DM: 'Dominica',
	DO: 'Dominican Republic (the)',
	EC: 'Ecuador',
	EG: 'Egypt',
	SV: 'El Salvador',
	GQ: 'Equatorial Guinea',
	ER: 'Eritrea',
	EE: 'Estonia',
	SZ: 'Eswatini',
	ET: 'Ethiopia',
	FK: 'Falkland Islands (the) [Malvinas]',
	FO: 'Faroe Islands (the)',
	FJ: 'Fiji',
	FI: 'Finland',
	FR: 'France',
	GF: 'French Guiana',
	PF: 'French Polynesia',
	TF: 'French Southern Territories (the)',
	GA: 'Gabon',
	GM: 'Gambia (the)',
	GE: 'Georgia',
	DE: 'Germany',
	GH: 'Ghana',
	GI: 'Gibraltar',
	GR: 'Greece',
	GL: 'Greenland',
	GD: 'Grenada',
	GP: 'Guadeloupe',
	GU: 'Guam',
	GT: 'Guatemala',
	GG: 'Guernsey',
	GN: 'Guinea',
	GW: 'Guinea-Bissau',
	GY: 'Guyana',
	HT: 'Haiti',
	HM: 'Heard Island and McDonald Islands',
	VA: 'Holy See (the)',
	HN: 'Honduras',
	HK: 'Hong Kong',
	HU: 'Hungary',
	IS: 'Iceland',
	IN: 'India',
	ID: 'Indonesia',
	IR: 'Iran (Islamic Republic of)',
	IQ: 'Iraq',
	IE: 'Ireland',
	IM: 'Isle of Man',
	IL: 'Israel',
	IT: 'Italy',
	JM: 'Jamaica',
	JP: 'Japan',
	JE: 'Jersey',
	JO: 'Jordan',
	KZ: 'Kazakhstan',
	KE: 'Kenya',
	KI: 'Kiribati',
	KP: "Korea (the Democratic People's Republic of)",
	KR: 'Korea (the Republic of)',
	KW: 'Kuwait',
	KG: 'Kyrgyzstan',
	LA: "Lao People's Democratic Republic (the)",
	LV: 'Latvia',
	LB: 'Lebanon',
	LS: 'Lesotho',
	LR: 'Liberia',
	LY: 'Libya',
	LI: 'Liechtenstein',
	LT: 'Lithuania',
	LU: 'Luxembourg',
	MO: 'Macao',
	MG: 'Madagascar',
	MW: 'Malawi',
	MY: 'Malaysia',
	MV: 'Maldives',
	ML: 'Mali',
	MT: 'Malta',
	MH: 'Marshall Islands (the)',
	MQ: 'Martinique',
	MR: 'Mauritania',
	MU: 'Mauritius',
	YT: 'Mayotte',
	MX: 'Mexico',
	FM: 'Micronesia (Federated States of)',
	MD: 'Moldova (the Republic of)',
	MC: 'Monaco',
	MN: 'Mongolia',
	ME: 'Montenegro',
	MS: 'Montserrat',
	MA: 'Morocco',
	MZ: 'Mozambique',
	MM: 'Myanmar',
	NA: 'Namibia',
	NR: 'Nauru',
	NP: 'Nepal',
	NL: 'Netherlands (the)',
	NC: 'New Caledonia',
	NZ: 'New Zealand',
	NI: 'Nicaragua',
	NE: 'Niger (the)',
	NG: 'Nigeria',
	NU: 'Niue',
	NF: 'Norfolk Island',
	MP: 'Northern Mariana Islands (the)',
	NO: 'Norway',
	OM: 'Oman',
	PK: 'Pakistan',
	PW: 'Palau',
	PS: 'Palestine, State of',
	PA: 'Panama',
	PG: 'Papua New Guinea',
	PY: 'Paraguay',
	PE: 'Peru',
	PH: 'Philippines (the)',
	PN: 'Pitcairn',
	PL: 'Poland',
	PT: 'Portugal',
	PR: 'Puerto Rico',
	QA: 'Qatar',
	MK: 'Republic of North Macedonia',
	RO: 'Romania',
	RU: 'Russian Federation (the)',
	RW: 'Rwanda',
	RE: 'Réunion',
	BL: 'Saint Barthélemy',
	SH: 'Saint Helena, Ascension and Tristan da Cunha',
	KN: 'Saint Kitts and Nevis',
	LC: 'Saint Lucia',
	MF: 'Saint Martin (French part)',
	PM: 'Saint Pierre and Miquelon',
	VC: 'Saint Vincent and the Grenadines',
	WS: 'Samoa',
	SM: 'San Marino',
	ST: 'Sao Tome and Principe',
	SA: 'Saudi Arabia',
	SN: 'Senegal',
	RS: 'Serbia',
	SC: 'Seychelles',
	SL: 'Sierra Leone',
	SG: 'Singapore',
	SX: 'Sint Maarten (Dutch part)',
	SK: 'Slovakia',
	SI: 'Slovenia',
	SB: 'Solomon Islands',
	SO: 'Somalia',
	ZA: 'South Africa',
	GS: 'South Georgia and the South Sandwich Islands',
	SS: 'South Sudan',
	ES: 'Spain',
	LK: 'Sri Lanka',
	SD: 'Sudan (the)',
	SR: 'Suriname',
	SJ: 'Svalbard and Jan Mayen',
	SE: 'Sweden',
	CH: 'Switzerland',
	SY: 'Syrian Arab Republic',
	TW: 'Taiwan',
	TJ: 'Tajikistan',
	TZ: 'Tanzania, United Republic of',
	TH: 'Thailand',
	TL: 'Timor-Leste',
	TG: 'Togo',
	TK: 'Tokelau',
	TO: 'Tonga',
	TT: 'Trinidad and Tobago',
	TN: 'Tunisia',
	TR: 'Turkey',
	TM: 'Turkmenistan',
	TC: 'Turks and Caicos Islands (the)',
	TV: 'Tuvalu',
	UG: 'Uganda',
	UA: 'Ukraine',
	AE: 'United Arab Emirates (the)',
	GB: 'United Kingdom of Great Britain and Northern Ireland (the)',
	UM: 'United States Minor Outlying Islands (the)',
	US: 'United States of America (the)',
	UY: 'Uruguay',
	UZ: 'Uzbekistan',
	VU: 'Vanuatu',
	VE: 'Venezuela (Bolivarian Republic of)',
	VN: 'Viet Nam',
	VG: 'Virgin Islands (British)',
	VI: 'Virgin Islands (U.S.)',
	WF: 'Wallis and Futuna',
	EH: 'Western Sahara',
	YE: 'Yemen',
	ZM: 'Zambia',
	ZW: 'Zimbabwe',
	AX: 'Åland Islands',
};

// function (productsArr) -> [] -> map

// function filterProductsByPrice(priceParam, amount)
// filterProductsByPrice("<", 2000) -> []

// function filter(propName, propValue)
// filter("brand", "apple", "<")

// function listCountriesByContinent("Asia") ->
// function findCountry("AZ")

// findUser(propsName, propVal) -> {} | null
// filterUsers(propsName, propVal) -> []

// filterUsers("city", "DC")
// OUTPUT:
// .....

Project

Project

  1. Generate some boilerplate for a basic React application.
    • Go into your workspace/projects directory using the terminal.
    • cd ~/Documents/FullStack/Workspace
    • mkdir rststore
    • npx create-react-app@latest frontend –use-npm
    • code .
    • cd frontend
    • npm start
    • Open public/index.html and clean up the file. Remove all the comments and change the title and meta content.
    • Delete all the files in the src folder. Create and add basic boilerplate code to App.js and index.js.

2. Chakra UI Installation and Setup

  • npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
  • npm install react-icons –save
  • Edit index.js file. Import ChakraProvider component and wrap the App component with it.

3. Create Header and Footer components

  • Create a folder called src/components in the src folder and add all components in that.

4. Create HomeScreen product listings

  • Create the HomeScreen component (all display/screen components will go in the /screens folder), along with the product and ratings components.

5. Install and Implement React Router

  • npm install react-router-dom
  • Complete all the React Router setup on the App page.
  • Modify Product cards, Header links etc. Use React Routers Link component instead.

6. Design and build the ProductScreen component.

  1. Setting up the backend
    • Close the React server.
    • Create a folder named backend outside the frontend folder in the root of our project.
    • npm init in the root. (not inside the backend or frontend folders, but outside in the root directory)
    • During npm init setup the main will be server.js
    • npm install express (in the root folder)
    • Create a file backend/server.js in the backend folder and a folder data and copy products.js to this folder.
    • Create some routes to serve the data from the backend
    • Create a script for start in package.json
    • Create 2 basic routes for ‘/’ and ‘/api/products’
    • Convert products.js export statement to commonjs format.
    • Create another route to fetch single product by id.
  1. Fetching data from our backend using React
    • Inside the frontend folder, run npm install axios
    • Modify the HomeScreen component to fetch and store data in the component.
    • To fix the issue of our backend address for now, we’ll add a proxy to the frontend’s package.json. Add this “proxy”: “http://127.0.0.1:5000”, to frontend/package.json
    • Make sure both frontend and backend are running in two terminals and test it out.
    • Modify the ProductScreen component to also make a request to our backend to fetch data.
    • Delete the projects.js file from our frontend’s src folder as we no longer need it.

9. More backend setup

  • In the root directory: run
  • npm install -D nodemon concurrently. ‘-D’ is a dev dependency, meaning we only need these modules during development.
  • These above packages will help us auto restart our server when we change our code, so we don’t have to do it manually.
  • Modify scripts in package.json (root folder) to add some scripts to use our npm command directly to work them.

10. Setup environment variables

  • npm install dotenv
  • Do the dotenv setup in server.js file and create a .env file in the root folder.

11. Convert imports to ES Modules

  • Add “type”: “module” to package.json file. Change all import and export statements to ES module style.
  • Note: You will have to add .js extension while using ES modules in the backend.

12. Install and setup MongoDB

  • After installation, setup MongoDB Compass
  • Use this as the connection string: mongodb://localhost:27017/rststore
  • Add the following in the .env
    MONGO_URI = mongodb://localhost:27017/rststore

13. Connect to the database

  • Install mongoose: npm install mongoose (in the root folder)
  • Create a folder named config in the backend folder and create a file named backend/config/db.js inside it.
  • Do all the mongoDB connection setup
  • Import db.js into server.js and run the connectDB function.
  • Start the server and check if any error.

14. Improve console log messages.

  • Run this command in the root folder: npm install colors
  • Add stylings to server and db console messages.

15. Create database models for data

  • Create a models folder inside the backend folder.
  • Create all our data model schemas.

16. Prepare sample data for the backend data seeding

  • Delete all the _id key-values from the products.js as MongoDB
    will automatically create it for us.
  • Create data/users.js file and fill it with a few user objects.
  • npm install bcryptjs – for password hashing
  • Use bcryptjs for the password fields to encrypt the password. (temporary)

17. Create database seeder for quick sample data generation (optional)

  • Create backend/seeder.js file inside the backend folder.
  • Add seeding logic and create import and destroy scripts.

18. Fetching products from the database

  • Create a folder named backend/routes in the backend folder.
  • Create a file named backend/routes/productRoutes.js
  • npm install express-async-handler – we will wrap our callbacks with this function so that we can do error handler in a better way.
  • Move the products and single product fetch routes to this file and add all the logic for now.
  • Test the routes in Postman

19. Do Postman setup to work with our API (optional)Custom error handling. Run the following in the root folder.

20. Custom error handling. Run the following in the root folder.

  • npm install express-async-handler
  • Create a folder named backend/middleware in the backend folder
  • Create an errorMiddleware.js and add logic to handle errors.

21. Introduction to Redux

  • The Redux Pattern
  • Download the Redux DevTools brower extension.
  • Go to the frontend folder. cd frontend
  • npm install redux react-redux redux-thunk redux-devtools-extension
  • In the src folder, create a file named store.js
  • Import Provider and store into the index.js and do all the setup.

22. Create our first reducer

  • In frontend/src create a folder called reducers – (frontend/src/reducers).
  • Create a file (our reducer) named productReducer.js inside the reducers folder and add all the reducer logic.
  • Next, import productListReducer to store.js and add it to the combineReducers({}) function’s argument object as a new key/value.
  • Create a folder called constants in the frontend/src folder and inside it create the productConstants.js file to store all our action names.
  • Create a folder called actions in the frontend/src folder and inside it create the productActions.js file to store all our action functions. We will dispatch actions to our reducer.
  • All these steps, we do for each resource of our app. So, whether it’s products, or users or some other model/feature, this is the format/pattern we will follow for Redux. We create the constant, the reducer the action and then we fire it off in the component.
  • Next, we now want to fire this action off in our HomeScreen components where we need this products data.

  1. Getting Redux State in the Home Screen
    • Clean up the file. Remove axios import, the [products, setProducts] state variables and remove everything from inside useEffect. We don’t need these anymore.
    • Import useDispatch and useSelector from ‘react-redux’. Also import listProducts from ‘../actions/productActions’.
    • The first hook will be used to dispatch/call an action, and the other is use to select parts of the state. Here we will need the productList part of the state.
    • Create the dispatch object using the useDispatch hook and call it in useEffect to fire the listProducts action.
    • To select products from our state, we need to use the useSelector hook. This hook will take in an arrow function. This function gets state and then we can select which part of the state do we want.
    • Add a conditional to display a loading messageerror message or our product list.

24. Create Message and Loader components.

  • Use the Spinner and Alert components from ChakraUI to add these.

25. Single product details screen Reducer and Action

  • Again, we will follow the same pattern/steps as earlier.
  • Start off by adding the required constants. Since this is for the single product screen, we will add the constants once again to the productConstants.js
  • Create a new reducer named productDetailsReducer in productReducers.js.
  • Whenever we create a new reducer, we have to add it to our store. So, import productDetailsReducer in the store.js file and add a new piece of state named productDetails.
  • Next, step will be to create an action. Add a new action named listProductDetails to the actions file.
  • Next, in the ProductScreen.js, get rid of axios and clean up useEffect. Import useDispatchuseSelector and the listProductDetails action that we just created.
  • Create the dispatch object and dispatch the listProductDetails action in the useEffect hook. You will now be able to see the state in Redux Devtools.
  • Use useSelector hook and select the productDetails piece of state. De-structure the correct values and use them in the JSX to display the product details, error and loading components.

26. Cart and Quantity

  • Add a quantity select box with it’s logic to only contain the number of items in stock.
  • The add to cart button should redirect to the a cart page/screen with the product id and quantity as a query string.

27. Cart Screen and Route

  • Create screens/CartScreen.js file in the screens folder.
  • Import this new CartScreen.js component in the App.js file and create a route for the Cart screen<Route path=’/cart/:id?’ component={CartScreen} />
  • The :id? question mark here means that this id is optional in the route/address. Because if we directly go to the cart page we will not have any id.

28. Cart Functionality

  • Create constants/cartConstants.js and add CART_ADD_ITEM and CART_REMOVE_ITEM constant varaibles to it.
  • Create reducers/cartReducer.js and add the reducer logic.
  • Import cartReducer.js in store.js and add the cartReducer function to the combineReducers argument object.
  • Create actions/cartActions.js. Do the below steps for the building the cart actions.
  • Import axios. We need axios to make a request to /api/products/:id to get the data/fields for that particular product.
  • Import CART_ADD_ITEM from actions/cartActions.js.
  • Then create the addToCart function which will get a (id, qty). We will get both these from the URL params.
  • We will need to use thunk as we are making an async request. So we will return an async function from it. This async function will get (dispatch, getState)dispatch is used for dispatching as usual, but getState will allow us to get our entire state tree. So anything we want like productListproductDetailscart, we can get it using getState.
  • After dispatching, we also want to store this in localStorage.
  • getState().cart.cartItems will give us back a JavaScript object and we can only store strings in the browser localStorage. Hence we have to stringify it. And when we want to take it out and read, we will have to parse it using JSON.parse
  • So we saved it to localStorage but where do we get it to actually fill the state, whenever we reload. We do that in the store.js.
  • We will first see if there is anything in cartItems in the localStorage. If it’s there, then we will add it to the initial state, so always loaded on the app’s first load. If nothing is present in the localStorage then we will just add an empty array.

29. Completing CartScreen.js and creating ‘add to cart’ functionality

  • Build the add to cart functionality.
  • Finish the CartScreen.js component.
  • Add functionality to the Remove Item from cart button. Follow the steps below:
  • Add CART_REMOVE_ITEM to the cartReducer.js file.
  • Create an action named removeFromCart in the cartActions.js file.
  • Fire this action in the removeFromCartHandler function in the CartScreen component.

Project

  1. Generate some boilerplate for a basic React application.
    • Go into your workspace/projects directory using the terminal.
    • cd ~/Documents/FullStack/Workspace
    • mkdir rststore
    • npx create-react-app@latest frontend –use-npm
    • code .
    • cd frontend
    • npm start
    • Open public/index.html and clean up the file. Remove all the comments and change the title and meta content.
    • Delete all the files in the src folder. Create and add basic boilerplate code to App.js and index.js.

2. Chakra UI Installation and Setup

  • npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
  • npm install react-icons –save
  • Edit index.js file. Import ChakraProvider component and wrap the App component with it.

Project

  1. Generate some boilerplate for a basic React application.
    • Go into your workspace/projects directory using the terminal.
    • cd ~/Documents/FullStack/Workspace
    • mkdir rststore
    • npx create-react-app@latest frontend –use-npm
    • code .
    • cd frontend
    • npm start
    • Open public/index.html and clean up the file. Remove all the comments and change the title and meta content.
    • Delete all the files in the src folder. Create and add basic boilerplate code to App.js and index.js.

2. Chakra UI Installation and Setup

  • npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
  • npm install react-icons –save
  • Edit index.js file. Import ChakraProvider component and wrap the App component with it.

3. Create Header and Footer components

  • Create a folder called src/components in the src folder and add all components in that.

4. Create HomeScreen product listings

  • Create the HomeScreen component (all display/screen components will go in the /screens folder), along with the product and ratings components.

5. Install and Implement React Router

  • npm install react-router-dom
  • Complete all the React Router setup on the App page.
  • Modify Product cards, Header links etc. Use React Routers Link component instead.

6. Design and build the ProductScreen component.

  1. Setting up the backend
    • Close the React server.
    • Create a folder named backend outside the frontend folder in the root of our project.
    • npm init in the root. (not inside the backend or frontend folders, but outside in the root directory)
    • During npm init setup the main will be server.js
    • npm install express (in the root folder)
    • Create a file backend/server.js in the backend folder and a folder data and copy products.js to this folder.
    • Create some routes to serve the data from the backend
    • Create a script for start in package.json
    • Create 2 basic routes for ‘/’ and ‘/api/products’
    • Convert products.js export statement to commonjs format.
    • Create another route to fetch single product by id.
  1. Fetching data from our backend using React
    • Inside the frontend folder, run npm install axios
    • Modify the HomeScreen component to fetch and store data in the component.
    • To fix the issue of our backend address for now, we’ll add a proxy to the frontend’s package.json. Add this “proxy”: “http://127.0.0.1:5000”, to frontend/package.json
    • Make sure both frontend and backend are running in two terminals and test it out.
    • Modify the ProductScreen component to also make a request to our backend to fetch data.
    • Delete the projects.js file from our frontend’s src folder as we no longer need it.

9. More backend setup

  • In the root directory: run
  • npm install -D nodemon concurrently. ‘-D’ is a dev dependency, meaning we only need these modules during development.
  • These above packages will help us auto restart our server when we change our code, so we don’t have to do it manually.
  • Modify scripts in package.json (root folder) to add some scripts to use our npm command directly to work them.

10. Setup environment variables

  • npm install dotenv
  • Do the dotenv setup in server.js file and create a .env file in the root folder.

11. Convert imports to ES Modules

  • Add “type”: “module” to package.json file. Change all import and export statements to ES module style.
  • Note: You will have to add .js extension while using ES modules in the backend.

12. Install and setup MongoDB

  • After installation, setup MongoDB Compass
  • Use this as the connection string: mongodb://localhost:27017/rststore
  • Add the following in the .env
    MONGO_URI = mongodb://localhost:27017/rststore

13. Connect to the database

  • Install mongoose: npm install mongoose (in the root folder)
  • Create a folder named config in the backend folder and create a file named backend/config/db.js inside it.
  • Do all the mongoDB connection setup
  • Import db.js into server.js and run the connectDB function.
  • Start the server and check if any error.

14. Improve console log messages.

  • Run this command in the root folder: npm install colors
  • Add stylings to server and db console messages.

15. Create database models for data

  • Create a models folder inside the backend folder.
  • Create all our data model schemas.

16. Prepare sample data for the backend data seeding

  • Delete all the _id key-values from the products.js as MongoDB
    will automatically create it for us.
  • Create data/users.js file and fill it with a few user objects.
  • npm install bcryptjs – for password hashing
  • Use bcryptjs for the password fields to encrypt the password. (temporary)

17. Create database seeder for quick sample data generation (optional)

  • Create backend/seeder.js file inside the backend folder.
  • Add seeding logic and create import and destroy scripts.

18. Fetching products from the database

  • Create a folder named backend/routes in the backend folder.
  • Create a file named backend/routes/productRoutes.js
  • npm install express-async-handler – we will wrap our callbacks with this function so that we can do error handler in a better way.
  • Move the products and single product fetch routes to this file and add all the logic for now.
  • Test the routes in Postman

19. Do Postman setup to work with our API (optional)Custom error handling. Run the following in the root folder.

20. Custom error handling. Run the following in the root folder.

  • npm install express-async-handler
  • Create a folder named backend/middleware in the backend folder
  • Create an errorMiddleware.js and add logic to handle errors.

21. Introduction to Redux

  • The Redux Pattern
  • Download the Redux DevTools brower extension.
  • Go to the frontend folder. cd frontend
  • npm install redux react-redux redux-thunk redux-devtools-extension
  • In the src folder, create a file named store.js
  • Import Provider and store into the index.js and do all the setup.

22. Create our first reducer

  • In frontend/src create a folder called reducers – (frontend/src/reducers).
  • Create a file (our reducer) named productReducer.js inside the reducers folder and add all the reducer logic.
  • Next, import productListReducer to store.js and add it to the combineReducers({}) function’s argument object as a new key/value.
  • Create a folder called constants in the frontend/src folder and inside it create the productConstants.js file to store all our action names.
  • Create a folder called actions in the frontend/src folder and inside it create the productActions.js file to store all our action functions. We will dispatch actions to our reducer.
  • All these steps, we do for each resource of our app. So, whether it’s products, or users or some other model/feature, this is the format/pattern we will follow for Redux. We create the constant, the reducer the action and then we fire it off in the component.
  • Next, we now want to fire this action off in our HomeScreen components where we need this products data.

  1. Getting Redux State in the Home Screen
    • Clean up the file. Remove axios import, the [products, setProducts] state variables and remove everything from inside useEffect. We don’t need these anymore.
    • Import useDispatch and useSelector from ‘react-redux’. Also import listProducts from ‘../actions/productActions’.
    • The first hook will be used to dispatch/call an action, and the other is use to select parts of the state. Here we will need the productList part of the state.
    • Create the dispatch object using the useDispatch hook and call it in useEffect to fire the listProducts action.
    • To select products from our state, we need to use the useSelector hook. This hook will take in an arrow function. This function gets state and then we can select which part of the state do we want.
    • Add a conditional to display a loading messageerror message or our product list.

24. Create Message and Loader components.

  • Use the Spinner and Alert components from ChakraUI to add these.

25. Single product details screen Reducer and Action

  • Again, we will follow the same pattern/steps as earlier.
  • Start off by adding the required constants. Since this is for the single product screen, we will add the constants once again to the productConstants.js
  • Create a new reducer named productDetailsReducer in productReducers.js.
  • Whenever we create a new reducer, we have to add it to our store. So, import productDetailsReducer in the store.js file and add a new piece of state named productDetails.
  • Next, step will be to create an action. Add a new action named listProductDetails to the actions file.
  • Next, in the ProductScreen.js, get rid of axios and clean up useEffect. Import useDispatchuseSelector and the listProductDetails action that we just created.
  • Create the dispatch object and dispatch the listProductDetails action in the useEffect hook. You will now be able to see the state in Redux Devtools.
  • Use useSelector hook and select the productDetails piece of state. De-structure the correct values and use them in the JSX to display the product details, error and loading components.

26. Cart and Quantity

  • Add a quantity select box with it’s logic to only contain the number of items in stock.
  • The add to cart button should redirect to the a cart page/screen with the product id and quantity as a query string.

27. Cart Screen and Route

  • Create screens/CartScreen.js file in the screens folder.
  • Import this new CartScreen.js component in the App.js file and create a route for the Cart screen<Route path=’/cart/:id?’ component={CartScreen} />
  • The :id? question mark here means that this id is optional in the route/address. Because if we directly go to the cart page we will not have any id.

28. Cart Functionality

  • Create constants/cartConstants.js and add CART_ADD_ITEM and CART_REMOVE_ITEM constant varaibles to it.
  • Create reducers/cartReducer.js and add the reducer logic.
  • Import cartReducer.js in store.js and add the cartReducer function to the combineReducers argument object.
  • Create actions/cartActions.js. Do the below steps for the building the cart actions.
  • Import axios. We need axios to make a request to /api/products/:id to get the data/fields for that particular product.
  • Import CART_ADD_ITEM from actions/cartActions.js.
  • Then create the addToCart function which will get a (id, qty). We will get both these from the URL params.
  • We will need to use thunk as we are making an async request. So we will return an async function from it. This async function will get (dispatch, getState)dispatch is used for dispatching as usual, but getState will allow us to get our entire state tree. So anything we want like productListproductDetailscart, we can get it using getState.
  • After dispatching, we also want to store this in localStorage.
  • getState().cart.cartItems will give us back a JavaScript object and we can only store strings in the browser localStorage. Hence we have to stringify it. And when we want to take it out and read, we will have to parse it using JSON.parse
  • So we saved it to localStorage but where do we get it to actually fill the state, whenever we reload. We do that in the store.js.
  • We will first see if there is anything in cartItems in the localStorage. If it’s there, then we will add it to the initial state, so always loaded on the app’s first load. If nothing is present in the localStorage then we will just add an empty array.

29. Completing CartScreen.js and creating ‘add to cart’ functionality

  • Build the add to cart functionality.
  • Finish the CartScreen.js component.
  • Add functionality to the Remove Item from cart button. Follow the steps below:
  • Add CART_REMOVE_ITEM to the cartReducer.js file.
  • Create an action named removeFromCart in the cartActions.js file.
  • Fire this action in the removeFromCartHandler function in the CartScreen component.

30. Clean up the backend routes by extracting their logic into controllers

  • In the backend folder, create a folder called controller and create a file called productController.js inside it.
  • Extract all the logic to the productController.js from the routes file. The routes file should now only be for routing and all logic will go in to the controllers.
  • In productRoutes.js instead of using the method router.use(), instead use router.route() and add the route inside and then chain the appropriate methods get, post, put, delete etc. to it. This way we can define different controller logic to the same route. We will see this in sometime.

31. User Authentication Endpoints (Backend Routes)

  • Create routes/userRoutes.js and controllers/userController.js.
  • Start by working on an auth route. So here we want to authenticate a user by email and password. And then we want to send back some data, a token which we can save on the client (browser), so in the frontend (browser) we can use that token to access protected pages/routes (react frontend routes).
  • Import the ../models/userModel.js as we will need it to create new users in the MongoDB database.
  • Create authUser controller function. Inside it, first thing is to get data from the body. This data is on the request object and is something that will be sent here (to the backend) by a POST request and is usually sent via a form on the frontend pages. We can also mimic this sending data using Postman.
  • Before getting the data, make a new folder in rststore Postman collection.. Add a folder called Users & Auth. Inside that create a new request. Name it POST /api/users/login with the url to {{URL}}/api/users/login and add an email & password object to Body of type JSON.
  • Now this object that we add to the body tab in Postman, what will be sent in an object (key-value) on the request object. We extract that from request.body.
  • But in order for parsing this JSON data that we get on the request object from the frontend/Postman, we need to add another middleware in server.js.
  • Add the following line after const app = express part. app.use(express.json())
  • Create the authUser controller function. Also import this into userRoutes.js and add a login route.
  • Also import userRoutes in server.js and add the routes for users..
  • app.use(‘/api/users’, userRoutes)
  • Use the findOne() method on the User model to get the user’s object from the database.
  • Password needs to be encrypted before checking as we are storing encrypted passwords in the database, so add a method on the User Model itself. Edit models/userModel.js and add a method on the userSchema – userSchema.methods.matchPassword.
  • Use this new method in userController.js and finished the implementation.
  • Don’t return the token for now. Just set it to null. Return all other details leaving the password as a json object and also add an else condition.
  • Test this new endpoint in POSTMAN. (start only the server for now)

32. Using Json Web Tokens (JWT)

  • What are JWTs and how do they work?
  • Installation: npm install jsonwebtoken
  • Create a folder called backend/utils. Put all helpers and utility functions here. Inside it create a file named generateToken.js and create the token generation function. Also add the JWT_SECRET to the env as this is needed for the token generation.
  • Import generateToken.js into userController.js and use the function in the response object’s token property (key).
  • Test in Postman. Add this request to Postman.

33. Creating custom Authentication Middleware to accessprotected routes.

  • Add a new request in Postman. GET /api/users/profile with request URL {{URL}}/api/users/profile.
  • Add getUserProfile controller method to userController.js and also export it. Also add the route for this in userRoutes.js.
  • Create a new file named middleware/authMiddleware.js. This middleware will validate the token.
  • Implement the protect middleware function. In our backend we will be getting the authorization tokens in the header object in requests (we will send it that way from React).
  • Import protect into routes/userRoutes.js. We need to add our middleware function here to the /profile endpoint.
  • Implement the complete of the protect middleware function.
  • Once done, we can now use this middleware to any endpoint (route) that we want to be protected, that is only accessible using a valid JWT.
  • Finish implementation of the getUserProfile controller function in userController.js
  • Save the token in Postman, so we don’t have to keep copying and pasting tokens to the Headers. Add Tests to login request so that the token can be set in an environment variable. After that set profile request Auth Type to Bearer Token.

34. User registration

  • Add a new request to Postman: POST /api/users with url as {{URL}}/api/users. This will be a POST request. So a GET request to the same endpoint will give us a total list of users, while a POST request will create a new user.
  • Add a new registerUser controller function to the userController.js file. After that, import this function to userRoutes.js and create a new register route.
  • #### Password Encryption ####
  • The password still isn’t encrypted as we sent it directly to the User.create() function. So to encrypt password while creating a new user and adding it to the database, create a new mongoose middleware.
  • In mongoose, we can set certain things to happen on saves or finds etc. So when we execute the User.create function, before saving to database, we can run some code to encrypt the password and then save.
  • Test the new endpoint in Postman.

35. User Login Reducer and Action

  • Add all constants for the login. Create the file constants/userConstants.js and add all the constants.
  • Create the reducers/userReducer.js file and add the userLoginReducer function. Add all the necessary actions and logic.
  • Import userLoginReducer to store.js and add it to the combineReducers function’s parameter object.
  • Create the actions file in actions/userActions.js and add the action logic. This is pretty much the same as the earlier actions. Only difference here is that we have to add some headers to the axios request, and also store the user data to localStorage.
  • Lastly, since we stored the user data in localStorage, we should load them in the initial state in store.js. Create a variable named userInfoFromStorage and set it to get it’s value from localStorage. In the initialState variable, add another key named userLogin and set it’s value to userInfouserLogin: { userInfo: userInfoFromStorage }

36. User Login Screen

  • Create a new component called components/FormContainer.js which will just be a simple wrapper for our form elements. Just a box with some styling, which we will use to add all our forms in.
  • Create a new screen in screens/LoginScreen.js and write the ui and logic.
  • Import it in App.js and create a route for it.
  • (styling changes overall if required)

37. Implement all the Login – Redux functionality in the LoginScreen component.

38. Header modification to show User and User Logout feature

  • Modify Header.js. Import redux modules, for running the LOGOUT action and getting access to the state.
    import {useDispatch, useSelector} from ‘react-redux’
  • Import Menu, MenuButton, MenuList, MenuItem from Chakra.
  • Get the userInfo state using useSelector.
  • Also import import { IoChevronDown } from ‘react-icons/io5’
  • Create a logout action in userActions.js.
  • Implement all the logic.

39. User Register, Constants, Reducer, Action and Screen.

  • Add new REGISTER constants to the userConstants.js
  • Create userRegisterReducer in the userReducers.js
  • Import this reducer in store.js and add it to combineReducers
  • Create register action in userActions.js
  • Create the RegisterScreen component and add it to the App.js router.

40. Update User Profile endpoint in the backend

  • Create a updateUserProfile controller method and export it.
  • Import updateUserProfile in userRoutes.js and add a PUT request on the same /profile route. This route will also take the middleware protect as this is a protected endpoint.

41. User Profile Screen and Getting User Details

  • Add USER DETAILS constants to the userConstants.js file.
  • Create userDetailsReducer in userReducer.js and import and add it to the Store.
  • Create and add a getUserDetails action in userActions.js
  • Create the ProfileScreen and add it to Router in App.js

42. Add Update User Profile functionality

  • Add new UPDATE PROFILE constants to the userConstants.js
  • Create userUpdateProfileReducer in the userReducers.js
  • Import this reducer in store.js and add it to combineReducers
  • Create updateUserProfile action in userActions.js\

42. Add Update User Profile functionality

  • Add new UPDATE PROFILE constants to the userConstants.js
  • Create userUpdateProfileReducer in the userReducers.js
  • Import this reducer in store.js and add it to combineReducers
  • Create updateUserProfile action in userActions.js

43. Shipping Screen and Save Address

  • Create a new component/screen in screen/ShippingScreen.js and add it to the Router in App.js
  • Complete the ShippingScreen component. Create all the local state required and build the shipping form.
  • In the submitHandler we want to dispatch an action that will save the shipping address to the Redux store.
  • Create a new constant named CART_SAVE_SHIPPING_ADDRESS in the constants/cartConstants.js file.
  • Create a new action named saveShippingAddress in the actions/cartActions.js file.
  • Create a new case CART_SAVE_SHIPPING_ADDRESS in the reducers/cartReducers.js file. Also in the cartReducer function’s initial state object, add another key named shippingAddress and set it to an empty object.
  • Since we are going to store the shippingAddress to localStorage, we also should check if it’s already present in the user’s machine and load it if present. Add the code to the store.js file.
  • Add all Redux related functionality to the ShippingScreen component and finish the implementation.

44. Checkout Steps Component

  • Create he component and then add it to the ShippingScreen component.

45. PaymentScreen – where users can choose the payment method

  • Create the PaymentScreen component in the screens folder.
  • Add CART_SAVE_PAYMENT_METHOD to the cartConstants.js file.
  • Create the savePaymentMethod action function in actions/cartActions.js file.
  • Create a new case CART_SAVE_PAYMENT_METHOD in the reducers/cartReducer.js
  • Import and add PaymentScreen to App.js router.

46. Place Order Screen

  • We will just create a basic screen/page for now. We will do all the real setup only once we have created a backend to actually accept an order.
  • Create a new screen named PlaceOrderScreen.js in the screen folder.
  • Complete the PlaceOrderScreen implementation for now. We will complete this fully when we are done with our order functionality in the backend.
  • Also calculate and set cart.itemsPrice, cart.shippingPrice, cart.taxPrice, cart.totalPrice

47. Backend: Order controller and endpoint (route)

  • Create controllers/orderController.js.
  • Create routes/orderRoutes.js. Import the orderController and connect it here to a endpoint.
  • Lastly add the main endpoint (route) to server.js

48. Create Order

  • Create an constants/orderConstants.js file and add all the constants.
  • Create a new reducer file in reducers/orderReducers.js and add a orderCreateReducer function in it. Import this in store.js and add it to combineReducers.
  • Create a new actions file in actions/orderActions.js and add a createOrder action function.
  • Import createOrder action into the PlaceOrderScreen component and complete the implementation.

49. Get Order By ID (Backend Endpoint)

  • Create the getORderById controller function in the orderController.js file.
  • Add ‘/:id’ route to the orderRoute.js file and attached it to the getOrderbyID controller function.

50. Create the order details reducer and action (frontend)

  • Add new order details related constants in the orderConstants.js file.
  • Create orderDetailsReducer to the orderReducer.js file and connect it in the store.js file.
  • Create a new getOrderDetails function in the orderActions.js file.

51. Create the Order Screen component

  • Create the OrderScreen.js file in screens.
  • Add this new screen to the App.js route.

52. Backend endpoint for updating an order to paid

  • Create a new updateOrderToPaid controller function in the backend/controllers/orderController.js file.
  • Import updateOrderToPaid in the routes/orderRoutes.js and add a route for the endpoint ‘/:id/pay’ making it a PUT request.

53. Order pay reducer and action

  • Add new ORDER_PAY_ constants to the constants/orderConstants.js file in the frontend.
  • Create a new reducer function orderPayReducer in the reducers/orderReducers.js. Import this in store.js and add it to the combineReducers function.
  • Create a new action named payOrder in the actions/orderAction.js file.

54. Adding PayPal Payments

55. Show Orders on Profile Page

  • In the backend, create a new controller function, controllers/getMyOrders.js
  • Import this controller in the routes/orderRoutes.js file and connect the route/endpoint.
  • (Optional) Test the endpoint in Postman.
  • Add new ORDER_MY_LIST constants to the constants/orderConstants.js file.
  • Create a reducer named orderMyListReducer in the reducers folder.
  • Import and add this reducer to the combineReducer function’s argument object in store.js
  • Create a new action named listMyOrders and add it to the orderAction.js.
  • Modify the ProfileScreen.js file and implement showing orders in there.

56. Clear state on logout

  • Create ORDER_MY_LIST_RESET in orderConstants.js and add that as a case to the orderMyListReducer function in orderReducer.js
  • Create USER_DETAILS_RESET in userConstants.js and add that as a case to the userDetailsReducer function in userReducer.js
  • Import USER_DETAILS_RESET and ORDER_MY_LIST_RESET and dispatch it in the logout action function.

57. Admin Middleware and Getting Users Endpoint

  • We will create routes that are admin protected and will only be accessible by admin users.
  • For testing purposed, add this as a request to Postman. {{URL}}/api/users. Make a new request for this URL and name this request GET /api/users.
  • In the backend, create a new controller named getUsers in controllers/userController.js
  • Import this controller in routes/userRoutes.js and add it as a get request.
  • Create a new admin auth middleware in middlewares/authMiddlewares.js. This will check if a user is an admin. Import this userRoutes.js and protect the required route.
  • Test route in Postman.

58. Admin User List – Frontend

  • Add new USER_LIST constants to userConstants.js
  • Import these constants and create a new reducer userListReducer in the userReducer.js file. Add it to store.js as well.
  • Create new action called listUsers in userActions.js
  • Create a component called UserListScreen.js in the screens folder. This screen will show admins the complete list of users.
  • Modify the Header.js to show the admin/manage menu and it’s links.

59. Admin Screen page security

  • Edit the UserListScreen.js. Bring in the userLogin state and read the current user login info. If the user is not an admin, then push the user to the ‘/login’ page.
  • Go to the userConstants.js file and add USER_LIST_RESET to it.
  • Import USER_LIST_RESET in the userReducers.js file and add the new case to the userListReducer function.
  • Import USER_LIST_RESET in the userActions.js file and dispatch it in the LOGOUT action. This will clear the users list from redux when an admin logs out.

60. Delete User Functionality (for Admins)

  • Create a new controller function named deleteUser in backend/controllers/userController.js.
  • Import this controller in routes/userRoutes.js and create a new /:id route and add the controller which should be protected by the protect and admin middlewares, to a new route of ‘/:id’.
  • Test this new backend route in Postman. After this, implement these features in the frontend.
  • Add new USER_DELETE_ constants in the frontend/constants/userConstants.js.
  • Add a new reducer function named userDeleteReducer in the reducers/userReducers.js file. Add this reducer to store.js.
  • Add a new action function named deleteUsers to the actions/userActions.js file. Dispatch this action in the UsersListScreen component.

61. Backend endpoints for getting and updating user by it’s ID

  • Add getUserById and updateUser controller methods to the userController.js file. Import these controllers in the userRoutes.js and add the routes.
  • Test these in Postman.

62. User Edit screen and User Details screen components

  • Update the edit link in UserListScreen.js
  • Create a new file named UserEditScreen and implement it.

63. Update user functionality

  • Add new USER_UPDATE_ constants in the userConstants.js file.
  • Create userUpdateReducer reducer function in the userReducers.js and attach it to the store.js
  • Create a new action named updateUser in the userActions.js file. Dispatch this action correctly in the screens/UserEditScreen.js

64. Admin – Product List

  • In the screens folder, create ProductListScreen.js and implement the component.
  • Import and create a route for it in App.js.

65. Admin – Delete Products

  • Create a new deleteProduct controller function in the backend/productController.js file.
  • Import this new controller in routes/productRoutes.js and create an endpoint for it. Protect this route with the product and admin middlewares.
  • (optional) Test the route in Postman.
  • Now implement the feature in the frontend. Add new PRODUCT_DELETE_ constants in the frontend/constants/productConstants.js file.
  • Import these constants in the reducers/productReducers.js file and create a new productDeleteReducer function. Import and add it to the store.js
  • Create a new deleteProduct action function in actions/productActions.js
  • Import the action back in ProductListScreen.js.
  • (for testing only) You can run npm run data:import. Remember to logout and shut down the server before doing this. Also this will reset all the data in the database, including the users and their orders.

66. Create and Update Product Backend Endpoints

  • The Create Product button will immediately add a product with some dummy data and take us to an edit page where we can edit that data.
  • In the productControllers.js file, add two new controller functions, createProduct and updateProduct.
  • Import and add those controller functions in routes/productRoutes.js
  • (optional) Test it in Postman

67. Admin – Create Product Screen

  • Add new PRODUCT_CREATE_ constants in productConstants.js
  • Add new productCreateReducer function to productReducers.js and add it to store.js
  • Add new createProduct action function in productActions.js
  • Complete the ProductListScreen and implement all the functionality.

68. Product Edit Screen

  • Create a new file named ProductEditScreen.js in the screen folder. Implement the entire component.

69. Admin – Update Product Functionality

  • Add new PRODUCT_UPDATE_ constants to the productConstants.js file.
  • Add new productUpdateReducer reducer function to the productReducers.js and add it to store.js
  • Add new updateProduct action function to the productActions.js
  • Dispatch the action in ProductEditScreen and do all required modifications.

70. Image Upload Configuration and Endpoint

  • Install multer in the root folder: npm install multer
  • In the root folder, we will create a folder called uploads. We will store all our uploads in this folder
  • Create uploadRoutes.js file in the routes folder. Complete the upload implementation.
  • In the server.js file create the main route for uploads and make /uploads folder static so we can use it to upload photos.

71. Upload images from the frontend

  • Edit the ProductEditScreen component and implement the upload button.

72. Admin – Order List

  • In controllers/orderController.js, add a new controller function named getOrders.
  • Import getOrders in the routes/orderRoutes.js file and add the route and controller.
  • Add new ORDER_LIST_ constants to the orderConstants.js file.
  • Create new orderListReducer reducer function in the reducers/orderReducers.js file. Add it to the store.js
  • Create new listOrders action function in the actions/orderActions.js file.
  • Create a new OrderListScreen.js to show the orders list to the admin. Add this new component to the App.js and it’s routes.

73. Admin – Mark order as delivered

  • In the backend, add a new controller function named updateOrderToDelivered in the controllers/orderController.js
  • Import the controller function in routes/orderRoutes.js and create a route for it.
  • Add new ORDER_DELIVER_ constants to orderConstants.js
  • Create new orderDeliverReducer reducer function in reducers/orderReducer.js. Add it to store.js
  • Create a new deliverOrder action function in orderActions.js
  • Dispatch this action in OrderScreen component and comlete the implementation.

74. Create Review Endpoint

  • Associate User to reviewSchema. Edit models/productModel.js and add a user object id ref.
  • Add a new createProductReview controller function in controllers/productControllers.js and add it to routes/productRoutes.js and create a route for it.

75. Create Review Endpoint

  • Associate User to reviewSchema. Edit models/productModel.js and add a user object id ref.
  • Add a new createProductReview controller function in controllers/productControllers.js and add it to routes/productRoutes.js and create a route for it.

76. Adding product reviews on the frontend

  • Add new PRODUCT_CREATE_REVIEW_ constants to productConstants.js
  • Create productReviewCreateReducer reducer function in productReducers.js and add it to store.js
  • Create a new createProductReview action function in productActions.js file.
  • Implement the functionality in the ProductScreen.js