diff --git a/README.md b/README.md index 1dca971e75686a68418f2b03b7afc5d4c07fe8ed..e3551d2e7a941e865940a018ec4358a392fe84e1 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,38 @@ Pour ce projet, nous allons utiliser pipenv pour créer un environnement virtuel sudo apt-get update sudo apt-get install build-essential libpq-dev python3-dev sudo apt install pipenv +``` +Si vous rencontrer un pb : +AttributeError: module 'collections' has no attribute 'MutableMapping' +faire un +``` + sudo apt remove pipenv + ``` + voila + + installpython3.12-dev +``` + + +I was getting the same error on ubuntu 22.04, This is how I solved it. + +remove pipenv if you have installed it using apt + +sudo apt remove pipenv + +install pipenv unsing pip + +pip3 install pipenv + +activate virtual environment + +python3 -m pipenv shell + +install from pipfile + +pipenv install + + ``` Une fois cela fait, on entrer dans l'environnement virtuel. @@ -39,7 +71,12 @@ pipenv shell ''' +sudo apt install postgresql postgresql-contrib +psql --version sudo -u postgres psql + +psql -U votre_utilisateur -d votre_base_de_donnees -h localhost -W + ALTER USER postgres WITH PASSWORD 'nouveau_mot_de_passe'; ''' ## Run the app diff --git a/app.py b/app.py index fea1cbcd62649647af759e2033ed863c6be0bec1..fad18cf8a257300fb2fa7ef96015cb77d2dab564 100644 --- a/app.py +++ b/app.py @@ -71,6 +71,16 @@ def index(): return render_template("index.html") # return "Hello, world" +@app.route('/ePhone') +def ePhone(): + return render_template("ePhone.html") + +@app.route('/ePhone16ProMax') +def ePhone16ProMax(): + return render_template("ePhone16ProMax.html") + # return "Hello, world" + + @app.route('/admin', methods=['GET', 'POST']) def admin(): diff --git a/templates/admin.html b/templates/admin.html index db5df41e9039bf4e4c195f47599a1921ae419eab..f227d3cdefdbc8f4a8eec22703f9936c1373a71e 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -1,22 +1,239 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <title>Admin - Ajouter des articles</title> -</head> -<body> - <h1>Ajouter un article</h1> - <form method="POST"> - <input type="text" name="title" placeholder="Titre" required> - <textarea name="description" placeholder="Description" required></textarea> - <input type="number" step="0.01" name="price" placeholder="Prix (€)" required> - <button type="submit">Ajouter</button> - </form> - - <h2>Articles disponibles</h2> - <ul> - {% for article in articles %} - <li>{{ article.title }} - {{ article.price }}€</li> - {% endfor %} - </ul> -</body> -</html> +<!DOCTYPE html> +<html lang="fr"> +<head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <title>Administration - Gestion des Articles</title> + <style> + /* Réinitialisation des styles */ + body, h1, p, nav, footer { + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; + } + body { + background: #f9f9f9; + color: #333; + } + + /* Bandeau en fond blanc */ + header { + background: white; + width: 100%; + border-bottom: 1px solid #eaeaea; + padding: 10px 0; + display: flex; + justify-content: space-between; + align-items: center; + padding-left: 20px; + } + + .logo { + display: flex; + align-items: center; + gap: 10px; + } + + .logo img { + height: 30px; + width: auto; + } + + nav { + display: flex; + justify-content: center; + gap: 20px; + flex-grow: 1; + text-align: center; + } + + nav a { + text-decoration: none; + color: #333; + font-weight: normal; + font-size: 1em; + padding: 10px 15px; + } + + nav a:hover { + text-decoration: underline; + } + + /* Contenu principal */ + main { + max-width: 800px; + margin: 50px auto; + background: #fff; + padding: 20px; + border-radius: 10px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + } + + h1 { + font-size: 2em; + text-align: center; + margin-bottom: 20px; + } + + /* Styles du formulaire */ + form { + margin-bottom: 30px; + display: flex; + flex-direction: column; + gap: 10px; + } + + form input, form textarea, form button { + padding: 10px; + font-size: 1em; + } + + form input, form textarea { + border: 1px solid #ccc; + border-radius: 5px; + width: 100%; + } + + form button { + background: #0078d7; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + width: 150px; + align-self: flex-start; + } + + form button:hover { + background: #005bb5; + } + + /* Styles de la liste */ + .article-list { + list-style: none; + padding: 0; + } + + .article-list li { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 0; + border-bottom: 1px solid #eaeaea; + } + + .article-list li:last-child { + border-bottom: none; + } + + .article-list button { + background: #d9534f; + color: white; + border: none; + border-radius: 5px; + padding: 5px 10px; + cursor: pointer; + } + + .article-list button:hover { + background: #c9302c; + } + </style> +</head> +<body> + + <header> + <div class="logo"> + <!-- Remplacez l'URL ci-dessous par celle de votre logo --> + <img src="https://1.bp.blogspot.com/_TkI9VbsKljk/Sx1UNvbXWSI/AAAAAAAAA_4/H-27hwu9C-o/s400/birneKopie.jpg" alt="Logo Pear"> + </div> + <nav> + <a href="/">Accueil</a> + <a href="/ePhone">ePhones</a> + </nav> + </header> + + <main> + <h1>Gestion des Articles</h1> + + <!-- Formulaire pour ajouter un nouvel article --> + <!-- (en front uniquement, pas d'envoi réel à un back-end dans cet exemple) --> + <form id="add-article-form"> + <input type="text" id="article-title" placeholder="Titre de l'article" required /> + <textarea id="article-description" placeholder="Description de l'article" required></textarea> + <input type="number" step="0.01" id="article-price" placeholder="Prix de l'article (€)" required /> + <button type="submit">Ajouter</button> + </form> + + <!-- Liste des articles ajoutés --> + <ul class="article-list" id="article-list"></ul> + </main> + + <script> + // Tableau qui stocke nos articles temporairement + const articles = []; + + // Fonction pour réafficher la liste complète + function renderArticles() { + const articleList = document.getElementById('article-list'); + // On vide la liste avant de la reconstruire + articleList.innerHTML = ''; + + // Pour chaque article du tableau, on crée un <li> et on l'ajoute + articles.forEach((article, index) => { + const li = document.createElement('li'); + li.innerHTML = ` + <div> + <strong>${article.title}</strong> - ${article.price} €<br> + ${article.description} + </div> + <button onclick="deleteArticle(${index})">Supprimer</button> + `; + articleList.appendChild(li); + }); + } + + // Supprimer un article en cliquant sur "Supprimer" + function deleteArticle(index) { + if (confirm('Voulez-vous vraiment supprimer cet article ?')) { + articles.splice(index, 1); // Retire l'article du tableau + renderArticles(); // Mets à jour l'affichage + } + } + + // Gestionnaire du formulaire : ajouter un nouvel article + document.getElementById('add-article-form').addEventListener('submit', function (e) { + e.preventDefault(); + + const titleField = document.getElementById('article-title'); + const descField = document.getElementById('article-description'); + const priceField = document.getElementById('article-price'); + + const title = titleField.value.trim(); + const description = descField.value.trim(); + const price = parseFloat(priceField.value); + + // Petite vérification + if (!title || !description || isNaN(price)) { + alert('Veuillez remplir tous les champs correctement.'); + return; + } + + // Ajout dans le tableau + articles.push({ title, description, price }); + + // Réaffiche la liste mise à jour + renderArticles(); + + // Réinitialise les champs + titleField.value = ''; + descField.value = ''; + priceField.value = ''; + }); + + // Initialisation : on affiche la liste (vide) au chargement + renderArticles(); + </script> + +</body> +</html> diff --git a/templates/ePhone.html b/templates/ePhone.html new file mode 100644 index 0000000000000000000000000000000000000000..9dccf2f3a73b7df47acfb7084e8e4bb35dae3fdc --- /dev/null +++ b/templates/ePhone.html @@ -0,0 +1,166 @@ +<!DOCTYPE html> +<html lang="fr"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>ePhone - Pear</title> + <style> + /* Réinitialisation des styles */ + body, h1, p, nav, footer { + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; + } + body { + background: #f4f4f4; + color: #333; + } + header { + background: white; /* Fond blanc */ + width: 100%; /* S'étend sur toute la largeur */ + border-bottom: 1px solid #eaeaea; + padding: 10px 0; /* Espacement vertical */ + display: flex; + justify-content: space-between; /* Espacement entre le logo et le menu */ + align-items: center; + padding-left: 20px; /* Espacement à gauche pour le logo */ + } + .logo { + display: flex; + align-items: center; + gap: 10px; + } + .logo img { + height: 30px; + width: auto; + } + nav { + display: flex; + justify-content: center; /* Centre le contenu horizontalement */ + gap: 20px; /* Espace entre les liens */ + flex-grow: 1; /* Permet au nav de prendre toute la largeur restante */ + text-align: center; /* Centre le texte des liens */ + } + nav a { + text-decoration: none; + color: #333; + font-weight: normal; + font-size: 1em; + padding: 10px 15px; + } + nav a:hover { + text-decoration: underline; + } + .product-section { + text-align: center; + margin-top: 30px; + } + .product-list { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 30px; + margin-top: 30px; + } + .product-item { + border: 1px solid #ddd; + border-radius: 15px; + padding: 30px; + width: 300px; + background: #fff; + text-align: center; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + transition: transform 0.3s; + } + .product-item:hover { + transform: translateY(-5px); + } + .product-item img { + width: 100%; + height: auto; + max-height: 300px; + object-fit: cover; + margin-bottom: 15px; + border-radius: 10px; + } + .product-item h2 { + font-size: 1.4em; + margin-bottom: 15px; + } + .product-item p { + font-size: 1em; + color: #666; + margin-bottom: 20px; + } + .product-item a { + text-decoration: none; + color: #fff; + background: #0078d7; + padding: 10px 20px; + border-radius: 5px; + font-weight: bold; + transition: background 0.3s; + } + .product-item a:hover { + background: #005bb5; + } + footer { + text-align: center; + padding: 20px; + font-size: 0.9em; + color: #777; + border-top: 1px solid #ccc; + margin-top: 30px; + } + </style> +</head> +<body> + <header> + <div class="logo"> + <img src="https://1.bp.blogspot.com/_TkI9VbsKljk/Sx1UNvbXWSI/AAAAAAAAA_4/H-27hwu9C-o/s400/birneKopie.jpg" alt="Logo Pear"> <!-- Remplace l'URL par celle de ton logo --> + </div> + <nav> + <a href="/">Accueil</a> + <a href="/admin">Administrateur</a> + </nav> + </header> + + <section class="product-section"> + <h1>Découvrez nos ePhones</h1> + <div class="product-list"> + <div class="product-item"> + <img src="https://store.storeimages.cdn-apple.com/4668/as-images.apple.com/is/iphone16promax-digitalmat-gallery-1-202409?wid=728&hei=666&fmt=p-jpg&qlt=95&.v=1723843667239" alt="ePhone 16 Pro Max"> + <h2>ePhone 16 Pro Max</h2> + <p>A partir de 900 €</p> + <p>Le dernier modèle avec des fonctionnalités révolutionnaires.</p> + <a href="/ePhone16ProMax">Voir l'article</a> + </div> + <div class="product-item"> + <img src="https://store.storeimages.cdn-apple.com/4668/as-images.apple.com/is/iphone16promax-digitalmat-gallery-1-202409?wid=728&hei=666&fmt=p-jpg&qlt=95&.v=1723843667239" alt="ePhone 16 Pro"> + <h2>ePhone 16 Pro</h2> + <p>A partir de 800 €</p> + <p>Des performances élevées et une autonomie incroyable.</p> + <a href="/ePhone16Pro">Voir l'article</a> + </div> + <div class="product-item"> + <img src="https://store.storeimages.cdn-apple.com/4668/as-images.apple.com/is/iphone16plus-digitalmat-gallery-1-202409?wid=728&hei=666&fmt=p-jpg&qlt=95&.v=1723669964512" alt="ePhone 16 Plus"> + <h2>ePhone 16 Plus</h2> + <p>A partir de 700 €</p> + <p>Compact, puissant et abordable.</p> + <a href="/ePhone16Plus">Voir l'article</a> + </div> + <div class="product-item"> + <img src="https://store.storeimages.cdn-apple.com/4668/as-images.apple.com/is/iphone16-digitalmat-gallery-1-202409?wid=728&hei=666&fmt=p-jpg&qlt=95&.v=1723669127470" alt="ePhone 16"> + <h2>ePhone 16</h2> + <p>A partir de 600 €</p> + <p>Le modèle classique, revisité pour durer.</p> + <a href="/ePhone16">Voir l'article</a> + </div> + </div> + </section> + + <footer> + © 2025 Pear Inc. Tous droits réservés. + </footer> +</body> +</html> diff --git a/templates/ePhone16ProMax.html b/templates/ePhone16ProMax.html new file mode 100644 index 0000000000000000000000000000000000000000..e9530828f21e9f4bb51245794d96ccd79f9bf22f --- /dev/null +++ b/templates/ePhone16ProMax.html @@ -0,0 +1,140 @@ +<!DOCTYPE html> +<html lang="fr"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>ePhone 16 Pro Max - Détails</title> + <style> + body, h1, p, form { + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; + background: #f9f9f9; + color: #333; + } + header { + background: white; + width: 100%; + padding: 20px 40px; + border-bottom: 1px solid #eaeaea; + display: flex; + justify-content: space-between; + align-items: center; + } + .logo img { + height: 40px; + width: auto; + } + main { + max-width: 900px; + margin: 50px auto; + padding: 30px; + background: white; + border-radius: 20px; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + overflow: hidden; + } + h1 { + font-size: 2.5em; + font-weight: 600; + color: #333; + margin-bottom: 15px; + } + p { + font-size: 1.1em; + line-height: 1.6; + color: #555; + margin-bottom: 30px; + } + .price { + font-size: 1.7em; + color: #0078d7; + font-weight: 600; + margin-bottom: 25px; + } + .details img { + border-radius: 15px; + max-width: 100%; + height: auto; + display: block; + margin-bottom: 20px; + } + .form-container { + background: #f1f1f1; + padding: 20px; + border-radius: 10px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + } + .form-container input { + padding: 12px; + width: 100%; + margin-bottom: 15px; + border: 1px solid #ccc; + border-radius: 10px; + font-size: 1em; + transition: border-color 0.3s ease; + } + .form-container input:focus { + border-color: #0078d7; + outline: none; + } + .form-container button { + padding: 12px; + width: 100%; + background-color: #0078d7; + color: white; + border: none; + border-radius: 10px; + font-size: 1.2em; + cursor: pointer; + transition: background-color 0.3s ease; + } + .form-container button:hover { + background-color: #005bb5; + } + </style> +</head> +<body> + <header> + <div class="logo"> + <img src="https://1.bp.blogspot.com/_TkI9VbsKljk/Sx1UNvbXWSI/AAAAAAAAA_4/H-27hwu9C-o/s400/birneKopie.jpg" alt="Logo Pear"> + </div> + </header> + + <main> + <h1>ePhone 16 Pro Max</h1> + <div class="details"> + <img src="https://store.storeimages.cdn-apple.com/4668/as-images.apple.com/is/iphone16pro-digitalmat-gallery-3-202409?wid=728&hei=666&fmt=p-jpg&qlt=95&.v=1723843057832" alt="ePhone 16 Pro Max"> + <p>Découvrez l'ePhone 16 Pro Max, un smartphone révolutionnaire avec des fonctionnalités haut de gamme : un écran OLED 6,7 pouces, un processeur A15 Bionic, un appareil photo de 108 MP, et bien plus encore.</p> + </div> + + <div class="price"> + Prix : 900 € + </div> + + <div class="form-container"> + <h2>Acheter maintenant</h2> + <form id="purchase-form"> + <input type="email" id="user-email" placeholder="Votre adresse email" required> + <button type="submit">Acheter</button> + </form> + </div> + </main> + + <script> + document.getElementById('purchase-form').addEventListener('submit', function (e) { + e.preventDefault(); + const email = document.getElementById('user-email').value; + const price = '900 €'; + + // Vérification de l'email + if (email) { + // Envoi d'une confirmation (simulé) + alert(`Confirmation d'achat envoyée à ${email}.\nPrix : ${price}`); + } else { + alert('Veuillez saisir une adresse email valide.'); + } + }); + </script> +</body> +</html> diff --git a/templates/index.html b/templates/index.html index ab04df295fdc7f953065b3976f815ebef2d7497a..1caafb73127d021f4c607c14b1bcef910a611e7f 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,43 +1,106 @@ <!DOCTYPE html> -<html lang="en"> +<html lang="fr"> <head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Accueil</title> - <style> - body { - font-family: Arial, sans-serif; - text-align: center; - margin: 50px; - } - h1 { - color: #333; - } - .links { - margin: 20px 0; - } - .link { - display: inline-block; - margin: 10px; - padding: 15px 25px; - background-color: #007bff; - color: white; - text-decoration: none; - border-radius: 5px; - transition: background-color 0.3s; - } - .link:hover { - background-color: #0056b3; - } - </style> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Accueil - Style Apple</title> + <style> + /* Réinitialisation de quelques styles de base */ + body, h1, p, nav, footer { + margin: 0; + padding: 0; + } + body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; + background: #fff; + color: #333; + line-height: 1.6; + } + header { + padding: 10px 20px; + border-bottom: 1px solid #eaeaea; + display: flex; + align-items: center; + justify-content: space-between; + } + .logo { + display: flex; + align-items: center; + gap: 10px; + } + .logo img { + height: 30px; + width: auto; + } + nav { + flex-grow: 1; + display: flex; + justify-content: center; + gap: 20px; + font-size: 0.9em; + } + nav a { + text-decoration: none; + color: #333; + padding: 10px; + } + nav a:hover { + text-decoration: underline; + } + .hero { + text-align: center; + padding: 100px 20px; + background: #f9f9f9; + } + .hero h1 { + font-size: 3em; + margin-bottom: 20px; + } + .hero p { + font-size: 1.2em; + color: #555; + } + footer { + text-align: center; + padding: 20px; + font-size: 0.8em; + color: #777; + border-top: 1px solid #eaeaea; + } + .product-item img { + width: 100%; + height: auto; + max-height: 300px; + object-fit: cover; + margin-bottom: 15px; + border-radius: 10px; + } + </style> </head> <body> - <h1>Bienvenue sur l'application</h1> - <p>Choisissez une action pour accéder à vos pages :</p> - - <div class="links"> - <a href="/admin" class="link">Page Administrateur</a> - <a href="/articles" class="link">Articles Disponibles</a> + <header> + <div class="logo"> + <img src="https://1.bp.blogspot.com/_TkI9VbsKljk/Sx1UNvbXWSI/AAAAAAAAA_4/H-27hwu9C-o/s400/birneKopie.jpg" alt="Logo Pear"> <!-- Remplace l'URL par celle de ton logo --> </div> + <nav> + <a href="ePhone">ePhone</a> + <a href="#">Moc</a> + <a href="#">ePad</a> + <a href="#">Watch</a> + <a href="#">TV</a> + <a href="#">Music</a> + <a href="#">Support</a> + <a href="admin">Administrateur</a> + </nav> + </header> + + <section class="hero"> + <h1>Bienvenue chez Pear</h1> + <p>Découvrez nos derniers produits et innovations.</p> + </section> + + <footer> + © 2025 Pear Inc. Tous droits réservés. + </footer> </body> </html>