Skip to content

Instantly share code, notes, and snippets.

@medkhelifi
Created July 27, 2021 12:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save medkhelifi/8c2fbaeea21ce813f1936354d257f355 to your computer and use it in GitHub Desktop.
Save medkhelifi/8c2fbaeea21ce813f1936354d257f355 to your computer and use it in GitHub Desktop.
const cart = document.getElementById("cart-list"); //section ou l'ensemble des information lié a page panier sont affiché.
const emptyCart = document.getElementById("empty-cart"); //balise qui s'affiche tant que le panier est vide.
let cartPrice = document.getElementById("cart-price");
cartPrice.style.display = "none";
const finalPrice = document.createElement("div"); //balise qui affichera le prix total de la commande.
finalPrice.classList.add("text-end"); //style bootstraps qui affichera le prix total sur la droite du panier.
finalPrice.classList.add("fs-4");
finalPrice.classList.add("pb-2");
let products = [], contact = {}; //variables néccessaire a l'appel et la réponse de l'API de commande.
let total = 0; //total = prix de l'ensemble du panier.
let counter = -1;
let gap = false; //permet d'éviter des probleme avec levent de selection quantité
//constante contenant le nombre de produit différents dans le panier, permettant l'itération de la boucle suivante.*
let supCount = 0;
let cartCounter = Number(localStorage.getItem("cart-counter"));
const quantityContainer = document.getElementsByClassName("quantity");
const supProduct = document.getElementsByClassName("trash");
//get all cart elements
const allCartItems = []; // Array to hold the keys
// Iterate over localStorage and insert the keys that meet the condition into allCartItems
for (var i = 0; i < localStorage.length; i++){
if (localStorage.key(i).substring(0,5) == 'cart-') {
allCartItems.push(localStorage.key(i));
}
}
allCartItems.sort();
/**
* Initialisation du panier
* @returns
*/
async function initialyse(){ //permet l'affichage initial des différents produits dans le panier et la mise en place des évenement
try{
for(let i =0; i<allCartItems.length-1; i++){
const onCart = JSON.parse(localStorage.getItem(allCartItems[i]));
const baseProductHTML = document.createElement("article");
let gen = await genCartProductInfos(baseProductHTML, onCart.id, onCart);
quantityContainer[i].addEventListener('input', changeQuantity);
supProduct[i].addEventListener('click', cartSuppression)
}
/*
@TODO TO BE DELETED
for (i=1; i<= cartCounter; ++i) {
//crée un objet a partir de la chaine de caractere représentant les articles dans le localStorage pour
//ensuite construire le HTML de ces produit.
const onCart = JSON.parse(localStorage.getItem("cart-" + i));
const baseProductHTML = document.createElement("article");
let gen = await genCartProductInfos(baseProductHTML, onCart.id, onCart);
if( cart.children.length-1 == cartCounter){
for(l = 0; l <= cartCounter-1; ++l){
quantityContainer[l].addEventListener('input', changeQuantity);
supProduct[l].addEventListener('click', cartSuppression)
}
}
}
*/
}
catch (error) {
console.error("erreur dans l'initialisation du panier: " + error);
alert("erreur dans l'initialisation du panier:" + error);
return;
}
}
/**
* récupération des informations d'un produit
* @param {*} elementHTML
* @param {*} id
* @param {*} oneProductOnCartInfo
* @returns
*/
async function genCartProductInfos(elementHTML, id, oneProductOnCartInfo) { //appel l'ensembles des autres fonctions de génération du html
try {
const data = await getProductAPIInfo(id);
const genProduct = await genProductHTML(elementHTML,data, oneProductOnCartInfo);
const genQuantitySelection = await genProductSelectQuantity(oneProductOnCartInfo);
const genPrice = await genCartFinalPrice(data, oneProductOnCartInfo);
}
catch (error) {
console.error("erreur dans les compilations des informations de génération du panier: " + error);
alert("erreur dans les compilations des informations de génération du panier: " + error);
return;
}
}
/**
* Récuperrer les informations d'un produit
* @param {*} id
* @returns
*/
async function getProductAPIInfo(id) { // récupération des informations d'un produit fournis pas l'API.
try {
const url = "http://localhost:3000/api/cameras/" + id;
const response = await fetch(url);
const data = await response.json();
return data;
} catch (error) {
console.error("erreur de connexion à l'api : " + error);
alert("erreur de connexion à l'api : " + error);
return;
}
}
/**
* Construction de l'html d'un produit
* @param {*} elementHTML
* @param {*} data
* @param {*} oneProductOnCartInfo
* @returns
*/
async function genProductHTML(elementHTML, data, oneProductOnCartInfo){ //création de l'element qui contiendra le html du produit dans le panier.
try{
const productHTMLElement = elementHTML;
//ajout des element crée dans la balise de section du HTML
if (productHTMLElement.innerHTML.length == 0){
cart.appendChild(productHTMLElement);
}
//création de l'affichage (HTML) des différents produits
productHTMLElement.innerHTML =
"<div class='container border-bottom mb-3 pb-3'>" +
" <div class='row'>" +
" <a class='product-image col' href='product.html?id=" + oneProductOnCartInfo.id + "'>" +
" <img class='img-fluid' src='" + data.imageUrl + "' alt=''>" +
" </a>" +
" <div class='product-description col fs-5'>" +
" <a class='link-warning text-decoration-none' href='product.html?id=" + oneProductOnCartInfo.id + "'>" +
" <h2 class='mb-4'>" + data.name + "</h2>" +
" </a>" +
" <span class='lens'>Lentille : <strong>" + oneProductOnCartInfo.spe + "</strong></span><br>"+
" <div class='quantity mt-3'> Quantité : </div> " +
" </div>" +
" <div class='container col row'>" +
" <div class='product-price col fs-4 text-end'>" +
" <strong class='fs-4'>" + (data.price/100)*Number(oneProductOnCartInfo.num) + "€</strong><br>" +
" <span class='fst-italic fs-5'>" + (data.price/100) + "€/unité</span><br>" +
" </div>" +
" <div class='container d-flex justify-content-end align-items-end'>" +
" <div class='border trash py-2 px-2' id='trash-btn-"+oneProductOnCartInfo.id+"__"+oneProductOnCartInfo.spe+"'>"+
" <input type='hidden' value='trash-hdn-spe-"+oneProductOnCartInfo.spe+"'"+
" <div class='fas fa-trash fa-2x'></div>"+
" </div>" +
" </div>" +
" </div>" +
" </div>"+
"</div>";
}
catch(error){
console.error("erreur lors de la génération du HTML : " + error);
alert("erreur lors de la génération du HTML : " + error);
return;
}
}
/**
*
* @param {*} oneProductOnCartInfo
* @returns
*/
async function genProductSelectQuantity(oneProductOnCartInfo){ //création de l'élément de selection et d'affichage des quantité des produits
try{
const quantitySelectionLabel = document.createElement("label");
if( gap == false){
counter++
quantityContainer[counter].appendChild(quantitySelectionLabel);
products.push(oneProductOnCartInfo.id);
}
else{
quantityContainer[k].appendChild(quantitySelectionLabel);
quantityContainer[k].addEventListener('input', changeQuantity);
}
//balise qui premettra de reselectionné a nouveau un nombre d'objet
const quantitySelection = document.createElement("select");
quantitySelection.setAttribute("id", "qte-slct-"+oneProductOnCartInfo.id+"__"+oneProductOnCartInfo.spe)
quantitySelectionLabel.appendChild(quantitySelection);
if (Number(oneProductOnCartInfo.num) > 9){
for(j=1; j <= Number(oneProductOnCartInfo.num); j++){ incrementeProductSelectOption(quantitySelection, j); }
}
else{
for(j=1; j<=9; j++){ incrementeProductSelectOption(quantitySelection, j); }
}
quantitySelection.selectedIndex = Number(oneProductOnCartInfo.num)-1;
//ajout de l'ID du produit ajouté au tableau product, nécéssaire a l'appel de l'API de commande.
}
catch(error){
console.error("erreur dans la génération de la séléction du nombre de produit : " + error);
alert("erreur dans la génération de la séléction du nombre de produit : " + error);
return;
}
}
/**
*
* @param {*} quantitySelectHTMLElement
* @param {*} num
*/
function incrementeProductSelectOption(quantitySelectHTMLElement, num){ //ajoute le nombre d'option nécessaire dans le select des quantité de chaque produit
const quantitySelectionOption = document.createElement("option");
quantitySelectionOption.textContent = num;
quantitySelectHTMLElement.appendChild(quantitySelectionOption);
}
/**
*
* @param {*} data
* @param {*} oneProductOnCartInfo
* @returns
*/
async function genCartFinalPrice(data, oneProductOnCartInfo){ //mes à jour le total de la commande et le html en rapport
if(allCartItems.length>0){
emptyCart.style.display = "none";
cartPrice.style.display = "block";
form.style.display = "block";
total = total+(data.price/100)*Number(oneProductOnCartInfo.num);
finalPrice.innerHTML = "Sous-total : <strong>" + total + "€ </strong>";
cart.appendChild(finalPrice);
}else{
emptyCart.style.display = "block";
cartPrice.style.display = "none";
form.style.display = "none";
}
/*
// @TODO TO BE DELETED
try{
//ajout du prix de l'article au total de la commande
total = total+(data.price/100)*Number(oneProductOnCartInfo.num);
//permet affichage du prix et de celui de certain élément en fonction de l'état du panier (vide/remplis)
if (cart.children.length == cartCounter) {
finalPrice.innerHTML = "Sous-total : <strong>" + total + "€ </strong>";
cart.appendChild(finalPrice);
form.style.display = "block";
emptyCart.style.display = "none";
cartPrice.style.display = "block";
}
}
catch(error){
console.error("erreur dans l'écriture du total de la commande : " + error);
alert("erreur dans l'écriture du total de la commande : " + error);
return;
}
*/
}
initialyse();
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~CHANGEMENT ARTICLE DANS LE PANIER//Supression~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
async function changeQuantity(e){
try{
/*
// @TODO TO BE DELETED
let changeProductElementHTML = e.composedPath()[6];
changeProductElementHTML.classList.add("change-cart-item");
*/
const changeProductSelect = e.composedPath()[0];
let itemToDelete = e.target.id;
itemToDelete = itemToDelete.replace("qte-slct-","");
let itemToDeleteArr = itemToDelete.split("__");
console.log(itemToDeleteArr);
if(itemToDeleteArr.length>=2){
for (m = 0; m < allCartItems.length; m++){
onCart = JSON.parse(localStorage.getItem(allCartItems[m]));
if(onCart.id == itemToDeleteArr[0] && onCart.spe == itemToDeleteArr[1]){
localStorage.setItem(allCartItems[m], '{"product":"' + onCart.product + '","spe":"' + onCart.spe + '","num":"' + changeProductSelect.value + '","id":"' + onCart.id + '"}');
window.location.href = "panier.html";
}
}
}else{
// @TODO THROW EXCEPTION
}
/*
// @TODO TO BE DELETED
for (k = 0; k <= (cart.children.length-(1)); k++){
if(changeProductElementHTML == cart.children[k]){
const onCartChange = JSON.parse(localStorage.getItem("cart-" + (Number(k)+(1-supCount))));
localStorage.setItem("cart-" + (Number(k)+(1-supCount)), '{"product":"' + onCartChange.product + '","spe":"' + onCartChange.spe + '","num":"' + changeProductSelect.value + '","id":"' + onCartChange.id + '"}');
window.location.href = "panier.html";
const onCartChange2 = JSON.parse(localStorage.getItem("cart-" + (Number(k)+(1-supCount))));
let data = await getProductAPIInfo(onCartChange.id);
total = (total - ((data.price/100)*(Number(onCartChange.num))))+((data.price/100)*(Number(onCartChange2.num)));
finalPrice.innerHTML = "Sous-total : <strong>" + total + "€ </strong>";
let regenHTML = await genProductHTML(changeProductElementHTML, data, onCartChange2);
gap = true;
let regenSelectQuantity = await genProductSelectQuantity(onCartChange2);
gap = false;
}
}
document.querySelector(".change-cart-item .trash").addEventListener('click', cartSuppression);
changeProductElementHTML.classList.remove("change-cart-item");
*/
}
catch(err){
console.log(err);
}
}
/**
* Suppression d'un article
* @param {*} e
*/
async function cartSuppression(e){
let onCart;
let supButton;
let supArticle;
let alreadyPass = false;
let itemToDelete = e.target.id;
itemToDelete = itemToDelete.replace("trash-btn-","");
let itemToDeleteArr = itemToDelete.split("__");
if(itemToDeleteArr.length>=2){
for (m = 0; m < allCartItems.length; m++){
onCart = JSON.parse(localStorage.getItem(allCartItems[m]));
console.log(onCart);
if(onCart.id == itemToDeleteArr[0] && onCart.spe == itemToDeleteArr[1]){
localStorage.removeItem(allCartItems[m]);
window.location.href = "panier.html";
}
}
}else{
// @TODO THROW EXCEPTION
}
/*
@TO BE DELETED
for (m = 0; m <= cartCounter-1; m++){
if ((e.composedPath()[0] == supProduct[m])||(e.composedPath()[1] == supProduct[m])){
if(e.composedPath()[0] == supProduct[m]){
supButton = e.composedPath()[0];
supArticle = e.composedPath()[5];
}
else{
supButton = e.composedPath()[1];
supArticle = e.composedPath()[6];
}
onCart = JSON.parse(localStorage.getItem("cart-" + (Number(m)+1)))
if (m+2 > cartCounter){
localStorage.removeItem("cart-" + ((m)+1));
}
else{
for(n = m+2; n <= (cartCounter); n++){
console.log(n);
let itemAfter = localStorage.getItem("cart-" + (n));
console.log(itemAfter)
localStorage.setItem("cart-" + (n-1), itemAfter);
localStorage.removeItem("cart-" + (n));
}
}
cartCounter--;
localStorage.setItem("cart-counter", actualCart);
}
if(supArticle != undefined){
supArticle.style.display = "none";
supButton.classList.remove('trash');
if(alreadyPass == false){
alreadyPass = true;
let data = await getProductAPIInfo(onCart.id);
total = total - ((data.price/100)*Number(onCart.num));
console.log((data.price/100)*Number(onCart.num));
supCount++;
}
finalPrice.innerHTML = "Sous-total : <strong>" + total + "€ </strong>";
}
}
if(actualCart == 0){
form.style.display = "none";
emptyCart.style.display = "block";
finalPrice.style.display = "none";
cartPrice.style.display = "none";
}
*/
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~FORMULAIRE DE COMMANDE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
//le formulaire de contact
const form = document.getElementById("form");
//les différents inputs du formulaire de contact
const lastName = document.getElementById("lastname");
const firstName = document.getElementById("firstname");
const address = document.getElementById("address");
const city = document.getElementById("city");
const zip = document.getElementById("zip");
const email = document.getElementById("email");
//les différentes REGEX permettant d'avoir des informations aux bon format dans le formulaire.
const regexText = /^[a-zÀ-ú]{2}[a-zÀ-ú\s\-]*$/i;
const regexPostalcode = /^\d{5}$/;
const regexAddress = /^[a-z0-9\s,]{8,}$/i;
const regexMail = /^[a-z0-9\._-]+@[a-z0-9\._-]+\.[a-z]{2,6}$/i;
//les différents événements lié aux champs des inputs
lastName.addEventListener( 'change', formChangementText);
firstName.addEventListener( 'change', formChangementText);
city.addEventListener( 'change', formChangementText);
address.addEventListener( 'change', formChangementAddress);
zip.addEventListener( 'change', formChangementPostalCode);
email.addEventListener( 'change', formChangementMail);
//fonction permettant feed-back a l'utilisateur sur sa completion des champs des différents inputs
function goodText(){
event.target.nextElementSibling.innerHTML = "<span style='font-size:20px;'>&#9989;</span>"}
function badText(){ event.target.nextElementSibling.innerHTML = "<span style='font-size:20px;'>&#10060;</span>"}
//les différentes fonctions lié aux feed back de la correcte completion des inputs
function formChangementText(event){
const result = event.target.value;
if(regexText.test(result)) {goodText();}
else {badText();};
}
function formChangementAddress(event){
const result = event.target.value;
if(regexAddress.test(result)) {goodText();}
else{badText();};
}
function formChangementPostalCode(event){
const result = event.target.value;
if(regexPostalcode.test(result)) {goodText();}
else {badText();};
}
function formChangementMail(event){
const result = event.target.value;
if(regexMail.test(result)) {goodText();}
else {badText();};
}
//événement lié au bouton commande du formulaire.
form.addEventListener("submit", sendCommand);
function sendCommand(event){
//empeche l'envoi normal du formulaire au back-end
event.preventDefault();
//vérifie si les champs des inputs sont correctement remplie
if(regexText.test(lastName.value) && regexText.test(firstName.value) &&
regexAddress.test(address.value) && regexPostalcode.test(zip.value) &&
regexText.test(city.value) && regexMail.test(email.value)){
//les deux constantes suivante permettent de crée un tableau avec les différentes valeurs contenue dans les inputs du formulaires
const formData = new FormData(form);
const constructContact = Array.from(formData);
//la boucle suivante permet d'ajouter à l'objet contact les informations contenue dans le formulaire
for (i = 0; i <= 5; i++ ){
if (i != 4){
contact[constructContact[i][0]] = constructContact[i][1];
}
//ajoute le code postale au city dans l'objet contact
else{
contact[constructContact[i-1][0]] += " " + constructContact[i][1];
}
}
//constante contenant le header du fetch d'appel a l'API suivante
const options = {
method: "POST",
body: JSON.stringify({contact, products}),
headers: { "Content-Type": "application/json" },
};
//appel a l'API
fetch("http://localhost:3000/api/cameras/order", options)
.then((res) => res.json())
.then((order) => {
//vide le localStorage pour pouvoir réaliser une nouvelle commande.
localStorage.clear();
//Ajoute les infos à afficher sur la page de confirmation de commande.
localStorage.setItem("order", order.orderId);
localStorage.setItem("name", order.contact.firstName);
localStorage.setItem("commandPrice", total)
//redirige l'utilisateur vers la page de finalisation de sa commande.
window.location.replace("commande.html");
})
.catch((err) => {
alert("Il y a eu une erreur : " + err);
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment