From: Daniel Karbach Date: Wed, 19 Nov 2025 13:23:28 +0000 (+0100) Subject: grouped rounds tournament type X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=91c715a25ab425a9793ef535bed9e359798eda88;p=alttp.git grouped rounds tournament type --- diff --git a/app/Http/Controllers/RoundController.php b/app/Http/Controllers/RoundController.php index 06cd7bd..589ab8d 100644 --- a/app/Http/Controllers/RoundController.php +++ b/app/Http/Controllers/RoundController.php @@ -22,23 +22,29 @@ class RoundController extends Controller $this->authorize('addRound', $tournament); $tournament->loadMax('rounds', 'number'); + $number = intval($tournament->rounds_max_number) + 1; + + $rounds = []; + + for ($i = 0; $i < $tournament->group_size; ++$i) { + $group = static::$GROUP_NAMES[$i]; + $round = Round::create([ + 'game' => $tournament->game, + 'group' => $group, + 'number' => $number, + 'no_record' => $tournament->no_record, + 'tournament_id' => $tournament->id, + ]); + Protocol::roundAdded( + $tournament, + $round, + $request->user(), + ); + RoundAdded::dispatch($round); + $rounds[] = $round; + } - $round = Round::create([ - 'game' => $tournament->game, - 'number' => intval($tournament->rounds_max_number) + 1, - 'no_record' => $tournament->no_record, - 'tournament_id' => $validatedData['tournament_id'], - ]); - - Protocol::roundAdded( - $tournament, - $round, - $request->user(), - ); - - RoundAdded::dispatch($round); - - return $round->toJson(); + return $rounds; } public function delete(Request $request, Round $round) { @@ -166,4 +172,8 @@ class RoundController extends Controller return $round->toJson(); } + private static $GROUP_NAMES = [ + 'A', 'B', 'C', 'D', 'E', + ]; + } diff --git a/app/Http/Controllers/TournamentController.php b/app/Http/Controllers/TournamentController.php index 58b6222..8e3df16 100644 --- a/app/Http/Controllers/TournamentController.php +++ b/app/Http/Controllers/TournamentController.php @@ -34,7 +34,10 @@ class TournamentController extends Controller 'participants', 'participants.user', ]); - $rounds = $tournament->rounds()->with(['results', 'results.user'])->limit(25)->get(); + $rounds = $tournament->rounds() + ->with(['results', 'results.user']) + ->limit($tournament->ceilRoundLimit(25)) + ->get(); foreach ($rounds as $round) { if (!Gate::allows('seeResults', $round)) { $round->hideResults($request->user()); @@ -91,7 +94,7 @@ class TournamentController extends Controller $rounds = $tournament->rounds() ->where('number', '<', $validatedData['last_known']) ->with(['results', 'results.user']) - ->limit(25)->get(); + ->limit($tournament->ceilRoundLimit(25))->get(); foreach ($rounds as $round) { if (!Gate::allows('seeResults', $round)) { $round->hideResults($request->user()); diff --git a/app/Models/Protocol.php b/app/Models/Protocol.php index 9c902ce..73dca93 100644 --- a/app/Models/Protocol.php +++ b/app/Models/Protocol.php @@ -274,6 +274,7 @@ class Protocol extends Model protected static function roundMemo(Round $round) { return [ 'id' => $round->id, + 'group' => $round->group, 'locked' => $round->locked, 'no_record' => $round->no_record, 'number' => $round->number, diff --git a/app/Models/Round.php b/app/Models/Round.php index c9435c2..4808322 100644 --- a/app/Models/Round.php +++ b/app/Models/Round.php @@ -130,6 +130,7 @@ class Round extends Model protected $fillable = [ 'game', + 'group', 'number', 'no_record', 'tournament_id', diff --git a/app/Models/Tournament.php b/app/Models/Tournament.php index 8080d2a..c2697a0 100644 --- a/app/Models/Tournament.php +++ b/app/Models/Tournament.php @@ -87,7 +87,7 @@ class Tournament extends Model { } public function rounds() { - return $this->hasMany(Round::class)->orderBy('number', 'DESC'); + return $this->hasMany(Round::class)->orderBy('number', 'DESC')->orderBy('group', 'ASC'); } public function getTranslatedTitle(): string { @@ -104,6 +104,13 @@ class Tournament extends Model { return ''; } + public function ceilRoundLimit(int $limit): int { + if ($this->group_size > 1 && ($limit % $this->group_size)) { + return $limit + $this->group_size - ($limit % $this->group_size); + } + return $limit; + } + protected $casts = [ 'accept_applications' => 'boolean', diff --git a/database/migrations/2025_11_19_083248_tournament_group_size.php b/database/migrations/2025_11_19_083248_tournament_group_size.php new file mode 100644 index 0000000..8c794ea --- /dev/null +++ b/database/migrations/2025_11_19_083248_tournament_group_size.php @@ -0,0 +1,29 @@ +unsignedInteger('group_size')->default(1); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('tournaments', function (Blueprint $table) { + $table->dropColumn('group_size'); + }); + } + +}; diff --git a/database/migrations/2025_11_19_085228_round_group.php b/database/migrations/2025_11_19_085228_round_group.php new file mode 100644 index 0000000..86d7379 --- /dev/null +++ b/database/migrations/2025_11_19_085228_round_group.php @@ -0,0 +1,29 @@ +string('group')->default('A'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('rounds', function (Blueprint $table) { + $table->dropColumn('group'); + }); + } + +}; diff --git a/resources/js/components/rounds/DeleteDialog.jsx b/resources/js/components/rounds/DeleteDialog.jsx index 188f082..376dd1f 100644 --- a/resources/js/components/rounds/DeleteDialog.jsx +++ b/resources/js/components/rounds/DeleteDialog.jsx @@ -5,10 +5,13 @@ import { Alert, Button, Modal } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; import toastr from 'toastr'; -const EditDialog = ({ +import { formatNumber } from '../../helpers/Round'; + +const DeleteDialog = ({ onHide, round, show, + tournament, }) => { const { t } = useTranslation(); @@ -32,6 +35,7 @@ const EditDialog = ({ {t('rounds.deleteConfirmMessage', { ...round, date: new Date(round.created_at), + number: formatNumber(tournament, round), })} @@ -46,7 +50,7 @@ const EditDialog = ({ ; }; -EditDialog.propTypes = { +DeleteDialog.propTypes = { onHide: PropTypes.func, round: PropTypes.shape({ created_at: PropTypes.string, @@ -57,4 +61,4 @@ EditDialog.propTypes = { }), }; -export default EditDialog; +export default DeleteDialog; diff --git a/resources/js/components/rounds/Item.jsx b/resources/js/components/rounds/Item.jsx index 9cd095f..39f4586 100644 --- a/resources/js/components/rounds/Item.jsx +++ b/resources/js/components/rounds/Item.jsx @@ -18,7 +18,7 @@ import { mayViewProtocol, isRunner, } from '../../helpers/permissions'; -import { isComplete } from '../../helpers/Round'; +import { formatNumber, isComplete } from '../../helpers/Round'; import { hasFinishedRound } from '../../helpers/User'; import { useUser } from '../../hooks/user'; @@ -56,7 +56,7 @@ const Item = ({

- {tournament.show_numbers && round.number ? `#${round.number} ` : ''} + {formatNumber(tournament, round)} {t('rounds.date', { date: new Date(round.created_at) })}

diff --git a/resources/js/helpers/Round.js b/resources/js/helpers/Round.js index 68579b8..d1f5ef3 100644 --- a/resources/js/helpers/Round.js +++ b/resources/js/helpers/Round.js @@ -1,6 +1,11 @@ import Participant from './Participant'; import Tournament from './Tournament'; +export const formatNumber = (tournament, round) => { + const group = (tournament?.group_size > 1 && round?.group) || ''; + return tournament.show_numbers && round?.number ? `#${round.number}${group} ` : ''; +}; + export const hasResults = (round) => { return round && round.results && round.results.length > 0; }; diff --git a/resources/js/i18n/de.js b/resources/js/i18n/de.js index ef57f67..738e0a3 100644 --- a/resources/js/i18n/de.js +++ b/resources/js/i18n/de.js @@ -608,7 +608,7 @@ export default { code: 'Code', date: '{{ date, L }}', delete: 'Runde löschen', - deleteConfirmMessage: 'Runde #{{ number }} vom {{ date, L }} löschen?', + deleteConfirmMessage: 'Runde {{ number }} vom {{ date, L }} löschen?', deleteError: 'Fehler beim Löschen', deleteSuccess: 'Runde gelöscht', edit: 'Runde bearbeiten', diff --git a/resources/js/i18n/en.js b/resources/js/i18n/en.js index 028e563..13c41c7 100644 --- a/resources/js/i18n/en.js +++ b/resources/js/i18n/en.js @@ -608,7 +608,7 @@ export default { code: 'Code', date: '{{ date, L }}', delete: 'Delete round', - deleteConfirmMessage: 'Remove round #{{ number }} from {{ date, L }}?', + deleteConfirmMessage: 'Remove round {{ number }} from {{ date, L }}?', deleteError: 'Error deleting round', deleteSuccess: 'Round deleted', edit: 'Edit round',