Add admin "create game" form; show total time on session-creation dropdown
New game_admin_game_new route/form (reuses AdminGameType, same pattern as editing a game's total time) so games - including the 3 upcoming Easy/Medium/Hard difficulty options - can be created through the admin panel instead of needing a direct DB insert. Also show each game's total time (in minutes) next to the player count in the "Create New Session" dropdown, since that's the actual difficulty signal players are choosing between - number of players alone didn't convey it. Difficulty itself needs no new session-level concept: each difficulty is just a separate Game row with its own TOTAL_TIME setting, which checkAllPlayersReady() already reads when starting the session's timer. Hint timing depending on difficulty is separate, upcoming work.
This commit is contained in:
@@ -5,7 +5,18 @@
|
||||
{% block admin_body %}
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.5rem;">
|
||||
<h1 style="margin: 0; font-size: 1.5rem; color: #0f172a;">Games</h1>
|
||||
<span style="color: #64748b; font-size: 0.9rem;">{{ games|length }} total</span>
|
||||
<div style="display: flex; align-items: center; gap: 1rem;">
|
||||
<span style="color: #64748b; font-size: 0.9rem;">{{ games|length }} total</span>
|
||||
<a href="{{ path('game_admin_game_new') }}" style="
|
||||
padding: 0.5rem 1rem;
|
||||
background: #3b82f6;
|
||||
color: #fff;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
">+ New Game</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.07); overflow: hidden;">
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
{% extends 'game/admin/base.html.twig' %}
|
||||
|
||||
{% block title %}New Game — Admin{% endblock %}
|
||||
|
||||
{% block admin_body %}
|
||||
<div style="margin-bottom: 1.5rem;">
|
||||
<a href="{{ path('game_admin_games') }}" style="color: #64748b; text-decoration: none; font-size: 0.9rem;">← Games</a>
|
||||
</div>
|
||||
|
||||
<h1 style="margin: 0 0 1.5rem; font-size: 1.5rem; color: #0f172a;">New game</h1>
|
||||
|
||||
<div style="background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.07); padding: 1.5rem; max-width: 500px;">
|
||||
{{ form_start(form, {attr: {style: 'display: flex; flex-direction: column; gap: 1.25rem;'}}) }}
|
||||
|
||||
<div>
|
||||
{{ form_label(form.name, null, {label_attr: {style: 'display: block; font-weight: 600; margin-bottom: 0.35rem; color: #374151; font-size: 0.875rem;'}}) }}
|
||||
{{ form_widget(form.name, {attr: {style: 'width: 100%; padding: 0.5rem 0.75rem; border: 1px solid #d1d5db; border-radius: 6px; font-size: 0.9rem; box-sizing: border-box;'}}) }}
|
||||
{{ form_errors(form.name) }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ form_label(form.numberOfPlayers, null, {label_attr: {style: 'display: block; font-weight: 600; margin-bottom: 0.35rem; color: #374151; font-size: 0.875rem;'}}) }}
|
||||
{{ form_widget(form.numberOfPlayers, {attr: {style: 'width: 100%; padding: 0.5rem 0.75rem; border: 1px solid #d1d5db; border-radius: 6px; font-size: 0.9rem; box-sizing: border-box;'}}) }}
|
||||
{{ form_errors(form.numberOfPlayers) }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ form_label(form.status, null, {label_attr: {style: 'display: block; font-weight: 600; margin-bottom: 0.35rem; color: #374151; font-size: 0.875rem;'}}) }}
|
||||
{{ form_widget(form.status, {attr: {style: 'width: 100%; padding: 0.5rem 0.75rem; border: 1px solid #d1d5db; border-radius: 6px; font-size: 0.9rem; box-sizing: border-box;'}}) }}
|
||||
{{ form_errors(form.status) }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ form_label(form.totalTime, null, {label_attr: {style: 'display: block; font-weight: 600; margin-bottom: 0.35rem; color: #374151; font-size: 0.875rem;'}}) }}
|
||||
{{ form_widget(form.totalTime, {attr: {style: 'width: 100%; padding: 0.5rem 0.75rem; border: 1px solid #d1d5db; border-radius: 6px; font-size: 0.9rem; box-sizing: border-box;'}}) }}
|
||||
<small style="color: #64748b; font-size: 0.8rem;">In seconds — e.g. 3600 = 1 hour</small>
|
||||
{{ form_errors(form.totalTime) }}
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 0.75rem; margin-top: 0.5rem;">
|
||||
<button type="submit" style="
|
||||
padding: 0.6rem 1.25rem;
|
||||
background: #3b82f6;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
">Create game</button>
|
||||
<a href="{{ path('game_admin_games') }}" style="
|
||||
padding: 0.6rem 1.25rem;
|
||||
background: #f1f5f9;
|
||||
color: #475569;
|
||||
border-radius: 6px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
">Cancel</a>
|
||||
</div>
|
||||
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -20,8 +20,15 @@
|
||||
<input type="hidden" name="_token" value="{{ csrf_token('create_session') }}">
|
||||
<select name="game_id" class="form-select mb-3">
|
||||
{% for game in availableGames %}
|
||||
{% set totalTime = null %}
|
||||
{% for setting in game.settings %}
|
||||
{% if setting.name.value == 'totalTime' %}
|
||||
{% set totalTime = setting.value %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<option value="{{ game.id }}">
|
||||
{{ game.name }} ({{ game.numberOfPlayers }} players)
|
||||
{{ game.name }} ({{ game.numberOfPlayers }} players{% if totalTime %}, {{ (totalTime / 60)|round }} min{% endif %})
|
||||
{% if is_granted('ROLE_ADMIN') %}
|
||||
[{{ game.status.value }}]
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user