Commit a31b0078 authored by Laurent Lecluse's avatar Laurent Lecluse
Browse files

Refactoring & amélioration du axios local & du flashMessenger

parent 367aa23b
Loading
Loading
Loading
Loading
Loading

js/Client/axios.js

0 → 100644
+77 −0
Original line number Diff line number Diff line
import axios from 'axios';
import flashMessenger from './flashMessenger';

// uvAxios est un clone du axops standard
let uvAxios = { ...axios};

/* Tunning d'Axios pour gérer l'interconnexion avec le serveur avec gestion des toasts */

// Permet d'afficher une animation de chargement dans un popover si l'objet submitter a été transmis
uvAxios.interceptors.request.use(config => {
    if (config.submitter) {
        let msg = config.msg ? config.msg : 'Action en cours';
        if (config.popover != undefined) {
            config.popover.dispose();
        }
        config.popover = new bootstrap.Popover(config.submitter, {
            content: "<div class=\"spinner-border text-primary\" role=\"status\">\n" +
                "  <span class=\"visually-hidden\">Loading...</span>\n" +
                "</div> " + msg,
            html: true,
            trigger: 'focus'
        });
        config.popover.show();
    }
    return config;
});

// On capte la réponse pour afficher le résultat si on avait un submitter, sinon on affiche des toasts
uvAxios.interceptors.response.use(response => {
    response.messages = response.data.messages;
    response.data = response.data.data;
    response.hasErrors = response.messages && response.messages.error && response.messages.error.length > 0 ? true : false;

    if (response.config.popover) {
        var popover = response.config.popover;

        let content = '';
        for (ns in response.messages) {
            for (mid in response.messages[ns]) {
                content += '<div class="alert fade show alert-' + (ns == 'error' ? 'danger' : ns) + '" role="alert">' + response.messages[ns][mid] + '</div>';
            }
        }

        // S'il y a un truc à afficher
        if (content) {
            popover._config.content = content;
            popover.setContent();
            setTimeout(() => {
                popover.dispose();
            }, 5000)
        } else {
            // la popover est masquée si tout est fini
            popover.dispose();
        }
    }
    if (response.messages) {
        flashMessenger.toasts(response.messages);
    }

    return response;
}, (error) => {
    let message = error.response.data;

    if (error.response.status == 403){
        message = '<h4>403 - Accès interdit</h4><br />Vous n\'êtes pas autorisé(e) à faire cette action.';
    }else{
        message = error.response.data;
    }

    flashMessenger.toast(message, 'error');
});

uvAxios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

export default {
    uvAxios
}
 No newline at end of file
