<!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>
    <div x-data class="fixed right-0 z-40 inset-y-0 max-w-full">
        <div x-cloak x-transition.opacity x-show="$store.asideBlocs.asides.find(aside => aside.name === 'storeLocatorAppointment')?.open" class="fixed inset-0 w-full h-full bg-dark-40 backdrop-blur-xl"></div>
        <div x-cloak x-transition:enter="transition ease-out duration-300" x-transition:enter-start="translate-x-full" x-transition:enter-end="translate-x-0" x-transition:leave="transition ease-in duration-300" x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full" x-show="$store.asideBlocs.asides.find(aside => aside.name === 'storeLocatorAppointment')?.open" class="h-full relative bg-light-white overflow-hidden w-screen md:max-w-screen-sm flex flex-col" @click.outside="$store.asideBlocs.closeAside('storeLocatorAppointment')">
            <div class="p-4 md:px-10 md:py-6 font-medium text-2xl flex justify-between items-center">
                Livraison et retours
                <button type="button" @click="$store.asideBlocs.closeAside('storeLocatorAppointment')" class="max-md:btn-size-sm btn btn-dark-ghost  btn-only-icon">
                    <svg class=" shrink-0" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.99469 7.9047C8.70179 7.6118 8.22692 7.6118 7.93403 7.9047C7.64113 8.19759 7.64113 8.67246 7.93403 8.96536L10.9392 11.9706L7.93403 14.9758C7.64114 15.2687 7.64114 15.7435 7.93403 16.0364C8.22693 16.3293 8.7018 16.3293 8.99469 16.0364L11.9999 13.0312L15.0051 16.0364C15.298 16.3293 15.7729 16.3293 16.0658 16.0364C16.3586 15.7435 16.3586 15.2687 16.0658 14.9758L13.0606 11.9706L16.0658 8.96536C16.3587 8.67246 16.3587 8.19759 16.0658 7.9047C15.7729 7.6118 15.298 7.6118 15.0051 7.9047L11.9999 10.9099L8.99469 7.9047Z" fill="currentColor" />
                    </svg>

                </button>
            </div>
            <div class="px-4 md:px-10 overflow-auto flex-1 border-t border-b border-neutral-200">
                <div x-data="stepInit()" x-init="init">
                    <template x-if="!isInitialized">
                        <div>Chargement...</div>
                    </template>

                    <template x-if="isInitialized">
                        <div class="w-full max-w-3xl mx-auto py-8">

                            <div x-show="!stepperData.completed">

                                <div class="relative">

                                    <div class="absolute top-4 w-full h-[1px] bg-gray-200">
                                        <div class="absolute top-0 left-0 h-full transition-all duration-500" :style="'width: ' + (((stepperData.currentStep - 1) / (stepperData.steps.length - 1)) * 100) + '%; background-color: #B8A369;'">
                                        </div>
                                    </div>

                                    <div class="relative flex justify-between">
                                        <template x-for="(step, index) in stepperData.steps" :key="step.id">
                                            <div class="flex flex-col items-center" :class="{ 'pointer-events-none': step.id === 1 }">

                                                <div class="w-8 h-8 rounded-full border-2 flex items-center justify-center relative bg-white" :class="{
                                                'border-brand-400 bg-brand-400 text-white': step.completed,
                                                'border-neutral-300 text-neutral-500': !step.completed && step.id !== stepperData.currentStep,
                                                'border-neutral-300 text-neutral-700': !step.completed && step.id === stepperData.currentStep
                                             }">
                                                    <template x-if="step.completed">
                                                        <svg class="text-brand-400 shrink-0" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                                                            <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM16.5303 9.86366L11.197 15.197C10.9041 15.4899 10.4292 15.4899 10.1363 15.197L7.46967 12.5303C7.17678 12.2374 7.17678 11.7626 7.46967 11.4697C7.76256 11.1768 8.23744 11.1768 8.53033 11.4697L10.6667 13.606L15.4697 8.803C15.7626 8.51011 16.2374 8.51011 16.5303 8.803C16.8232 9.0959 16.8232 9.57077 16.5303 9.86366Z" fill="currentColor" />
                                                        </svg>
                                                    </template>
                                                    <template x-if="!step.completed">
                                                        <span x-text="step.id"></span>
                                                    </template>
                                                </div>

                                                <span class="mt-2 text-sm font-medium" :class="{
                                                'text-brand-400': step.completed || step.id === stepperData.currentStep,
                                                'text-neutral-500': !step.completed && step.id !== stepperData.currentStep
                                              }" x-text="step.title"></span>
                                            </div>
                                        </template>
                                    </div>
                                </div>

                                <div class="space-y-6">
                                    <template x-for="(item, index) in stepperData.data" :key="index">
                                        <div class="border-b border-gray-200 pb-4 last:border-b-0">
                                            <p class="text-sm font-normal text-gray-500 mb-1" x-text="item.title"></p>
                                            <div class="flex justify-between items-center">
                                                <p class="text-base text-gray-900" x-text="item.value"></p>
                                                <button class="text-sm text-gray-900 underline hover:no-underline focus:outline-none" @click="goToStep(index + 1)">
                                                    Modifier
                                                </button>
                                            </div>
                                        </div>
                                    </template>

                                    <template x-if="stepperData.data.length <= 1">
                                        <p class="text-sm text-gray-500 italic">
                                            Complétez les étapes suivantes pour voir le récapitulatif
                                        </p>
                                    </template>
                                </div>

                                <div class="mt-8 p-6">
                                    <template x-for="step in stepperData.steps" :key="step.id">
                                        <div x-show="stepperData.currentStep === step.id" class="space-y-4">
                                            <div x-show="step.id === 2">
                                                <div x-data="servicesInit()" class="w-full max-w-3xl mx-auto space-y-6">
                                                    <!-- Pour chaque catégorie -->
                                                    <template x-for="(code, index) in Object.keys(categories)" :key="code">
                                                        <div class="border-b border-gray-200 last:border-b-0" x-show="services[code]">
                                                            <div class="py-4">
                                                                <h2 class="text-gray-600 text-sm font-medium mb-4" x-text="categories[code].title"></h2>

                                                                <!-- Liste des services -->
                                                                <div class="space-y-4">
                                                                    <template x-for="service in services[code]" :key="service.serviceCode">
                                                                        <div x-data="serviceCardInit()" class="bg-white rounded-2xl shadow-sm hover:shadow-md transition-shadow duration-200 cursor-pointer p-6" @click="selectService($event, service)">
                                                                            <div class="flex items-start gap-4">
                                                                                <!-- Icône du service -->
                                                                                <div class="flex-shrink-0">
                                                                                    <div class="w-8 h-8 text-[#B8A369]">
                                                                                        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
                                                                                            <path d="M7 3H17V5H19V8C19 9.9 17.7 11.4 16 11.9V19C16 20.7 14.7 22 13 22H11C9.3 22 8 20.7 8 19V11.9C6.3 11.4 5 9.9 5 8V5H7V3ZM9 3V5H15V3H9ZM7 7V8C7 9.7 8.3 11 10 11H14C15.7 11 17 9.7 17 8V7H7Z" />
                                                                                        </svg>
                                                                                    </div>
                                                                                </div>

                                                                                <!-- Contenu principal -->
                                                                                <div class="flex-1">
                                                                                    <div class="flex flex-col">
                                                                                        <h3 class="text-lg text-neutral-900 font-medium mb-1" x-text="service.service"></h3>
                                                                                        <div data-expand-trigger @click.stop="isExpanded = !isExpanded">
                                                                                            <button class="text-neutral-500 text-sm hover:text-neutral-700 transition-colors w-fit" :class="{ 'underline': !isExpanded }">
                                                                                                <span x-text="isExpanded ? 'Masquer' : 'En savoir plus'"></span>
                                                                                                <span class="inline-block ml-1 transition-transform duration-200" :class="{ 'rotate-180': isExpanded }"></span>
                                                                                            </button>
                                                                                        </div>
                                                                                    </div>

                                                                                    <!-- Contenu dépliable -->
                                                                                    <div x-show="isExpanded" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 transform -translate-y-2" x-transition:enter-end="opacity-100 transform translate-y-0" class="mt-4 space-y-4" @click.stop>
                                                                                        <p class="text-sm text-neutral-600">
                                                                                            Durée approximative : <span x-text="service.duration + ' minutes'"></span>
                                                                                        </p>
                                                                                    </div>
                                                                                </div>
                                                                            </div>
                                                                        </div>
                                                                    </template>
                                                                </div>
                                                            </div>
                                                        </div>
                                                    </template>
                                                </div>

                                                <script>
                                                    function servicesInit() {
                                                        return {
                                                            services: [],
                                                            categories: {
                                                                'AR-001': {
                                                                    title: 'SANTÉ DES YEUX',
                                                                    icon: 'library--vision-test'
                                                                },
                                                                'AR-002': {
                                                                    title: 'LENTILLES',
                                                                    icon: 'library--contact-lenses'
                                                                },
                                                                'AR-004': {
                                                                    title: 'VISAGISME',
                                                                    icon: 'library--glasses'
                                                                }
                                                            },
                                                            async init() {
                                                                try {
                                                                    const response = await fetch(`${window.location.origin}/js/json/getStoreServices.json`);
                                                                    const data = await response.json();
                                                                    // Grouper les services par areaCode
                                                                    this.services = data.reduce((acc, service) => {
                                                                        if (!acc[service.areaCode]) {
                                                                            acc[service.areaCode] = [];
                                                                        }
                                                                        acc[service.areaCode].push(service);
                                                                        return acc;
                                                                    }, {});
                                                                } catch (error) {
                                                                    console.error('Erreur lors du chargement des services:', error);
                                                                    this.services = {};
                                                                }
                                                            }
                                                        }
                                                    }

                                                    function serviceCardInit() {
                                                        return {
                                                            isExpanded: false,
                                                            selectService(event, currentService) {
                                                                // Ignorer si le clic est sur le bouton 'En savoir plus' ou son conteneur
                                                                if (event.target.closest('[data-expand-trigger]')) {
                                                                    return;
                                                                }
                                                                // Utiliser le store locator pour mettre à jour les données
                                                                this.$store.locator.updateStepperData(
                                                                    'SUJET DU RENDEZ-VOUS',
                                                                    currentService.service,
                                                                    this.$store.locator.stepperData.currentStep + 1
                                                                );
                                                            }
                                                        }
                                                    }
                                                </script>
                                            </div>
                                            <div x-show="step.id === 3">

                                                <div x-data="datePicker()" x-init="init().then()" class="w-full max-w-3xl mx-auto space-y-8">
                                                    <h1 class="text-3xl font-normal mb-8">Date et heure du rendez-vous</h1>

                                                    <div class="bg-white rounded-3xl p-8">

                                                        <div class="flex justify-center items-center mb-8 relative">
                                                            <button @click="handlePreviousClick().then()" class="absolute left-0 w-10 h-10 flex items-center justify-center rounded-full bg-neutral-100 hover:bg-neutral-200 transition-colors">
                                                                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-neutral-600">
                                                                    <path d="M15 18l-6-6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
                                                                </svg>
                                                            </button>

                                                            <span x-text="displayRange" class="text-xl font-normal"></span>

                                                            <button @click="handleNextClick().then()" class="absolute right-0 w-10 h-10 flex items-center justify-center rounded-full bg-neutral-100 hover:bg-neutral-200 transition-colors">
                                                                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-neutral-600">
                                                                    <path d="M9 18l6-6-6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
                                                                </svg>
                                                            </button>
                                                        </div>

                                                        <div class="grid grid-cols-7 gap-0">

                                                            <template x-for="day in ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim']">
                                                                <div class="text-center py-2 text-neutral-900 font-normal text-lg" x-text="day"></div>
                                                            </template>

                                                            <template x-for="day in days">
                                                                <div class="relative border-[0.5px] border-neutral-200">
                                                                    <button @click="selectDate(day)" class="w-full aspect-square flex items-center justify-center relative" :class="{
								'bg-green-50': day.isAvailable,
								'cursor-pointer hover:bg-green-100': day.isAvailable,
								'cursor-not-allowed bg-neutral-50': !day.isAvailable
							}" :disabled="!day.isAvailable">

                                                                        <div x-show="!day.isAvailable" class="absolute inset-0 bg-[linear-gradient(to_top_right,transparent_calc(50%_-_1px),#e5e7eb,transparent_calc(50%_+_1px))]">
                                                                        </div>

                                                                        <div class="relative flex flex-col items-center" :class="{
								 'text-green-700': day.isAvailable,
								 'text-neutral-400': !day.isAvailable
							 }">
                                                                            <span class="text-lg" x-text="day.dayOfMonth"></span>
                                                                            <div x-show="day.isAvailable" class="w-1.5 h-1.5 rounded-full bg-green-700 mt-1">
                                                                            </div>
                                                                        </div>

                                                                        <div x-show="selectedDate && day.date.getTime() === selectedDate.getTime()" class="absolute inset-0 border-2 border-green-700 pointer-events-none">
                                                                        </div>
                                                                    </button>
                                                                </div>
                                                            </template>
                                                        </div>

                                                        <div class="mt-4 flex items-center gap-2 text-green-700">
                                                            <div class="w-1.5 h-1.5 rounded-full bg-green-700"></div>
                                                            <span class="text-sm">Jours avec des horaires disponibles</span>
                                                        </div>
                                                    </div>

                                                    <div x-show="selectedDate" class="space-y-4">
                                                        <h2 class="text-xl">Sélectionner l'horaire</h2>
                                                        <div class="grid grid-cols-4 gap-4">
                                                            <template x-for="slot in availableHours" :key="slot.initialHour">
                                                                <button @click="selectTime(slot.initialHour)" class="py-3 px-6 rounded-full border border-gray-200 hover:border-brand-400 transition-colors" :class="{
                        'bg-brand-50 border-brand-400': selectedTime === slot.initialHour,
                        'bg-white': selectedTime !== slot.initialHour
                    }">
                                                                    <span x-text="slot.initialHour"></span>
                                                                </button>
                                                            </template>
                                                        </div>
                                                    </div>
                                                </div>

                                                <script>
                                                    function datePicker() {
                                                        return {
                                                            // États initiaux explicitement définis
                                                            startDate: new Date(), // On initialise directement avec une date par défaut
                                                            selectedDate: null,
                                                            selectedTime: null,
                                                            days: [],
                                                            availabilities: {},
                                                            availableHours: [],
                                                            isLoading: false,
                                                            displayRange: '',
                                                            initialized: false,
                                                            // Getter pour accéder aux données du stepper
                                                            get stepperData() {
                                                                return this.$store.locator.stepperData;
                                                            },
                                                            // Nouvelle méthode d'initialisation
                                                            async init() {
                                                                if (this.initialized) return;
                                                                try {
                                                                    this.isLoading = true;
                                                                    // Initialisation avec la date du jour
                                                                    const today = new Date();
                                                                    // Calcul du début de la semaine
                                                                    let startOfWeek = new Date(today);
                                                                    startOfWeek.setHours(0, 0, 0, 0);
                                                                    // Ajustement pour commencer au lundi
                                                                    const dayOfWeek = today.getDay();
                                                                    const diff = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
                                                                    startOfWeek.setDate(today.getDate() + diff);
                                                                    // Définition explicite de la date de début
                                                                    this.startDate = startOfWeek;
                                                                    // Initialisation du calendrier
                                                                    await this.updateDateRange(this.startDate);
                                                                    this.initialized = true;
                                                                } catch (error) {
                                                                    console.error('Erreur lors de l\'initialisation:', error);
                                                                } finally {
                                                                    this.isLoading = false;
                                                                }
                                                            },
                                                            // Le reste des méthodes reste identique à votre code original
                                                            async fetchAvailabilities(startDate, endDate) {
                                                                try {
                                                                    const url = new URL(`${window.location.origin}/js/json/getStoreServiceAvailabilities.json`);
                                                                    url.searchParams.append('date_start', this.formatDateISO(startDate));
                                                                    url.searchParams.append('date_end', this.formatDateISO(endDate));
                                                                    const response = await fetch(url);
                                                                    const data = await response.json();
                                                                    this.availabilities = data.reduce((acc, item) => {
                                                                        acc[item.disponibilityDay] = item.disponibilityHours;
                                                                        return acc;
                                                                    }, {});
                                                                } catch (error) {
                                                                    console.error('Erreur lors de la récupération des disponibilités:', error);
                                                                    this.availabilities = {};
                                                                }
                                                            },
                                                            // Mise à jour améliorée du calendrier
                                                            async updateDateRange(newStartDate) {
                                                                if (!newStartDate) return;
                                                                try {
                                                                    this.isLoading = true;
                                                                    // Création d'une copie de la date de début
                                                                    const startDate = new Date(newStartDate);
                                                                    startDate.setHours(0, 0, 0, 0);
                                                                    // Calcul de la date de fin
                                                                    const endDate = new Date(startDate);
                                                                    endDate.setDate(startDate.getDate() + 13);
                                                                    // Récupération des disponibilités
                                                                    await this.fetchAvailabilities(startDate, endDate);
                                                                    // Mise à jour de l'état
                                                                    this.startDate = startDate;
                                                                    // Mise à jour de l'affichage
                                                                    this.updateCalendarDisplay();
                                                                } catch (error) {
                                                                    console.error('Erreur lors de la mise à jour:', error);
                                                                } finally {
                                                                    this.isLoading = false;
                                                                }
                                                            },
                                                            // Navigation améliorée
                                                            async handlePreviousClick() {
                                                                if (this.isLoading) return;
                                                                const newStartDate = new Date(this.startDate);
                                                                newStartDate.setDate(newStartDate.getDate() - 14);
                                                                await this.updateDateRange(newStartDate);
                                                            },
                                                            async handleNextClick() {
                                                                if (this.isLoading) return;
                                                                const newStartDate = new Date(this.startDate);
                                                                newStartDate.setDate(newStartDate.getDate() + 14);
                                                                await this.updateDateRange(newStartDate);
                                                            },
                                                            // Mise à jour robuste de l'affichage du calendrier
                                                            updateCalendarDisplay() {
                                                                if (!this.startDate) return;
                                                                const newDays = [];
                                                                const endDate = new Date(this.startDate);
                                                                endDate.setDate(endDate.getDate() + 13);
                                                                // Itération sur les dates
                                                                for (let currentDate = new Date(this.startDate); currentDate <= endDate; currentDate.setDate(currentDate.getDate() + 1)) {
                                                                    const dateStr = this.formatDateISO(new Date(currentDate));
                                                                    const isAvailable = Boolean(
                                                                        this.availabilities &&
                                                                        this.availabilities[dateStr] &&
                                                                        this.availabilities[dateStr].length > 0
                                                                    );
                                                                    newDays.push({
                                                                        date: new Date(currentDate),
                                                                        dayOfMonth: currentDate.getDate(),
                                                                        isAvailable,
                                                                        dateStr
                                                                    });
                                                                }
                                                                this.days = newDays;
                                                                this.updateDisplayRange();
                                                            },
                                                            // Formatage amélioré des dates
                                                            formatDateISO(date) {
                                                                const d = new Date(date);
                                                                const year = d.getFullYear();
                                                                const month = String(d.getMonth() + 1).padStart(2, '0');
                                                                const day = String(d.getDate()).padStart(2, '0');
                                                                return `${year}-${month}-${day}`;
                                                            },
                                                            updateDisplayRange() {
                                                                if (!this.startDate) return;
                                                                const endDate = new Date(this.startDate);
                                                                endDate.setDate(endDate.getDate() + 13);
                                                                const formatOptions = {
                                                                    day: 'numeric',
                                                                    month: 'short',
                                                                    year: 'numeric'
                                                                };
                                                                this.displayRange = `du ${this.startDate.toLocaleDateString('fr-FR', formatOptions)} au ${endDate.toLocaleDateString('fr-FR', formatOptions)}`;
                                                            },
                                                            // Sélection d'une date
                                                            selectDate(day) {
                                                                if (!day.isAvailable) return;
                                                                this.selectedDate = day.date;
                                                                this.selectedTime = null;
                                                                this.availableHours = this.availabilities[day.dateStr] || [];
                                                            },
                                                            // Formatage d'une date selon le format demandé
                                                            formatDate(date, format = 'long') {
                                                                const options = format === 'long' ?
                                                                    {
                                                                        weekday: 'long',
                                                                        day: 'numeric',
                                                                        month: 'long',
                                                                        year: 'numeric'
                                                                    } :
                                                                    {
                                                                        day: 'numeric',
                                                                        month: 'short',
                                                                        year: 'numeric'
                                                                    };
                                                                return date.toLocaleDateString('fr-FR', options);
                                                            },
                                                            // Sélection d'un créneau horaire
                                                            selectTime(time) {
                                                                if (!this.selectedDate) return;
                                                                // Formatage de la date et l'heure pour l'affichage
                                                                const dateStr = this.selectedDate.toLocaleDateString('fr-FR', {
                                                                    weekday: 'long',
                                                                    day: 'numeric',
                                                                    month: 'long',
                                                                    year: 'numeric'
                                                                });
                                                                // Mise à jour des données du stepper et passage à l'étape suivante
                                                                this.$store.locator.updateStepperData(
                                                                    'DATE ET HEURE DU RENDEZ-VOUS',
                                                                    `${dateStr} à ${time}`,
                                                                    this.stepperData.currentStep + 1
                                                                );
                                                            }
                                                        };
                                                    }
                                                </script>
                                            </div>
                                            <div x-show="step.id === 4">
                                                <div x-data="formAppointment()" class="w-full max-w-3xl mx-auto space-y-8">
                                                    <h1 class="text-3xl font-normal">Information du contact</h1>

                                                    <div class="bg-neutral-50 rounded-lg p-6 flex items-center justify-between">
                                                        <div class="flex items-center gap-4">
                                                            <div class="w-6 h-6">
                                                                <svg class="text-neutral-900 shrink-0" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                                                                    <path fill-rule="evenodd" clip-rule="evenodd" d="M12 3.75C14.3472 3.75 16.25 5.65279 16.25 8C16.25 10.3472 14.3472 12.25 12 12.25C9.65279 12.25 7.75 10.3472 7.75 8C7.75 5.65279 9.65279 3.75 12 3.75ZM15.1254 12.8272C16.7051 11.8024 17.75 10.0232 17.75 8C17.75 4.82436 15.1756 2.25 12 2.25C8.82436 2.25 6.25 4.82436 6.25 8C6.25 10.0232 7.29494 11.8024 8.87458 12.8272C7.73658 13.2624 6.69098 13.9347 5.81282 14.8128C4.17187 16.4538 3.25 18.6794 3.25 21C3.25 21.4142 3.58579 21.75 4 21.75C4.41421 21.75 4.75 21.4142 4.75 21C4.75 19.0772 5.51384 17.2331 6.87348 15.8735C8.23311 14.5138 10.0772 13.75 12 13.75C13.9228 13.75 15.7669 14.5138 17.1265 15.8735C18.4862 17.2331 19.25 19.0772 19.25 21C19.25 21.4142 19.5858 21.75 20 21.75C20.4142 21.75 20.75 21.4142 20.75 21C20.75 18.6794 19.8281 16.4538 18.1872 14.8128C17.309 13.9347 16.2634 13.2624 15.1254 12.8272Z" fill="currentColor" />
                                                                </svg>
                                                            </div>
                                                            <p class="text-neutral-900">
                                                                Vous avez déjà un compte ?
                                                                <a href="#" class="text-neutral-900 underline hover:no-underline">Connectez-vous</a>
                                                                pour retrouver vos informations et gérer vos rendez-vous.
                                                            </p>
                                                        </div>
                                                        <div class="w-6 h-6">
                                                            <svg class="text-neutral-900 shrink-0" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                                                                <path fill-rule="evenodd" clip-rule="evenodd" d="M14.5303 11.4697C14.8232 11.7626 14.8232 12.2374 14.5303 12.5303L10.5303 16.5303C10.2374 16.8232 9.76256 16.8232 9.46967 16.5303C9.17678 16.2374 9.17678 15.7626 9.46967 15.4697L12.9393 12L9.46967 8.53033C9.17678 8.23744 9.17678 7.76256 9.46967 7.46967C9.76256 7.17678 10.2374 7.17678 10.5303 7.46967L14.5303 11.4697Z" fill="currentColor" />
                                                            </svg>
                                                        </div>
                                                    </div>

                                                    <form @submit.prevent="validateForm" class="space-y-6">

                                                        <div>
                                                            <label class="block text-neutral-900 mb-2">
                                                                Prénom <span class="text-red-500">*</span>
                                                            </label>
                                                            <input type="text" x-model="formData.firstName" class="w-full px-4 py-3 rounded-lg border border-neutral-200 focus:border-brand-400 focus:ring-1 focus:ring-brand-400" :class="{ 'border-red-500': errors.firstName }">
                                                            <p x-show="errors.firstName" x-text="errors.firstName" class="mt-1 text-red-500 text-sm"></p>
                                                        </div>

                                                        <div>
                                                            <label class="block text-neutral-900 mb-2">
                                                                Nom <span class="text-red-500">*</span>
                                                            </label>
                                                            <input type="text" x-model="formData.lastName" class="w-full px-4 py-3 rounded-lg border border-neutral-200 focus:border-brand-400 focus:ring-1 focus:ring-brand-400" :class="{ 'border-red-500': errors.lastName }">
                                                            <p x-show="errors.lastName" x-text="errors.lastName" class="mt-1 text-red-500 text-sm"></p>
                                                        </div>

                                                        <div>
                                                            <label class="block text-neutral-900 mb-2">
                                                                E-mail <span class="text-red-500">*</span>
                                                            </label>
                                                            <input type="email" x-model="formData.email" class="w-full px-4 py-3 rounded-lg border border-neutral-200 focus:border-brand-400 focus:ring-1 focus:ring-brand-400" :class="{ 'border-red-500': errors.email }">
                                                            <p x-show="errors.email" x-text="errors.email" class="mt-1 text-red-500 text-sm"></p>
                                                        </div>

                                                        <div>
                                                            <label class="block text-neutral-900 mb-2">
                                                                Téléphone <span class="text-red-500">*</span>
                                                            </label>
                                                            <input type="tel" x-model="formData.phone" class="w-full px-4 py-3 rounded-lg border border-neutral-200 focus:border-brand-400 focus:ring-1 focus:ring-brand-400" :class="{ 'border-red-500': errors.phone }">
                                                            <p x-show="errors.phone" x-text="errors.phone" class="mt-1 text-red-500 text-sm"></p>
                                                        </div>

                                                        <div>
                                                            <button type="button" @click="showComment = !showComment" class="flex items-center gap-2 text-neutral-900 hover:underline">
                                                                <span class="w-6 h-6">+</span>
                                                                Ajouter un commentaire (facultatif)
                                                            </button>

                                                            <div x-show="showComment" x-transition class="mt-4">
                                                                <textarea x-model="formData.comment" class="w-full px-4 py-3 rounded-lg border border-neutral-200 focus:border-brand-400 focus:ring-1 focus:ring-brand-400" rows="4"></textarea>
                                                            </div>
                                                        </div>

                                                        <div class="space-y-4">
                                                            <label class="flex items-start gap-3 cursor-pointer">
                                                                <input type="checkbox" x-model="formData.acceptPolicy" class="mt-1 rounded border-neutral-300 text-brand-400 focus:ring-brand-400" :class="{ 'border-red-500': errors.policy }">
                                                                <span class="text-sm">
                                                                    ALAIN AFFLELOU, en tant que responsable de traitement, collecte vos données
                                                                    personnelles afin de créer votre compte, vous faire parvenir vos informations de
                                                                    rendez-vous et nos offres commerciales lorsque vous l'acceptez. Pour en savoir plus
                                                                    sur vos droits et la gestion de vos données personnelles, consultez notre
                                                                    <a href="#" class="underline hover:no-underline">Politique de confidentialité</a>.
                                                                </span>
                                                            </label>
                                                            <p x-show="errors.policy" x-text="errors.policy" class="text-red-500 text-sm"></p>
                                                        </div>

                                                        <button type="submit" class="w-full py-4 bg-neutral-500 text-white rounded-lg hover:bg-neutral-600 transition-colors">
                                                            Confirmer mon rendez-vous
                                                        </button>
                                                    </form>
                                                </div>

                                                <script>
                                                    function formAppointment() {
                                                        return {
                                                            formData: {
                                                                firstName: '',
                                                                lastName: '',
                                                                email: '',
                                                                phone: '',
                                                                comment: '',
                                                                acceptPolicy: false
                                                            },
                                                            showComment: false,
                                                            errors: {},
                                                            isInitialized: false,
                                                            isSubmitting: false, // Nouveau flag pour gérer l'état de soumission
                                                            get stepperData() {
                                                                return this.$store.locator.stepperData;
                                                            },
                                                            init() {
                                                                // S'il y a déjà des données à l'étape 4, charger les données immédiatement
                                                                if (this.stepperData?.currentStep === 4) {
                                                                    this.loadSavedData();
                                                                }
                                                            },
                                                            // Le reste des méthodes de votre composant restent inchangées
                                                            loadSavedData() {
                                                                const contactInfo = this.stepperData.data.find(item => item.title === 'INFORMATION DU CONTACT');
                                                                if (contactInfo && contactInfo.details) {
                                                                    this.formData = {
                                                                        ...this.formData,
                                                                        ...contactInfo.details
                                                                    };
                                                                }
                                                            },
                                                            validateForm() {
                                                                this.errors = {};
                                                                if (!this.formData.firstName) this.errors.firstName = 'Le prénom est requis';
                                                                if (!this.formData.lastName) this.errors.lastName = 'Le nom est requis';
                                                                if (!this.formData.email) this.errors.email = 'L\'email est requis';
                                                                if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.formData.email)) {
                                                                    this.errors.email = 'L\'email n\'est pas valide';
                                                                }
                                                                if (!this.formData.phone) this.errors.phone = 'Le téléphone est requis';
                                                                if (!this.formData.acceptPolicy) this.errors.policy = 'Vous devez accepter la politique de confidentialité';
                                                                if (Object.keys(this.errors).length === 0) {
                                                                    this.submitForm();
                                                                }
                                                            },
                                                            async submitForm() {
                                                                if (!this.isInitialized || this.isSubmitting) return;
                                                                this.isSubmitting = true;
                                                                try {
                                                                    const appointmentData = {
                                                                        store: this.stepperData.data.find(item => item.title === 'MAGASIN')?.value,
                                                                        service: this.stepperData.data.find(item => item.title === 'SUJET DU RENDEZ-VOUS')?.value,
                                                                        datetime: this.stepperData.data.find(item => item.title === 'DATE ET HEURE DU RENDEZ-VOUS')?.value,
                                                                        contact: {
                                                                            firstName: this.formData.firstName,
                                                                            lastName: this.formData.lastName,
                                                                            email: this.formData.email,
                                                                            phone: this.formData.phone,
                                                                            comment: this.formData.comment,
                                                                        },
                                                                        metadata: {
                                                                            code_mur: this.stepperData.code_mur,
                                                                            type: this.stepperData.type
                                                                        }
                                                                    };
                                                                    // Simulation d'un délai réseau
                                                                    await new Promise(resolve => setTimeout(resolve, 1000));
                                                                    // Choisir aléatoirement entre succès et erreur
                                                                    const mockApiUrl = Math.random() < 0.7 ?
                                                                        '/js/json/appointment-success.json' // 70% de chance de succès
                                                                        :
                                                                        '/js/json/appointment-error.json'; // 30% de chance d'erreur
                                                                    const response = await fetch(mockApiUrl);
                                                                    // Exemple d'appel api
                                                                    // const response = await fetch('/api/appointments', {
                                                                    // 	method: 'POST',
                                                                    // 	headers: {'Content-Type': 'application/json'},
                                                                    // 	body: JSON.stringify(appointmentData)
                                                                    // });
                                                                    const data = await response.json();
                                                                    if (!data.success) {
                                                                        throw new Error(data.error.message);
                                                                    }
                                                                    // Si succès, mettre à jour le stepperData
                                                                    this.$store.locator.updateStepperData(
                                                                        'INFORMATION DU CONTACT',
                                                                        `${this.formData.firstName} ${this.formData.lastName}`,
                                                                        null, {
                                                                            details: {
                                                                                firstName: this.formData.firstName,
                                                                                lastName: this.formData.lastName,
                                                                                email: this.formData.email,
                                                                                phone: this.formData.phone,
                                                                                comment: this.formData.comment,
                                                                                acceptPolicy: this.formData.acceptPolicy,
                                                                                appointmentDetails: data.data // Stocker les détails du rendez-vous
                                                                            }
                                                                        }
                                                                    );
                                                                    // Marquer comme complété
                                                                    this.$store.locator.completeStepperData(data.appointmentId);
                                                                    // Message de succès
                                                                    this.$dispatch('show-toast', {
                                                                        type: 'success',
                                                                        message: data.message
                                                                    });
                                                                } catch (error) {
                                                                    console.error('Erreur lors de la soumission:', error);
                                                                    // Message d'erreur
                                                                    this.$dispatch('show-toast', {
                                                                        type: 'error',
                                                                        message: error.message || 'Une erreur est survenue lors de la prise de rendez-vous. Veuillez réessayer.'
                                                                    });
                                                                } finally {
                                                                    this.isSubmitting = false;
                                                                }
                                                            }
                                                        }
                                                    }
                                                </script>
                                            </div>
                                        </div>
                                    </template>
                                </div>
                            </div>

                            <div x-show="stepperData.completed">

                                <div x-data="appointmentConfirmation()" x-init="init()" class="w-full max-w-3xl mx-auto space-y-12">

                                    <div class="bg-green-50 rounded-2xl p-8 space-y-8">

                                        <div class="flex items-center gap-4">
                                            <div class="w-8 h-8 text-green-600">
                                                <svg class="text-green-600 w-8 h-8 shrink-0" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                                                    <path fill-rule="evenodd" clip-rule="evenodd" d="M2.75 12C2.75 6.89137 6.89137 2.75 12 2.75C17.1086 2.75 21.25 6.89137 21.25 12C21.25 17.1086 17.1086 21.25 12 21.25C6.89137 21.25 2.75 17.1086 2.75 12ZM12 1.25C6.06294 1.25 1.25 6.06294 1.25 12C1.25 17.9371 6.06294 22.75 12 22.75C17.9371 22.75 22.75 17.9371 22.75 12C22.75 6.06294 17.9371 1.25 12 1.25ZM16.5303 9.86366C16.8232 9.57077 16.8232 9.0959 16.5303 8.803C16.2374 8.51011 15.7626 8.51011 15.4697 8.803L10.6667 13.606L8.53033 11.4697C8.23744 11.1768 7.76256 11.1768 7.46967 11.4697C7.17678 11.7626 7.17678 12.2374 7.46967 12.5303L10.1363 15.197C10.4292 15.4899 10.9041 15.4899 11.197 15.197L16.5303 9.86366Z" fill="currentColor" />
                                                </svg>
                                            </div>
                                            <h1 class="text-3xl font-normal">Rendez-vous confirmé</h1>
                                        </div>

                                        <p class="text-neutral-700">
                                            Vous trouverez le récapitulatif de votre rendez-vous ci-dessous. Nous vous l'envoyons également par e-mail (vérifiez vos spams) et par SMS si vous avez activé cette option.
                                        </p>

                                        <div class="bg-white rounded-xl p-6 space-y-4">
                                            <template x-for="item in stepperData.data" :key="item.title">
                                                <div>
                                                    <p class="text-neutral-600" x-text="item.title + ' : '"></p>
                                                    <p class="font-medium" x-text="item.value"></p>
                                                    <template x-if="item.details">
                                                        <div class="mt-2 text-sm text-neutral-500">
                                                            <template x-if="item.title === 'INFORMATION DU CONTACT'">
                                                                <div>
                                                                    <p x-text="'Email : ' + item.details.email"></p>
                                                                    <p x-text="'Téléphone : ' + item.details.phone"></p>
                                                                    <template x-if="item.details.comment">
                                                                        <p x-text="'Commentaire : ' + item.details.comment"></p>
                                                                    </template>
                                                                </div>
                                                            </template>
                                                        </div>
                                                    </template>
                                                </div>
                                            </template>
                                        </div>

                                        <div class="space-y-4">
                                            <p class="text-neutral-700">Ne manquez pas votre rendez-vous en l'ajoutant à votre agenda en ligne :</p>

                                            <div class="flex gap-4 flex-wrap">
                                                <a href="#" target="_blank" rel="noopenner noreferer" :href="getGoogleCalendarUrl()" class=" btn btn-dark-subtle ">
                                                    Ajouter à Google Agenda

                                                </a>
                                                <a href="#" target="_blank" rel="noopenner noreferer" :href="getOutlookCalendarUrl()" class=" btn btn-dark-subtle ">
                                                    Ajouter à l'agenda Outlook

                                                </a>
                                            </div>
                                        </div>
                                    </div>

                                    <div class="space-y-6">
                                        <h2 class="text-3xl font-normal">Votre pré-bilan pour gagner du temps</h2>

                                        <p class="text-neutral-700">
                                            Avant votre rendez-vous, remplissez ce questionnaire qui aidera votre opticien à vous recommander les solutions les plus adaptées à votre quotidien.
                                        </p>

                                        <a href="#" target="_blank" rel="noopenner noreferer" class=" btn btn-dark-ghost ">
                                            Répondre au questionnaire

                                        </a>
                                    </div>
                                </div>

                                <script>
                                    function appointmentConfirmation() {
                                        return {
                                            get stepperData() {
                                                return this.$store.locator.stepperData;
                                            },
                                            init() {
                                                this.$watch('stepperData.completed', (value) => {
                                                    if (value) {
                                                        console.log('Composant confirmation visible, initialisation...');
                                                    }
                                                });
                                            },
                                            getCalendarData() {
                                                if (!this.stepperData?.data) return null;
                                                const location = this.stepperData.data.find(item => item.title === 'MAGASIN')?.value || '';
                                                const subject = this.stepperData.data.find(item => item.title === 'SUJET DU RENDEZ-VOUS')?.value || '';
                                                const datetime = this.stepperData.data.find(item => item.title === 'DATE ET HEURE DU RENDEZ-VOUS')?.value || '';
                                                const contact = this.stepperData.data.find(item => item.title === 'INFORMATION DU CONTACT');
                                                return {
                                                    location,
                                                    subject,
                                                    datetime,
                                                    contact: contact?.value || '',
                                                    email: contact?.details?.email || '',
                                                    phone: contact?.details?.phone || ''
                                                };
                                            },
                                            getGoogleCalendarUrl() {
                                                const data = this.getCalendarData();
                                                if (!data) return '#';
                                                const params = new URLSearchParams({
                                                    action: 'TEMPLATE',
                                                    text: `${data.subject} - Afflelou`,
                                                    details: `Rendez-vous chez Afflelou\n${data.contact}\nEmail: ${data.email}\nTél: ${data.phone}`,
                                                    location: data.location,
                                                    dates: this.formatDateForCalendar(data.datetime)
                                                });
                                                return `https://calendar.google.com/calendar/render?${params.toString()}`;
                                            },
                                            getOutlookCalendarUrl() {
                                                const data = this.getCalendarData();
                                                if (!data) return '#';
                                                const params = new URLSearchParams({
                                                    path: '/calendar/action/compose',
                                                    rru: 'addevent',
                                                    subject: `${data.subject} - Afflelou`,
                                                    body: `Rendez-vous chez Afflelou\n${data.contact}\nEmail: ${data.email}\nTél: ${data.phone}`,
                                                    location: data.location,
                                                    startdt: this.formatDateForCalendar(data.datetime)
                                                });
                                                return `https://outlook.live.com/calendar/0/${params.toString()}`;
                                            },
                                            formatDateForCalendar(datetimeStr) {
                                                // Exemple de format d'entrée : "Lundi 15 janvier 2024 à 14:30"
                                                const dateRegex = /(\d{1,2})\s+(\w+)\s+(\d{4})\s+à\s+(\d{1,2}):(\d{2})/;
                                                const matches = datetimeStr.match(dateRegex);
                                                if (!matches) return '';
                                                const [, day, month, year, hour, minute] = matches;
                                                const monthMap = {
                                                    'janvier': '01',
                                                    'février': '02',
                                                    'mars': '03',
                                                    'avril': '04',
                                                    'mai': '05',
                                                    'juin': '06',
                                                    'juillet': '07',
                                                    'août': '08',
                                                    'septembre': '09',
                                                    'octobre': '10',
                                                    'novembre': '11',
                                                    'décembre': '12'
                                                };
                                                const monthNum = monthMap[month.toLowerCase()];
                                                const dateObj = new Date(`${year}-${monthNum}-${day}T${hour}:${minute}:00`);
                                                return dateObj.toISOString().replace(/[:-]/g, '').split('.')[0] + 'Z';
                                            }
                                        }
                                    }
                                </script>
                            </div>
                        </div>
                    </template>
                </div>

                <script>
                    function stepInit() {
                        return {
                            isInitialized: false,
                            init() {
                                this.isInitialized = true;
                            },
                            get stepperData() {
                                return this.$store.locator.stepperData || this.$store.locator.defaultStepperState;
                            },
                            nextStep() {
                                if (!this.isInitialized) return;
                                if (this.stepperData.currentStep < 4) {
                                    this.$store.locator.updateStepperSteps(this.stepperData.currentStep + 1);
                                } else {
                                    this.$store.locator.stepperData.completed = true;
                                }
                            },
                            previousStep() {
                                if (!this.isInitialized) return;
                                if (this.stepperData.currentStep > 2) {
                                    this.$store.locator.updateStepperSteps(this.stepperData.currentStep - 1);
                                }
                            },
                            goToStep(targetStep) {
                                if (!this.isInitialized) return;
                                this.$store.locator.goToStepperStep(targetStep);
                            },
                            updateStepData(title, value, targetStep) {
                                if (!this.isInitialized) return;
                                this.$store.locator.updateStepperData(title, value, targetStep);
                            }
                        }
                    }
                </script>

            </div>
        </div>
    </div>
    <div x-data class="fixed right-0 z-40 inset-y-0 max-w-full">
        <div x-cloak x-transition.opacity x-show="$store.asideBlocs.asides.find(aside => aside.name === 'storeLocatorFilter')?.open" class="fixed inset-0 w-full h-full bg-dark-40 backdrop-blur-xl"></div>
        <div x-cloak x-transition:enter="transition ease-out duration-300" x-transition:enter-start="translate-x-full" x-transition:enter-end="translate-x-0" x-transition:leave="transition ease-in duration-300" x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full" x-show="$store.asideBlocs.asides.find(aside => aside.name === 'storeLocatorFilter')?.open" class="h-full relative bg-light-white overflow-hidden w-screen md:max-w-screen-sm flex flex-col" @click.outside="$store.asideBlocs.closeAside('storeLocatorFilter')">
            <div class="p-4 md:px-10 md:py-6 font-medium text-2xl flex justify-between items-center">
                Filtrer
                <button type="button" @click="$store.asideBlocs.closeAside('storeLocatorFilter')" class="max-md:btn-size-sm btn btn-dark-ghost  btn-only-icon">
                    <svg class=" shrink-0" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.99469 7.9047C8.70179 7.6118 8.22692 7.6118 7.93403 7.9047C7.64113 8.19759 7.64113 8.67246 7.93403 8.96536L10.9392 11.9706L7.93403 14.9758C7.64114 15.2687 7.64114 15.7435 7.93403 16.0364C8.22693 16.3293 8.7018 16.3293 8.99469 16.0364L11.9999 13.0312L15.0051 16.0364C15.298 16.3293 15.7729 16.3293 16.0658 16.0364C16.3586 15.7435 16.3586 15.2687 16.0658 14.9758L13.0606 11.9706L16.0658 8.96536C16.3587 8.67246 16.3587 8.19759 16.0658 7.9047C15.7729 7.6118 15.298 7.6118 15.0051 7.9047L11.9999 10.9099L8.99469 7.9047Z" fill="currentColor" />
                    </svg>

                </button>
            </div>
            <div class="px-4 md:px-10 overflow-auto flex-1 border-t border-b border-neutral-200">

                <div x-cloak class="text-neutral-800">
                    <div class="flex flex-col gap-2 flex-wrap">

                        <p class="font-medium py-4 md:pt-6 md:pb-3 text-base md:text-xl">Spécialités du magasin</p>
                        <div x-data="storeFilters('types')" class="flex flex-col gap-4 md:gap-6 w-full">
                            <div x-show="items.length > 0" class="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6 pb-4 md:pb-3">
                                <template x-for="item in filteredItems" :key="item.label">
                                    <label class="selection-control-label selection-control-size-md">
                                        <input :checked="$store.locator.currentSelectedFilters[category].includes(item.label)" @click="$store.locator.updateFilter(category, item.label)" type="checkbox">
                                        <span x-text="item.label + ' (' + item.count + ')'"></span>
                                    </label>
                                </template>
                            </div>
                        </div>

                        <script>
                            function storeFilters(category) {
                                return {
                                    search: '',
                                    category: category,
                                    items: [],
                                    init() {
                                        // Observer les changements dans les filtres du type actuel
                                        this.$watch('$store.locator.currentFilterList', (value) => {
                                            if (value && value[this.category]) {
                                                this.items = value[this.category];
                                            }
                                        }, {
                                            deep: true
                                        });
                                        // Initialisation immédiate si les données sont déjà disponibles
                                        if (this.$store.locator.currentFilterList?.[this.category]) {
                                            this.items = this.$store.locator.currentFilterList[this.category];
                                        }
                                    },
                                }
                            }
                        </script>

                        <div x-data="{ expanded: false }" class="border-b border-neutral-200 md:pb-3 text-neutral-800 text-neutral-800">
                            <h2 class="font-medium py-4 md:pt-6 md:pb-3 text-base md:text-xl">
                                <button type="button" @click="expanded = !expanded " class="flex justify-between items-center w-full ">
                                    <span class="flex flex-wrap gap-3">
                                        Mutuelles
                                    </span>

                                    <span :class="expanded ? 'rotate-180' : ''" class="transform transition-transform duration-300">
                                        <svg class=" shrink-0" width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                                            <path fill-rule="evenodd" clip-rule="evenodd" d="M12.5303 14.5303C12.2374 14.8232 11.7626 14.8232 11.4697 14.5303L7.46967 10.5303C7.17678 10.2374 7.17678 9.76256 7.46967 9.46967C7.76256 9.17678 8.23744 9.17678 8.53033 9.46967L12 12.9393L15.4697 9.46967C15.7626 9.17678 16.2374 9.17678 16.5303 9.46967C16.8232 9.76256 16.8232 10.2374 16.5303 10.5303L12.5303 14.5303Z" fill="currentColor" />
                                        </svg>
                                    </span>
                                </button>
                            </h2>
                            <div x-cloak x-show="expanded" x-collapse class=" ">
                                <div x-data="storeFilters('mutuals')" class="flex flex-col gap-4 md:gap-6 w-full">
                                    <label class="relative">
                                        <input x-model="search" type="text" placeholder="Rechercher" class="w-full leading-icon">
                                        <svg class=" shrink-0" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                                            <path fill-rule="evenodd" clip-rule="evenodd" d="M11 3.75C6.99594 3.75 3.75 6.99594 3.75 11C3.75 15.0041 6.99594 18.25 11 18.25C15.0041 18.25 18.25 15.0041 18.25 11C18.25 6.99594 15.0041 3.75 11 3.75ZM2.25 11C2.25 6.16751 6.16751 2.25 11 2.25C15.8325 2.25 19.75 6.16751 19.75 11C19.75 13.1462 18.9773 15.112 17.6949 16.6342L21.5303 20.4697C21.8232 20.7626 21.8232 21.2374 21.5303 21.5303C21.2374 21.8232 20.7626 21.8232 20.4697 21.5303L16.6342 17.6949C15.112 18.9773 13.1462 19.75 11 19.75C6.16751 19.75 2.25 15.8325 2.25 11Z" fill="currentColor" />
                                        </svg>
                                    </label>

                                    <div x-show="items.length > 0" class="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6 pb-4 md:pb-3">
                                        <template x-for="item in filteredItems" :key="item.label">
                                            <label class="selection-control-label selection-control-size-md">
                                                <input :checked="$store.locator.currentSelectedFilters[category].includes(item.label)" @click="$store.locator.updateFilter(category, item.label)" type="checkbox">
                                                <span x-text="item.label + ' (' + item.count + ')'"></span>
                                            </label>
                                        </template>
                                    </div>
                                </div>

                                <script>
                                    function storeFilters(category) {
                                        return {
                                            search: '',
                                            category: category,
                                            items: [],
                                            init() {
                                                // Observer les changements dans les filtres du type actuel
                                                this.$watch('$store.locator.currentFilterList', (value) => {
                                                    if (value && value[this.category]) {
                                                        this.items = value[this.category];
                                                    }
                                                }, {
                                                    deep: true
                                                });
                                                // Initialisation immédiate si les données sont déjà disponibles
                                                if (this.$store.locator.currentFilterList?.[this.category]) {
                                                    this.items = this.$store.locator.currentFilterList[this.category];
                                                }
                                            },
                                            get filteredItems() {
                                                if (this.search === '') {
                                                    return this.items;
                                                }
                                                return this.items.filter(item =>
                                                    item.toLowerCase()
                                                    .replace(/ /g, '')
                                                    .includes(this.search.toLowerCase().replace(/ /g, ''))
                                                );
                                            }
                                        }
                                    }
                                </script>

                            </div>
                        </div>

                        <div x-data="{ expanded: false }" class="border-b border-neutral-200 md:pb-3 text-neutral-800 text-neutral-800">
                            <h2 class="font-medium py-4 md:pt-6 md:pb-3 text-base md:text-xl">
                                <button type="button" @click="expanded = !expanded " class="flex justify-between items-center w-full ">
                                    <span class="flex flex-wrap gap-3">
                                        Marques
                                    </span>

                                    <span :class="expanded ? 'rotate-180' : ''" class="transform transition-transform duration-300">
                                        <svg class=" shrink-0" width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                                            <path fill-rule="evenodd" clip-rule="evenodd" d="M12.5303 14.5303C12.2374 14.8232 11.7626 14.8232 11.4697 14.5303L7.46967 10.5303C7.17678 10.2374 7.17678 9.76256 7.46967 9.46967C7.76256 9.17678 8.23744 9.17678 8.53033 9.46967L12 12.9393L15.4697 9.46967C15.7626 9.17678 16.2374 9.17678 16.5303 9.46967C16.8232 9.76256 16.8232 10.2374 16.5303 10.5303L12.5303 14.5303Z" fill="currentColor" />
                                        </svg>
                                    </span>
                                </button>
                            </h2>
                            <div x-cloak x-show="expanded" x-collapse class=" ">
                                <div x-data="storeFilters('brands')" class="flex flex-col gap-4 md:gap-6 w-full">
                                    <label class="relative">
                                        <input x-model="search" type="text" placeholder="Rechercher" class="w-full leading-icon">
                                        <svg class=" shrink-0" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                                            <path fill-rule="evenodd" clip-rule="evenodd" d="M11 3.75C6.99594 3.75 3.75 6.99594 3.75 11C3.75 15.0041 6.99594 18.25 11 18.25C15.0041 18.25 18.25 15.0041 18.25 11C18.25 6.99594 15.0041 3.75 11 3.75ZM2.25 11C2.25 6.16751 6.16751 2.25 11 2.25C15.8325 2.25 19.75 6.16751 19.75 11C19.75 13.1462 18.9773 15.112 17.6949 16.6342L21.5303 20.4697C21.8232 20.7626 21.8232 21.2374 21.5303 21.5303C21.2374 21.8232 20.7626 21.8232 20.4697 21.5303L16.6342 17.6949C15.112 18.9773 13.1462 19.75 11 19.75C6.16751 19.75 2.25 15.8325 2.25 11Z" fill="currentColor" />
                                        </svg>
                                    </label>

                                    <div x-show="items.length > 0" class="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6 pb-4 md:pb-3">
                                        <template x-for="item in filteredItems" :key="item.label">
                                            <label class="selection-control-label selection-control-size-md">
                                                <input :checked="$store.locator.currentSelectedFilters[category].includes(item.label)" @click="$store.locator.updateFilter(category, item.label)" type="checkbox">
                                                <span x-text="item.label + ' (' + item.count + ')'"></span>
                                            </label>
                                        </template>
                                    </div>
                                </div>

                                <script>
                                    function storeFilters(category) {
                                        return {
                                            search: '',
                                            category: category,
                                            items: [],
                                            init() {
                                                // Observer les changements dans les filtres du type actuel
                                                this.$watch('$store.locator.currentFilterList', (value) => {
                                                    if (value && value[this.category]) {
                                                        this.items = value[this.category];
                                                    }
                                                }, {
                                                    deep: true
                                                });
                                                // Initialisation immédiate si les données sont déjà disponibles
                                                if (this.$store.locator.currentFilterList?.[this.category]) {
                                                    this.items = this.$store.locator.currentFilterList[this.category];
                                                }
                                            },
                                            get filteredItems() {
                                                if (this.search === '') {
                                                    return this.items;
                                                }
                                                return this.items.filter(item =>
                                                    item.toLowerCase()
                                                    .replace(/ /g, '')
                                                    .includes(this.search.toLowerCase().replace(/ /g, ''))
                                                );
                                            }
                                        }
                                    }
                                </script>

                            </div>
                        </div>
                    </div>
                </div>

            </div>
            <div class="p-2 md:px-10 md:py-6">
                <div class="flex items-center justify-between">
                    <a href="#" x-data="{ buttonLabel() { return `Voir les ${$store.locator.countStore} magasins` } }" @click="$store.locator.applyFilters(); $store.asideBlocs.closeAside('storeLocatorFilter')" :class="$store.locator.isAudio ? 'btn-audio' : 'btn-dark'" x-text="buttonLabel()" class="w-full  btn btn-audio btn-size-lg">
                        Voir les magasins

                    </a>
                </div>
            </div>
        </div>
    </div>

    <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 "@storelocator-appointment" %}
    {% render "@storelocator-filter" %}
    {{ yield }}
{% endblock %}
/* No context defined. */

No notes defined.