templates/_partials/courses/_detail.html.twig line 1

Open in your IDE?
  1. <script>
  2. function toggleSession(sessionId, button) {
  3. var session = button.parentElement;
  4. var allSessions = document.querySelectorAll('.session');
  5. allSessions.forEach(function (s) {
  6. if (s !== session) {
  7. s.classList.remove('open');
  8. }
  9. });
  10. session.classList.toggle('open');
  11. }
  12. function toggleAllSessions(button) {
  13. var allSessions = document.querySelectorAll('.session');
  14. var allOpen = Array.from(allSessions).every(function (s) {
  15. return s.classList.contains('open');
  16. });
  17. allSessions.forEach(function (s) {
  18. if (allOpen) {
  19. s.classList.remove('open');
  20. } else {
  21. s.classList.add('open');
  22. }
  23. });
  24. }
  25. </script>
  26. <section id="content">
  27. <h2 id="course_name">
  28. {{ nombre[app.request.locale] | default(nombre | first) | raw }}
  29. </h2>
  30. <div class="course-actions">
  31. {% include '_partials/courses/_favorito.html.twig' with {
  32. actividad: actividad,
  33. tipo: tipo
  34. } %}
  35. {% include '_partials/courses/_share.html.twig' with {
  36. actividad: actividad,
  37. tipo: tipo
  38. } %}
  39. </div>
  40. <div id="course_description">
  41. {{ descripcion[app.request.locale] | default(descripcion | first) | raw }}
  42. </div>
  43. {% if primeraGrupoDeSolicitud is defined and primeraGrupoDeSolicitud is not empty and primeraGrupoDeSolicitud.grupoSesiones is defined %}
  44. <div id="sesiones">
  45. <div class="sessions-container">
  46. <div class="session">
  47. <button class="session-toggle" onclick="toggleAllSessions(this)">
  48. <span class="session-line"></span>
  49. Sesiones
  50. <i class="fas fa-chevron-down arrow"></i>
  51. </button>
  52. {% for gs in primeraGrupoDeSolicitud.grupoSesiones %}
  53. {% set sessionId = "sesion-" ~ loop.index %}
  54. <div id="{{ sessionId }}" class="session-content">
  55. {{ gs.dataHoraInici ? gs.dataHoraInici|date('d-m-Y H:i') : 'Sin inicio' }} -
  56. {{ gs.dataHoraFinal ? gs.dataHoraFinal|date('d-m-Y H:i') : 'Sin fin' }}
  57. </div>
  58. {% endfor %}
  59. </div>
  60. </div>
  61. </div>
  62. {% endif %}
  63. {# Mensaje de motivo del rechazo #}
  64. {% if actividad.inscripcion is defined and actividad.inscripcion.motivoRechazo %}
  65. {% if actividad.inscripcion.estado == 'RECHAZADO_SUBSANABLE' %}
  66. <div class="alert alert-warning" role="alert">
  67. <strong>Motiu del rebuig:</strong> {{ actividad.inscripcion.motivoRechazo }}
  68. </div>
  69. {% elseif actividad.inscripcion.estado in ['RECHAZADO', 'RECHAZADO_DEFINITIVO'] %}
  70. <div class="alert alert-danger" role="alert">
  71. <strong>Motiu del rebuig:</strong> {{ actividad.inscripcion.motivoRechazo }}
  72. </div>
  73. {% endif %}
  74. {% endif %}
  75. <div class="actions mt-4">
  76. {# Definir variables que se usan en todo el template (INC-670) #}
  77. {% set isDefinitivelyRejected = actividad.inscripcion is defined and actividad.inscripcion.estado in ['RECHAZADO', 'RECHAZADO_DEFINITIVO'] %}
  78. {% set isRejected = actividad.inscripcion is defined and actividad.inscripcion.estado in ['RECHAZADO', 'RECHAZADO_DEFINITIVO', 'RECHAZADO_SUBSANABLE'] %}
  79. {# INC-670: Detectar baja solicitada tanto por el flag explícito como por el estado #}
  80. {% set bajaSolicitada = (actividad.inscripcion.bajaSolicitada is defined and actividad.inscripcion.bajaSolicitada)
  81. or (actividad.estado is defined and actividad.estado == 'dado_de_baja')
  82. or (actividad.inscripcion.estado is defined and actividad.inscripcion.estado == 'DADO_DE_BAJA') %}
  83. {# --- INICIO LÓGICA CORREGIDA PARA BAJA (INC-670) --- #}
  84. {% if bajaSolicitada %}
  85. <div class="alert alert-info">
  86. <i class="fas fa-info-circle"></i>
  87. Has solicitado la baja de este curso
  88. {# INC-670: Buscar fecha de baja en inscripcion.fechaBaja o actividad.fechaBaja #}
  89. {% set fechaBajaDisplay = actividad.inscripcion.fechaBaja is defined and actividad.inscripcion.fechaBaja
  90. ? actividad.inscripcion.fechaBaja
  91. : (actividad.fechaBaja is defined ? actividad.fechaBaja : null) %}
  92. {% if fechaBajaDisplay %}
  93. en fecha {{ fechaBajaDisplay|date('d/m/Y') }}.
  94. {% else %}
  95. .
  96. {% endif %}
  97. {% if actividad.inscripcion.motivoBaja is defined and actividad.inscripcion.motivoBaja %}
  98. <br><strong>Motiu:</strong> {{ ('course.baja.motivo.' ~ actividad.inscripcion.motivoBaja)|trans({}, 'courses')|default(actividad.inscripcion.motivoBaja) }}
  99. {% endif %}
  100. </div>
  101. {# A continuación, mostrar el botón para volver a solicitar, que antes estaba oculto #}
  102. <a href="{{ path('dashboard_solicitud_categoria_new_2', {
  103. 'slug': 'anexo_1',
  104. 'callback': callback.reset()
  105. .insertar(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({'grupo_id': actividad.id}))
  106. .insertar('inscripcion_firma_redirect', {'grupo_id': actividad.id})
  107. .token()
  108. }) }}"
  109. class="btn btn-success">
  110. {{ 'Solicitar curso de nuevo'|trans({}, 'courses') }}
  111. </a>
  112. {# Si no está de baja, entonces se muestra el resto de acciones originales #}
  113. {% else %}
  114. {% if tipo == 'grupo' and (actividad.inscrito is defined and actividad.inscrito) %}
  115. {% if not isRejected %}
  116. <span class="btn btn-secondary disabled">{{ 'Inscrito'|trans({}, 'courses')|default('Inscrito') }}</span>
  117. {% endif %}
  118. {# Botón de Cuestionarios #}
  119. {% if not isDefinitivelyRejected and actividad.cuestionario is defined and actividad.cuestionario is not null %}
  120. {% if actividad.cuestionario.formularioRespuesta is not null %}
  121. <a href="{{ path('dashboard_solicitud_categoria_show', {
  122. solicitud_categoria: actividad.cuestionario.formulario,
  123. id: actividad.cuestionario.formularioRespuesta,
  124. callback: callback.reset()
  125. .insertar(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({'grupo_id': actividad.id}))
  126. .token()
  127. }) }}" class="btn btn-primary">Qüestionaris</a>
  128. {% else %}
  129. {% if actividad.estado in ['en_curso', 'finalizado'] %}
  130. <a href="{{ path('dashboard_solicitud_categoria_new_2', {
  131. slug: enum('App\\Enum\\TipoCuestionarioEnum', 'FINALIZACION'),
  132. callback: callback.reset()
  133. .insertar(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({'grupo_id': actividad.id}))
  134. .token()
  135. }) }}" class="btn btn-primary">Qüestionaris</a>
  136. {% endif %}
  137. {% endif %}
  138. {% endif %}
  139. {# Botón de Solicitud de Baja (INC-670: Lógica simplificada y explícita) #}
  140. {# Condiciones para mostrar el botón:
  141. - El curso es tipo 'grupo' (ya estamos en ese bloque)
  142. - El usuario está inscrito (actividad.inscrito - ya verificado arriba)
  143. - El curso NO ha finalizado
  144. - NO es un rechazo definitivo
  145. - NO se ha solicitado la baja previamente
  146. - El estado de inscripción permite solicitar baja (FIRMADO, INSCRITO, PREINSCRITO)
  147. #}
  148. {% set estadosPermitidosBaja = ['FIRMADO', 'INSCRITO', 'PREINSCRITO'] %}
  149. {% set puedesolicitarBaja = not isDefinitivelyRejected
  150. and actividad.estado != 'finalizado'
  151. and not bajaSolicitada
  152. and (actividad.inscripcion.estado is not defined
  153. or actividad.inscripcion.estado in estadosPermitidosBaja) %}
  154. {% if puedesolicitarBaja %}
  155. <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#modalBajaCurso">
  156. Sol·licitud de baixa
  157. </button>
  158. {% elseif bajaSolicitada %}
  159. {# INC-670: Mostrar mensaje explícito si ya se solicitó la baja #}
  160. <span class="btn btn-outline-secondary disabled" title="Ya has solicitado la baja de este curso">
  161. <i class="fas fa-check"></i> Baixa sol·licitada
  162. </span>
  163. {% endif %}
  164. {# Botón para descargar el Certificado #}
  165. {% if not isDefinitivelyRejected and actividad.certificadoUrl is defined and actividad.certificadoUrl %}
  166. <a href="{{ actividad.certificadoUrl }}" target="_blank" class="btn btn-secondary">Certificat</a>
  167. {% endif %}
  168. {# Botón de Documentació pendent o mensajes de rechazo #}
  169. {% if actividad.inscripcion is defined %}
  170. {% if actividad.inscripcion.estado == 'RECHAZADO_SUBSANABLE' %}
  171. {# Rechazo subsanable - permitir editar #}
  172. {% if actividad.inscripcion.idFormularioRespuesta %}
  173. <a href="{{ path('dashboard_solicitud_categoria_edit_2', {
  174. 'slug': 'anexo_1',
  175. 'id': actividad.inscripcion.idFormularioRespuesta,
  176. 'nocache': 1,
  177. 'callback': callback.reset()
  178. .insertar(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({'grupo_id': actividad.id}))
  179. .insertar('inscripcion_firma_redirect', {'grupo_id': actividad.id})
  180. .token()
  181. }) }}" class="btn btn-secondary btn-warning">Editar Anexo (Rechazado)</a>
  182. {% else %}
  183. <a href="{{ path('dashboard_solicitud_categoria_new_2', {
  184. 'slug': 'anexo_1',
  185. 'callback': callback.reset()
  186. .insertar(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({'grupo_id': actividad.id}))
  187. .insertar('inscripcion_firma_redirect', {'grupo_id': actividad.id})
  188. .token()
  189. }) }}" class="btn btn-secondary btn-warning">Editar Anexo (Rechazado)</a>
  190. {% endif %}
  191. {% elseif actividad.inscripcion.estado in ['RECHAZADO', 'RECHAZADO_DEFINITIVO'] %}
  192. {# Rechazo definitivo - solo mostrar mensaje #}
  193. <span class="btn btn-danger disabled">{{ 'action.definitively_rejected'|trans({}, 'courses') }}</span>
  194. {% elseif actividad.inscripcion.estado == 'PREINSCRITO' and not actividad.inscripcion.rutaPdfFirmado %}
  195. {# Preinscritos que no están firmados #}
  196. {% if actividad.inscripcion.idFormularioRespuesta %}
  197. <a href="{{ path('dashboard_solicitud_categoria_edit_2', {
  198. 'slug': 'anexo_1',
  199. 'id': actividad.inscripcion.idFormularioRespuesta,
  200. 'nocache': 1,
  201. 'callback': callback.reset()
  202. .insertar(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({'grupo_id': actividad.id}))
  203. .insertar('inscripcion_firma_redirect', {'grupo_id': actividad.id})
  204. .token()
  205. }) }}" class="btn btn-secondary btn-warning">Documentació pendent</a>
  206. {% else %}
  207. <a href="{{ path('dashboard_solicitud_categoria_new_2', {
  208. 'slug': 'anexo_1',
  209. 'nocache': 1,
  210. 'callback': callback.reset()
  211. .insertar(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({'grupo_id': actividad.id}))
  212. .insertar('inscripcion_firma_redirect', {'grupo_id': actividad.id})
  213. .token()
  214. }) }}" class="btn btn-secondary btn-warning">Documentació pendent</a>
  215. {% endif %}
  216. {% endif %}
  217. {% endif %}
  218. {# --- INICIO MODIFICACIÓN: Envolver el bloque de solicitud en la condición --- #}
  219. {% elseif not isDefinitivelyRejected and tipo == 'grupo' %}
  220. {% if not (actividad.inscripcionEfectivamenteCerrada ?? false) %}
  221. {# Si la inscripción NO está cerrada, mostrar los botones #}
  222. {% if app.user and constant('App\\Enum\\RolEnum::PARTICIPANTE') in app.user.roles %}
  223. {% if actividad.usuarioYaInscritoEnCurso is defined and actividad.usuarioYaInscritoEnCurso %}
  224. <span class="btn btn-secondary disabled">{{ 'courses.already_enrolled'|trans({}, 'courses')|default('Ya inscrito en este curso') }}</span>
  225. {% else %}
  226. <a href="{{ path('dashboard_solicitud_categoria_new_2', {
  227. 'slug': 'anexo_1',
  228. 'callback': callback.reset()
  229. .insertar(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({'grupo_id': actividad.id}))
  230. .insertar('inscripcion_firma_redirect', {'grupo_id': actividad.id})
  231. .token()
  232. }) }}"
  233. class="btn btn-success">
  234. {{ 'Solicitar curso'|trans({}, 'courses')|default('Solicitar curso') }}
  235. </a>
  236. {% endif %}
  237. {% elseif app.user and constant('App\\Enum\\RolEnum::EMPRESA') in app.user.roles %}
  238. {% if actividad.empresaYaInscritaEnCurso.empresa is defined and actividad.empresaYaInscritaEnCurso.empresa %}
  239. <span class="btn btn-secondary disabled">{{ 'courses.already_enrolled'|trans({}, 'courses')|default('Ya inscrito en este curso') }}</span>
  240. {% else %}
  241. {% set btnColor = actividad.empresaYaInscritaEnCurso.empleado | default(false) ? 'btn-primary' : 'btn-secondary' %}
  242. <button type="button" class="btn {{ btnColor }} solicitar-curso-empresa"
  243. data-actividad-id="{{ actividad.id }}"
  244. data-actividad-tipo="{{ tipo }}"
  245. data-curso-nombre="{{ nombre[app.request.locale] | default(nombre | first) }}">
  246. {{ 'Solicitar curso'|trans({}, 'courses')|default('Solicitar curso') }}
  247. </button>
  248. {% endif %}
  249. {% elseif not app.user %}
  250. <a href="{{ path('login_request_credentials') }}" class="btn btn-success solicitar-curso-no-access">
  251. {{ 'Solicitar curso'|trans({}, 'courses')|default('Solicitar curso') }}
  252. </a>
  253. {% endif %}
  254. {% endif %}
  255. {% endif %}
  256. {# --- FIN MODIFICACIÓN --- #}
  257. {% endif %}
  258. {# --- FIN LÓGICA CORREGIDA PARA BAJA --- #}
  259. {% if not isDefinitivelyRejected and ((app.user and (constant('App\\Enum\\RolEnum::PARTICIPANTE') in app.user.roles or constant('App\\Enum\\RolEnum::EMPRESA') in app.user.roles)) or not app.user) %}
  260. {% include '_partials/courses/_interes.html.twig' with {
  261. actividad: actividad,
  262. tipo: tipo,
  263. mostrar_boton: tipo == 'solicitud'
  264. } %}
  265. {% endif %}
  266. {# Botón URL Programa - SIEMPRE VISIBLE si existe la URL #}
  267. {% if actividad.urlPrograma is defined and actividad.urlPrograma %}
  268. <a href="{{ actividad.urlPrograma }}" target="_blank" class="btn btn-info" title="{{ 'course.program_url'|trans({}, 'courses') }}">
  269. <i class="fas fa-external-link-alt"></i>
  270. {{ 'course.program'|trans({}, 'courses') }}
  271. </a>
  272. {% endif %}
  273. </div>
  274. </section>
  275. {# Incluir modal y JavaScript de baja solo si el usuario está inscrito #}
  276. {% if actividad.inscrito is defined and actividad.inscrito %}
  277. {% include '_partials/courses/_modal_baja_curso.html.twig' %}
  278. {% include '_partials/courses/_baja_curso.js.twig' with { actividad: actividad } %}
  279. {% endif %}
  280. {% include '_partials/courses/_js_solicitar_curso_no_access.html.twig' %}