const cache = { basket: [], shopItems: [], totalCheckout: 0, inCheckout: false, paymentOption: null, useBlackMoney: false, texts: {} }; /** * Opens the menu UI and initializes the shop state. * @function openMenu * @param {object[]} shopItems - Array of shop items to display. * @param {string} shopName - The name of the shop. * @param {string[]} categories - List of categories to display. * @param {boolean} useBlackMoney - Whether or not to use black money. */ function openMenu(shopItems, shopName, categories, useBlackMoney) { // Display the UI $(".ui").fadeIn(); // Set the shop title $("#shopTitle").html(shopName); // Setup categories, items, and search functionality setupCategories(categories); setupShopItems(shopItems); setupSearch(shopItems); // Initialize cache values cache.useBlackMoney = useBlackMoney; cache.inCheckout = false; // Clear the basket clearBasket(); // Show "No products added" message if the basket is empty if (!cache.basket.length) $("#noProductsAdded").fadeIn(); } /** * Sets up the categories in the shop. * @function setupCategories * @param {string[]} categories - The list of categories to display. */ function setupCategories(categories) { // Get the shop categories container const shopCategories = $("#shopCategorys"); // Clear any existing categories shopCategories.html(""); // Add the "All" category with a reset function shopCategories.append(`
All
`); // Iterate over each category in the categories list categories.forEach((category) => { const categoryID = `category-${category}`; // Append each category to the shop categories container shopCategories.append(`
${category}
`); // Add a click event listener to each category $(`#${categoryID}`).click(() => { if (!cache.inCheckout) searchByCategory(category); }); }); } /** * Filters the shop items by category. * @function searchByCategory * @param {string} category The category to filter by. */ function searchByCategory(category) { // Remove the active class from all categories $(".shopCategory").removeClass("active"); // Add the active class to the selected category $(`#category-${category}`).addClass("active"); // Loop through the shop items and show/hide based on the category cache.shopItems.forEach((shopItem) => { const shopItemElement = $(`#shopItem-${shopItem.itemID}`); // If the item matches the category, show it, otherwise hide it if (shopItem.itemCategory === category) { shopItemElement.show(); } else { shopItemElement.hide(); } }); } /** * Resets the shop categories to show all items. * @function resetCategory */ function resetCategory() { // Remove the active class from all categories $(".shopCategory").removeClass("active"); // Add the active class to the 'All' category $("#category-all").addClass("active"); // Show all shop items cache.shopItems.forEach((shopItem) => { $(`#shopItem-${shopItem.itemID}`).show(); }); } /** * Sets up the shop items container. * @function setupShopItems * @param {object[]} shopItems - The shop items. */ function setupShopItems(shopItems) { const shopItemsContainer = $("#shopItems"); shopItemsContainer.html(""); cache.shopItems = shopItems; // Loop through the shop items shopItems.forEach((shopItem) => { const shopItemID = `shopItem-${shopItem.itemID}`; // Check if the item is already in the container if (!$(`#${shopItemID}`).hasClass('item-set')) { // Add the item to the container shopItemsContainer.append(`
${shopItem.itemPrice}$
`); // Add a click event to the item $(`#${shopItemID}`).click(() => { // Check if we are not in the checkout if (!cache.inCheckout) { // Add the item to the basket addToBasket(shopItem); } }); } }); } /** * Adds an item to the basket. * @function addToBasket * @param {object} shopItem - The shop item to add. */ function addToBasket(shopItem) { // Hide the "No products added" message $("#noProductsAdded").hide(); // Search the shop item in the basket let searchShopItem = cache.basket.find((product) => product.itemID === shopItem.itemID); // If the item is already in the basket, increase the quantity if (searchShopItem) { searchShopItem.itemQuantity++; searchShopItem.itemTotal += shopItem.itemPrice; // Update the UI updateBasketItemUI(searchShopItem); } else { // If the item is not in the basket, add it searchShopItem = Object.assign({}, shopItem, { itemQuantity: 1, itemTotal: shopItem.itemPrice, }); // Add the item to the basket cache.basket.push(searchShopItem); // Append the item to the basket UI appendBasketItemUI(shopItem); } // Update the total checkout price updateTotalCheckout(shopItem.itemPrice); } /** * Updates the quantity and price of a basket item in the UI. * @function updateBasketItemUI * @param {object} item - The item to update. */ function updateBasketItemUI(item) { // Update the quantity $(`#basketItem-Quantity-${item.itemID}`).html(`x${item.itemQuantity}`); // Update the price $(`#basketItem-Price-${item.itemID}`).html(`${item.itemTotal}$`); } /** * Appends a new item to the basket UI. * @function appendBasketItemUI * @param {object} shopItem - The shop item to append. */ function appendBasketItemUI(shopItem) { const backgroundStyle = cache.useBlackMoney ? "rgba(255, 84, 84, 0.7)" : "rgba(56, 168, 5, 0.71)"; $("#basketItems").append(`
${shopItem.itemLabel}x1
`); // Add event listeners to the basket item $(`#basketItem-${shopItem.itemID}`).click(() => { if (!cache.inCheckout) removeFromBasket(shopItem); }); $(`#basketItem-${shopItem.itemID}`).on("contextmenu", (e) => { if (!cache.inCheckout) removeFromBasketCompletamente(shopItem); }); } /** * Removes all items of a given shop item from the basket. * @function removeFromBasketCompletamente * @param {object} shopItem - The shop item to remove. * * This function removes all items of the given shop item from the basket. * It also updates the total checkout price and removes the item from the UI. */ function removeFromBasketCompletamente(shopItem) { // Find the item in the basket const basketItem = cache.basket.find(item => item.itemID === shopItem.itemID); if (basketItem) { // Update the total checkout price updateTotalCheckout(-basketItem.itemTotal); // Remove the item from the basket cache.basket = cache.basket.filter(item => item.itemID !== shopItem.itemID); // Remove the item from the UI $(`#basketItem-${shopItem.itemID}`).remove(); // Check if the basket is empty if (cache.basket.length === 0) { // Show the "No products added" message $("#noProductsAdded").fadeIn(); } } } function updateTotalCheckout(amount) { cache.totalCheckout += amount; $("#totalcheckout").html(`${cache.totalCheckout}$`); } /** * Removes one item from the basket. * @function removeFromBasket * @param {object} shopItem - The shop item to remove. */ function removeFromBasket(shopItem) { // Search the shop item in the basket const searchShopItem = cache.basket.find((product) => product.itemID === shopItem.itemID); if (searchShopItem) { // Decrease the item quantity searchShopItem.itemQuantity--; // Decrease the item total price searchShopItem.itemTotal -= shopItem.itemPrice; // Update the UI updateBasketItemUI(searchShopItem); // If the item quantity is 0, remove it from the basket if (searchShopItem.itemQuantity === 0) { cache.basket = cache.basket.filter(item => item.itemID !== shopItem.itemID); // Remove the item HTML element $(`#basketItem-${shopItem.itemID}`).remove(); } // Update the total checkout price updateTotalCheckout(-shopItem.itemPrice); // If the total checkout price is 0, show the "No products added" message if (cache.totalCheckout === 0) { $("#noProductsAdded").fadeIn(); } } } /** * Proceeds to checkout. * @function proceedCheckout */ function proceedCheckout() { // Check if the total checkout amount is greater than 0 if (cache.totalCheckout > 0) { // If it is, toggle the checkout state toggleCheckoutState(); } else { // If it is not, flash a message indicating that there are no products added to the basket flashNoProductsMessage(); } } /** * Toggles the checkout mode. * @function toggleCheckoutState */ function toggleCheckoutState() { // If we are currently in checkout mode, exit it if (cache.inCheckout) { exitCheckoutMode(); } // If we are not in checkout mode, enter it else { enterCheckoutMode(); } // Toggle the boolean value cache.inCheckout = !cache.inCheckout; } /** * Enters the checkout mode. * @function enterCheckoutMode */ function enterCheckoutMode() { // Clear the HTML of the more-btns element $("#more-btns").html(""); // Get the current date const date = Date.now(); // Declare the button template const btnTemplate = cache.useBlackMoney ? ["blackmoney"] : ["cash", "bank"]; // Loop through the button template and create a new button for each type btnTemplate.forEach(type => { // Append the button template to the more-btns element $("#more-btns").append(` `); // Show the button and add a click event to it $(`#${type}-${date}`).show().click(() => submitCheckout(type)); }); // Set the opacity of the UI elements to 0.5 setUIOpacity(0.5); // Show the more-btns element $("#more-btns").show(); // Update the text of the checkout button $("#checkout").html('CANCEL'); } /** * Exits the checkout mode. * @function exitCheckoutMode */ function exitCheckoutMode() { // Reset the opacity of the UI elements setUIOpacity(1); // Reset the text of the checkout button $("#checkout").html('CHECKOUT'); // Hide the additional buttons $("#more-btns").hide(); } /** * Sets the opacity of the UI elements to the given value. * @param {number} opacity the opacity value (between 0 and 1) */ function setUIOpacity(opacity) { // Set the opacity of the shop categories, shop items, basket items, and clear basket button $("#shopCategorys, #shopItems, #basketItems, #shopSearch-ClearBasket").css("opacity", opacity); } let checkoutSent = false; /** * Submits the checkout to the server. * @param {string} paymentType the type of payment used (cash, bank, blackmoney) */ function submitCheckout(paymentType) { // Prevent the checkout from being sent multiple times if (checkoutSent) return; checkoutSent = true; $.post(`http://${GetParentResourceName()}/goToCheckout`, JSON.stringify({ // Total amount to be paid totalPayment: cache.totalCheckout, // Items in the basket basket: cache.basket, // Type of payment used paymentType, // Whether or not to use black money useBlackMoney: cache.useBlackMoney })); // Close the menu after checkout closeMenu(); } /** * Flashes a message indicating that there are no products added to the basket. * Temporarily changes the color of the "no products" text to red and then reverts it to white. */ function flashNoProductsMessage() { const noProductsText = $("#noProductsAdded-Text"); // Change text color to red noProductsText.css("color", "red"); // Revert text color to white after 100 milliseconds setTimeout(() => noProductsText.css("color", "white"), 100); } function setupSearch(shopItems) { const searchInput = $("#shopSearch-Input"); searchInput.on("input", () => { const searchValue = searchInput.val().toLowerCase(); shopItems.forEach(({ itemID, itemLabel }) => { const shouldDisplay = itemLabel.toLowerCase().startsWith(searchValue); $(`#shopItem-${itemID}`).toggle(shouldDisplay); }); }); } /** * Clear the basket and reset the total checkout amount. */ function clearBasket() { // Clear the basket. cache.basket = []; // Reset the total checkout amount. cache.totalCheckout = 0; // Clear the basket items UI. $("#basketItems").html(''); // Show the "no products added" message. $("#noProductsAdded").fadeIn(); // Reset the total checkout label. $("#totalcheckout").html(`0$`); } /** * Close the menu and reset the shop state. */ function closeMenu() { // Notify the server that the menu was closed. $.post(`http://${GetParentResourceName()}/CloseMenu`, JSON.stringify({})); // Reset the state of the shop. cache.basket = []; // empty the basket cache.shopItems = []; // remove all shop items cache.totalCheckout = 0; // reset the total checkout amount cache.inCheckout = false; // exit checkout mode cache.useBlackMoney = false; // disable black money // Reset the UI setUIOpacity(1); // set the opacity of the UI to 1 $("#checkout").html('CHECKOUT'); // reset the text of the checkout button $(".shopButtonCheckout-Btn").hide(); // hide the checkout button $("#totalcheckout").html(`0$`); // reset the total checkout label $("#checkout").show(); // show the checkout button // Reset the checkout sent flag checkoutSent = false; }