templates/base.html.twig line 136

Open in your IDE?
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  6. <title>{% block title %}Corepetitus{% endblock %}</title>
  7. {% for css_file in encore_entry_css_files('app') %}
  8. <link rel="stylesheet" href="{{ css_file }}?v=5.1"/>
  9. {% endfor %}
  10. <link rel="manifest" href="/manifest.json">
  11. <link rel="mask-icon" href="{{ asset('assets/images/safari-pinned-tab.svg') }}" color="#1b6690">
  12. <link rel="icon" href="{{ asset('assets/images/core-logo-min.png') }}" type="image/png">
  13. <meta name="msapplication-TileColor" content="#2d89ef">
  14. <meta name="msapplication-config" content="{{ asset('/browserconfig.xml') }}">
  15. <meta name="theme-color" content="#2d89ef">
  16. {% block stylesheets %}
  17. <style>
  18. #loader {
  19. transition: all 0.3s ease-in-out;
  20. opacity: 1;
  21. visibility: visible;
  22. position: fixed;
  23. height: 100vh;
  24. width: 100%;
  25. background: #fff;
  26. z-index: 90000;
  27. }
  28. #loader.fadeOut {
  29. opacity: 0;
  30. visibility: hidden;
  31. }
  32. .spinner {
  33. width: 40px;
  34. height: 40px;
  35. position: absolute;
  36. top: calc(50% - 20px);
  37. left: calc(50% - 20px);
  38. background-color: #333;
  39. border-radius: 100%;
  40. -webkit-animation: sk-scaleout 1.0s infinite ease-in-out;
  41. animation: sk-scaleout 1.0s infinite ease-in-out;
  42. }
  43. @-webkit-keyframes sk-scaleout {
  44. 0% {
  45. -webkit-transform: scale(0)
  46. }
  47. 100% {
  48. -webkit-transform: scale(1.0);
  49. opacity: 0;
  50. }
  51. }
  52. @keyframes sk-scaleout {
  53. 0% {
  54. -webkit-transform: scale(0);
  55. transform: scale(0);
  56. }
  57. 100% {
  58. -webkit-transform: scale(1.0);
  59. transform: scale(1.0);
  60. opacity: 0;
  61. }
  62. }
  63. </style>
  64. {% endblock %}
  65. </head>
  66. <body class="{% block bodyclass %}app{% endblock %}">
  67. <!-- @TOC -->
  68. <!-- =================================================== -->
  69. <!--
  70. + @Page Loader
  71. + @App Content
  72. - #Left Sidebar
  73. > $Sidebar Header
  74. > $Sidebar Menu
  75. - #Main
  76. > $Topbar
  77. > $App Screen Content
  78. -->
  79. <!-- @Page Loader -->
  80. <!-- =================================================== -->
  81. {% if app.environment != 'dev' %}
  82. <div id='loader'>
  83. <div class="spinner"></div>
  84. </div>
  85. {% endif %}
  86. <!-- @App Content -->
  87. <!-- =================================================== -->
  88. {# <div class="{{ app.request.attributes.get('_route') }}"> #}
  89. <div class="{% if is_granted('ROLE_GUARDIAN') or is_granted('ROLE_TEACHER') or is_granted('ROLE_CHILD') %}version_2{% endif %}">
  90. <!-- ### Left side bar menu ### -->
  91. {{ include('menu_components/side_menu/left_sidebar_menu_v2.html.twig') }}
  92. <!-- #Main ============================ -->
  93. {% if getInfoLines() is not empty %}
  94. {% set infoLine = getInfoLines()|first %}
  95. {% if is_granted('ROLE_TEACHER') and app.user.id == 517%}
  96. {% else %}
  97. <div class="wrapperrunngline">
  98. <div class="marquee">
  99. {% for i in 0..20 %}
  100. <a target="_blank"
  101. href="{{ infoLine.link }}">
  102. <img src="http://corepetitus.lt/wp-content/uploads/2024/10/favicon.svg" alt="corepetitus">
  103. {{ infoLine.description|replace({" ": "&nbsp;"})|raw }}
  104. </a>
  105. {% endfor %}
  106. </div>
  107. </div>
  108. {% endif %}
  109. {% endif %}
  110. <div class="page-container">
  111. <!-- ### $Topbar ### -->
  112. {% if is_granted('IS_IMPERSONATOR') %}
  113. <div class="peer" style="bottom: 0;z-index: 10000;position: fixed;">
  114. <a class="btn btn-success" href="{{ impersonation_exit_path(path('dashboard') ) }}">Grįžti į savo
  115. sesiją</a>
  116. </div>
  117. {% endif %}
  118. {{ include('menu_components/header_nav_bar/header_nav_bar_new.html.twig') }}
  119. <!-- ### $MainBody ### -->
  120. {% block body %}
  121. {% endblock %}
  122. {% if is_granted("ROLE_TEACHER") and (survey_data is not defined or survey_data is empty) %}
  123. {% set firstLessonSurveyData = getTeacherFirstLessonSurveyData() %}
  124. {% if firstLessonSurveyData is not empty %}
  125. {% include 'me/teacher/me_teacher_after_first_lesson_modal.html.twig' with {survey_data:firstLessonSurveyData} %}
  126. {% endif %}
  127. {% if show_preference_modal is defined and show_preference_modal %}
  128. {% include 'me/teacher/me_teacher_auto_preferences_modal.html.twig'%}
  129. {% endif %}
  130. {% endif %}
  131. {% if is_granted('ROLE_TEACHER') %}
  132. {% if app.user.qrCode is null or app.user.qrCode.documentPath is null %}
  133. {% include '/me/teacher/me_teacher_missing_qr_code_modal.html.twig' %}
  134. {% endif %}
  135. {% set lastLessonSurveyData = getTeacherLastLessonSurveyData() %}
  136. {% if lastLessonSurveyData is not empty %}
  137. {% include 'me/teacher/me_teacher_after_last_lesson_modal.html.twig' with {survey_data:lastLessonSurveyData} %}
  138. {% endif %}
  139. {% endif %}
  140. {% if is_granted("ROLE_ADMIN") %}
  141. {{ render(controller(
  142. 'App\\Controller\\BugReport\\BugReportController::form'
  143. )) }}
  144. {% endif %}
  145. <!-- ### $App Screen Footer ### -->
  146. <footer style="background: #FFF" class="bdT ta-c p-30 lh-0 fsz-sm c-grey-600">
  147. <span>2026 Copyright © COREPETITUS.LT</span>
  148. </footer>
  149. </div>
  150. </div>
  151. {% set allowed_ips = ['84.15.151.106', '83.181.124.158', '78.56.131.247'] %}
  152. {% if is_granted('ROLE_GUARDIAN') or is_granted('ROLE_TEACHER') or is_granted('ROLE_CHILD') %}
  153. {{ include('me/chat_widget.html.twig') }}
  154. {% endif %}
  155. <script>
  156. (function () {
  157. if ('serviceWorker' in navigator) {
  158. navigator.serviceWorker.register('/assets/service-worker.js');
  159. }
  160. })();
  161. window.addEventListener('load', function () {
  162. const loader = document.getElementById('loader');
  163. if (loader) {
  164. setTimeout(function () {
  165. loader.classList.add('fadeOut');
  166. }, 300);
  167. }
  168. });
  169. </script>
  170. {% block javascripts %}
  171. {# <script src="{{ asset('assets/runtime.js') }}?v=v3"></script>#}
  172. {# <script src="{{ asset('assets/app.js') }}?v=v3"></script>#}
  173. {% for js_file in encore_entry_js_files('app') %}
  174. {% set src = js_file|replace({'<script src="': '', '"></script>': ''}) %}
  175. <script src="{{ src }}?v=3"></script>
  176. {% endfor %}
  177. {% if is_granted('ROLE_GUARDIAN') or is_granted('ROLE_TEACHER') %}
  178. <script>
  179. const unreadNotifs = {{ getUserNotificationCount() }};
  180. if (unreadNotifs > 0 && !getCookie('ceNModal') && !window.location.href.includes('notifications')) {
  181. Swal.fire({
  182. html: `
  183. <div class='card blue'>
  184. <div class='card-body'>
  185. <div class="icon">
  186. <i style="font-size: 24px;
  187. margin-bottom: 15px;" class="fa-solid fa-bell"></i>
  188. </div>Svarbu! turi ${unreadNotifs} neperskaitytus pranešimus!</div>
  189. </div>`,
  190. showCancelButton: true,
  191. confirmButtonColor: "#1AB2FE",
  192. cancelButtonColor: "#d33",
  193. confirmButtonText: "Peržiūrėti",
  194. cancelButtonText: "Priminti vėliau",
  195. customClass: {
  196. container: "version_2",
  197. icon: 'border-0'
  198. }
  199. }).then((result) => {
  200. if (result.isConfirmed) {
  201. setCookie('ceNModal', true, 30);
  202. window.location = `{{ path('app_me_notification_index') }}`;
  203. } else {
  204. setCookie('ceNModal', true, 30);
  205. }
  206. })
  207. }
  208. </script>
  209. {% endif %}
  210. {% if is_granted('ROLE_TEACHER') and teacherHasLessonsToday() %}
  211. <script>
  212. (function () {
  213. const storageKey = 'teacherLessonReviewReminder';
  214. function getNextResetAt8AM() {
  215. const now = new Date();
  216. const reset = new Date(now);
  217. reset.setHours(8, 0, 0, 0);
  218. if (now.getTime() >= reset.getTime()) {
  219. reset.setDate(reset.getDate() + 1);
  220. }
  221. return reset.getTime();
  222. }
  223. const storedUntil = parseInt(localStorage.getItem(storageKey) || '0', 10);
  224. if (Date.now() < storedUntil) {
  225. return;
  226. }
  227. localStorage.setItem(storageKey, String(getNextResetAt8AM()));
  228. Swal.fire({
  229. title: 'Primename',
  230. customClass: "version_2",
  231. html:`
  232. <div class='card blue'>
  233. <div class='card-body'>
  234. <div class="icon">
  235. <i style="font-size: 24px;
  236. margin-bottom: 15px;" class="fa-solid fa-bell"></i>
  237. </div>Mokiniai jus vertina po kiekvienos pamokos.</div>
  238. </div>
  239. `,
  240. confirmButtonText: 'Ok',
  241. });
  242. })();
  243. </script>
  244. {% endif %}
  245. {% if is_granted('ROLE_CHILD') %}
  246. {% set childLessonReminder = getChildClosestLessonReminder() %}
  247. {% if childLessonReminder %}
  248. {% set childLessonReviewModalHtml %}
  249. {% include 'child_lesson_review/_review_modal_content.html.twig' with {lesson: childLessonReminder} %}
  250. {% endset %}
  251. <script>
  252. (function () {
  253. const lesson = {{ childLessonReminder|json_encode|raw }};
  254. const submitUrl = '{{ path('app_child_lesson_review_submit') }}';
  255. const dismissUrl = '{{ path('app_child_lesson_review_dismiss') }}';
  256. const originalTitle = document.title;
  257. const alertTitle = '(1) Corepetitus įvertinimas';
  258. let titleFlashTimer = null;
  259. function startTitleFlash() {
  260. if (titleFlashTimer) {
  261. return;
  262. }
  263. let showAlert = false;
  264. titleFlashTimer = setInterval(() => {
  265. document.title = showAlert ? originalTitle : alertTitle;
  266. showAlert = !showAlert;
  267. }, 1000);
  268. }
  269. function stopTitleFlash() {
  270. if (titleFlashTimer) {
  271. clearInterval(titleFlashTimer);
  272. titleFlashTimer = null;
  273. }
  274. document.title = originalTitle;
  275. }
  276. const now = Date.now();
  277. const triggerAt = new Date(lesson.triggerAt).getTime();
  278. const forceUntil = lesson.forceUntil ? new Date(lesson.forceUntil).getTime() : null;
  279. if (forceUntil !== null && now >= forceUntil) {
  280. return;
  281. }
  282. const fire = () => {
  283. if (forceUntil !== null && Date.now() >= forceUntil) {
  284. return;
  285. }
  286. startTitleFlash();
  287. if (forceUntil !== null && forceUntil > Date.now()) {
  288. setTimeout(stopTitleFlash, forceUntil - Date.now());
  289. }
  290. let selectedRating = null;
  291. Swal.fire({
  292. title: 'Įvertink pamoką',
  293. customClass: { popup: 'version_2 child-lesson-review-swal' },
  294. html: {{ childLessonReviewModalHtml|json_encode|raw }},
  295. confirmButtonText: 'Pateikti',
  296. confirmButtonColor: '#1AB2FE',
  297. showCancelButton: false,
  298. showCloseButton: true,
  299. allowOutsideClick: false,
  300. allowEscapeKey: false,
  301. focusConfirm: false,
  302. didOpen: () => {
  303. document.querySelectorAll('.child-lesson-review-rating').forEach((btn) => {
  304. btn.addEventListener('click', () => {
  305. document.querySelectorAll('.child-lesson-review-rating').forEach((b) => b.classList.remove('is-selected'));
  306. btn.classList.add('is-selected');
  307. selectedRating = parseInt(btn.dataset.rating, 10);
  308. });
  309. });
  310. },
  311. preConfirm: () => {
  312. if (!selectedRating) {
  313. Swal.showValidationMessage('Pasirink įvertinimą');
  314. return false;
  315. }
  316. const commentEl = document.getElementById('child-lesson-review-comment');
  317. return {
  318. rating: selectedRating,
  319. comment: commentEl ? commentEl.value.trim() : '',
  320. };
  321. },
  322. }).then(async (result) => {
  323. if (result.dismiss) {
  324. stopTitleFlash();
  325. await fetch(dismissUrl, {
  326. method: 'POST',
  327. headers: { 'Content-Type': 'application/json' },
  328. body: JSON.stringify({ lessonId: lesson.lessonId }),
  329. });
  330. window.location.reload();
  331. return;
  332. }
  333. if (!result.isConfirmed || !result.value) {
  334. return;
  335. }
  336. try {
  337. const response = await fetch(submitUrl, {
  338. method: 'POST',
  339. headers: { 'Content-Type': 'application/json' },
  340. body: JSON.stringify({
  341. lessonId: lesson.lessonId,
  342. rating: result.value.rating,
  343. comment: result.value.comment,
  344. }),
  345. });
  346. const data = await response.json();
  347. if (!response.ok) {
  348. throw new Error(data.message || 'Nepavyko išsaugoti');
  349. }
  350. stopTitleFlash();
  351. await Swal.fire({
  352. icon: 'success',
  353. title: 'Ačiū!',
  354. text: 'Jūsų atsiliepimas išsaugotas.',
  355. confirmButtonText: 'Ok',
  356. customClass: { popup: 'version_2' },
  357. });
  358. window.location.reload();
  359. } catch (error) {
  360. Swal.fire({
  361. icon: 'error',
  362. title: 'Klaida',
  363. text: error.message || 'Nepavyko išsaugoti',
  364. confirmButtonText: 'Ok',
  365. customClass: { popup: 'version_2' },
  366. });
  367. }
  368. });
  369. };
  370. if (now >= triggerAt) {
  371. fire();
  372. } else {
  373. setTimeout(fire, triggerAt - now);
  374. }
  375. })();
  376. </script>
  377. {% endif %}
  378. {% endif %}
  379. {% endblock %}
  380. </body>
  381. </html>