templates/base.html.twig line 1

Open in your IDE?
  1. <!DOCTYPE html>
  2. <html lang="{{ app.session.get('_locale') }}">
  3.     {% set lang = app.session.get('_locale') %}
  4.     {% if lang is null or  app.session.get('_locale') =='' %}
  5.     {% set lang  = 'en'%}
  6.     {% endif%}
  7.     <head>
  8.         <link rel="icon" type="image/x-icon" href="{{ asset('icons/favicon.ico') }}" />
  9.         <meta charset="UTF-8">
  10.         <title>
  11.                 {% set lang = app.session.get('_locale') %}
  12.                 {{ ('title' ~ lang ) |trans({}, 'messages') }}
  13.         </title>
  14.         <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text></svg>">
  15.         {# ═════════════ PWA (Progressive Web App) ═════════════ #}
  16.         <link rel="manifest" href="{{ asset('manifest.json') }}">
  17.         <meta name="theme-color" content="#00a7b5">
  18.         <meta name="mobile-web-app-capable" content="yes">
  19.         <meta name="apple-mobile-web-app-capable" content="yes">
  20.         <meta name="apple-mobile-web-app-status-bar-style" content="default">
  21.         <meta name="apple-mobile-web-app-title" content="Julico">
  22.         <link rel="apple-touch-icon" href="{{ asset('images/julico-icon-192.png') }}">
  23.         <link rel="apple-touch-icon" sizes="192x192" href="{{ asset('images/julico-icon-192.png') }}">
  24.         <link rel="apple-touch-icon" sizes="512x512" href="{{ asset('images/julico-icon-512.png') }}">
  25.         {# ════════════════════════════════════════════════════ #}
  26.         {# Run `composer require symfony/webpack-encore-bundle` to start using Symfony UX #}
  27.         {% block stylesheets %}
  28.             {# {{ encore_entry_link_tags('app') }} #}
  29.             <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
  30.             <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  31.             <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  32.             
  33.             <link rel="stylesheet" href="{{asset('css/style.css') }}">
  34.             {# ═════════════ Julico mobile nav drawer (additive, ≤768px only) ═════════════ #}
  35.             <style>
  36.             @media (max-width: 768px){
  37.                 /* hide the cramped horizontal category bar + redundant desktop user menu */
  38.                 #categoriesnav,
  39.                 .navigation-user-menu{ display:none !important; }
  40.                 /* keep the burger visible + tappable on mobile */
  41.                 #burgernav{
  42.                     display:inline-flex !important;
  43.                     align-items:center !important;
  44.                     justify-content:center !important;
  45.                     background:transparent !important;
  46.                     border:none !important;
  47.                     box-shadow:none !important;
  48.                     padding:8px 10px !important;
  49.                     min-height:44px !important;
  50.                 }
  51.                 #openBtn{ text-decoration:none !important; }
  52.                 #openBtn .burger-icon{ display:inline-block; width:26px; }
  53.                 #openBtn .burger-icon span{
  54.                     display:block; height:3px; margin:5px 0;
  55.                     background:#00a7b5; border-radius:2px;
  56.                 }
  57.                 /* off-canvas slide-out drawer */
  58.                 #mySidenav.sidenav{
  59.                     position:fixed !important;
  60.                     top:0 !important;
  61.                     left:0 !important;
  62.                     height:100% !important;
  63.                     height:100dvh !important;
  64.                     width:82% !important;
  65.                     max-width:320px !important;
  66.                     background:#ffffff !important;
  67.                     z-index:2000 !important;
  68.                     transform:translateX(-100%) !important;
  69.                     transition:transform .28s ease !important;
  70.                     overflow-y:auto !important;
  71.                     -webkit-overflow-scrolling:touch;
  72.                     box-shadow:2px 0 18px rgba(0,0,0,.25) !important;
  73.                     padding:56px 16px 28px !important;
  74.                 }
  75.                 body.julico-nav-open #mySidenav.sidenav{ transform:translateX(0) !important; }
  76.                 /* backdrop */
  77.                 #julico-nav-backdrop{
  78.                     position:fixed; inset:0;
  79.                     background:rgba(0,0,0,.45);
  80.                     opacity:0; visibility:hidden;
  81.                     transition:opacity .28s ease;
  82.                     z-index:1999;
  83.                 }
  84.                 body.julico-nav-open #julico-nav-backdrop{ opacity:1; visibility:visible; }
  85.                 body.julico-nav-open{ overflow:hidden; }
  86.                 /* close (×) button */
  87.                 #mySidenav #closeBtn.close{
  88.                     position:absolute !important;
  89.                     top:8px !important;
  90.                     right:16px !important;
  91.                     font-size:34px !important;
  92.                     line-height:1 !important;
  93.                     color:#333 !important;
  94.                     text-decoration:none !important;
  95.                     z-index:5;
  96.                 }
  97.                 /* drawer items → full-width 44px tap targets */
  98.                 #mySidenav ul{ list-style:none !important; padding:0 !important; margin:0 !important; }
  99.                 #mySidenav form{ margin:0 !important; }
  100.                 #mySidenav .btn,
  101.                 #mySidenav .main-button{
  102.                     display:block !important;
  103.                     width:100% !important;
  104.                     text-align:left !important;
  105.                     min-height:44px !important;
  106.                     padding:12px 14px !important;
  107.                     margin:2px 0 !important;
  108.                     border-radius:8px !important;
  109.                     font-size:16px !important;
  110.                     box-shadow:none !important;
  111.                 }
  112.                 #mySidenav .navigation-cat-main-menu .main-button{
  113.                     font-weight:600 !important;
  114.                     color:#00a7b5 !important;
  115.                 }
  116.                 #mySidenav .navigation-action-br{
  117.                     display:flex !important;
  118.                     gap:8px !important;
  119.                     margin-top:10px !important;
  120.                     border-top:1px solid #eee !important;
  121.                     padding-top:12px !important;
  122.                 }
  123.                 #mySidenav .navigation-action-br .btn{ width:auto !important; flex:1 !important; text-align:center !important; }
  124.             }
  125.             </style>
  126.             {# ════════════════════════════════════════════════════════════════════════════ #}
  127.         {% endblock %}
  128.         <meta name="viewport" content="width=device-width, initial-scale=1.0">
  129.         <meta name="description" content="{%block metaDescription %} Shoping Online Beirut Lebanon Commandes{% endblock%} ">
  130.     </head>
  131.     <body>
  132.         
  133.         {% if not app.request.cookies.get('cookies_accepted') %}
  134. <div id="cookie-banner" style="position: fixed; bottom: 0; width: 100%; background: #222; color: #fff; padding: 1em; text-align: center; z-index: 1000;">
  135.     Ce site utilise des cookies pour améliorer votre expérience. 
  136.     <button onclick="acceptCookies()" style="margin-left: 10px;">
  137.         
  138.     {{ ('accepter' ~ lang ) |trans({}, 'messages') }}
  139.     </button>
  140.     <button onclick="refuseCookies()" style="margin-left: 5px;">
  141.         {{ ('refuser' ~ lang ) |trans({}, 'messages') }}
  142.         </button>
  143. </div>
  144. <script>
  145.     function acceptCookies() {
  146.         document.cookie = "cookies_accepted=true; path=/; max-age=31536000";
  147.         document.getElementById("cookie-banner").style.display = "none";
  148.         location.reload();
  149.     }
  150.     function refuseCookies() {
  151.         document.cookie = "cookies_accepted=false; path=/; max-age=31536000";
  152.         document.getElementById("cookie-banner").style.display = "none";
  153.     }
  154. </script>
  155. {% endif %}
  156.         
  157.         {#
  158.             {% if app.user and app.user.isVerified == false%}       
  159.                 <div class="alert alert-warning alert-dissmissible" role="alert">
  160.                 
  161.                        <button type="button" class="btn-close" data-bs-dismiss="alert" arial-label="close"> 
  162.                     </button>
  163.                  
  164.         
  165.                     <div class="alert-message">
  166.                         <strong> Votre compte n'est pas activé </strong> , renvoyer le lien d'activ ation     
  167.                     <div>
  168.                 </div>
  169.             {% endif %}
  170.         #}
  171.         {% include('/_flash.html.twig') %}
  172.         {% include 'includes/popup.html.twig' with {'message_popup': 'Voici un message dynamique dans le popup!'} %}
  173.     <div class="bodymain">
  174.        
  175.             
  176.         <div id="main-head" class="header-container">
  177.              <div class="cards">
  178.             <div class="  languages">
  179.                 <ul class="cardtextlang">
  180.                     <li><a href="{{ path('app_locale', {'_locale': 'en'}) }}">English</a></li>
  181.                     <span> | </span>
  182.                     <li><a href="{{ path('app_locale', {'_locale': 'fr'}) }}">Français</a></li>
  183.                 </ul>
  184.             </div>
  185.         </div>
  186.             <div id="pub-head" class=" h-container h-pub-container">
  187.                 <div class="cardflexrowcenter navigation-action">   
  188.                     <form>
  189.                         <button class="btn navbar-brand main-button" formaction="/"> 
  190.                             {{ ('discount' ~ lang ) |trans({}, 'messages') }}
  191.                             PROFITEZ -50%
  192.                         
  193.                         </button>
  194.                     </form>  
  195.                 
  196.                 </div>
  197.               
  198.            
  199.             </div>
  200.             <div class=" h-container navigation-sticky ">
  201.                 <!--<button class="cta-button">Click Me</button>
  202.                 <div class="promo-icon">
  203.                 </div>-->
  204.                 <div class="navigation-action ">
  205.                 <div id="burgernav" class="card btn btn-default btn-light burgernav">
  206.                     {{ render(controller(
  207.                         'App\\Controller\\BaseCommonController::burgerbar'
  208.                         )) }}
  209.                 </div>
  210.                 <div id="searchnav" class="card btn btn-default btn-light  btn searchnav">
  211.                     {{ render(controller(
  212.                         'App\\Controller\\BaseCommonController::searchbar'
  213.                         )) }}
  214.                 </div>
  215.                 </div>
  216.                 
  217.                 <div class="card cardlogo navigation-logo logo-l-o logomob navigation-sticky " >
  218.                     <a class="" id="logo-link" href="/home">
  219.                             <!--<i class="fa-solid fa-glasses"></i>-->
  220.                             <img src="/images/julico-logo.png"  class="cardimglogo" alt="MDN" />
  221.                         </img>
  222.                     </a>
  223.                     
  224.                 </div>  
  225.                   
  226.                 <div class="card cardlogo navigation-logo logo-l-o logomain " >
  227.                     <a class="" id="logo-link" href="/home">
  228.                             <!--<i class="fa-solid fa-glasses"></i>-->
  229.                             <img src="/images/julico-logo.png"  class="cardimglogo" alt="MDN" />
  230.                         </img>
  231.                     </a>
  232.                     
  233.                 </div>  
  234.                     {% if app.request.headers.get('User-Agent') matches '/Mobile/i' %}
  235.                 <!-- Affichage du menu burger pour la version mobile -->
  236.                 {% else %}
  237.                 <!-- Affichage du menu complet pour les autres versions -->
  238.                 {% endif %}
  239.                 <div id="categoriesnav" class="categoriesnav">
  240.                     {{ render(controller(
  241.                         'App\\Controller\\BaseCommonController::navbar',
  242.                         { 'max': 3 }
  243.                     )) }} 
  244.                 </div>
  245.                     
  246.             <div class="navigation-action" >
  247.                 
  248.                 {% if app.user %}
  249.                 <form>
  250.                     <button class="card btn btn-default btn-light" formaction="/profile"> <i class="fa-regular fa-user"></i></button>
  251.                 </form>
  252.                 {% else %}
  253.                 
  254.                     <form>
  255.                         <button class="card btn btn-default btn-light" formaction="/login"> <i class="fa-regular fa-user"></i></button>
  256.                     </form>
  257.                 {% endif %}
  258.                 <form>
  259.                     <button class="card btn btn-default btn-light" formaction="/aboutus"> 
  260.                         <i class="fa-solid fa-id-card-clip"></i>
  261.                     </button>
  262.                 </form>
  263.                     <form>
  264.                         <button class="card btn btn-default btn-light" formaction="/panier"><i class="fa-solid fa-cart-shopping"></i></button>
  265.                     
  266.                     </form>
  267.                 </div>
  268.                 
  269.                 
  270.                 
  271.             </div> 
  272.             <div class="h-container navigation-user-menu">
  273.                     {% if app.user %}
  274.                     <div>
  275.                         <ul>
  276.                             <li><a class="btn btn-default btn-light" href="{{path('app_logout')}}">
  277.                                  
  278.                                 {{  ('logout' ~ lang )|trans({}, 'messages') }}
  279.                                 <a></li>
  280.                         </ul>
  281.                     </div>
  282.                             {% if  is_granted('ROLE_USER')  %}
  283.                             <div>
  284.                                 <span>
  285.                                 </span>
  286.                                     <ul>
  287.                                         <li><a class="btn btn-default btn-light" href="{{ path('show_commande_user') }}">
  288.                             {{ ('listedescommandes' ~ lang ) |trans({}, 'messages') }}
  289.                              </a> </li>
  290.                                         
  291.                                     </ul>
  292.                              </div>
  293.                             
  294.                             
  295.                             {% endif %}
  296.                             
  297.                             {% if  is_granted('ROLE_ADMIN')  %}
  298.                             <div>
  299.                                 <span> 
  300.                                 </span>
  301.                                     <ul>
  302.                                         <li><a class="btn btn-default btn-light" href="{{ path('app_category') }}">
  303.                                             {{ ('gestionstock' ~ lang ) |trans({}, 'messages') }}
  304.                                             
  305.                                              </a> </li>
  306.                                         <li><a class="btn btn-default btn-light" href="{{ path('admin_promotions') }}">
  307.                                             {{ ('gestionpromotion' ~ lang ) |trans({}, 'messages') }}
  308.                                             
  309.                                              </a> </li>
  310.                                         <li><a class="btn btn-default btn-light" href="{{ path('maintenance_new') }}">
  311.                                             {{ ('gestionmaintenance' ~ lang ) |trans({}, 'messages') }}
  312.                                             <i class="fas fa-toolbox"></i>
  313.                                              </a> </li>
  314.                                         
  315.                                         
  316.                                         <li><a class="btn btn-default btn-light" href="{{ path('app_home') }}">
  317.                                             
  318.                                             {{ ('suspensionutilisateur' ~ lang ) |trans({}, 'messages') }}
  319.                                          </a> </li>
  320.                                        {% if 
  321.                                         app.request.attributes.get('_route') == 'show_facture'
  322.                                         %}
  323.                                         <li><a class="btn btn-default btn-light" href="{{ path('app_home') }}">Not used</a> </li>
  324.                                         {% endif%}
  325.                                     </ul>
  326.                             </div>
  327.                             {% endif %}
  328.                     {% else %}    
  329.                     <div class="cards">
  330.                         <ul>
  331.                             <li><a class="btn btn-default btn-light " href="{{path('app_login')}}">
  332.                                {{ ('login' ~ lang )    |trans({}, 'messages') }}
  333.                               
  334.                              </a></li>
  335.                             
  336.                             <li><a class="btn btn-default btn-light" href="{{path('app_register')}}">
  337.                                 {{  ('register' ~ lang ) |trans({}, 'messages') }}
  338.                                 
  339.                                   </a></li>
  340.                         </ul>
  341.                     </div>
  342.                     {% endif %}
  343.             
  344.                 </div>
  345.                
  346.                 
  347.             
  348.                 
  349.        
  350.             </div>
  351.         </div>
  352.     </div>
  353.         <main>
  354.             
  355.             {% block body %}
  356.             {% endblock %}
  357.             <div class=" cardflexcol"> 
  358.                 <div id="footer">
  359.                             {% include('/footer.html.twig') %}
  360.                 </div>
  361.             </div>
  362.                     
  363.                     {% block javascripts %}
  364.                     {# {{ encore_entry_script_tags('app') }} #}
  365.                     <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.3.5/axios.min.js" integrity="sha512-nnNHpffPSgINrsR8ZAIgFUIMexORL5tPwsfktOTxVYSv+AUAILuFYWES8IHl+hhIhpFGlKvWFiz9ZEusrPcSBQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  366.                     <script src="{{asset('js/script.js')}}"></script>        
  367.                     {# ═════════════ Julico mobile nav drawer toggle (additive) ═════════════ #}
  368.                     <script>
  369.                     (function(){
  370.                         function init(){
  371.                             var nav  = document.getElementById('mySidenav');
  372.                             if(!nav){ return; }
  373.                             var open  = document.getElementById('openBtn');
  374.                             var close = document.getElementById('closeBtn');
  375.                             var bd = document.getElementById('julico-nav-backdrop');
  376.                             if(!bd){
  377.                                 bd = document.createElement('div');
  378.                                 bd.id = 'julico-nav-backdrop';
  379.                                 document.body.appendChild(bd);
  380.                             }
  381.                             function openNav(e){ if(e){ e.preventDefault(); } document.body.classList.add('julico-nav-open'); }
  382.                             function closeNav(e){ if(e){ e.preventDefault(); } document.body.classList.remove('julico-nav-open'); }
  383.                             if(open){ open.addEventListener('click', openNav); }
  384.                             if(close){ close.addEventListener('click', closeNav); }
  385.                             bd.addEventListener('click', closeNav);
  386.                             // close drawer when a real link/button inside it is tapped
  387.                             nav.addEventListener('click', function(ev){
  388.                                 var t = ev.target.closest('a, button');
  389.                                 if(t && t.id !== 'closeBtn'){ document.body.classList.remove('julico-nav-open'); }
  390.                             });
  391.                             // Esc closes
  392.                             document.addEventListener('keydown', function(ev){
  393.                                 if(ev.key === 'Escape'){ closeNav(); }
  394.                             });
  395.                         }
  396.                         if(document.readyState === 'loading'){
  397.                             document.addEventListener('DOMContentLoaded', init);
  398.                         } else {
  399.                             init();
  400.                         }
  401.                     })();
  402.                     </script>
  403.                     {# ══════════════════════════════════════════════════════════════════════ #}
  404.                     <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js" type="text/javascript"></script>
  405.                     <script src="https://www.google.com/recaptcha/api.js" async defer></script>
  406.                         {% if app.request.attributes.get('_route') starts with 'admin_promotions' %}
  407.                             <script src="{{ asset('./js/promo.js') }}"></script>
  408.                         {% endif %}
  409.                     {# ═════════════ PWA: service worker + install handler ═════════════ #}
  410.                     <script>
  411.                     // Register service worker
  412.                     if ('serviceWorker' in navigator) {
  413.                       window.addEventListener('load', function() {
  414.                         navigator.serviceWorker.register('/sw.js', { scope: '/' })
  415.                           .then(function(reg) { console.log('[PWA] SW registered:', reg.scope); })
  416.                           .catch(function(err) { console.warn('[PWA] SW registration failed:', err); });
  417.                       });
  418.                     }
  419.                     // Capture install prompt event
  420.                     window.__pwaPromptEvent = null;
  421.                     window.addEventListener('beforeinstallprompt', function(e) {
  422.                       e.preventDefault();
  423.                       window.__pwaPromptEvent = e;
  424.                       console.log('[PWA] Install prompt captured — button is now active');
  425.                       // Reveal any install buttons
  426.                       document.querySelectorAll('.pwa-install-btn').forEach(function(btn) {
  427.                         btn.style.display = '';
  428.                         btn.removeAttribute('hidden');
  429.                       });
  430.                     });
  431.                     // Click handler for any element with class="pwa-install-btn"
  432.                     document.addEventListener('click', function(ev) {
  433.                       var btn = ev.target.closest('.pwa-install-btn');
  434.                       if (!btn) return;
  435.                       ev.preventDefault();
  436.                       var prompt = window.__pwaPromptEvent;
  437.                       if (!prompt) {
  438.                         // Already installed, unsupported browser, or prompt not yet captured
  439.                         if (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches) {
  440.                           alert('Julico is already installed! Look for it in your taskbar or applications.');
  441.                         } else if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
  442.                           alert('To install Julico on iOS:\n1. Tap the Share button\n2. Tap "Add to Home Screen"');
  443.                         } else {
  444.                           alert('To install Julico:\n• On Chrome/Edge desktop: look for the install icon in the address bar\n• Or open the browser menu and click "Install Julico…"');
  445.                         }
  446.                         return;
  447.                       }
  448.                       prompt.prompt();
  449.                       prompt.userChoice.then(function(choice) {
  450.                         console.log('[PWA] User choice:', choice.outcome);
  451.                         window.__pwaPromptEvent = null;
  452.                       });
  453.                     });
  454.                     // When installed, hide the install button
  455.                     window.addEventListener('appinstalled', function() {
  456.                       document.querySelectorAll('.pwa-install-btn').forEach(function(btn) {
  457.                         btn.style.display = 'none';
  458.                       });
  459.                       console.log('[PWA] App installed successfully');
  460.                     });
  461.                     </script>
  462.                     {# ════════════════════════════════════════════════════════════════ #}
  463.                     {% endblock %}
  464.         </main>
  465.     
  466.     </body>
  467. </html>