mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-09 19:40:19 +00:00
Implémentation 3DSv2 + résolution bugs eboutic + amélioration pages admin (#558)
Eboutic : - Implémentation de la norme 3DSecure v2 pour les paiement par carte bancaire - Amélioration générale de l'interface utilisateur - Résolution du problème avec les caractères spéciaux dans le panier sur Safari - Réparation du cookie du panier de l'eboutic qui n'était pas fonctionnel Autre : - Mise à jour de la documentation - Mise à jour des dépendances Javascript - Suppression du code inutilisé dans `subscription/models.py` - Amélioration des pages administrateur (back-office Django) Co-authored-by: thomas girod <56346771+imperosol@users.noreply.github.com> Co-authored-by: Théo DURR <git@theodurr.fr> Co-authored-by: Julien Constant <julienconstant190@gmail.com>
This commit is contained in:
6
core/static/core/easymde/easymde.min.css
vendored
6
core/static/core/easymde/easymde.min.css
vendored
File diff suppressed because one or more lines are too long
6
core/static/core/easymde/easymde.min.js
vendored
6
core/static/core/easymde/easymde.min.js
vendored
File diff suppressed because one or more lines are too long
2
core/static/core/js/alpinejs.min.js
vendored
2
core/static/core/js/alpinejs.min.js
vendored
File diff suppressed because one or more lines are too long
4
core/static/core/js/jquery-3.1.0.min.js
vendored
4
core/static/core/js/jquery-3.1.0.min.js
vendored
File diff suppressed because one or more lines are too long
2
core/static/core/js/jquery-3.6.2.min.js
vendored
Normal file
2
core/static/core/js/jquery-3.6.2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -49,36 +49,27 @@ body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
input[type=button], input[type=submit], input[type=reset],input[type=file] {
|
||||
button, input[type=button], input[type=submit], input[type=reset],input[type=file] {
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
background-color: $background-button-color;
|
||||
padding: 0.4em;
|
||||
margin: 0.1em;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
box-shadow: $shadow-color 0px 0px 1px;
|
||||
&:hover {
|
||||
background: hsl(0, 0%, 83%);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: hsl(0, 0%, 83%);
|
||||
}
|
||||
input[type=button], input[type=submit], input[type=reset],input[type=file] {
|
||||
font-weight: bold;
|
||||
}
|
||||
button{
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
background-color: $background-button-color;
|
||||
padding: 0.4em;
|
||||
margin: 0.1em;
|
||||
font-size: 1.18em;
|
||||
border-radius: 5px;
|
||||
box-shadow: $shadow-color 0px 0px 1px;
|
||||
|
||||
button:not(:disabled), input[type=button]:not(:disabled), input[type=submit]:not(:disabled), input[type=reset]:not(:disabled),input[type=file]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: hsl(0, 0%, 83%);
|
||||
}
|
||||
}
|
||||
|
||||
input,textarea[type=text],[type=number]{
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
@ -123,6 +114,38 @@ a {
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
.collapse {
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
|
||||
.collapse-header {
|
||||
color: white;
|
||||
background-color: #354a5f;
|
||||
padding: 5px 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
.collapse-header-text {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.collapse-header-icon {
|
||||
transition: all ease-in-out 150ms;
|
||||
&.reverse {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
.collapse-body {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.shadow {
|
||||
box-shadow: rgba(60, 64, 67, .3) 0 1px 3px 0, rgba(60, 64, 67, .15) 0 4px 8px 3px;
|
||||
}
|
||||
|
||||
.w_big {
|
||||
width: 75%;
|
||||
}
|
||||
@ -135,10 +158,12 @@ a {
|
||||
width: 23%;
|
||||
}
|
||||
|
||||
.clickable:hover {
|
||||
.clickable:not(:disabled):hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
[x-cloak] { display: none !important; }
|
||||
|
||||
/*--------------------------------HEADER-------------------------------*/
|
||||
|
||||
#header_language_chooser {
|
||||
@ -170,21 +195,11 @@ header {
|
||||
background-color: $primary-neutral-dark-color;
|
||||
border-radius: 0px 0px 10px 10px;
|
||||
|
||||
// PINKTOBER
|
||||
// background-color: $pinktober;
|
||||
// border-bottom: 5px solid $pinktober-secondary;
|
||||
// margin-bottom: -5px;
|
||||
// border-radius: 0 0 5px 7px;
|
||||
|
||||
#header_logo {
|
||||
background-color: $white-color;
|
||||
padding: 0.2em;
|
||||
border-radius: 0px 0px 0px 9px;
|
||||
|
||||
//PINKTOBER
|
||||
// border-bottom: 5px solid $shadow-color;
|
||||
// border-radius: 0px 0px 0px 5px;
|
||||
// margin-bottom: -5px;
|
||||
border-radius: 0 0 0 9px;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
@ -211,14 +226,8 @@ header {
|
||||
width: 100%;
|
||||
label {
|
||||
display: inline;
|
||||
|
||||
// PINKTOBER
|
||||
// color: $pinktober-primary-text;
|
||||
}
|
||||
}
|
||||
a {
|
||||
display: button;
|
||||
}
|
||||
}
|
||||
|
||||
#header_bar {
|
||||
@ -243,16 +252,6 @@ header {
|
||||
flex: initial;
|
||||
list-style-type: none;
|
||||
margin: 0.2em 0.2em;
|
||||
|
||||
/*
|
||||
PINKTOBER
|
||||
& .fa.fa-times {
|
||||
color: $pinktober-bar-closed !important;
|
||||
}
|
||||
|
||||
& .fa.fa-check {
|
||||
color: $pinktober-bar-opened !important;
|
||||
}*/
|
||||
}
|
||||
|
||||
#header_search {
|
||||
@ -445,6 +444,36 @@ header {
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
color: white;
|
||||
min-width: 60px;
|
||||
padding: 5px 10px;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
|
||||
&.btn-blue {
|
||||
background-color: #354a5f;
|
||||
}
|
||||
|
||||
&.btn-blue:disabled {
|
||||
background-color: rgba(70, 90, 126, 0.4);
|
||||
}
|
||||
|
||||
&.btn-blue.clickable:not(:disabled):hover {
|
||||
background-color: #2c3646;
|
||||
}
|
||||
|
||||
&.btn-grey {
|
||||
background-color: grey;
|
||||
}
|
||||
|
||||
&.btn-grey.clickable:not(:disabled):hover {
|
||||
background-color:hsl(210,5%,30%);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------CONTENT------------------------------*/
|
||||
#quick_notif {
|
||||
width: 100%;
|
||||
@ -466,10 +495,7 @@ header {
|
||||
|
||||
.alert {
|
||||
margin: 10px;
|
||||
border: #fc8181 1px solid;
|
||||
background-color: rgb(255,245,245);
|
||||
border-radius: 4px;
|
||||
color: #c53030;
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
@ -477,6 +503,18 @@ header {
|
||||
align-items: center;
|
||||
text-align: justify;
|
||||
|
||||
&.alert-green {
|
||||
background-color: rgb(245, 255, 245);
|
||||
color: rgb(3, 84, 63);
|
||||
border: rgb(14, 159, 110) 1px solid;
|
||||
}
|
||||
|
||||
&.alert-red {
|
||||
background-color: rgb(255,245,245);
|
||||
color: #c53030;
|
||||
border: #fc8181 1px solid;
|
||||
}
|
||||
|
||||
.alert-main {
|
||||
flex: 2;
|
||||
}
|
||||
@ -1497,7 +1535,7 @@ textarea {
|
||||
margin: 10px 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 20p;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
.search_check {
|
||||
|
@ -1,191 +0,0 @@
|
||||
#eboutic {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
align-items: flex-start;
|
||||
column-gap: 20px;
|
||||
margin: 0 20px 20px;
|
||||
}
|
||||
|
||||
#eboutic-title {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
#eboutic h3 {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
#basket {
|
||||
min-width: 300px;
|
||||
border-radius: 8px;
|
||||
box-shadow: rgb(60 64 67 / 30%) 0 1px 3px 0, rgb(60 64 67 / 15%) 0 4px 8px 3px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#basket h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 765px) {
|
||||
#eboutic {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 10px;
|
||||
row-gap: 20px;
|
||||
}
|
||||
#eboutic-title {
|
||||
margin-bottom: 20px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
#basket {
|
||||
}
|
||||
}
|
||||
|
||||
#eboutic #basket .error-message {
|
||||
margin-top: 5px;
|
||||
background-color: #f8d7da;
|
||||
border: #f5c6cb 1px solid;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 7px;
|
||||
}
|
||||
#eboutic #basket .error-message p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#eboutic .item-list {
|
||||
margin-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#eboutic .item-list li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px
|
||||
}
|
||||
|
||||
#eboutic .item-name {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#eboutic .item-price, #eboutic .item-quantity {
|
||||
width: 65px;
|
||||
}
|
||||
|
||||
#eboutic .item-quantity {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#eboutic .fa-plus, #eboutic .fa-minus {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#eboutic .item-price {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* CSS du catalogue */
|
||||
|
||||
#eboutic #catalog {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
row-gap: 30px;
|
||||
}
|
||||
|
||||
#eboutic .category-header {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#eboutic .product-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 15px;
|
||||
row-gap: 15px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 765px) {
|
||||
#eboutic #catalog {
|
||||
row-gap: 15px;
|
||||
}
|
||||
|
||||
#eboutic section {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#eboutic .product-group {
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
|
||||
#eboutic .product-button {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
min-width: 120px;
|
||||
max-width: 150px;
|
||||
padding: 10px;
|
||||
overflow: hidden;
|
||||
box-shadow: rgb(60 64 67 / 30%) 0 1px 3px 0, rgb(60 64 67 / 15%) 0 4px 8px 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
#eboutic .product-button:active {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#eboutic .product-button img, #eboutic .product-button .fa {
|
||||
margin: 0;
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
#eboutic .product-button p {
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#eboutic .catalog-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
column-gap: 30px;
|
||||
margin: 30px 0 0;
|
||||
}
|
||||
|
||||
#eboutic input {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
#eboutic .catalog-buttons button {
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
color: white;
|
||||
min-width: 60px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#eboutic .catalog-buttons .validate {
|
||||
background-color: #354a5f;
|
||||
}
|
||||
#eboutic .catalog-buttons .clear {
|
||||
background-color: gray;
|
||||
}
|
||||
#eboutic .catalog-buttons button i {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
#eboutic .catalog-buttons button.validate:hover {
|
||||
background-color: #2c3646;
|
||||
}
|
||||
|
||||
#eboutic .catalog-buttons button.clear:hover {
|
||||
background-color:hsl(210,5%,30%);
|
||||
}
|
||||
|
||||
#eboutic .catalog-buttons form {
|
||||
margin: 0;
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
function getCookie(name) {
|
||||
let cookieValue = null;
|
||||
if (document.cookie && document.cookie !== '') {
|
||||
const cookies = document.cookie.split(';');
|
||||
for (let i = 0; i < cookies.length; i++) {
|
||||
const cookie = cookies[i].trim();
|
||||
// Does this cookie string begin with the name we want?
|
||||
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
||||
|
||||
function get_starting_items() {
|
||||
const cookie = getCookie("basket_items")
|
||||
try {
|
||||
// django cookie backend does an utter mess on non-trivial data types
|
||||
// so we must perform a conversion of our own
|
||||
const biscuit = JSON.parse(JSON.parse(cookie.replace(/\\054/g, ',')));
|
||||
if (Array.isArray(biscuit)) {
|
||||
return biscuit;
|
||||
}
|
||||
return [];
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('basket', () => ({
|
||||
items: get_starting_items(),
|
||||
|
||||
get_total() {
|
||||
let total = 0;
|
||||
for (const item of this.items) {
|
||||
total += item["quantity"] * item["unit_price"];
|
||||
}
|
||||
return total;
|
||||
},
|
||||
|
||||
add(item) {
|
||||
item.quantity++;
|
||||
this.edit_cookies()
|
||||
},
|
||||
|
||||
remove(item_id) {
|
||||
const index = this.items.findIndex(e => e.id === item_id);
|
||||
if (index < 0) return;
|
||||
this.items[index].quantity -= 1;
|
||||
if (this.items[index].quantity === 0) {
|
||||
this.items = this.items.filter((e) => e.id !== this.items[index].id);
|
||||
}
|
||||
this.edit_cookies();
|
||||
},
|
||||
|
||||
clear_basket() {
|
||||
this.items = []
|
||||
this.edit_cookies();
|
||||
},
|
||||
|
||||
edit_cookies() {
|
||||
// a cookie survives an hour
|
||||
document.cookie = "basket_items=" + JSON.stringify(this.items) + ";Max-Age=3600";
|
||||
},
|
||||
|
||||
/**
|
||||
* Create an item in the basket if it was not already in
|
||||
* @param id : int the id of the product to add
|
||||
* @param name : String the name of the product
|
||||
* @param price : number the unit price of the product
|
||||
*/
|
||||
create_item(id, name, price) {
|
||||
let new_item = {
|
||||
id: id,
|
||||
name: name,
|
||||
quantity: 0,
|
||||
unit_price: price
|
||||
};
|
||||
this.items.push(new_item);
|
||||
this.add(new_item);
|
||||
},
|
||||
|
||||
/**
|
||||
* add an item to the basket.
|
||||
* This is called when the user click
|
||||
* on a button in the catalog (left side of the page)
|
||||
* @param id : int the id of the product to add
|
||||
* @param name : String the name of the product
|
||||
* @param price : number the unit price of the product
|
||||
*/
|
||||
add_from_catalog(id, name, price) {
|
||||
const item = this.items.find(e => e.id === id)
|
||||
if (item === undefined) {
|
||||
this.create_item(id, name, price);
|
||||
} else {
|
||||
// the user clicked on an item which is already in the basket
|
||||
this.add(item);
|
||||
}
|
||||
},
|
||||
}))
|
||||
})
|
Reference in New Issue
Block a user