Refactor elimination feature and improve backoffice usability

This commit introduces a refactored EliminationFactory for better modularity, updates the elimination preparation process, and adds functionality to view eliminations. Backoffice templates and forms have been reorganized, minor translations were corrected, and additional assets like styles and flashes were included for enhanced user experience.
This commit is contained in:
2025-05-30 20:38:20 +02:00
parent e0350c8c31
commit d3e5cb0569
45 changed files with 1569 additions and 978 deletions

View File

@@ -1,49 +1,3 @@
<!DOCTYPE html>
<html lang="nl" data-bs-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"></script>
<script
src="https://js-de.sentry-cdn.com/30cf438bc708c97e6f45c127bed9af96.min.js"
crossorigin="anonymous"
></script>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<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><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
<title>
{% block title %}Tijd voor de test{% endblock title %}
</title>
{% block stylesheets %}
{% endblock %}
{% block javascripts %}
{% endblock %}
</head>
<body>
{% block nav %}
{{ include('backoffice/nav.html.twig') }}
{% endblock nav %}
<main>
<div class="container">
{% for label, messages in app.flashes() %}
{% for message in messages %}
<div class="alert alert-{{ label }} alert-dismissible " role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endfor %}
{% block body %}
{% endblock body %}
</div>
</main>
</body>
</html>
{% extends 'base.html.twig' %}
{% block importmap %}{{ importmap('backoffice') }}{% endblock %}
{% block nav %}{{ include('backoffice/nav.html.twig') }}{% endblock %}

View File