+84 −25
Original line number Diff line number Diff line
function toasts(messages)
{
function toasts(messages) {
    for (let s in messages) {
        for (let m in messages[s]) {
            toast(messages[s][m], s);
@@ -8,6 +7,50 @@ function toasts(messages)
}


function toastContainer() {
    let toastContainer = document.getElementById('unicaen-vue-toast-container');
    if (!toastContainer) {
        toastContainer = document.createElement('div');
        toastContainer.id = 'unicaen-vue-toast-container';
        toastContainer.classList.add('toast-container', 'position-fixed', 'top-0', 'end-0', 'p-3');
        document.body.appendChild(toastContainer);
    }
    return toastContainer;
}


function prepareMessage(message) {
    message = removeAlert(message);
    message = removeIcon(message);

    return message;
}


function removeAlert(message) {
    const el = document.createElement("div");
    el.innerHTML = message;

    // Si on trouve une alert, alors on la retire pour éviter de faire double affichage
    const alert = el.querySelector('.alert');
    if (alert) {
        return alert.innerHTML;
    } else {
        return el.innerHTML;
    }
}


function removeIcon(message) {
    const el = document.createElement("div");
    el.innerHTML = message;

    // on masque l'icône /!\ qui fait doublon si on en trouve
    const fasIcons = el.querySelectorAll('i.fas');
    fasIcons.forEach(icon => icon.style.display = "none");

    return el.innerHTML;
}


function toast(message, severity) {
@@ -24,41 +67,57 @@ function toast(message, severity) {
        error: 'exclamation-triangle'
    };

    let toastContainer = document.getElementById('unicaen-vue-toast-container');
    if (!toastContainer) {
        toastContainer = document.createElement('div');
        toastContainer.id = 'unicaen-vue-toast-container';
        toastContainer.classList.add('toast-container', 'position-fixed', 'top-0', 'end-0', 'p-3');
        document.body.appendChild(toastContainer);
    }
    // Crée le bouton de fermeture
    const closeButton = document.createElement('button');
    closeButton.classList.add('btn-close', 'btn-close-white', 'h5');
    closeButton.style.float = 'right';
    closeButton.setAttribute('data-bs-dismiss', 'toast');
    closeButton.setAttribute('aria-label', 'Close');

    // Crée l'icône
    const icon = document.createElement('i');
    icon.classList.add('icon', 'fas', `fa-${iconClasses[severity]}`);
    icon.style.float = 'left';
    icon.style.fontSize = '26pt';
    icon.style.paddingLeft = '.4rem';
    icon.style.marginTop = '.4rem';
    icon.style.paddingRight = '1rem';

    // Crée le corps du toast
    const body = document.createElement('div');
    body.classList.add('toast-body');
    body.innerHTML = prepareMessage(message);

    // Crée le contenu du toast en ajoutant les éléments créés précédemment
    const content = document.createElement('div');
    content.appendChild(closeButton);
    content.appendChild(icon);
    content.appendChild(body);

    // Création de l'élément HTML pour le toast
    const toast = document.createElement('div');
    toast.classList.add('toast', 'show', 'text-white', bgClasses[severity] ? bgClasses[severity] : 'bg-secondary');
    toast.classList.add('toast', 'text-white', bgClasses[severity] ? bgClasses[severity] : 'bg-secondary');
    toast.setAttribute('role', 'alert');
    toast.setAttribute('aria-live', 'assertive');
    toast.setAttribute('aria-atomic', 'true');

    // On élargit le toast pour ahhicher tout ça...
    if (severity === 'error' && message.length > 500) {
        toast.setAttribute('style', 'width:700px');
    }

    const toastContent =
        '<button class="btn-close btn-close-white h5" style="float:right" data-bs-dismiss="toast" aria-label="Close"></button>' +
        '<i class="icon fas fa-' + iconClasses[severity] + '" style="float: left;font-size: 26pt;padding-left: .4rem;margin-top:.4rem;padding-right: 1rem;"></i>' +
        '<div class="toast-body">' + message + '  </div>';

    toast.innerHTML = toastContent;
    toast.appendChild(content);

    // Ajout du toast à l'élément du conteneur de toasts
    toastContainer.appendChild(toast);
    toastContainer().appendChild(toast);

    // Masquage du toast si ce n'est pas une erreur
    if (severity !== 'error') {
        setTimeout(() => {
            toast.classList.remove('show');
        }, 5000);
    }
    // Création et affichage du toast avec bootstrap
    const options = {
        animation: true,
        delay: 5000,
        autohide: severity !== 'error'
    };
    let bsToast = new bootstrap.Toast(toast, options);
    bsToast.show();
}


+2 −80
Original line number Diff line number Diff line
import axios from 'axios';
import axios from './axios';
import flashMessenger from './flashMessenger';

const unicaenVue = {
    axios: axios,
    axios: axios.uvAxios,
    flashMessenger: flashMessenger,

    /**
@@ -31,84 +31,6 @@ const unicaenVue = {
};


/* Tunning d'Axios pour gérer l'interconnexion avec le serveur avec gestion des alertes */
unicaenVue.axios.interceptors.request.use(config => {
    if (config.submitter) {
        let msg = config.msg ? config.msg : 'Action en cours';
        if (config.popover != undefined) {
            config.popover.dispose();
        }
        config.popover = new bootstrap.Popover(config.submitter, {
            content: "<div class=\"spinner-border text-primary\" role=\"status\">\n" +
                "  <span class=\"visually-hidden\">Loading...</span>\n" +
                "</div> " + msg,
            html: true,
            trigger: 'focus'
        });
        config.popover.show();
    }
    return config;
});

unicaenVue.axios.interceptors.response.use(response => {
    response.messages = response.data.messages;
    response.data = response.data.data;
    response.hasErrors = response.messages && response.messages.error && response.messages.error.length > 0 ? true : false;

    if (response.config.popover) {
        var popover = response.config.popover;

        let content = '';
        for (ns in response.messages) {
            for (mid in response.messages[ns]) {
                content += '<div class="alert fade show alert-' + (ns == 'error' ? 'danger' : ns) + '" role="alert">' + response.messages[ns][mid] + '</div>';
            }
        }

        // S'il y a un truc à afficher
        if (content) {
            popover._config.content = content;
            popover.setContent();
            setTimeout(() => {
                popover.dispose();
            }, 3000)
        } else {
            // la popover est masquée si tout est fini
            popover.dispose();
        }
    }
    if (response.messages) {
        flashMessenger.toasts(response.messages);
    }

    return response;
}, (error) => {
    let message = error.response.data;

    if (error.response.status == 403){
        message = '<h4>403 - Accès interdit</h4><br />Vous n\'êtes pas autorisé(e) à faire cette action.';
    }else if (error.response.status == 500) {
        const text = document.createElement("div");
        text.innerHTML = error.response.data;

        // on masque l'icône /!\ qui fait doublon si on en trouve
        const fasIcons = text.querySelectorAll('i.fas');
        fasIcons.forEach(icon => icon.style.display = "none");

        message = text.querySelector('.alert').innerHTML;
        if (message === undefined){
            message = error.response.data;
        }
    }else{
        message = error.response.data;
    }

    flashMessenger.toast(message, 'error');
});

unicaenVue.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';


// workaround pour rendre unicaenVue disponible de partout
window.unicaenVue = unicaenVue;