{"id":2870,"date":"2025-10-19T17:36:22","date_gmt":"2025-10-19T17:36:22","guid":{"rendered":"http:\/\/epee33.fr\/?page_id=2870"},"modified":"2025-10-28T07:20:45","modified_gmt":"2025-10-28T07:20:45","slug":"the-room","status":"publish","type":"page","link":"https:\/\/epee33.fr\/?page_id=2870","title":{"rendered":"THE ROOM"},"content":{"rendered":"    \n    <!-- FullCalendar -->\n    <link href=\"https:\/\/cdn.jsdelivr.net\/npm\/fullcalendar@6.1.11\/index.global.min.css\" rel=\"stylesheet\">\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/fullcalendar@6.1.11\/index.global.min.js\"><\/script>\n\n    <div style=\"max-width:850px;margin:auto;\">\n        <h2>\ud83d\udd4a R\u00e9servation de la salle<\/h2>\n        <div id=\"calendar\"><\/div>\n\n        <!-- \ud83d\udd3d MESSAGE AJOUT\u00c9 ICI -->\n        <div id=\"selection-message\"\n             style=\"display:none;margin-top:15px;padding:10px;background:#e6ffed;border:1px solid #166534;\n             color:#166534;font-weight:500;border-radius:8px;\">\n        <\/div>\n\n        <hr style=\"margin:30px 0;\">\n\n        <h3>\ud83d\udcc5 Faire une r\u00e9servation<\/h3>\n        <form id=\"reservation-form\" style=\"background:#f9f9f9;padding:15px;border-radius:10px;\">\n            <label>Votre nom :<\/label><br>\n            <input type=\"text\" id=\"agenda_nom\" required><br><br>\n\n            <label>Email :<\/label><br>\n            <input type=\"email\" id=\"agenda_email\" required><br><br>\n\n            <label>Date :<\/label><br>\n            <input type=\"date\" id=\"agenda_date_resa\" required><br><br>\n\n            <label>Heure de d\u00e9but :<\/label><br>\n            <input type=\"time\" id=\"agenda_heure_debut\" required><br><br>\n\n            <label>Dur\u00e9e :<\/label><br>\n            <select id=\"agenda_duree\" required>\n                <option value=\"1\">1 heure<\/option>\n                <option value=\"2\">2 heures<\/option>\n                <option value=\"3\">3 heures<\/option>\n                <option value=\"4\">4 heures<\/option>\n            <\/select><br><br>\n\n            <button type=\"submit\">R\u00e9server<\/button>\n        <\/form>\n    <\/div>\n\n<script>\n    const theRoomUser = {\n        name: false,\n        email: false    };\n<\/script>\n\n<script>\ndocument.addEventListener('DOMContentLoaded', function() {\n\n    \/\/ \ud83d\udd3d REMPLIR AUTOMATIQUEMENT NOM + EMAIL\n    document.getElementById(\"agenda_nom\").value = theRoomUser.name;\n    document.getElementById(\"agenda_email\").value = theRoomUser.email;\n\t\n    const calendarEl = document.getElementById('calendar');\n    const form = document.getElementById('reservation-form');\n    const selectionMessage = document.getElementById('selection-message');\n    const currentUser = document.body.getAttribute('data-current-user') || '';\n\n    let selectedStart = null;\n    let selectedEnd = null;\n\n    const calendar = new FullCalendar.Calendar(calendarEl, {\n        initialView: 'timeGridWeek',\n        slotMinTime: \"05:00:00\",\n        slotMaxTime: \"23:00:00\",\n\t\tslotDuration: \"01:00:00\",\n        snapDuration: \"01:00:00\",\n        locale: 'fr',\n        allDaySlot: false,\n        selectable: true,\n        editable: true,\n        eventStartEditable: true,\n        eventDurationEditable: true,\n        nowIndicator: true,\n        timeZone: 'local',\n        selectOverlap: false,\n\n        events: async function(fetchInfo, successCallback, failureCallback) {\n            try {\n                const response = await fetch('\/wp-json\/the-room\/v1\/reservations');\n                const data = await response.json();\n                const events = data.map(evt => ({\n                    ...evt,\n                    start: new Date(evt.start),\n                    end: new Date(evt.end),\n                    editable: evt.email === currentUser,\n                    color: evt.email === currentUser ? '#58a6ff' : '#b0b0b0'\n                }));\n                successCallback(events);\n            } catch (err) {\n                console.error(\"Erreur chargement :\", err);\n                failureCallback(err);\n            }\n        },\n\n        \/\/ \ud83d\udd3d\ud83d\udd3d\ud83d\udd3d CHANGEMENT ICI : AFFICHAGE DU CR\u00c9NEAU S\u00c9LECTIONN\u00c9 SOUS LE CALENDRIER\n        select: function(info) {\n            const start = info.start;\n            const end = info.end;\n            const duration = (end - start) \/ (1000 * 60 * 60);\n\n            if (duration > 4) {\n                alert(\"\u26d4 Maximum 4 heures !\");\n                calendar.unselect();\n                return;\n            }\n\n            selectedStart = start;\n            selectedEnd = end;\n\n            document.getElementById('agenda_date_resa').value = start.toISOString().split('T')[0];\n            document.getElementById('agenda_heure_debut').value = start.toTimeString().substring(0,5);\n            document.getElementById('agenda_duree').value = duration;\n\n            const startText = start.toLocaleString('fr-FR', {\n                weekday: 'long', hour: '2-digit', minute: '2-digit'\n            });\n            const endText = end.toLocaleTimeString('fr-FR', {\n                hour: '2-digit', minute: '2-digit'\n            });\n\n            selectionMessage.innerText = `\ud83d\udccc Cr\u00e9neau s\u00e9lectionn\u00e9 : ${startText} \u2192 ${endText}`;\n            selectionMessage.style.display = \"block\";\n        },\n        \/\/ \ud83d\udd3c\ud83d\udd3c\ud83d\udd3c FIN DU CHANGEMENT\n\n        eventDrop: async function(info) {\n            if (info.event.extendedProps.email !== currentUser) {\n                alert(\"\u26d4 Vous ne pouvez modifier que vos propres r\u00e9servations.\");\n                info.revert();\n                return;\n            }\n            await updateEvent(info.event);\n        },\n\n        eventResize: async function(info) {\n            if (info.event.extendedProps.email !== currentUser) {\n                alert(\"\u26d4 Vous ne pouvez modifier que vos propres r\u00e9servations.\");\n                info.revert();\n                return;\n            }\n            await updateEvent(info.event);\n        },\n\n        eventClick: async function(info) {\n            const evt = info.event;\n            if (evt.extendedProps.email !== currentUser) return;\n\n            if (confirm(`\ud83d\uddd1\ufe0f Supprimer la r\u00e9servation \"${evt.title}\" ?`)) {\n                try {\n                    const response = await fetch(`\/wp-json\/the-room\/v1\/reservations\/${evt.id}`, {\n                        method: 'DELETE'\n                    });\n                    if (response.ok) {\n                        await calendar.refetchEvents();\n                        alert(\"\u2705 R\u00e9servation supprim\u00e9e !\");\n                    } else {\n                        alert(\"\u274c Erreur lors de la suppression.\");\n                    }\n                } catch (err) {\n                    console.error(\"Erreur suppression :\", err);\n                }\n            }\n        }\n    });\n\n    calendar.render();\n\n    form.addEventListener('submit', async function(e) {\n        e.preventDefault();\n\n        const nom = document.getElementById('agenda_nom').value;\n        const email = document.getElementById('agenda_email').value;\n        const date = document.getElementById('agenda_date_resa').value;\n        const heure = document.getElementById('agenda_heure_debut').value;\n        const duree = parseInt(document.getElementById('agenda_duree').value);\n\n        let start = selectedStart;\n        let end = selectedEnd;\n\n        if (!start) {\n            start = new Date(`${date}T${heure}:00`);\n            end = new Date(start.getTime() + duree * 60 * 60 * 1000);\n        }\n\n        const diffHours = (end - start) \/ (1000 * 60 * 60);\n        if (diffHours > 4) {\n            alert(\"\u26d4 Dur\u00e9e maximum 4 heures.\");\n            return;\n        }\n\n        const formatLocal = (d) => {\n            const pad = (n) => n < 10 ? '0' + n : n;\n            return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) +\n                'T' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':00';\n        };\n\n        const newEvent = {\n            title: nom,\n            start: formatLocal(start),\n            end: formatLocal(end),\n            name: nom,\n            email: email\n        };\n\n        try {\n            const response = await fetch('\/wp-json\/the-room\/v1\/reservations', {\n                method: 'POST',\n                headers: {'Content-Type': 'application\/json'},\n                body: JSON.stringify(newEvent)\n            });\n\n            if (response.ok) {\n                await calendar.refetchEvents();\n                alert(\"\u2705 R\u00e9servation enregistr\u00e9e !\");\n                form.reset();\n                selectionMessage.style.display = \"none\";\n                selectedStart = null;\n                selectedEnd = null;\n            } else {\n                const err = await response.json();\n\n                if (err.error === \"overlap\") {\n                    alert(\"\u26d4 Impossible : un autre priant a d\u00e9j\u00e0 r\u00e9serv\u00e9 ce cr\u00e9neau.\");\n                } else {\n                    alert(\"\u274c Erreur lors de la r\u00e9servation.\");\n                }\n            }\n\n            } catch (err) {\n                console.error(err);\n            }\n        });\n\n    async function updateEvent(event) {\n        const formatLocal = (d) => {\n            const pad = (n) => n < 10 ? '0' + n : n;\n            return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) +\n                'T' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':00';\n        };\n\n        const updated = {\n            id: event.id,\n            title: event.title,\n            start: formatLocal(event.start),\n            end: formatLocal(event.end),\n            email: event.extendedProps.email\n        };\n\n        try {\n            const response = await fetch(`\/wp-json\/the-room\/v1\/reservations\/${event.id}`, {\n                method: 'PUT',\n                headers: {'Content-Type': 'application\/json'},\n                body: JSON.stringify(updated)\n            });\n\n            if (response.ok) {\n                await calendar.refetchEvents();\n                alert(\"\u2705 R\u00e9servation mise \u00e0 jour !\");\n            } else {\n                alert(\"\u274c Erreur lors de la mise \u00e0 jour.\");\n            }\n        } catch (err) {\n            console.error(\"Erreur mise \u00e0 jour :\", err);\n        }\n    }\n});\n<\/script>\n\n\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"qubely_global_settings":"","qubely_interactions":"","_crdt_document":"","_uag_custom_page_level_css":"","advgb_blocks_editor_width":"","advgb_blocks_columns_visual_guide":"","_themeisle_gutenberg_block_has_review":false,"footnotes":""},"class_list":["post-2870","page","type-page","status-publish","hentry"],"featured_image_src":null,"featured_image_src_square":null,"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false,"ab-block-post-grid-landscape":false,"ab-block-post-grid-square":false,"qubely_landscape":false,"qubely_portrait":false,"qubely_thumbnail":false,"gb-block-post-grid-landscape":false,"gb-block-post-grid-square":false,"hestia-blog":false},"uagb_author_info":{"display_name":"Guillaume Gerbore","author_link":"https:\/\/epee33.fr\/?author=2"},"uagb_comment_info":0,"uagb_excerpt":null,"coauthors":[],"author_meta":{"author_link":"https:\/\/epee33.fr\/?author=2","display_name":"Guillaume Gerbore"},"relative_dates":{"created":"Publi\u00e9 6 mois il y a","modified":"Mis \u00e0 jour 6 mois il y a"},"absolute_dates":{"created":"Publi\u00e9 le 19 octobre 2025","modified":"Mise \u00e0 jour le 28 octobre 2025"},"absolute_dates_time":{"created":"Publi\u00e9 le 19 octobre 2025 5:36 pm","modified":"Mise \u00e0 jour le 28 octobre 2025 7:20 am"},"featured_img_caption":"","featured_img":false,"series_order":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/epee33.fr\/index.php?rest_route=\/wp\/v2\/pages\/2870","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/epee33.fr\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/epee33.fr\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/epee33.fr\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/epee33.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2870"}],"version-history":[{"count":5,"href":"https:\/\/epee33.fr\/index.php?rest_route=\/wp\/v2\/pages\/2870\/revisions"}],"predecessor-version":[{"id":2882,"href":"https:\/\/epee33.fr\/index.php?rest_route=\/wp\/v2\/pages\/2870\/revisions\/2882"}],"wp:attachment":[{"href":"https:\/\/epee33.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2870"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}