Précédente

Réalisations

Suivante

Primevère-Calculateur

Association 1901 dans le domaine de l’écologie

Projet :

Application de calcul de prix de stand exposant

Description

L’association Primevère, à l’initiative d’un des plus importants salon annuel de l’écologie à Lyon, souhaitait disposer d’une plateforme en ligne permettant à chaque exposant d’évaluer le prix de son futur stand, en fonction de critères multiples.
Le dispositif devait être facile d’utilisation, avec une séquence iterative de saisie/résultat, permettant à l’exposant d’ajuster ses options en fonction de l’évolution du prix.
Un récapitulatif des options sélectionnées et du prix total devait être téléchargeable au format pdf.

Solutions proposées

  1. Le développement d’une Web App, application développée sur mesure via une approche prioritairement front-end afin d’optimiser l’interactivité.
  2. Conception de composants JavaScript modulaires, classes de widgets interconnectés, wrappers destinés à enrichir les comportements natifs des éléments de formulaire.

Technologies

html

css

javascript (Vanilla)

php

dompdf

Mustache

Extrait code composants


export class SelectWidget{


    constructor(parameters){

        this.value      =    null;          
        this.isActive   =   true;
        this.isRequired =   true;            
        this.callbacks = {                        
            'dependance'    :   null,
            'display'       :   null
        };
         
        this.name               =   parameters.name;        
        this.containerSelector  =   parameters.container;                
        this.labelSelector      =   parameters.label;                
        this.widgetSelector     =   parameters.widget;
        this.unit               =   parameters.unit;                      
        this.changeHandler      =   this.changeHandler.bind(this);
        this.addCallback        =   this.addCallback.bind(this);
        this.setValueByLibelle  =   this.setValueByLibelle.bind(this);        
    }

    load() {
        this.container  =   document.querySelector(this.containerSelector);        
        this.label      =   document.querySelector(this.labelSelector);
        this.widget     =   document.querySelector(this.widgetSelector);
        this.setValueByIndex(0);
        this.widget.addEventListener('change', this.changeHandler, false);
    }

    changeHandler() {          
        this.value = (this.widget.value == 'null')? null : this.widget.value;
        if(this.callbacks.length>0 ){
            this.callbacks.map(function(callback){
                callback(this);
            }.bind(this));
        }       
        if(this.callbacks.dependance != null)
            this.callbacks.dependance(this); 
        if(this.callbacks.display != null)
            this.callbacks.display(this);     
              
    }    
    
    getName(){
        return this.name;
    }

    getValue() {
        this.value = (this.widget.value == 'null')? null : this.widget.value;        
        return this.value;
    }   

    getLibelle() {
        var libelle = '';
        Array.from(this.widget.options).map(function(option){                       
            if(option.selected == true){                   
                libelle = option.text;
            }
        }.bind(this));
        return libelle;
    }

    isLibelleSelected(libelle){ 
        var selected = false       
        Array.from(this.widget.options).map(function(option){
            if(option.selected == true){
                if(option.text == libelle){
                    selected = true;                
                }                
            }            
        }.bind(this));
        return selected;
    }

    setValueByLibelle(libelle) {        
        Array.from(this.widget.options).map(function(option){
            if(option.text == libelle){                
                option.selected='selected';  
                this.value = option.value;
            }            
        }.bind(this));
    }

    setValueByIndex(index){        
        this.widget.options[index].selected='selected';        
        this.value = this.widget.options[index].value;       
    }   

    setStyles(element, styles) {
        for(var style in styles){
            element.style[style] = styles[style];
        }
    }

    setRequired(required){
        this.isRequired = required;       
    }

    show(){        
        this.isActive = true;
        this.setRequired(true);        
        this.setStyles(this.container, {display: 'block'});
    }

    hide(){        
        this.isActive = false;
        this.setRequired(false);
        this.setValueByIndex(0);
        this.setStyles(this.container, {display: 'none'});
    }

    addCallback(callbackname, callback) {        
        this.callbacks[callbackname] = callback;
    }

}

export class WidgetsManager {


    constructor() {

        this.allWidgetsList = [];
        this.points = 0;
        this.selecteds = [];
        this.constante_calcul = 0;
        this.droits_entree_base = 0;
        this.callbacks = {
            'display': null
        };        
        this.load = this.load.bind(this);
        this.getPoints = this.getPoints.bind(this);
        this.requiredWidgetsList = [];
        this.unrequiredWidgetsList = [];
        this.pointsWidgetsList = [];
        this.eurosWidgetsList = [];
    }

    setConstantes(constantes) {
        this.constante_calcul = constantes.constante_calcul;
        this.droits_entree_base = constantes.droits_entree_base;
    }

    load() {
        this.allWidgetsList.map(function (widget) {
            widget.addCallback('display', this.callbacks.display);
        }.bind(this));
    }