@@ -1,3 +1,40 @@
{% extends 'backoffice/base.html.twig' %}
{% block body %}
<div class="row">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ path('app_backoffice_index') }}">Home</a></li>
<li class="breadcrumb-item"><a
href="{{ path('app_backoffice_season', {seasonCode: elimination.quiz.season.seasonCode}) }}">{{ elimination.quiz.season.name }}</a>
</li>
<li class="breadcrumb-item"><a
href="{{ path('app_backoffice_quiz', {seasonCode: elimination.quiz.season.seasonCode, quiz: elimination.quiz.id}) }}">{{ elimination.quiz.name }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Prepare Elimination</li>
</ol>
</nav>
</div>
<div class="row">
<div class="col-12 col-md-6">
<form>
{%~ for candidate, colour in elimination.data %}
<div class="row mb-3">
<label for="colour-{{ candidate|lower }}" class="col-4 col-form-label">{{ candidate }}</label>
<div class="col-4">
<select id="colour-{{ candidate|lower }}" class="form-select"
name="colour-{{ candidate|lower }}">
<option value="green"{% if colour == 'green' %} selected{% endif %}>Green</option>
<option value="red"{% if colour == 'red' %} selected{% endif %}>Red</option>
</select>
</div>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">{{ 'Save'|trans }}</button>
</form>
</div>
<div class="col-12 col-md-6">
<p>Hier kan dus weer wat uitleg komen</p>
</div>
</div>
{% endblock %}

View File

@@ -14,7 +14,7 @@
<div id="questions">
<h4 class="py-2">{{ 'Questions'|trans }}</h4>
<div class="accordion">
{% for question in quiz.questions %}
{%~ for question in quiz.questions ~%}
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed"
@@ -23,23 +23,23 @@
data-bs-target="#question-{{ loop.index0 }}"
aria-controls="question-{{ loop.index0 }}">
{% set questionErrors = question.getErrors %}
{% if questionErrors %}
{%~ if questionErrors -%}
<span data-bs-toggle="tooltip"
title="{{ questionErrors }}"
class="badge text-bg-danger rounded-pill me-2">!</span>
{% endif %}
{{ loop.index }}. {{ question.question }}
{{~ loop.index -}}. {{ question.question -}}
</button>
</h2>
<div id="question-{{ loop.index0 }}"
class="accordion-collapse collapse">
<div class="accordion-body">
<ul>
{% for answer in question.answers %}
<li {% if answer.isRightAnswer %}class="text-decoration-underline"{% endif %}>{{ answer.text }}</li>
{% else %}
{{ 'There are no answers for this question'|trans }}
{% endfor %}
{%~ for answer in question.answers %}
<li{% if answer.isRightAnswer %} class="text-decoration-underline"{% endif %}>{{ answer.text -}}</li>
{%~ else %}
{{ 'There are no answers for this question'|trans -}}
{%~ endfor %}
</ul>
</div>
</div>
@@ -50,17 +50,23 @@
</div>
</div>
<div class="scores">
<p>
<h4>{{ 'Score'|trans }}</h4>
</p>
<h4 class="py-2">{{ 'Score'|trans }}</h4>
<div class="btn-toolbar" role="toolbar">
<div class="btn-group btn-group-lg me-2">
<a class="btn btn-primary">{{ 'Start Elimination'|trans }}</a>
</div>
<div class="btn-group btn-group-lg">
<a href="{{ path('app_prepare_elimination', {seasonCode: season.seasonCode, quiz: quiz.id}) }}"
class="btn btn-secondary">{{ 'Prepare Custom Elimination'|trans }}</a>
<a class="btn btn-secondary">{{ 'Load Prepared Elimination'|trans }}</a>
{%~ if not quiz.eliminations.empty %}
<button class="btn btn-secondary dropdown-toggle"
data-bs-toggle="dropdown">{{ 'Load Prepared Elimination'|trans }}</button>
<ul class="dropdown-menu">
{%~ for elimination in quiz.eliminations %}
<li><a class="dropdown-item"
href="{{ path('app_prepare_elimination_view', {elimination: elimination.id}) }}">{{ elimination.created | format_datetime() }}</a>
</li>
{%~ endfor %}
</ul>
{% endif %}
</div>
</div>
<p>{{ 'Number of dropouts:'|trans }} {{ quiz.dropouts }} </p>
@@ -75,9 +81,9 @@
</tr>
</thead>
<tbody>
{% for candidate in result %}
{%~ for candidate in result ~%}
<tr class="table-{% if loop.revindex > quiz.dropouts %}success{% else %}danger{% endif %}">
<td>{{ candidate.0.name }}</td>
<td>{{ candidate.name }}</td>
<td>{{ candidate.correct|default('0') }}</td>
<td>{{ candidate.corrections|default('0') }}</td>
<td>{{ candidate.score|default('x') }}</td>
@@ -93,6 +99,7 @@
</div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>
document.addEventListener('DOMContentLoaded', function () {
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')

View File

@@ -3,7 +3,7 @@
{% block body %}
<div class="row">
<div class="col-md-6 col-12">
<h2 class="py-2">{{ t('Add a quiz to %name%', {'%name%': season.name})|trans }} </h2>
<h2 class="py-2">{{ t('Add a quiz to %name%',{'%name%': season.name})|trans }} </h2>
{{ form_start(form) }}
{{ form_row(form.name) }}
{{ form_row(form.sheet) }}

29
templates/base.html.twig Normal file
View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="nl" data-bs-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script
src="https://js-de.sentry-cdn.com/30cf438bc708c97e6f45c127bed9af96.min.js"
crossorigin="anonymous"
></script>
<title>
{% block title %}Tijd voor de test{% endblock title %}
</title>
{% block stylesheets %}{% endblock %}
{% block javascripts %}{% block importmap %}{% endblock %}{% endblock %}
</head>
<body>
{% block nav %}
{% endblock nav %}
<main>
{% block main %}
<div class="container">
{{ include('flashes.html.twig') }}
{% block body %}
{% endblock body %}
</div>
{% endblock %}
</main>
</body>
</html>

View File

@@ -0,0 +1,13 @@
{% set flashes=app.flashes() %}
{% if flashes is not empty %}
<div class="py-2">
{% for label, messages in flashes %}
{% for message in messages %}
<div class="alert alert-{{ label }} alert-dismissible " role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endfor %}
</div>
{% endif %}

View File

@@ -1,26 +0,0 @@
{% extends 'backoffice/base.html.twig' %}
{% block body %}
<div class="row">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ path('app_backoffice_index') }}">Home</a></li>
<li class="breadcrumb-item"><a
href="{{ path('app_backoffice_season', {seasonCode: season.seasonCode}) }}">{{ season.name }}</a>
</li>
<li class="breadcrumb-item"><a
href="{{ path('app_backoffice_quiz', {seasonCode: season.seasonCode, quiz: quiz.id}) }}">{{ quiz.name }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Prepare Elimination</li>
</ol>
</nav>
</div>
<div class="row">
<div class="col-12 col-md-6">
</div>
<div class="col-12 col-md-6">
<p>Hier kan dus weer wat uitleg komen</p>
</div>
</div>
{% endblock %}

View File

@@ -1,55 +1,2 @@
<!DOCTYPE html>
<html lang="nl" data-bs-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"></script>
<script
src="https://js-de.sentry-cdn.com/30cf438bc708c97e6f45c127bed9af96.min.js"
crossorigin="anonymous"
></script>
<title>
{% block title %}
Tijd voor de test
{% endblock title %}
</title>
<style>
html, body {
height: 100%;
background-image: url("{{ asset('/img/background.png') }}");
background-position: center center;
background-repeat: no-repeat;
background-color: black;
color: white;
display: grid;
align-items: center;
justify-self: center;
}
</style>
</head>
<body>
<main>
<div class="container">
{% for label, messages in app.flashes() %}
{% for message in messages %}
<div class="alert alert-{{ label }} alert-dismissible " role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endfor %}
{% block body %}
{% endblock body %}
</div>
{% block script %}
{% endblock script %}
</main>
</body>
</html>
{% extends 'base.html.twig' %}
{% block importmap %}{{ importmap('quiz') }}{% endblock %}