templates/vitrine/fr/homepage.html.twig line 1

Open in your IDE?
  1. {% extends 'vitrine/fr/layout.html.twig' %}
  2. {% block title %}Suite Cathedrale Heritage - Location 8 pers Strasbourg Centre{% endblock title %}
  3. {% block description %}Louez notre suite de 83m² au cœur de Strasbourg. 3 chambres, 8 personnes, à 100m de la Cathédrale. Cuisine équipée, 2 salles de bain. Réservez votre séjour!{% endblock description %}
  4. {% block robots %}index,follow{% endblock robots %}
  5. {% block canonical %}
  6. <link rel="canonical" href="https://cathedraleheritage.com/fr" />
  7. <link rel="alternate" hreflang="fr" href="https://cathedraleheritage.com/fr" />
  8. <link rel="alternate" hreflang="en" href="https://cathedraleheritage.com" />
  9. <link rel="alternate" hreflang="x-default" href="https://cathedraleheritage.com" />
  10. {% endblock canonical %}
  11. {% block body %}
  12. <section id="hero" class="text-light no-top no-bottom relative overflow-hidden z-1000">
  13. <div class="abs w-100 abs-centered z-2">
  14. <div class="container">
  15. <div class="spacer-double"></div>
  16. <div class="row g-4 align-items-center justify-content-center">
  17. <div class="col-md-8 text-center">
  18. <h1 class="mb-2" style="color:white;">Bienvenue sur la Suite Cathédrale Héritage</h1>
  19. <p class="lead mb-3" style="color:white; font-size:22px;">Appartement d'exception, pouvant accueillir jusqu'à 8 personnes au cœur du prestigieux centre historique de Strasbourg</p>
  20. <a class="btn-main btn-line bg-blur fx-slide" href="#about" style="color:white;"><span>Découverte</span></a>
  21. </div>
  22. </div>
  23. </div>
  24. </div>
  25. <div class="vertical-center">
  26. <div class="swiper">
  27. <div class="swiper-wrapper">
  28. <div class="swiper-slide">
  29. <div class="swiper-inner" data-bgimage="url(/images/salon2.jpeg)">
  30. <div class="sw-overlay op-5"></div>
  31. </div>
  32. </div>
  33. <div class="swiper-slide">
  34. <div class="swiper-inner" data-bgimage="url(/images/chambre2.jpeg)">
  35. <div class="sw-overlay op-5"></div>
  36. </div>
  37. </div>
  38. <div class="swiper-slide">
  39. <div class="swiper-inner" data-bgimage="url(/images/noel.jpeg)">
  40. <div class="sw-overlay op-5"></div>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. </div>
  46. <div class="abs w-100 bottom-0 z-2 pb-4 sm-hide">
  47. <div class="container">
  48. <div class="row">
  49. <div class="col-lg-12">
  50. <div class="d-flex justify-content-between">
  51. <div>
  52. <h6 style="color:white;">Cathédrale à 100m</h6>
  53. </div>
  54. <div>
  55. <h6 style="color:white;">Musées à 200m</h6>
  56. </div>
  57. <div>
  58. <h6 style="color:white;">Petite France à 300m</h6>
  59. </div>
  60. </div>
  61. </div>
  62. </div>
  63. </div>
  64. </div>
  65. <div class="gradient-edge-bottom op-8"></div>
  66. </section>
  67. <section id="about">
  68. <div class="container">
  69. <div class="row g-4 align-items-end justify-content-between">
  70. <div class="col-lg-5">
  71. <div class="subtitle">A propos de l'appartement</div>
  72. <h2>Suite moderne en hyper centre de la grande île de Strasbourg</h2>
  73. </div>
  74. <div class="col-lg-4">
  75. <p class="mb-4" style="color:#212121;">
  76. Logement spacieux idéal pour familles et groupes jusqu'à 8 personnes, comprenant deux chambres doubles dont une suite parentale avec une salle de bain, une chambre avec deux lits superposés doubles (4 couchages) maximum de 100kg pour les lits en hauteur.
  77. </p>
  78. <p class="mb-4" style="color:#212121;">
  79. Cuisine entièrement équipée et salon-salle à manger convivial pour partager de bons moments ensemble.
  80. </p>
  81. <p class="mb-4" style="color:#212121;">
  82. Équipements : sèche-cheveux, lave-vaisselle, lave-linge séchant, micro-ondes, four, planche à repasser avec fer, cafetière Nespresso, bouilloire, télévision, Wi-Fi et prises USB pour recharger vos appareils.
  83. </p>
  84. </div>
  85. </div>
  86. <div class="spacer-single"></div>
  87. <div class="row g-4">
  88. <div class="col-md-2">
  89. <div class="relative">
  90. <h5>Taille</h5>
  91. <div class="d-flex justify-content-start align-items-center" style="padding-top:6px;">
  92. <img src="/images/home.png" width="37" class="me-3" alt="">
  93. <div class="fs-20 fw-600" style="color:#212121;">83 m²</div>
  94. </div>
  95. </div>
  96. </div>
  97. <div class="col-md-2">
  98. <div class="relative">
  99. <h5>Chambres</h5>
  100. <div class="d-flex justify-content-start align-items-center" style="padding-top:4px;">
  101. <img src="/images/bed.png" width="37" class="me-3" alt="">
  102. <div class="fs-20 fw-600" style="color:#212121;">3</div>
  103. </div>
  104. </div>
  105. </div>
  106. <div class="col-md-2">
  107. <div class="relative">
  108. <h5>Salon</h5>
  109. <div class="d-flex justify-content-start align-items-center">
  110. <img src="/images/sofa.png" width="50" class="me-3" alt="">
  111. <div class="fs-20 fw-600" style="color:#212121;">Inclus</div>
  112. </div>
  113. </div>
  114. </div>
  115. <div class="col-md-2">
  116. <div class="relative">
  117. <h5>Cuisine</h5>
  118. <div class="d-flex justify-content-start align-items-center" style="padding-top:6px;">
  119. <img src="/images/cooking.png" width="37" class="me-3" alt="">
  120. <div class="fs-20 fw-600" style="color:#212121;">Inclus</div>
  121. </div>
  122. </div>
  123. </div>
  124. <div class="col-md-2">
  125. <div class="relative">
  126. <h5>Salle de bain</h5>
  127. <div class="d-flex justify-content-start align-items-center" style="padding-top:4px;">
  128. <img src="/images/bathroom.png" width="40" class="me-3" alt="">
  129. <div class="fs-20 fw-600" style="color:#212121;">2</div>
  130. </div>
  131. </div>
  132. </div>
  133. <div class="col-md-2">
  134. <div class="relative">
  135. <h5>Personnes</h5>
  136. <div class="d-flex justify-content-start align-items-center" style="padding-top:5px;">
  137. <img src="/images/user.png" width="37" class="me-3" alt="">
  138. <div class="fs-20 fw-600" style="color:#212121;">8</div>
  139. </div>
  140. </div>
  141. </div>
  142. </div>
  143. </div>
  144. </section>
  145. <section id="rooms" class="p-0 overflow-hidden">
  146. <div class="container-fluid">
  147. <div class="row">
  148. <div class="col-lg-12">
  149. <div class="owl-custom-nav menu-float" data-target="#room-carousel">
  150. <a class="btn-next"></a>
  151. <a class="btn-prev"></a>
  152. <div id="room-carousel" class="owl-2-cols-center owl-carousel owl-theme">
  153. <div class="item">
  154. <div class="relative">
  155. <div class="overflow-hidden text-light">
  156. <div class="abs h-100 start-0 z-2 p-4">
  157. <h3 style="color:white;">Salon</h3>
  158. </div>
  159. <img src="/images/salon2.jpeg" class="w-100" alt="Salon">
  160. </div>
  161. </div>
  162. </div>
  163. <div class="item">
  164. <div class="relative">
  165. <div class="overflow-hidden text-light">
  166. <div class="abs h-100 start-1 z-2 p-4">
  167. <h3 style="color:white;">Chambre 1</h3>
  168. </div>
  169. <img src="/images/chambre1.jpeg" class="w-100" alt="Chambre 1">
  170. </div>
  171. </div>
  172. </div>
  173. <div class="item">
  174. <div class="relative">
  175. <div class="overflow-hidden text-light">
  176. <div class="abs h-100 start-2 z-2 p-4">
  177. <h3 style="color:white;">Chambre 2</h3>
  178. </div>
  179. <img src="/images/chambre2.jpeg" class="w-100" alt="Chambre 2">
  180. </div>
  181. </div>
  182. </div>
  183. <div class="item">
  184. <div class="relative">
  185. <div class="overflow-hidden text-light">
  186. <div class="abs h-100 start-3 z-2 p-4">
  187. <h3 style="color:white;">Chambre 3</h3>
  188. </div>
  189. <img src="/images/chambre3.jpeg" class="w-100" alt="Chambre 3">
  190. </div>
  191. </div>
  192. </div>
  193. <div class="item">
  194. <div class="relative">
  195. <div class="overflow-hidden text-light">
  196. <div class="abs h-100 start-4 z-2 p-4">
  197. <h3 style="color:white;">Cuisine</h3>
  198. </div>
  199. <img src="/images/cuisine.jpeg" class="w-100" alt="Cuisine">
  200. </div>
  201. </div>
  202. </div>
  203. <div class="item">
  204. <div class="relative">
  205. <div class="overflow-hidden text-light">
  206. <div class="abs h-100 start-5 z-2 p-4">
  207. <h3 style="color:white;">Salle de bain</h3>
  208. </div>
  209. <img src="/images/salledebain.jpeg" class="w-100" alt="Salle de bain 1">
  210. </div>
  211. </div>
  212. </div>
  213. <div class="item">
  214. <div class="relative">
  215. <div class="overflow-hidden text-light">
  216. <div class="abs h-100 start-6 z-2 p-4">
  217. <h3 style="color:white;">Salle de bain 2</h3>
  218. </div>
  219. <img src="/images/salledebain2.jpeg" class="w-100" alt="Salle de bain 2">
  220. </div>
  221. </div>
  222. </div>
  223. </div>
  224. </div>
  225. </div>
  226. </div>
  227. </div>
  228. </section>
  229. <section id="services" class="overlay-dark-1">
  230. <div class="container">
  231. <div class="row g-4 justify-content-between">
  232. <div class="col-lg-5 relative z-3">
  233. <div class="me-lg-3">
  234. <div class="subtitle wow fadeInUp" data-wow-delay=".0s">Votre séjour à Strasbourg</div>
  235. <h2 class="wow fadeInUp" data-wow-delay=".2s">Tarifs et services</h2>
  236. <p style="color:#212121; font-size:18px;">Une suite d'exception au cœur de Strasbourg, avec conciergerie dédiée pour vous accompagner tout au long de votre séjour.</p>
  237. <p style="color:#212121; font-size:18px;">Réservation minimum deux nuits.</p>
  238. <a href="#reservation" class="btn-main" style="color:white;">Réservation</a>
  239. </div>
  240. </div>
  241. <div class="col-lg-6" style="color:black;">
  242. <div class="spacer-single spacer-double"></div>
  243. <div class="row">
  244. <div class="col-md-6 wow fadeInUp" data-wow-delay=".2s">
  245. {#
  246. <h5 class=" mb-3">Haute saison</h5>
  247. <p class="fs-500"><small>Du 1er juin au 30 septembre • 25 novembre au 05 janvier</small></p>
  248. <ul class="ul-check fs-500">
  249. <li>960 € la nuit</li>
  250. <li>10% de remise à partir de 7 nuits</li>
  251. </ul>
  252. <h5 class="mb-3 mt-4">Hors Saison</h5>
  253. #}
  254. <ul class="ul-check fs-500">
  255. <li>à partir de 350€ la nuit </li>
  256. <li>10% de remise à partir de 7 nuits</li>
  257. </ul>
  258. </div>
  259. <div class="col-md-6 wow fadeInUp" data-wow-delay=".4s">
  260. <h5 class="mb-3">Services optionnels</h5>
  261. <ul class="ul-check fs-500">
  262. <li>Une place de parking : 24 €/jour ou 150 €/semaine</li>
  263. <li>Ménage supplémentaire durant votre séjour : 60 euros</li>
  264. <li>Apéro alsacien : sur commande</li>
  265. <li>Atelier pour enfants, équipements bébé, chiens acceptés sur demande (les autres animaux ne sont malheureusement pas autorisés dans l'appartement), Décoration pour occasions spéciales,…</li>
  266. </ul>
  267. <div class="mt-4">
  268. <p class="fs-500"><strong>Conciergerie sur place</strong><br>
  269. <small>Mardi au samedi • 10h-18h45 <br /> Conciergerie privée sur demande selon disponibilité <br /> Sur devis (Correspond à 10% de la réservation)</small>
  270. </p>
  271. </div>
  272. </div>
  273. </div>
  274. </div>
  275. </div>
  276. </div>
  277. </section>
  278. <section id="section-gallery" class="relative">
  279. <div class="container relative z-2" id="photos">
  280. <div class="row g-4 gx-5 justify-content-center">
  281. <div class="col-lg-6 text-center">
  282. <h2 class="wow fadeInUp" data-wow-delay=".2s">Galerie de l'Appartement</h2>
  283. <p class="wow fadeInUp" data-wow-delay=".3s" style="color:#212121;">Voici les images de l'appartement qui vous permettront de découvrir les différents espaces : chambres, salon, cuisine, salle de bain et extérieur.</p>
  284. </div>
  285. </div>
  286. <div class="row">
  287. <div class="col-md-12 text-center">
  288. <ul id="filters" class="wow fadeInUp" data-wow-delay="0s">
  289. <li><a href="#" data-filter="*" class="selected" style="color:#212121;">Tout afficher</a></li>
  290. <li><a href="#" data-filter=".chambre" style="color:#212121;">Chambres</a></li>
  291. <li><a href="#" data-filter=".salon" style="color:#212121;">Salon</a></li>
  292. <li><a href="#" data-filter=".cuisine" style="color:#212121;">Cuisine</a></li>
  293. <li><a href="#" data-filter=".salledebain" style="color:#212121;">Salle de bain</a></li>
  294. <li><a href="#" data-filter=".exterieur" style="color:#212121;">Extérieur</a></li>
  295. </ul>
  296. </div>
  297. </div>
  298. <div id="gallery" class="row g-3 wow fadeInUp" data-wow-delay=".3s">
  299. <!-- Chambres -->
  300. <div class="col-md-3 col-sm-6 col-12 item chambre">
  301. <a href="images/chambre1.jpeg" class="image-popup d-block hover">
  302. <div class="relative overflow-hidden">
  303. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  304. Voir
  305. </div>
  306. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  307. <img src="images/chambre1.jpeg" class="w-100 hover-scale-1-2" alt="Chambre">
  308. </div>
  309. </a>
  310. </div>
  311. <div class="col-md-3 col-sm-6 col-12 item chambre">
  312. <a href="images/chambre2.jpeg" class="image-popup d-block hover">
  313. <div class="relative overflow-hidden">
  314. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  315. Voir
  316. </div>
  317. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  318. <img src="images/chambre2.jpeg" class="w-100 hover-scale-1-2" alt="Chambre 2">
  319. </div>
  320. </a>
  321. </div>
  322. <div class="col-md-3 col-sm-6 col-12 item chambre">
  323. <a href="images/chambre3.jpeg" class="image-popup d-block hover">
  324. <div class="relative overflow-hidden">
  325. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  326. Voir
  327. </div>
  328. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  329. <img src="images/chambre3.jpeg" class="w-100 hover-scale-1-2" alt="Chambre 3">
  330. </div>
  331. </a>
  332. </div>
  333. <!-- Salon -->
  334. <div class="col-md-3 col-sm-6 col-12 item salon">
  335. <a href="images/salon.jpeg" class="image-popup d-block hover">
  336. <div class="relative overflow-hidden">
  337. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  338. Voir
  339. </div>
  340. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  341. <img src="images/salon.jpeg" class="w-100 hover-scale-1-2" alt="Salon">
  342. </div>
  343. </a>
  344. </div>
  345. <div class="col-md-3 col-sm-6 col-12 item salon">
  346. <a href="images/salon2.jpeg" class="image-popup d-block hover">
  347. <div class="relative overflow-hidden">
  348. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  349. Voir
  350. </div>
  351. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  352. <img src="images/salon2.jpeg" class="w-100 hover-scale-1-2" alt="Salon 2">
  353. </div>
  354. </a>
  355. </div>
  356. <div class="col-md-3 col-sm-6 col-12 item salon">
  357. <a href="images/salon3.jpeg" class="image-popup d-block hover">
  358. <div class="relative overflow-hidden">
  359. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  360. Voir
  361. </div>
  362. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  363. <img src="images/salon3.jpeg" class="w-100 hover-scale-1-2" alt="Salon 3">
  364. </div>
  365. </a>
  366. </div>
  367. <div class="col-md-3 col-sm-6 col-12 item salon">
  368. <a href="images/salon4.jpeg" class="image-popup d-block hover">
  369. <div class="relative overflow-hidden">
  370. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  371. Voir
  372. </div>
  373. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  374. <img src="images/salon4.jpeg" class="w-100 hover-scale-1-2" alt="Salon 4">
  375. </div>
  376. </a>
  377. </div>
  378. <div class="col-md-3 col-sm-6 col-12 item salon">
  379. <a href="images/salon5.jpeg" class="image-popup d-block hover">
  380. <div class="relative overflow-hidden">
  381. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  382. Voir
  383. </div>
  384. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  385. <img src="images/salon5.jpeg" class="w-100 hover-scale-1-2" alt="Salon 5">
  386. </div>
  387. </a>
  388. </div>
  389. <!-- Cuisine -->
  390. <div class="col-md-3 col-sm-6 col-12 item cuisine">
  391. <a href="images/cuisine.jpeg" class="image-popup d-block hover">
  392. <div class="relative overflow-hidden">
  393. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  394. Voir
  395. </div>
  396. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  397. <img src="images/cuisine.jpeg" class="w-100 hover-scale-1-2" alt="Cuisine">
  398. </div>
  399. </a>
  400. </div>
  401. <!-- Salle de bain -->
  402. <div class="col-md-3 col-sm-6 col-12 item salledebain">
  403. <a href="images/salledebain.jpeg" class="image-popup d-block hover">
  404. <div class="relative overflow-hidden">
  405. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  406. Voir
  407. </div>
  408. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  409. <img src="images/salledebain.jpeg" class="w-100 hover-scale-1-2" alt="Salle de bain">
  410. </div>
  411. </a>
  412. </div>
  413. <div class="col-md-3 col-sm-6 col-12 item salledebain">
  414. <a href="images/salledebain2.jpeg" class="image-popup d-block hover">
  415. <div class="relative overflow-hidden">
  416. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  417. Voir
  418. </div>
  419. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  420. <img src="images/salledebain2.jpeg" class="w-100 hover-scale-1-2" alt="Salle de bain 2">
  421. </div>
  422. </a>
  423. </div>
  424. <!-- Extérieur -->
  425. <div class="col-md-3 col-sm-6 col-12 item exterieur">
  426. <a href="images/exterieur.jpeg" class="image-popup d-block hover">
  427. <div class="relative overflow-hidden">
  428. <div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">
  429. Voir
  430. </div>
  431. <div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div>
  432. <img src="images/exterieur.jpeg" class="w-100 hover-scale-1-2" alt="Extérieur">
  433. </div>
  434. </a>
  435. </div>
  436. </div>
  437. </div>
  438. </section>
  439. {# =================================================== #}
  440. {# ============ SECTION RÉSERVATION (refondue) ======= #}
  441. {# =================================================== #}
  442. <section id="reservation" class="text-light">
  443. <div class="container">
  444. <div class="row g-4 justify-content-center">
  445. <div class="col-lg-6 text-center">
  446. <h2 class="wow fadeInUp" data-wow-delay=".2s">Réservez votre séjour</h2>
  447. </div>
  448. </div>
  449. <div class="row g-4 justify-content-center">
  450. <div class="col-lg-8">
  451. <div class="booking-card">
  452. {{ form_start(form) }}
  453. {# ----- CALENDRIER ----- #}
  454. <div class="calendar-container" style="height:300px;">
  455. <input type="text" id="date_range_picker">
  456. </div>
  457. {# ----- DATES RÉCAP (juste sous le calendrier) ----- #}
  458. <div class="row g-3 mt-2 dates-recap">
  459. <div class="col-4 text-center">
  460. <div class="recap-label">Arrivée</div>
  461. <div class="recap-value" id="info-start">-</div>
  462. </div>
  463. <div class="col-4 text-center">
  464. <div class="recap-label">Départ</div>
  465. <div class="recap-value" id="info-end">-</div>
  466. </div>
  467. <div class="col-4 text-center">
  468. <div class="recap-label">Nuits</div>
  469. <div class="recap-value" id="info-nights">-</div>
  470. </div>
  471. </div>
  472. <hr class="booking-divider">
  473. {# ----- WIDGET COMPTEURS ----- #}
  474. <h4 class="booking-title">Indiquez le nombre d'hébergements et de personnes</h4>
  475. <div class="counter-row">
  476. <div class="counter-label">
  477. <div class="counter-title">Chambres</div>
  478. <div class="counter-sub">Selon le nombre de voyageurs</div>
  479. </div>
  480. <div class="counter-controls">
  481. <button type="button" class="counter-btn" data-action="dec" data-target="rooms">−</button>
  482. <span class="counter-value" id="cnt-rooms">1</span>
  483. <button type="button" class="counter-btn" data-action="inc" data-target="rooms">+</button>
  484. </div>
  485. </div>
  486. <div class="counter-row">
  487. <div class="counter-label">
  488. <div class="counter-title">Adultes</div>
  489. </div>
  490. <div class="counter-controls">
  491. <button type="button" class="counter-btn" data-action="dec" data-target="adults">−</button>
  492. <span class="counter-value" id="cnt-adults">2</span>
  493. <button type="button" class="counter-btn" data-action="inc" data-target="adults">+</button>
  494. </div>
  495. </div>
  496. <div class="counter-row">
  497. <div class="counter-label">
  498. <div class="counter-title">Enfants</div>
  499. <div class="counter-sub">1 - 17 ans</div>
  500. </div>
  501. <div class="counter-controls">
  502. <button type="button" class="counter-btn" data-action="dec" data-target="children">−</button>
  503. <span class="counter-value" id="cnt-children">0</span>
  504. <button type="button" class="counter-btn" data-action="inc" data-target="children">+</button>
  505. </div>
  506. </div>
  507. <div id="capacity-warning" class="capacity-warning" style="display:none;"></div>
  508. {# ----- RÉSULTAT PRIX ----- #}
  509. <div id="results" class="mt-3"></div>
  510. <hr class="booking-divider">
  511. {# ----- INFOS PERSONNELLES ----- #}
  512. <div class="row g-3">
  513. <div class="col-md-6">
  514. <label class="booking-label">Nom</label>
  515. {{ form_widget(form.lastname) }}
  516. </div>
  517. <div class="col-md-6">
  518. <label class="booking-label">Prénom</label>
  519. {{ form_widget(form.name) }}
  520. </div>
  521. <div class="col-md-12">
  522. <label class="booking-label">Email</label>
  523. {{ form_widget(form.email) }}
  524. </div>
  525. <div class="col-md-12">
  526. <label class="booking-label">Message</label>
  527. {{ form_widget(form.message) }}
  528. </div>
  529. </div>
  530. {# ----- CGV + SUBMIT ----- #}
  531. <div class="text-center mt-4 cgv-block">
  532. <input type="checkbox" id="acceptCGV"> J'accepte les <a href="{{ path('locale_cgv') }}" target="_blank" style="color:#212121; text-decoration:underline;">CGV</a>
  533. </div>
  534. <div class="text-center mt-3">
  535. <button type="submit" name="submit" value="1" class="btn-main" style="color:white;">Confirmer la réservation</button>
  536. </div>
  537. {# Champs cachés #}
  538. {{ form_widget(form.start) }}
  539. {{ form_widget(form.end) }}
  540. {{ form_widget(form.rooms) }}
  541. {{ form_widget(form.adults) }}
  542. {{ form_widget(form.children) }}
  543. {{ form_widget(form.persons) }}
  544. {{ form_rest(form) }}
  545. {{ form_end(form) }}
  546. </div>
  547. </div>
  548. </div>
  549. </div>
  550. </section>
  551. <section id="faq" class="text-light">
  552. <div class="container">
  553. <div class="row g-4 justify-content-center">
  554. <div class="col-lg-6 text-center">
  555. <h2 class="wow fadeInUp" data-wow-delay=".2s">FAQ</h2>
  556. </div>
  557. </div>
  558. <div class="row g-4 justify-content-center">
  559. <div class="col-lg-6 text-left" style="color:black !important;">
  560. <h3 style="margin-top:7px;">Comment réserver le logement ?</h3>
  561. <div>Vous pouvez réserver directement sur notre site et bientôt via les plateformes partenaires. Le paiement sécurisé confirme immédiatement votre réservation.</div>
  562. <h3 style="margin-top:7px;">Quels sont les horaires d'arrivée et de départ ?</h3>
  563. <ul>
  564. <li>Arrivée : à partir de 15h</li>
  565. <li>Départ : avant 11h</li>
  566. </ul>
  567. <h3 style="margin-top:7px;">Le logement est-il entièrement équipé ?</h3>
  568. <div>Oui, le logement est entièrement meublé et équipé : cuisine, literie, serviettes, électroménager, Wi-Fi,…</div>
  569. <h3 style="margin-top:7px;">Y a-t-il un parking disponible ?</h3>
  570. <div>Oui, un parking privatif est possible en option au prix de 24 euros les 24h ou 150 euros la semaine (7 nuits).</div>
  571. <h3 style="margin-top:7px;">Le logement est-il adapté aux enfants ?</h3>
  572. <div>Oui, nous proposons certains équipements pour enfants (lit bébé, chaise haute, vaisselle adaptée) sur demande.</div>
  573. <h3 style="margin-top:7px;">Les animaux sont-ils acceptés ?</h3>
  574. <div>Merci de nous contacter avant de réserver si vous souhaitez venir avec un animal, les chiens sont les seuls animaux acceptés, mais soumis à une demande préalable.</div>
  575. <h3 style="margin-top:7px;">Puis-je annuler ou modifier ma réservation ?</h3>
  576. <div>Oui, nos conditions d'annulation sont précisées lors de la réservation. Remboursement de 85% du montant de la location si annulation plus d'un mois avant la date d'arrivée, puis 50 % remboursés si annulation entre 1 mois et 15 jours avant la date d'arrivée. Pas de remboursement si annulation moins de 15 jours avant la date d'arrivée.</div>
  577. <h3 style="margin-top:7px;">Le logement est-il accessible en transport public ?</h3>
  578. <div>Oui, les principaux transports sont proches. La station de tram « Langstross, Grand'rue » est à moins de 100 mètres de l'appartement. La gare de Strasbourg est à 10 minutes à pieds.</div>
  579. <h3 style="margin-top:7px;">Y a-t-il des commerces ou restaurants à proximité ?</h3>
  580. <div>Oui, vous trouverez supermarchés, cafés, restaurants et activités touristiques au pied de l'immeuble.</div>
  581. <h3 style="margin-top:7px;">Que faire en cas de problème pendant le séjour ?</h3>
  582. <div>Nous restons disponibles 24h/24 par mail, pour toute urgence ou question concernant le logement, vous pouvez aussi nous joindre entre 9h et 20h par téléphone au 07 61 05 82 43 et nous sommes disponibles</div>
  583. </div>
  584. </div>
  585. </div>
  586. </section>
  587. {% endblock body %}
  588. {% block footerjs %}
  589. <script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
  590. <script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/fr.js"></script>
  591. {# Grille tarifaire exposée au JS #}
  592. <script>
  593. window.PRICING_MATRIX = {{ pricingMatrix|json_encode|raw }};
  594. window.SIMULATION_URL = "{{ path('locale_simulation_pricing', {'_locale': 'fr'}) }}";
  595. console.log('📋 Grille basse saison chargée :', window.PRICING_MATRIX);
  596. console.log('🔗 URL simulation :', window.SIMULATION_URL);
  597. </script>
  598. <script>
  599. // ===========================================================
  600. // Logique chambres / adultes / enfants
  601. //
  602. // Configuration physique :
  603. // - Chambre A : lit double → 2 personnes
  604. // - Chambre B : lit double → 2 personnes
  605. // - Chambre C : lits superposés → 4 personnes (adultes/enfants)
  606. //
  607. // Le nombre de chambres est DÉTERMINÉ automatiquement (pas de choix) :
  608. //
  609. // SANS ENFANTS :
  610. // 1-2 ad → 1 ch
  611. // 3-4 ad → 2 ch
  612. // 5-8 ad → 3 ch
  613. //
  614. // AVEC ENFANTS :
  615. // 1-2 ad → 2 ch (chambre A + chambre superposés)
  616. // 3+ ad → 3 ch (A + B + chambre superposés)
  617. //
  618. // Contraintes : adults + children ≤ 8, children ≤ 4, adults ≥ 1
  619. // ===========================================================
  620. function roomsForCombo(adults, children) {
  621. if (children > 0) {
  622. return adults <= 2 ? 2 : 3;
  623. }
  624. if (adults <= 2) return 1;
  625. if (adults <= 4) return 2;
  626. return 3;
  627. }
  628. function canAddAdult(state) {
  629. if (state.adults >= 8) return false;
  630. return (state.adults + 1 + state.children) <= 8;
  631. }
  632. function canAddChild(state) {
  633. if (state.children >= 4) return false;
  634. return (state.adults + state.children + 1) <= 8;
  635. }
  636. const state = { rooms: 1, adults: 2, children: 0 };
  637. function updateDisplay() {
  638. // Le nombre de chambres est recalculé automatiquement à chaque update
  639. state.rooms = roomsForCombo(state.adults, state.children);
  640. $('#cnt-rooms').text(state.rooms);
  641. $('#cnt-adults').text(state.adults);
  642. $('#cnt-children').text(state.children);
  643. $('#reservation_form_rooms').val(state.rooms);
  644. $('#reservation_form_adults').val(state.adults);
  645. $('#reservation_form_children').val(state.children);
  646. $('#reservation_form_persons').val(state.adults + state.children);
  647. $('.counter-btn').each(function() {
  648. const target = $(this).data('target');
  649. const action = $(this).data('action');
  650. let disabled = false;
  651. if (target === 'rooms') {
  652. // Chambres = toujours verrouillé (déterminé par adultes/enfants)
  653. disabled = true;
  654. }
  655. if (target === 'adults') {
  656. if (action === 'dec' && state.adults <= 1) disabled = true;
  657. if (action === 'inc' && !canAddAdult(state)) disabled = true;
  658. }
  659. if (target === 'children') {
  660. if (action === 'dec' && state.children <= 0) disabled = true;
  661. if (action === 'inc' && !canAddChild(state)) disabled = true;
  662. }
  663. $(this).prop('disabled', disabled).toggleClass('disabled', disabled);
  664. });
  665. $('#capacity-warning').hide();
  666. }
  667. $(document).on('click', '.counter-btn', function() {
  668. if ($(this).prop('disabled')) return;
  669. const target = $(this).data('target');
  670. const action = $(this).data('action');
  671. // Aucune action sur "rooms" (toujours désactivé)
  672. if (target === 'adults') {
  673. if (action === 'inc' && canAddAdult(state)) state.adults++;
  674. if (action === 'dec' && state.adults > 1) state.adults--;
  675. }
  676. if (target === 'children') {
  677. if (action === 'inc' && canAddChild(state)) state.children++;
  678. if (action === 'dec' && state.children > 0) state.children--;
  679. }
  680. updateDisplay();
  681. updateSimulation();
  682. });
  683. function updateSimulation() {
  684. const start = $("#reservation_form_start").val();
  685. const end = $("#reservation_form_end").val();
  686. const persons = state.adults + state.children;
  687. console.log('🔄 updateSimulation', { start, end, rooms: state.rooms, adults: state.adults, children: state.children });
  688. if (!start || !end || persons < 1) {
  689. $("#results").html('');
  690. return;
  691. }
  692. $("#results").html('<div class="loading" style="color:#212121;">Calcul en cours...</div>');
  693. $.post(
  694. window.SIMULATION_URL,
  695. { start: start, end: end, rooms: state.rooms, adults: state.adults, children: state.children }
  696. )
  697. .done(function(data) {
  698. console.log('✅ Simulation OK');
  699. $("#results").html(data);
  700. })
  701. .fail(function(xhr) {
  702. console.error('❌ Simulation KO', xhr.status, xhr.responseText);
  703. $("#results").html('<div class="error" style="color:#a00;">Erreur lors du calcul du prix (' + xhr.status + ')</div>');
  704. });
  705. }
  706. $(document).ready(function() {
  707. updateDisplay();
  708. // Bouton submit désactivé tant que CGV non cochées
  709. $('button[type="submit"]').prop('disabled', true);
  710. $('#acceptCGV').change(function() {
  711. $('button[type="submit"]').prop('disabled', !$(this).is(':checked'));
  712. });
  713. });
  714. </script>
  715. <script>
  716. // ===========================================================
  717. // Flatpickr calendrier
  718. // ===========================================================
  719. $(document).ready(function() {
  720. let bookedRanges = [];
  721. $.ajax({
  722. url: '{{ env('WEBHOOK_CALENDAR_AVAILABILITY') }}',
  723. method: 'POST',
  724. contentType: 'application/json',
  725. data: ''
  726. })
  727. .done(function(data) {
  728. bookedRanges = data.bookings || [];
  729. initDatePicker();
  730. })
  731. .fail(function() { initDatePicker(); });
  732. function parseLocalDate(dateStr) {
  733. const [year, month, day] = dateStr.split('-').map(Number);
  734. return new Date(year, month - 1, day);
  735. }
  736. const isMobile = window.innerWidth <= 900;
  737. function initDatePicker() {
  738. flatpickr("#date_range_picker", {
  739. inline: true,
  740. mode: "range",
  741. locale: "fr",
  742. minDate: new Date(new Date().setDate(new Date().getDate() + 1)),
  743. dateFormat: "Y-m-d",
  744. showMonths: isMobile ? 1 : 2,
  745. disable: [
  746. function(date) {
  747. const checkDate = new Date(date);
  748. checkDate.setHours(0, 0, 0, 0);
  749. return bookedRanges.some(range => {
  750. const start = parseLocalDate(range.start_date);
  751. const end = parseLocalDate(range.end_date);
  752. return checkDate >= start && checkDate <= end;
  753. });
  754. }
  755. ],
  756. onChange: function(selectedDates, dateStr, instance) {
  757. if (selectedDates.length === 2) {
  758. const start = selectedDates[0];
  759. const end = selectedDates[1];
  760. if (isRangeAvailable(start, end)) {
  761. $('#reservation_form_start').val(formatDate(start)).trigger('change');
  762. $('#reservation_form_end').val(formatDate(end)).trigger('change');
  763. updateSelectedInfo(start, end);
  764. updateSimulation();
  765. } else {
  766. alert('⚠️ Cette période contient des dates déjà réservées.');
  767. instance.clear();
  768. clearSymfonyFields();
  769. hideSelectedInfo();
  770. $("#results").html('');
  771. }
  772. } else {
  773. clearSymfonyFields();
  774. hideSelectedInfo();
  775. $("#results").html('');
  776. }
  777. },
  778. onDayCreate: function(dObj, dStr, fp, dayElem) {
  779. const date = new Date(dayElem.dateObj);
  780. date.setHours(0, 0, 0, 0);
  781. const isBooked = bookedRanges.some(range => {
  782. const start = parseLocalDate(range.start_date);
  783. const end = parseLocalDate(range.end_date);
  784. return date >= start && date <= end;
  785. });
  786. if (isBooked) {
  787. dayElem.classList.add('booked');
  788. dayElem.title = 'Date indisponible (réservée)';
  789. } else if (date >= new Date()) {
  790. dayElem.classList.add('available');
  791. }
  792. }
  793. });
  794. }
  795. function isRangeAvailable(startDate, endDate) {
  796. let currentDate = new Date(startDate);
  797. currentDate.setHours(0, 0, 0, 0);
  798. const endCheck = new Date(endDate);
  799. endCheck.setHours(0, 0, 0, 0);
  800. while (currentDate <= endCheck) {
  801. const isBooked = bookedRanges.some(range => {
  802. const start = parseLocalDate(range.start_date);
  803. const end = parseLocalDate(range.end_date);
  804. return currentDate >= start && currentDate <= end;
  805. });
  806. if (isBooked) return false;
  807. currentDate.setDate(currentDate.getDate() + 1);
  808. }
  809. return true;
  810. }
  811. function updateSelectedInfo(start, end) {
  812. const nights = Math.ceil((end - start) / (1000 * 60 * 60 * 24));
  813. $('#info-start').text(start.toLocaleDateString('fr-FR'));
  814. $('#info-end').text(end.toLocaleDateString('fr-FR'));
  815. $('#info-nights').text(`${nights} nuit${nights > 1 ? 's' : ''}`);
  816. }
  817. function hideSelectedInfo() {
  818. $('#info-start').text('-');
  819. $('#info-end').text('-');
  820. $('#info-nights').text('-');
  821. }
  822. function clearSymfonyFields() {
  823. $('#reservation_form_start').val('');
  824. $('#reservation_form_end').val('');
  825. }
  826. function formatDate(date) {
  827. return date.getFullYear() + '-' +
  828. String(date.getMonth() + 1).padStart(2, '0') + '-' +
  829. String(date.getDate()).padStart(2, '0');
  830. }
  831. });
  832. </script>
  833. {% endblock footerjs %}
  834. {% block css %}
  835. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
  836. <style>
  837. /* ===========================================================
  838. Booking card (border blanc, fond transparent, texte noir)
  839. =========================================================== */
  840. .booking-card {
  841. background: transparent;
  842. border: 2px solid white;
  843. border-radius: 12px;
  844. padding: 32px;
  845. color: #212121;
  846. }
  847. .booking-title {
  848. color: #212121;
  849. font-weight: 700;
  850. margin-bottom: 24px;
  851. }
  852. .booking-divider {
  853. border-top: 1px solid rgba(0,0,0,0.15);
  854. margin: 28px 0;
  855. }
  856. .booking-label {
  857. color: #212121;
  858. font-weight: 500;
  859. margin-bottom: 6px;
  860. display: block;
  861. }
  862. .booking-card input.form-control,
  863. .booking-card textarea.form-control {
  864. background: rgba(255,255,255,0.85) !important;
  865. border: 1px solid rgba(0,0,0,0.2) !important;
  866. color: #212121 !important;
  867. }
  868. .booking-card input.form-control::placeholder,
  869. .booking-card textarea.form-control::placeholder {
  870. color: rgba(0,0,0,0.4) !important;
  871. }
  872. .booking-card input.form-control:focus,
  873. .booking-card textarea.form-control:focus {
  874. border-color: #212121 !important;
  875. box-shadow: 0 0 0 0.2rem rgba(0,0,0,0.08) !important;
  876. }
  877. .cgv-block { color: #212121; }
  878. .cgv-block a { color: #212121; text-decoration: underline; }
  879. /* ----- Dates récap ----- */
  880. .dates-recap { color: #212121; }
  881. .recap-label {
  882. font-size: 13px;
  883. text-transform: uppercase;
  884. letter-spacing: 0.5px;
  885. opacity: 0.7;
  886. }
  887. .recap-value {
  888. font-size: 18px;
  889. font-weight: 600;
  890. margin-top: 4px;
  891. }
  892. /* ----- Widget compteurs ----- */
  893. .counter-row {
  894. display: flex;
  895. justify-content: space-between;
  896. align-items: center;
  897. padding: 14px 0;
  898. border-bottom: 1px solid rgba(0,0,0,0.1);
  899. }
  900. .counter-row:last-of-type { border-bottom: none; }
  901. .counter-title {
  902. font-size: 16px;
  903. font-weight: 500;
  904. color: #212121;
  905. }
  906. .counter-sub {
  907. font-size: 12px;
  908. color: rgba(0,0,0,0.6);
  909. margin-top: 2px;
  910. }
  911. .counter-controls {
  912. display: flex;
  913. align-items: center;
  914. gap: 12px;
  915. }
  916. .counter-btn {
  917. width: 40px;
  918. height: 40px;
  919. border-radius: 8px;
  920. border: 1.5px solid #212121;
  921. background: transparent;
  922. color: #212121;
  923. font-size: 20px;
  924. font-weight: 600;
  925. line-height: 1;
  926. cursor: pointer;
  927. transition: all 0.15s;
  928. }
  929. .counter-btn:hover:not(.disabled) {
  930. background: rgba(0,0,0,0.06);
  931. }
  932. .counter-btn.disabled,
  933. .counter-btn:disabled {
  934. border-color: rgba(0,0,0,0.2);
  935. color: rgba(0,0,0,0.25);
  936. cursor: not-allowed;
  937. background: transparent;
  938. }
  939. .counter-value {
  940. min-width: 28px;
  941. text-align: center;
  942. font-size: 16px;
  943. font-weight: 500;
  944. color: #212121;
  945. }
  946. .capacity-warning {
  947. margin-top: 12px;
  948. padding: 10px 14px;
  949. background: rgba(255,180,0,0.18);
  950. border: 1px solid rgba(180,120,0,0.5);
  951. border-radius: 6px;
  952. color: #8a4500;
  953. font-size: 14px;
  954. }
  955. /* ===========================================================
  956. Calendrier
  957. =========================================================== */
  958. .calendar-container {
  959. margin: 0 0 8px 0;
  960. width: 100%;
  961. display: flex;
  962. justify-content: center;
  963. }
  964. #date_range_picker { display: none; }
  965. .flatpickr-calendar.inline {
  966. box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  967. border-radius: 8px;
  968. }
  969. .flatpickr-day.booked {
  970. background-color: #ff4444 !important;
  971. color: white !important;
  972. cursor: not-allowed !important;
  973. position: relative;
  974. }
  975. .flatpickr-day.booked::after {
  976. content: "✕";
  977. position: absolute;
  978. top: 50%; left: 50%;
  979. transform: translate(-50%, -50%);
  980. font-size: 20px;
  981. font-weight: bold;
  982. }
  983. .flatpickr-day.booked:hover { background-color: #ff0000 !important; }
  984. .flatpickr-day.available:hover { background-color: #28a745; color: white; }
  985. @media (max-width: 768px) {
  986. .booking-card { padding: 20px; }
  987. .calendar-container { margin: 0 0 8px 0; padding: 0; }
  988. .flatpickr-calendar.inline { width: 100% !important; max-width: 100% !important; }
  989. .flatpickr-months { padding: 8px 10px; }
  990. .flatpickr-days { width: 100% !important; }
  991. .dayContainer {
  992. width: 100% !important;
  993. min-width: 100% !important;
  994. max-width: 100% !important;
  995. }
  996. .flatpickr-day {
  997. height: 40px !important;
  998. line-height: 40px !important;
  999. flex-basis: 14.2857% !important;
  1000. max-width: 14.2857% !important;
  1001. }
  1002. }
  1003. </style>
  1004. {% endblock css %}