    addWidgets(list) {        
        list.map(function(item){
            if(item[1] == 'required'){
                this.requiredWidgetsList.push(item[0]);
            }
            if(item[1] == 'unrequired'){
                this.unrequiredWidgetsList.push(item[0]);
            }
            if(item[2] == 'point'){                
                this.pointsWidgetsList.push(item[0]);
            }
            if(item[2] == 'euro'){
                this.eurosWidgetsList.push(item[0]);
            }
            this.allWidgetsList.push(item[0]);
        }.bind(this));
    }    
     
    getPoints() {        
        var points = this.getSum(this.pointsWidgetsList);        
        return points;
    }

    getEuros(){        
        var euros = this.getSum(this.eurosWidgetsList);
        return euros;
    }

    getSum(widgetlist){
        var sum = 0;
        widgetlist.map(function(widget){
            if(widget.isActive == true){
                var value = (widget.getValue() == null) ? 0 : widget.getValue(); 
                if (value.toString().indexOf('/') != -1) {
                    var value = parseFloat(value.toString().split(' ')[1]);
                    sum = sum / value;
                }
                else if (value.toString().indexOf('x') != -1) {
                    var value = parseFloat(value.toString().split(' ')[1]);
                    sum = sum * value;
                }
                else {
                    sum += parseFloat(value);
                }   
            }    
        });
        return sum;
    }

    getUnselectedRequiredWidgets(){
        var widgetsList = [];
        this.requiredWidgetsList.map(function(widget){
            if(widget.isActive == true && widget.getValue() == null){
                widgetsList.push(widget);
            }
        });
        return widgetsList;
    }    
    
    getIndice(coefficient, points) {
        var indice = null;
        if (points != null && coefficient != null) {
            indice = parseFloat(points) * parseFloat(coefficient);
        }
        return indice;
    }

    getSurface(profondeur, longueur) {
        var surface = null;
        if (profondeur != null && longueur != null) {
            surface = parseFloat(profondeur) * parseFloat(longueur);
        }
        return surface;
    }

    getPrixStand(surface, indice, profondeur, angles) {
        if(this.getUnselectedRequiredWidgets().length>0) return 0;
        var prixStand = 0;
        if (surface != null
            && indice != null
            && angles != null
            && profondeur != null) {
            prixStand = (surface * indice) + (indice * this.constante_calcul * profondeur * angles);
        }
        return prixStand;
    }  

    
    getPrixElectricite_old(tarification, puissance) {
        if (tarification == null || puissance == null) return 0;
        var base = parseFloat(tarification);
        var watts = parseFloat(puissance);
        var pas = watts / 100;
        var prix = 0;
        if (base == 47.5) {
            prix = base + (pas * 21.5);
        }
        if (base == 218) {
            prix = base + (pas * 7.5);
        }
        return prix;
    }



    getPrixElectricite(tarification, puissance, parametres_electricite) {
        if (tarification.getValue() == null || puissance.getValue() == null) return 0;        
        var pas = parseFloat(parametres_electricite.puissance.pas);
        var base = parseFloat(tarification.getValue());
        var puissance = parseFloat(puissance.getValue());
        var multiplicateur;
        parametres_electricite.tarifs.map(function(tarif){
            if (parseFloat(tarif.base) == base){        
                multiplicateur = parseFloat(tarif.multiplicateur);
            }
        });        
        var segments = puissance / pas;        
        var prix = 0;
        prix = base + ((segments - 1) * multiplicateur);        
        return prix;
    }


    
    getValueDisplay(value, unit){
        var valueDisplay = '';
        if (value.toString().indexOf('/') != -1) {          
            valueDisplay = 'Total ' + unit + 's / ' + parseFloat(value.toString().split(' ')[1]);                 
        }
        else if (value.toString().indexOf('x') != -1) {          
            valueDisplay = 'Total '+ unit + 's x ' + parseFloat(value.toString().split(' ')[1]);                 
        }
        else{
            if(unit == 'euro'){
                valueDisplay = this.formatEuros(value);
            }
            else if(unit == 'point'){   
                valueDisplay = value + ' pt(s)';
            }            
        }
        return valueDisplay;
    }
    

    formatEuros(value) {
        var formatter = new Intl.NumberFormat('fr-FR', {
            style: 'currency',
            currency: 'EUR'
        });
        return formatter.format(value);       
    }

    
    toggleWidgetsContainers() {
        var containers = Array.from(document.querySelectorAll('.widgets-container-list'));
        for (var i = 0; i < containers.length; i++) {
            var container = containers[i];
            var subcontainers = Array.from(container.querySelectorAll('.widget-container'));
            var undisplays = 0;
            for (var j = 0; j < subcontainers.length; j++) {
                var subcontainer = subcontainers[j];
                var display = window.getComputedStyle(subcontainer, null).getPropertyValue('display');
                if (display == 'none') undisplays++;
            }
            if (undisplays == subcontainers.length) {
                container.style.display = 'none';
            }
            else {
                container.style.display = 'block';
            }
        }
    }

    showModal(body, title) {
        var modal = $('.modal');
        modal.find('.modal-title').html(title);
        modal.find('.modal-body').html(body);
        modal.modal('toggle');
    }


    addCallback(callbackname, callback) {
        this.callbacks[callbackname] = callback;
    }

}

Charte graphique