<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Preview Layout</title>
    <link media="all" rel="stylesheet" href="../../css/plyr.css">
    <link media="all" rel="stylesheet" href="../../css/swiper-bundle.min.css">
    <link media="all" rel="stylesheet" href="../../css/styles.css">
    <script>
        window.APP = {
            modules: {},
            addModule: function(name, config) {
                this.modules[name] = this.modules[name] || [];
                this.modules[name].push(config);
            },
            DEBUG: 0,
            CONFIG: {},
        };
    </script>

    <style>
        body {
            margin: 25px !important;
        }
    </style>
</head>

<body style="background-color: " class="antialiased text-base font-sans ">
    <script>
        'use strict';
        (function(hyva, undefined) {
            function lifetimeToExpires(options, defaults) {
                const lifetime = options.lifetime || defaults.lifetime;
                if (lifetime) {
                    const date = new Date;
                    date.setTime(date.getTime() + lifetime * 1000);
                    return date;
                }
                return null;
            }

            function generateRandomString() {
                const allowedCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
                    length = 16;
                let formKey = '',
                    charactersLength = allowedCharacters.length;
                for (let i = 0; i < length; i++) {
                    formKey += allowedCharacters[Math.round(Math.random() * (charactersLength - 1))]
                }
                return formKey;
            }
            const sessionCookieMarker = {
                noLifetime: true
            }
            const cookieTempStorage = {};
            const internalCookie = {
                get(name) {
                    const v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
                    return v ? v[2] : null;
                },
                set(name, value, days, skipSetDomain) {
                    let expires,
                        path,
                        domain,
                        secure,
                        samesite;
                    const defaultCookieConfig = {
                        expires: null,
                        path: '/',
                        domain: null,
                        secure: false,
                        lifetime: null,
                        samesite: 'lax'
                    };
                    const cookieConfig = window.COOKIE_CONFIG || {};
                    expires = days && days !== sessionCookieMarker ?
                        lifetimeToExpires({
                            lifetime: 24 * 60 * 60 * days,
                            expires: null
                        }, defaultCookieConfig) :
                        lifetimeToExpires(window.COOKIE_CONFIG, defaultCookieConfig) || defaultCookieConfig.expires;
                    path = cookieConfig.path || defaultCookieConfig.path;
                    domain = !skipSetDomain && (cookieConfig.domain || defaultCookieConfig.domain);
                    secure = cookieConfig.secure || defaultCookieConfig.secure;
                    samesite = cookieConfig.samesite || defaultCookieConfig.samesite;
                    document.cookie = name + "=" + encodeURIComponent(value) +
                        (expires && days !== sessionCookieMarker ? '; expires=' + expires.toGMTString() : '') +
                        (path ? '; path=' + path : '') +
                        (domain ? '; domain=' + domain : '') +
                        (secure ? '; secure' : '') +
                        (samesite ? '; samesite=' + samesite : 'lax');
                },
                isWebsiteAllowedToSaveCookie() {
                    const allowedCookies = this.get('user_allowed_save_cookie');
                    if (allowedCookies) {
                        const allowedWebsites = JSON.parse(unescape(allowedCookies));
                        return allowedWebsites[CURRENT_WEBSITE_ID] === 1;
                    }
                    return false;
                },
                getGroupByCookieName(name) {
                    const cookieConsentConfig = window.cookie_consent_config || {};
                    let group = null;
                    for (let prop in cookieConsentConfig) {
                        if (!cookieConsentConfig.hasOwnProperty(prop)) continue;
                        if (cookieConsentConfig[prop].includes(name)) {
                            group = prop;
                            break;
                        }
                    }
                    return group;
                },
                isCookieAllowed(name) {
                    const cookieGroup = this.getGroupByCookieName(name);
                    return cookieGroup ?
                        window.cookie_consent_groups[cookieGroup] :
                        this.isWebsiteAllowedToSaveCookie();
                },
                saveTempStorageCookies() {
                    for (const [name, data] of Object.entries(cookieTempStorage)) {
                        if (this.isCookieAllowed(name)) {
                            this.set(name, data['value'], data['days'], data['skipSetDomain']);
                            delete cookieTempStorage[name];
                        }
                    }
                }
            };
            hyva.getCookie = (name) => {
                const cookieConfig = window.COOKIE_CONFIG || {};
                if (cookieConfig.cookie_restriction_enabled && !internalCookie.isCookieAllowed(name)) {
                    return cookieTempStorage[name] ? cookieTempStorage[name]['value'] : null;
                }
                return internalCookie.get(name);
            }
            hyva.setCookie = (name, value, days, skipSetDomain) => {
                const cookieConfig = window.COOKIE_CONFIG || {};
                if (cookieConfig.cookie_restriction_enabled && !internalCookie.isCookieAllowed(name)) {
                    cookieTempStorage[name] = {
                        value,
                        days,
                        skipSetDomain
                    };
                    return;
                }
                return internalCookie.set(name, value, days, skipSetDomain);
            }
            hyva.setSessionCookie = (name, value, skipSetDomain) => {
                return hyva.setCookie(name, value, sessionCookieMarker, skipSetDomain)
            }
            hyva.getBrowserStorage = () => {
                const browserStorage = window.localStorage || window.sessionStorage;
                if (!browserStorage) {
                    console.warn('Browser Storage is unavailable');
                    return false;
                }
                try {
                    browserStorage.setItem('storage_test', '1');
                    browserStorage.removeItem('storage_test');
                } catch (error) {
                    console.warn('Browser Storage is not accessible', error);
                    return false;
                }
                return browserStorage;
            }
            hyva.postForm = (postParams) => {
                const form = document.createElement("form");
                let data = postParams.data;
                if (!postParams.skipUenc && !data.uenc) {
                    data.uenc = btoa(window.location.href);
                }
                form.method = "POST";
                form.action = postParams.action;
                Object.keys(postParams.data).map(key => {
                    const field = document.createElement("input");
                    field.type = 'hidden'
                    field.value = postParams.data[key];
                    field.name = key;
                    form.appendChild(field);
                });
                const form_key = document.createElement("input");
                form_key.type = 'hidden';
                form_key.value = hyva.getFormKey();
                form_key.name = "form_key";
                form.appendChild(form_key);
                document.body.appendChild(form);
                form.submit();
            }
            hyva.getFormKey = function() {
                let formKey = hyva.getCookie('form_key');
                if (!formKey) {
                    formKey = generateRandomString();
                    hyva.setCookie('form_key', formKey);
                }
                return formKey;
            }
            hyva.formatPrice = (value, showSign, options = {}) => {
                const formatter = new Intl.NumberFormat(
                    'en-US',
                    Object.assign({
                        style: 'currency',
                        currency: 'EUR',
                        signDisplay: showSign ? 'always' : 'auto'
                    }, options)
                );
                return (typeof Intl.NumberFormat.prototype.formatToParts === 'function') ?
                    formatter.formatToParts(value).map(({
                        type,
                        value
                    }) => {
                        switch (type) {
                            case 'currency':
                                return '€' || value;
                            case 'minusSign':
                                return '- ';
                            case 'plusSign':
                                return '+ ';
                            default:
                                return value;
                        }
                    }).reduce((string, part) => string + part) :
                    formatter.format(value);
            }
            /**
             * Internal string replacement function implementation, see hyva.str() for usage details.
             *
             * @param string str Template string with optional placeholders
             * @param int nStart Offset for placeholders, 0 means %0 is replaced with args[0], 1 means %1 is replaced with args[0]
             * @param array ...args Positional replacement arguments. Rest arguments support isn't at 97% yet, so Array.from(arguments).slice() is used instead.
             */
            const formatStr = function(str, nStart) {
                const args = Array.from(arguments).slice(2);
                return str.replace(/(%+)([0-9]+)/g, (m, p, n) => {
                    const idx = parseInt(n) - nStart;
                    if (args[idx] === null || args[idx] === void 0) {
                        return m;
                    }
                    return p.length % 2 ?
                        p.slice(0, -1).replace('%%', '%') + args[idx] :
                        p.replace('%%', '%') + n;
                })
            }
            /**
             * Replace positional parameters like %1 in string with the rest argument in the matching position.
             * The first rest argument replaces %1, the second %2 and so on.
             *
             * Example: hyva.str('%3 %2 %1', 'a', 'b', 'c') => "c b a"
             *
             * To insert a literal % symbol followed by a number, duplicate the %, for example %%2 is returned as %2.
             */
            hyva.str = function(string) {
                const args = Array.from(arguments);
                args.splice(1, 0, 1);
                return formatStr.apply(undefined, args);
            }
            /**
             * Zero based version of hyva.str(): the first rest argument replaces %0, the second %1 and so on.
             *
             * Example: hyva.strf('%2 %1 %0', 'a', 'b', 'c') => "c b a"
             *
             * If in doubt whether to use hyva.str() or hyva.strf(), prefer hyva.str() because it is more similar to __()
             * and it might be possible to reuse existing phrase translations with placeholders.
             */
            hyva.strf = function() {
                const args = Array.from(arguments);
                args.splice(1, 0, 0);
                return formatStr.apply(undefined, args);
            }
            /**
             * Take a html string as `content` parameter and
             * extract an element from the DOM to replace in
             * the current page under the same selector,
             * defined by `targetSelector`
             */
            hyva.replaceDomElement = (targetSelector, content) => {
                // Parse the content and extract the DOM node using the `targetSelector`
                const parser = new DOMParser();
                const doc = parser.parseFromString(content, 'text/html');
                const contentNode = doc.querySelector(targetSelector);
                // Bail if content can't be found
                if (!contentNode) {
                    return;
                }
                hyva.activateScripts(contentNode)
                // Replace the old DOM node with the new content
                document.querySelector(targetSelector).replaceWith(contentNode);
                // Reload customerSectionData and display cookie-messages if present
                window.dispatchEvent(new CustomEvent("reload-customer-section-data"));
                hyva.initMessages();
            }
            hyva.activateScripts = (contentNode) => {
                // Extract all the script tags from the content.
                // Script tags won't execute when inserted into a dom-element directly,
                // therefore we need to inject them to the head of the document.
                const tmpScripts = contentNode.getElementsByTagName('script');
                if (tmpScripts.length > 0) {
                    // Push all script tags into an array
                    // (to prevent dom manipulation while iterating over dom nodes)
                    const scripts = [];
                    for (let i = 0; i < tmpScripts.length; i++) {
                        scripts.push(tmpScripts[i]);
                    }
                    // Iterate over all script tags and duplicate+inject each into the head
                    for (let i = 0; i < scripts.length; i++) {
                        let script = document.createElement('script');
                        script.innerHTML = scripts[i].innerHTML;
                        document.head.appendChild(script);
                        // Remove the original (non-executing) node from the content
                        scripts[i].parentNode.removeChild(scripts[i]);
                    }
                }
                return contentNode;
            }
            /**
             * Return base64 encoded current URL that can be used by Magento to redirect the visitor back to the current page.
             * The func hyva.getUenc handles additional encoding of +, / and = like \Magento\Framework\Url\Encoder::encode().
             */
            const replace = {
                ['+']: '-',
                ['/']: '_',
                ['=']: ','
            };
            hyva.getUenc = () => btoa(window.location.href).replace(/[+/=]/g, match => replace[match]);
            let currentTrap;
            const focusableElements = (rootElement) => {
                const selector = 'button, [href], input, select, textarea, details, [tabindex]:not([tabindex="-1"]';
                return Array.from(rootElement.querySelectorAll(selector))
                    .filter(el => {
                        return el.style.display !== 'none' &&
                            !el.disabled &&
                            el.tabIndex !== -1 &&
                            (el.offsetWidth || el.offsetHeight || el.getClientRects().length)
                    })
            }
            const focusTrap = (e) => {
                const isTabPressed = e.key === 'Tab' || e.keyCode === 9;
                if (!isTabPressed) return;
                const focusable = focusableElements(currentTrap)
                const firstFocusableElement = focusable[0]
                const lastFocusableElement = focusable[focusable.length - 1]
                e.shiftKey ?
                    document.activeElement === firstFocusableElement && (lastFocusableElement.focus(), e.preventDefault()) :
                    document.activeElement === lastFocusableElement && (firstFocusableElement.focus(), e.preventDefault())
            };
            hyva.releaseFocus = (rootElement) => {
                if (currentTrap && (!rootElement || rootElement === currentTrap)) {
                    currentTrap.removeEventListener('keydown', focusTrap)
                    currentTrap = null
                }
            }
            hyva.trapFocus = (rootElement) => {
                if (!rootElement) return;
                hyva.releaseFocus()
                currentTrap = rootElement
                rootElement.addEventListener('keydown', focusTrap)
                const firstElement = focusableElements(rootElement)[0]
                firstElement && firstElement.focus()
            }
            hyva.alpineInitialized = (fn) => window.addEventListener('alpine:initialized', fn, {
                once: true
            })
            window.addEventListener('alpine:initialized', () => {
                console.log('Alpine.js initialized')
            })
            window.addEventListener('user-allowed-save-cookie', () => internalCookie.saveTempStorageCookies())
        }(window.hyva = window.hyva || {}));
    </script>
    <button type="button" x-data x-init="$store.asideBlocs.addAside('')" @click="$store.asideBlocs.toggleAside('')" class="max-md:btn-size-md btn btn-dark ">
        Open side panel

    </button>

    <script src="../../js/gsap.min.js" defer crossorigin></script>
    <script src="../../js/scrollTrigger.min.js" defer crossorigin></script>
    <script src="../../js/swiper-bundle.min.js" defer crossorigin></script>
    <script type="module" src="../../js/anchor.min.js" defer crossorigin></script>
    <script type="module" src="../../js/persist.min.js" defer crossorigin></script>
    <script type="module" src="../../js/intersect.min.js" defer crossorigin></script>
    <script type="module" src="../../js/plyr.min.js" defer crossorigin></script>
    <script type="module" src="../../js/collapse.min.js" defer crossorigin></script>
    <script type="module" src="../../js/alpine3.min.js" defer crossorigin></script>
    <script>
        (g => {
            var h, a, k, p = "The Google Maps JavaScript API",
                c = "google",
                l = "importLibrary",
                q = "__ib__",
                m = document,
                b = window;
            b = b[c] || (b[c] = {});
            var d = b.maps || (b.maps = {}),
                r = new Set,
                e = new URLSearchParams,
                u = () => h || (h = new Promise(async (f, n) => {
                    await (a = m.createElement("script"));
                    e.set("libraries", [...r] + "");
                    for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]);
                    e.set("callback", c + ".maps." + q);
                    a.src = `https://maps.${c}apis.com/maps/api/js?` + e;
                    d[q] = f;
                    a.onerror = () => h = n(Error(p + " could not load."));
                    a.nonce = m.querySelector("script[nonce]")?.nonce || "";
                    m.head.append(a)
                }));
            d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n))
        })({
            key: "AIzaSyAmlBHNWuFlAL7elylRqvhRn4MD7ko0sWs",
            v: "weekly",
            // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
            // Add other bootstrap parameters as needed, using camel case.
        });
    </script>
    <script src="../../js/markerclusterer.min.js" defer crossorigin></script>

    <script>
        window.addEventListener('alpine:init', () => {
            console.log('Alpine.js has been initialized');
            Alpine.store('screen', {
                isMobile: window.matchMedia('(max-width: 768px)').matches,
                isTablet: window.matchMedia('(max-width: 1024px)').matches,
                // Méthode d'initialisation pour mettre à jour `isMobile` en fonction de la taille de l'écran
                init() {
                    const mobileMedia = window.matchMedia('(max-width: 768px)');
                    const tabletMedia = window.matchMedia('(max-width: 1024px)');
                    this.isMobile = mobileMedia.matches;
                    this.isTablet = tabletMedia.matches;
                    const updateScreen = (event, type) => {
                        if (type === 'mobile') this.isMobile = event.matches;
                        if (type === 'tablet') this.isTablet = event.matches;
                    };
                    [{
                            media: mobileMedia,
                            type: 'mobile'
                        },
                        {
                            media: tabletMedia,
                            type: 'tablet'
                        }
                    ].forEach(({
                        media,
                        type
                    }) => {
                        if (typeof media.onchange !== 'object') {
                            media.addListener((e) => updateScreen(e, type));
                        } else {
                            media.addEventListener('change', (e) => updateScreen(e, type));
                        }
                    });
                }
            });
            Alpine.store('filter', {
                filters: [],
                getFilter(type, value) {
                    return this.filters.some((filter) => filter.type === type && filter.value === value);
                },
                toggleFilter(type, value) {
                    const filterArray = this.filters.selected[type];
                    const index = filterArray.indexOf(value);
                    if (index === -1) {
                        filterArray.push(value);
                    } else {
                        filterArray.splice(index, 1);
                    }
                    this.applyFilters();
                },
                clearFilters() {
                    this.filters = [];
                }
            });
            Alpine.store('asideBlocs', {
                asides: [],
                // Ajouter un nouvel aside au tableau
                addAside(name, customProperties = {}) {
                    if (!this.asides.find(aside => aside.name === name)) {
                        this.asides.push({
                            name,
                            open: false,
                            ...customProperties, // Ajoute des propriétés spécifiques
                        });
                    }
                },
                // Supprimer un aside par son nom
                removeAside(name) {
                    this.asides = this.asides.filter(aside => aside.name !== name);
                },
                // Basculer l'état d'ouverture d'un aside
                toggleAside(name) {
                    const aside = this.asides.find(aside => aside.name === name);
                    if (aside) {
                        aside.open = !aside.open;
                        document.body.classList.toggle('overflow-hidden', aside.open);
                    }
                },
                // Fermer un aside spécifique
                closeAside(name) {
                    const aside = this.asides.find(aside => aside.name === name);
                    if (aside) {
                        aside.open = false;
                        document.body.classList.remove('overflow-hidden');
                    }
                },
                // Ouvrir un aside spécifique
                openAside(name) {
                    const aside = this.asides.find(aside => aside.name === name);
                    if (aside) {
                        aside.open = true;
                        document.body.classList.add('overflow-hidden');
                    }
                }
            });
            Alpine.store('locator', {
                allStores: [], // Liste complète des magasins
                countStore: "",
                filteredStores: [], // Liste des magasins filtrés
                filteredDistanceStores: null, //Liste des magasins trié par distance
                selectedStore: null, // Magasin sélectionné
                isAudio: false, // Type de magasin affiché (true = audio, false = optique)
                loading: true, // État de chargement
                mapCenter: null, // Centre lat et lng de la google map
                mapInstance: null, // Instance de la google map. ( /!\ Toutes les fonctions ne sont pas disponible )
                // Listes des filtres disponibles (extraites des données)
                filterLists: {
                    audio: {
                        mutuals: [], // Liste des mutuelles optique disponibles
                        brands: [], // Liste des marques optique disponibles
                        types: [] // Contiendra ['optic', 'teleophtalmologie'] selon disponibilité
                    },
                    optic: {
                        mutuals: [], // Liste des mutuelles optique disponibles
                        brands: [], // Liste des marques optique disponibles
                        types: [] // Contiendra ['audio', 'teleophtalmologie'] selon disponibilité
                    }
                },
                // Modification des selectedFilters pour inclure les types
                selectedFilters: {
                    audio: {
                        mutuals: [], // Mutuelles audio sélectionnées
                        brands: [], // Marques audio sélectionnées
                        types: [] // Les types sélectionnés
                    },
                    optic: {
                        mutuals: [], // Mutuelles audio sélectionnées
                        brands: [], // Marques audio sélectionnées
                        types: [] // Les types sélectionnés
                    },
                    search: ''
                },
                // Défault donnée des prises de rdv
                defaultStepperState: {
                    steps: [{
                            id: 1,
                            title: 'Où',
                            completed: true
                        },
                        {
                            id: 2,
                            title: 'Quoi',
                            completed: false
                        },
                        {
                            id: 3,
                            title: 'Quand',
                            completed: false
                        },
                        {
                            id: 4,
                            title: 'Qui',
                            completed: false
                        }
                    ],
                    completed: false,
                    currentStep: 2,
                    code_mur: null,
                    type: null,
                    data: []
                },
                // Initialisation avec persist
                stepperData: Alpine.$persist(function() {
                    return {
                        ...this.defaultStepperState
                    }
                }).as('stepperData'),
                // Getters
                get currentFilterList() {
                    return this.filterLists[this.currentType];
                },
                get currentType() {
                    return this.isAudio ? 'audio' : 'optic';
                },
                get currentSelectedFilters() {
                    return this.selectedFilters[this.currentType];
                },
                async init() {
                    try {
                        // Détection du type depuis l'URL
                        try {
                            const pathname = window.location.pathname;
                            this.isAudio = pathname.includes('/acousticien');
                        } catch (error) {
                            console.error('Erreur lors de la détection du type depuis l\'URL:', error);
                            this.isAudio = false; // Défault value
                        }
                        await this.loadLibraries();
                        await this.loadStores();
                        this.extractFiltersFromStores();
                        this.applyFilters();
                    } finally {
                        this.loading = false;
                    }
                },
                async loadLibraries() {
                    const [geometry] = await Promise.all([
                        google.maps.importLibrary("geometry"),
                    ]);
                },
                async loadStores() {
                    try {
                        const response = await fetch(`${window.location.origin}/js/json/getListv2.json`);
                        const data = await response.json();
                        if (data.success) {
                            this.countStore = data.data.totalCount ?? data.data.items.length;
                            this.allStores = data.data.items;
                        }
                    } catch (error) {
                        console.error('Erreur lors du chargement des magasins:', error);
                        this.allStores = [];
                    }
                },
                extractFiltersFromStores() {
                    const storesArray = Object.values(this.allStores);
                    // Pour les magasins Audio
                    const audioStores = storesArray.filter(store =>
                        store.locations.some(location => location.is_audio)
                    );
                    // Comptage pour les mutuelles audio
                    const audioMutualCounts = new Map();
                    audioStores.forEach(store => {
                        store.locations
                            .filter(location => location.is_audio)
                            .forEach(location => {
                                (location.mutuelles || []).forEach(mutual => {
                                    audioMutualCounts.set(mutual, (audioMutualCounts.get(mutual) || 0) + 1);
                                });
                            });
                    });
                    // Comptage pour les marques audio
                    const audioBrandCounts = new Map();
                    audioStores.forEach(store => {
                        store.locations
                            .filter(location => location.is_audio)
                            .forEach(location => {
                                (location.brands || []).forEach(brand => {
                                    audioBrandCounts.set(brand, (audioBrandCounts.get(brand) || 0) + 1);
                                });
                            });
                    });
                    // Pour les magasins Optique
                    const opticStores = storesArray.filter(store =>
                        store.locations.some(location => !location.is_audio)
                    );
                    // Comptage pour les mutuelles optique
                    const opticMutualCounts = new Map();
                    opticStores.forEach(store => {
                        store.locations
                            .filter(location => !location.is_audio)
                            .forEach(location => {
                                (location.mutuelles || []).forEach(mutual => {
                                    opticMutualCounts.set(mutual, (opticMutualCounts.get(mutual) || 0) + 1);
                                });
                            });
                    });
                    // Comptage pour les marques optique
                    const opticBrandCounts = new Map();
                    opticStores.forEach(store => {
                        store.locations
                            .filter(location => !location.is_audio)
                            .forEach(location => {
                                (location.brands || []).forEach(brand => {
                                    opticBrandCounts.set(brand, (opticBrandCounts.get(brand) || 0) + 1);
                                });
                            });
                    });
                    this.filterLists.audio = {
                        mutuals: Array.from(audioMutualCounts.entries())
                            .map(([id, count]) => ({
                                id,
                                label: id,
                                count
                            }))
                            .sort((a, b) => a.label.localeCompare(b.label)),
                        brands: Array.from(audioBrandCounts.entries())
                            .map(([id, count]) => ({
                                id,
                                label: id,
                                count
                            }))
                            .sort((a, b) => a.label.localeCompare(b.label)),
                        types: this.extractAvailableTypes(audioStores, true)
                    };
                    this.filterLists.optic = {
                        mutuals: Array.from(opticMutualCounts.entries())
                            .map(([id, count]) => ({
                                id,
                                label: id,
                                count
                            }))
                            .sort((a, b) => a.label.localeCompare(b.label)),
                        brands: Array.from(opticBrandCounts.entries())
                            .map(([id, count]) => ({
                                id,
                                label: id,
                                count
                            }))
                            .sort((a, b) => a.label.localeCompare(b.label)),
                        types: this.extractAvailableTypes(opticStores, false)
                    };
                },
                // Méthode pour extraire les types disponibles
                extractAvailableTypes(stores, isAudio) {
                    const types = new Set();
                    const counts = {
                        [isAudio ? 'optic' : 'audio']: 0,
                        teleophtalmologie: 0
                    };
                    stores.forEach(store => {
                        // Vérifie si le magasin a l'autre type de service
                        const hasOtherService = store.locations.some(location =>
                            isAudio ? !location.is_audio : location.is_audio
                        );
                        if (hasOtherService) {
                            types.add(isAudio ? 'optic' : 'audio');
                            counts[isAudio ? 'optic' : 'audio']++;
                        }
                        // Vérifie si le magasin a la téléophtalmologie
                        const hasTelephtalmology = store.locations.some(location =>
                            location.attributes.teleophtalmologie?.value === "1"
                        );
                        if (hasTelephtalmology) {
                            types.add('teleophtalmologie');
                            counts.teleophtalmologie++;
                        }
                    });
                    // Retourne un tableau d'objets avec le type et son count
                    return Array.from(types).sort().map(type => ({
                        id: type,
                        label: type,
                        count: counts[type]
                    }));
                },
                // Dans toggleStoreType du store locator
                toggleStoreType(isAudio) {
                    if (isAudio !== undefined) {
                        this.isAudio = isAudio;
                    } else {
                        this.isAudio = !this.isAudio;
                    }
                    // Mise à jour de l'URL
                    try {
                        const currentUrl = new URL(window.location.href);
                        const params = new URLSearchParams(currentUrl.search);
                        // Changer le pathname en gardant la même base
                        const newPathname = currentUrl.pathname.replace(
                            /(\/opticien|\/acousticien)/,
                            this.isAudio ? '/acousticien' : '/opticien'
                        );
                        // Construire la nouvelle URL avec les paramètres existants
                        const newUrl = `${currentUrl.origin}${newPathname}${params.toString() ? '?' + params.toString() : ''}`;
                        // Mettre à jour l'URL sans recharger la page
                        window.history.pushState({}, '', newUrl);
                    } catch (error) {
                        console.error('Erreur lors de la mise à jour de l\'URL:', error);
                    }
                    this.selectedStore = null;
                    this.clearFilters();
                    this.applyFilters();
                },
                updateFilter(category, value) {
                    const filters = this.selectedFilters[this.currentType][category];
                    const index = filters.indexOf(value.id || value);
                    if (index === -1) {
                        filters.push(value.id || value);
                    } else {
                        filters.splice(index, 1);
                    }
                },
                updateSearchTerm(term) {
                    this.filters.selected.search = term;
                    this.applyFilters();
                },
                clearFilters() {
                    this.selectedFilters[this.currentType].mutuals = [];
                    this.selectedFilters[this.currentType].brands = [];
                    this.selectedFilters[this.currentType].types = [];
                    this.selectedFilters.search = '';
                    this.applyFilters();
                },
                // Application des filtres modifiée
                applyFilters() {
                    const searchTerm = this.selectedFilters.search?.toLowerCase() || '';
                    const selectedMutuals = this.selectedFilters[this.currentType].mutuals || [];
                    const selectedBrands = this.selectedFilters[this.currentType].brands || [];
                    const selectedTypes = this.selectedFilters[this.currentType].types || [];
                    const filteredStores = Object.values(this.allStores).filter(store => {
                        // 1. Vérification du service principal (toujours requis)
                        const hasMainService = store.locations.some(location =>
                            this.isAudio ? location.is_audio : !location.is_audio
                        );
                        if (!hasMainService) return false;
                        // 2. Vérification des types additionnels si sélectionnés
                        if (selectedTypes.length > 0) {
                            // Vérifie l'autre service si sélectionné
                            const otherServiceType = this.isAudio ? 'optic' : 'audio';
                            if (selectedTypes.includes(otherServiceType)) {
                                const hasOtherService = store.locations.some(location =>
                                    this.isAudio ? !location.is_audio : location.is_audio
                                );
                                if (!hasOtherService) return false;
                            }
                            // Vérifie la téléophtalmologie si sélectionnée
                            if (selectedTypes.includes('teleophtalmologie')) {
                                const hasTelephtalmology = store.locations.some(location =>
                                    location.attributes.teleophtalmologie?.value === "1"
                                );
                                if (!hasTelephtalmology) return false;
                            }
                        }
                        // Filtres existants inchangés
                        if (searchTerm && !this.matchesSearch(store, searchTerm)) return false;
                        // Filtre par mutuelles
                        if (selectedMutuals.length > 0) {
                            const storeMutuals = store.locations
                                .filter(location => this.isAudio ? location.is_audio : !location.is_audio)
                                .flatMap(location => location.mutuelles || []);
                            if (!selectedMutuals.some(mutualId => storeMutuals.includes(mutualId))) {
                                return false;
                            }
                        }
                        if (selectedBrands.length > 0) {
                            const storeBrands = store.locations
                                .filter(location => this.isAudio ? location.is_audio : !location.is_audio)
                                .flatMap(location => location.brands || []);
                            if (!selectedBrands.some(brandId => storeBrands.includes(brandId))) {
                                return false;
                            }
                        }
                        return true;
                    });
                    this.filteredStores = filteredStores;
                    this.updateDistances(filteredStores);
                },
                // Mise à jour de la méthode matchesSearch également si nécessaire
                matchesSearch(store, searchTerm) {
                    return store.locations.some(location =>
                        location.name?.toLowerCase().includes(searchTerm) ||
                        store.city?.toLowerCase().includes(searchTerm) ||
                        store.zip?.toLowerCase().includes(searchTerm)
                    );
                },
                selectStore(store) {
                    this.selectedStore = store;
                },
                isFilterSelected(category, value) {
                    return this.selectedFilters[category].includes(value);
                },
                updateDistances(filteredStores) {
                    if (!this.mapInstance) return;
                    const center = this.mapInstance.getCenter();
                    const stores = Object.values(filteredStores || {});
                    // Créer de nouveaux objets avec les distances au lieu de modifier les existants
                    this.filteredDistanceStores = stores.map(store => {
                        const distance = google.maps.geometry.spherical.computeDistanceBetween(
                            center, {
                                lat: parseFloat(store.lat),
                                lng: parseFloat(store.lng)
                            }
                        );
                        // Retourner un nouvel objet au lieu de modifier l'original
                        return {
                            ...store,
                            distance: (distance / 1000).toFixed(1) + ' km'
                        };
                    }).sort((a, b) => {
                        const distA = parseFloat(a.distance);
                        const distB = parseFloat(b.distance);
                        return distA - distB;
                    });
                },
                setMapCenter(lat, lng, zoom) {
                    if (!isNaN(lat) && !isNaN(lng)) {
                        this.mapInstance.panTo({
                            lat,
                            lng
                        })
                    }
                    if (zoom) {
                        this.mapInstance.setZoom(zoom)
                    }
                },
                goToStore(store) {
                    if (!this.mapInstance || !store) return;
                    const lat = parseFloat(store.lat);
                    const lng = parseFloat(store.lng);
                    if (isNaN(lat) || isNaN(lng)) return;
                    this.setMapCenter(lat, lng, 15)
                    this.selectStore(store);
                },
                // PARTIE: PRISE DE RENDEZ-VOUS
                initStepper(store) {
                    this.stepperData = {
                        ...this.defaultStepperState,
                        code_mur: store.mur_code,
                        type: this.isAudio,
                        data: [{
                            title: 'MAGASIN',
                            value: `${store.address}, ${store.zip} ${store.city}`
                        }]
                    };
                },
                updateStepperData(title, value, targetStep) {
                    if (!this.stepperData) return;
                    // Trouver l'index de la donnée existante
                    const currentIndex = this.stepperData.data.findIndex(item => item.title === title);
                    // Mise à jour ou ajout des données
                    if (currentIndex === -1) {
                        // Ajout d'une nouvelle entrée
                        this.stepperData.data.push({
                            title,
                            value
                        });
                    } else if (this.stepperData.data[currentIndex].value !== value) {
                        // Si la valeur change, on supprime les données suivantes
                        this.stepperData.data = this.stepperData.data.slice(0, currentIndex + 1);
                        this.stepperData.data[currentIndex] = {
                            title,
                            value
                        };
                    }
                    // Mise à jour du step et des états des étapes si nécessaire
                    if (targetStep) {
                        this.stepperData.currentStep = targetStep;
                        this.stepperData.steps = this.stepperData.steps.map(step => ({
                            ...step,
                            completed: step.id < targetStep
                        }));
                    }
                    // Alpine.persist se charge automatiquement de la persistance
                    return this.stepperData;
                },
                completeStepperData(appointmentId) {
                    if (!this.stepperData) return;
                    // Marquer toutes les étapes comme complétées
                    this.stepperData.steps = this.stepperData.steps.map(step => ({
                        ...step,
                        completed: true
                    }));
                    // Marquer le stepper comme complété et ajouter l'ID du rendez-vous
                    this.stepperData.completed = true;
                    this.stepperData.appointmentId = appointmentId;
                },
                goToStepperStep(targetStep) {
                    // Vérifier que l'étape cible est valide
                    if (!this.stepperData || targetStep < 1 || targetStep > 4) return;
                    // Si on retourne à l'étape 1, réinitialiser complètement
                    if (targetStep === 1) {
                        this.resetStepperData();
                        this.$store.asideBlocs.closeAside('storeLocatorAppointment');
                        return;
                    }
                    // Mettre à jour l'étape courante et l'état des étapes
                    this.stepperData.currentStep = targetStep;
                    this.stepperData.steps = this.stepperData.steps.map(step => ({
                        ...step,
                        completed: step.id < targetStep
                    }));
                },
                resetStepperData() {
                    // Réinitialiser avec les valeurs par défaut
                    this.stepperData = Alpine.persist({
                        ...this.defaultStepperState
                    }, 'stepperData');
                }
            });
        });
    </script>

</body>

</html>
{% extends '@layout' %}

{% block yield %}
    {% render "@template-button" with {
        mobile_size:'md',
        label:'Open side panel',
        color: colorType|default('dark'),
        button_attribute: ('x-data x-init="$store.asideBlocs.addAside(\'' ~ _target.meta.name ~ '\')" @click="$store.asideBlocs.toggleAside(\'' ~ _target.meta.name ~ '\')"')|replace({"\'": "'"}),
    } %}
    {{ yield }}
{% endblock %}
/* No context defined. */

No notes defined.