mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-11 12:29:24 +00:00
Go for a more generic js bundling architecture
* Don't tie the output name to webpack itself * Don't call js bundling webpack in python code * Make the doc more generic about js bundling
This commit is contained in:
155
eboutic/static/bundled/eboutic/eboutic-index.ts
Normal file
155
eboutic/static/bundled/eboutic/eboutic-index.ts
Normal file
@ -0,0 +1,155 @@
|
||||
export {};
|
||||
|
||||
interface BasketItem {
|
||||
id: number;
|
||||
name: string;
|
||||
quantity: number;
|
||||
// biome-ignore lint/style/useNamingConvention: the python code is snake_case
|
||||
unit_price: number;
|
||||
}
|
||||
|
||||
const BASKET_ITEMS_COOKIE_NAME: string = "basket_items";
|
||||
|
||||
/**
|
||||
* Search for a cookie by name
|
||||
* @param name Name of the cookie to get
|
||||
* @returns the value of the cookie or null if it does not exist, undefined if not found
|
||||
*/
|
||||
function getCookie(name: string): string | null | undefined {
|
||||
if (!document.cookie || document.cookie.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const found = document.cookie
|
||||
.split(";")
|
||||
.map((c) => c.trim())
|
||||
.find((c) => c.startsWith(`${name}=`));
|
||||
|
||||
return found === undefined ? undefined : decodeURIComponent(found.split("=")[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the basket items from the associated cookie
|
||||
* @returns the items in the basket
|
||||
*/
|
||||
function getStartingItems(): BasketItem[] {
|
||||
const cookie = getCookie(BASKET_ITEMS_COOKIE_NAME);
|
||||
if (!cookie) {
|
||||
return [];
|
||||
}
|
||||
// Django cookie backend converts `,` to `\054`
|
||||
let parsed = JSON.parse(cookie.replace(/\\054/g, ","));
|
||||
if (typeof parsed === "string") {
|
||||
// In some conditions, a second parsing is needed
|
||||
parsed = JSON.parse(parsed);
|
||||
}
|
||||
const res = Array.isArray(parsed) ? parsed : [];
|
||||
return res.filter((i) => !!document.getElementById(i.id));
|
||||
}
|
||||
|
||||
document.addEventListener("alpine:init", () => {
|
||||
Alpine.data("basket", () => ({
|
||||
items: getStartingItems() as BasketItem[],
|
||||
|
||||
/**
|
||||
* Get the total price of the basket
|
||||
* @returns {number} The total price of the basket
|
||||
*/
|
||||
getTotal() {
|
||||
return this.items.reduce(
|
||||
(acc: number, item: BasketItem) => acc + item.quantity * item.unit_price,
|
||||
0,
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add 1 to the quantity of an item in the basket
|
||||
* @param {BasketItem} item
|
||||
*/
|
||||
add(item: BasketItem) {
|
||||
item.quantity++;
|
||||
this.setCookies();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove 1 to the quantity of an item in the basket
|
||||
* @param itemId the id of the item to remove
|
||||
*/
|
||||
remove(itemId: number) {
|
||||
const index = this.items.findIndex((e: BasketItem) => e.id === itemId);
|
||||
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
this.items[index].quantity -= 1;
|
||||
|
||||
if (this.items[index].quantity === 0) {
|
||||
this.items = this.items.filter(
|
||||
(e: BasketItem) => e.id !== this.items[index].id,
|
||||
);
|
||||
}
|
||||
this.setCookies();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all the items from the basket & cleans the catalog CSS classes
|
||||
*/
|
||||
clearBasket() {
|
||||
this.items = [];
|
||||
this.setCookies();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the cookie in the browser with the basket items
|
||||
* ! the cookie survives an hour
|
||||
*/
|
||||
setCookies() {
|
||||
if (this.items.length === 0) {
|
||||
document.cookie = `${BASKET_ITEMS_COOKIE_NAME}=;Max-Age=0`;
|
||||
} else {
|
||||
document.cookie = `${BASKET_ITEMS_COOKIE_NAME}=${encodeURIComponent(JSON.stringify(this.items))};Max-Age=3600`;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create an item in the basket if it was not already in
|
||||
* @param id The id of the product to add
|
||||
* @param name The name of the product
|
||||
* @param price The unit price of the product
|
||||
* @returns The created item
|
||||
*/
|
||||
createItem(id: number, name: string, price: number): BasketItem {
|
||||
const newItem = {
|
||||
id,
|
||||
name,
|
||||
quantity: 0,
|
||||
// biome-ignore lint/style/useNamingConvention: the python code is snake_case
|
||||
unit_price: price,
|
||||
} as BasketItem;
|
||||
|
||||
this.items.push(newItem);
|
||||
this.add(newItem);
|
||||
|
||||
return newItem;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add an item to the basket.
|
||||
* This is called when the user click on a button in the catalog
|
||||
* @param id The id of the product to add
|
||||
* @param name The name of the product
|
||||
* @param price The unit price of the product
|
||||
*/
|
||||
addFromCatalog(id: number, name: string, price: number) {
|
||||
let item = this.items.find((e: BasketItem) => e.id === id);
|
||||
|
||||
// if the item is not in the basket, we create it
|
||||
// else we add + 1 to it
|
||||
if (item) {
|
||||
this.add(item);
|
||||
} else {
|
||||
item = this.createItem(id, name, price);
|
||||
}
|
||||
},
|
||||
}));
|
||||
});
|
Reference in New Issue
Block a user