let express = require("@runkit/runkit/express-endpoint/1.0.0");
let app = express(module.exports);
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Expose-Headers", "runkit-rate-limit-remaining");
res.header("Access-Control-Expose-Headers", "tonic-rate-limit-remaining");
var reqHeaders = req.get("Access-Control-Request-Headers");
if (reqHeaders) res.header("Access-Control-Allow-Headers", reqHeaders);
var reqMethods = req.get("Access-Control-Request-Methods");
if (reqMethods) res.header("Access-Control-Allow-Methods", reqMethods);
next();
});
const data = [
{
id: 1,
name: "Practical Concrete Salad",
slug: "practical-concrete-salad",
material: "Metal",
color: "green",
description:
"Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals",
price: "762.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 2,
name: "Awesome Concrete Hat",
slug: "awesome-concrete-hat",
material: "Soft",
color: "orchid",
description:
"The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality",
price: "767.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 3,
name: "Fantastic Plastic Fish",
slug: "fantastic-plastic-fish",
material: "Wooden",
color: "lavender",
description:
"Ergonomic executive chair upholstered in bonded black leather and PVC padded seat and back for all-day comfort and support",
price: "944.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 4,
name: "Gorgeous Rubber Fish",
slug: "gorgeous-rubber-fish",
material: "Steel",
color: "ivory",
description:
"The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality",
price: "926.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 5,
name: "Tasty Frozen Mouse",
slug: "tasty-frozen-mouse",
material: "Metal",
color: "azure",
description:
"The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality",
price: "794.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 6,
name: "Handcrafted Plastic Pants",
slug: "handcrafted-plastic-pants",
material: "Plastic",
color: "tan",
description:
"Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals",
price: "509.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 7,
name: "Handcrafted Metal Cheese",
slug: "handcrafted-metal-cheese",
material: "Concrete",
color: "pink",
description:
"New range of formal shirts are designed keeping you in mind. With fits and styling that will make you stand apart",
price: "404.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 8,
name: "Incredible Granite Shirt",
slug: "incredible-granite-shirt",
material: "Granite",
color: "salmon",
description:
"New ABC 13 9370, 13.3, 5th Gen CoreA5-8250U, 8GB RAM, 256GB SSD, power UHD Graphics, OS 10 Home, OS Office A & J 2016",
price: "663.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 9,
name: "Ergonomic Granite Towels",
slug: "ergonomic-granite-towels",
material: "Rubber",
color: "orchid",
description:
"Boston's most advanced compression wear technology increases muscle oxygenation, stabilizes active muscles",
price: "7.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 10,
name: "Intelligent Soft Chicken",
slug: "intelligent-soft-chicken",
material: "Rubber",
color: "purple",
description:
"The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design",
price: "49.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 11,
name: "Awesome Wooden Shirt",
slug: "awesome-wooden-shirt",
material: "Fresh",
color: "gold",
description:
"New range of formal shirts are designed keeping you in mind. With fits and styling that will make you stand apart",
price: "208.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 12,
name: "Practical Concrete Chair",
slug: "practical-concrete-chair",
material: "Frozen",
color: "olive",
description:
"The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J",
price: "28.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 13,
name: "Gorgeous Concrete Salad",
slug: "gorgeous-concrete-salad",
material: "Concrete",
color: "turquoise",
description: "The Football Is Good For Training And Recreational Purposes",
price: "769.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 14,
name: "Unbranded Fresh Hat",
slug: "unbranded-fresh-hat",
material: "Granite",
color: "orange",
description:
"Ergonomic executive chair upholstered in bonded black leather and PVC padded seat and back for all-day comfort and support",
price: "561.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 15,
name: "Fantastic Granite Fish",
slug: "fantastic-granite-fish",
material: "Rubber",
color: "ivory",
description: "The Football Is Good For Training And Recreational Purposes",
price: "528.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 16,
name: "Awesome Metal Chips",
slug: "awesome-metal-chips",
material: "Plastic",
color: "fuchsia",
description:
"New range of formal shirts are designed keeping you in mind. With fits and styling that will make you stand apart",
price: "768.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
{
id: 17,
name: "Refined Metal Fish",
slug: "refined-metal-fish",
material: "Concrete",
color: "green",
description:
"The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality",
price: "241.00",
currency: "BGN",
image: "https://picsum.photos/640/640",
},
];
let basket = {
lineItems: [],
total: 0,
numOfItems: 0,
};
let wishlist = [];
const transfromBasket = (b) => {
return b.lineItems.reduce(
(a, v) => {
const total = Number(a.total) + Number(v.price) * v.quantity;
const numOfItems = Number(a.numOfItems) + Number(v.quantity);
return {
total,
numOfItems,
items: a.items.concat(v),
};
},
{
items: [],
total: 0,
numOfItems: 0,
}
);
};
const isInBasket = (id) => basket.lineItems.some((l) => l.id == id);
const isInWishlist = (id) => wishlist.some((l) => l.id == id);
const isInCatalog = (id) => data.some((l) => l.id == id);
const findProductById = (id) => data.find((d) => d.id == id);
const findInBasketById = (id) => basket.lineItems.find((l) => l.id == id);
app.get("/products", (_, res) => res.status(200).send(data));
app.get("/basket", (_, res) => res.status(200).send(transfromBasket(basket)));
app.post("/basket/:id", (req, res) => {
const { id } = req.params;
if (id) {
if (isInBasket(id)) {
return res.status(400).send("Error, id already in basket");
}
const newItem = findProductById(id);
if (newItem) {
basket.lineItems = basket.lineItems.concat({ ...newItem, quantity: 1 });
return res.status(204).send();
}
return res.status(400).send("Error, id does not exist");
}
return res.status(400).send("Error, no id passed");
});
app.delete("/basket/:id", (req, res) => {
const { id } = req.params;
if (id) {
if (!isInBasket(id)) {
return res.status(400).send("Error, id not in basket");
}
const newBasket = basket.lineItems.filter((b) => b.id != id);
if (newBasket.length < basket.lineItems.length) {
basket.lineItems = newBasket;
return res.status(204).send();
}
return res.status(400).send("Error, id does not exist or not deleted");
}
return res.status(400).send("Error, no id passed");
});
app.patch("/basket/:id/increase", (req, res) => {
const { id } = req.params;
if (id) {
if (!isInBasket(id)) {
return res.status(400).send("Error, id not in basket");
}
if (isInCatalog(id)) {
basket.lineItems.forEach((b) => {
if (b.id == id) {
b.quantity++;
}
});
return res.status(204).send();
}
return res.status(400).send("Error, id does not exist");
}
return res.status(400).send("Error, no id passed");
});
app.patch("/basket/:id/decrease", (req, res) => {
const { id } = req.params;
if (id) {
if (!isInBasket(id)) {
return res.status(400).send("Error, id not in basket");
}
const lineItem = findInBasketById(id);
if (lineItem.quantity <= 1) {
return res
.status(400)
.send("Error, quantity is already at 1, cannot be 0 or negative");
}
if (isInCatalog(id)) {
basket.lineItems.forEach((b) => {
if (b.id == id) {
b.quantity--;
}
});
return res.status(204).send();
}
return res.status(400).send("Error, id does not exist");
}
return res.status(400).send("Error, no id passed");
});
app.get("/wishlist", (_, res) => res.status(200).send(wishlist));
app.post("/wishlist/:id", (req, res) => {
const { id } = req.params;
if (id) {
if (isInWishlist(id)) {
return res.status(400).send("Error, id already in wishlist");
}
const newItem = findProductById(id);
if (newItem) {
wishlist = wishlist.concat(newItem);
return res.status(204).send();
}
return res.status(400).send("Error, id does not exist");
}
return res.status(400).send("Error, no id passed");
});
app.delete("/wishlist/:id", (req, res) => {
const { id } = req.params;
if (id) {
if (!isInWishlist(id)) {
return res.status(400).send("Error, id not in wishlist");
}
const newWishlist = wishlist.filter((b) => b.id != id);
if (newWishlist.length < wishlist.length) {
wishlist = newWishlist;
return res.status(204).send();
}
return res.status(400).send("Error, id does not exist or not deleted");
}
return res.status(400).send("Error, no id passed");
});