From ee841a4de0732176690f6c6a4e7feba6a3196bb8 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Thu, 27 Nov 2025 12:27:15 +0100 Subject: [PATCH] per result protocol --- app/Http/Controllers/ProtocolController.php | 20 +++++++ resources/js/components/groups/SwapButton.jsx | 7 ++- .../js/components/protocol/ResultProtocol.jsx | 54 +++++++++++++++++++ resources/js/components/results/Table.jsx | 11 +++- resources/js/components/results/TableRow.jsx | 15 ++++++ resources/js/i18n/de.js | 14 ++--- resources/js/i18n/en.js | 14 ++--- resources/sass/results.scss | 9 ++++ routes/api.php | 1 + 9 files changed, 128 insertions(+), 17 deletions(-) create mode 100644 resources/js/components/protocol/ResultProtocol.jsx diff --git a/app/Http/Controllers/ProtocolController.php b/app/Http/Controllers/ProtocolController.php index c1077b0..401e623 100644 --- a/app/Http/Controllers/ProtocolController.php +++ b/app/Http/Controllers/ProtocolController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers; use App\Models\Round; use App\Models\Tournament; +use App\Models\User; class ProtocolController extends Controller { @@ -19,6 +20,25 @@ class ProtocolController extends Controller return $protocol->values()->toJson(); } + public function forRoundAndRunner(Tournament $tournament, Round $round, User $runner) { + $this->authorize('viewProtocol', $round->tournament); + $protocol = $round + ->protocols() + ->where(function ($query) use ($runner) { + $query->where(function ($subquery) use ($runner) { + $subquery->where('user_id', '=', $runner->id); + $subquery->whereIn('type', ['result.comment', 'result.report', 'round.getseed']); + }); + $query->orWhere('details->runner->id', '=', $runner->id); + $query->orWhere('details->assignee->id', '=', $runner->id); + }) + ->with('user') + ->orderBy('created_at', 'desc') + ->limit(150) + ->get(); + return $protocol->values()->toJson(); + } + public function forTournament(Tournament $tournament) { $this->authorize('viewProtocol', $tournament); $protocol = $tournament diff --git a/resources/js/components/groups/SwapButton.jsx b/resources/js/components/groups/SwapButton.jsx index 0fbba01..35fcdf1 100644 --- a/resources/js/components/groups/SwapButton.jsx +++ b/resources/js/components/groups/SwapButton.jsx @@ -1,12 +1,15 @@ import PropTypes from 'prop-types'; import React from 'react'; import { Button } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; import Icon from '../common/Icon'; const SwapButton = ({ onClick }) => { - return ; }; diff --git a/resources/js/components/protocol/ResultProtocol.jsx b/resources/js/components/protocol/ResultProtocol.jsx new file mode 100644 index 0000000..6c545b3 --- /dev/null +++ b/resources/js/components/protocol/ResultProtocol.jsx @@ -0,0 +1,54 @@ +import axios from 'axios'; +import PropTypes from 'prop-types'; +import React, { useEffect, useState } from 'react'; +import { Button } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; + +import Dialog from './Dialog'; +import Icon from '../common/Icon'; + +const ResultProtocol = ({ roundId, tournamentId, userId }) => { + const [showDialog, setShowDialog] = useState(false); + const [protocol, setProtocol] = useState([]); + + const { t } = useTranslation(); + + useEffect(() => { + if (!showDialog) return; + const ctrl = new AbortController(); + axios + .get(`/api/protocol/${tournamentId}/${roundId}/${userId}`, { signal: ctrl.signal }) + .then(response => { + setProtocol(response.data); + }); + return () => { + ctrl.abort(); + }; + }, [roundId, showDialog, tournamentId, userId]); + + return ( + <> + + setShowDialog(false)} + protocol={protocol} + show={showDialog} + /> + + ); +}; + +ResultProtocol.propTypes = { + roundId: PropTypes.number, + tournamentId: PropTypes.number, + userId: PropTypes.number, +}; + +export default ResultProtocol; diff --git a/resources/js/components/results/Table.jsx b/resources/js/components/results/Table.jsx index 2a784f3..af3417c 100644 --- a/resources/js/components/results/Table.jsx +++ b/resources/js/components/results/Table.jsx @@ -4,7 +4,8 @@ import { Table } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; import TableRow from './TableRow'; -import { maySeeResults } from '../../helpers/permissions'; +import Icon from '../common/Icon'; +import { maySeeResults, mayViewProtocol } from '../../helpers/permissions'; import { compileResults } from '../../helpers/Round'; import { useUser } from '../../hooks/user'; @@ -20,10 +21,17 @@ const ResultTable = ({ actions, round, tournament }) => { () => maySeeResults(user, tournament, round), [round, tournament, user], ); + const mayProtocol = React.useMemo( + () => mayViewProtocol(user, tournament, round), + [round, tournament, user], + ); return + {mayProtocol ? + + : null} {maySee ? @@ -39,6 +47,7 @@ const ResultTable = ({ actions, round, tournament }) => { key={result.id} round={round} showPlacement={maySee} + showProtocol={mayProtocol} tournament={tournament} user={result.user} /> diff --git a/resources/js/components/results/TableRow.jsx b/resources/js/components/results/TableRow.jsx index c024bff..feefb54 100644 --- a/resources/js/components/results/TableRow.jsx +++ b/resources/js/components/results/TableRow.jsx @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'; import Badge from './Badge'; import VodLink from './VodLink'; +import ResultProtocol from '../protocol/ResultProtocol'; import Box from '../users/Box'; import { maySeeResult, mayVerifyResult } from '../../helpers/permissions'; import { findResult } from '../../helpers/User'; @@ -13,6 +14,7 @@ const TableRow = ({ actions, round, showPlacement = false, + showProtocol = false, tournament, user, }) => { @@ -33,6 +35,17 @@ const TableRow = ({ ); return + {showProtocol ? + + : null} @@ -60,7 +73,9 @@ TableRow.propTypes = { round: PropTypes.shape({ }), showPlacement: PropTypes.bool, + showProtocol: PropTypes.bool, tournament: PropTypes.shape({ + id: PropTypes.number, }), user: PropTypes.shape({ }), diff --git a/resources/js/i18n/de.js b/resources/js/i18n/de.js index 8b3068a..b060a6a 100644 --- a/resources/js/i18n/de.js +++ b/resources/js/i18n/de.js @@ -596,13 +596,13 @@ export default { verify: 'Ergebnis in Runde {{number}} von {{runner}} (<2>{{time}}) verifiziert', }, round: { - create: 'Runde #{{number}} hinzugefügt', - delete: 'Runde #{{number}} gelöscht', - edit: 'Runde #{{number}} bearbeitet', - getseed: 'Seed für Runde #{{number}} bezogen', - lock: 'Runde #{{number}} gesperrt', - seed: 'Seed für Runde #{{number}} eingetragen', - unlock: 'Runde #{{number}} entsperrt', + create: 'Runde {{number}} hinzugefügt', + delete: 'Runde {{number}} gelöscht', + edit: 'Runde {{number}} bearbeitet', + getseed: 'Seed für Runde {{number}} bezogen', + lock: 'Runde {{number}} gesperrt', + seed: 'Seed für Runde {{number}} eingetragen', + unlock: 'Runde {{number}} entsperrt', }, tournament: { close: 'Anmeldung geschlossen', diff --git a/resources/js/i18n/en.js b/resources/js/i18n/en.js index 8b978e6..2c2a332 100644 --- a/resources/js/i18n/en.js +++ b/resources/js/i18n/en.js @@ -596,13 +596,13 @@ export default { verify: 'Verified round {{number}} result of {{runner}} (<2>{{time}})', }, round: { - create: 'Added round #{{number}}', - delete: 'Deleted round #{{number}}', - edit: 'Edited round #{{number}}', - getseed: 'Got seed for round #{{number}}', - lock: 'Round #{{number}} locked', - seed: 'Set seed for round #{{number}}', - unlock: 'Round #{{number}} unlocked', + create: 'Added round {{number}}', + delete: 'Deleted round {{number}}', + edit: 'Edited round {{number}}', + getseed: 'Got seed for round {{number}}', + lock: 'Round {{number}} locked', + seed: 'Set seed for round {{number}}', + unlock: 'Round {{number}} unlocked', }, tournament: { close: 'Registration closed', diff --git a/resources/sass/results.scss b/resources/sass/results.scss index e90bcca..69a232a 100644 --- a/resources/sass/results.scss +++ b/resources/sass/results.scss @@ -44,6 +44,15 @@ .result-table { width: 100%; + td { + vertical-align: middle; + } + + .result-protocol { + text-align: center; + width: 5ex; + } + .result-time, .result-vod { text-align: right; diff --git a/routes/api.php b/routes/api.php index 88f19bf..5afc0ef 100644 --- a/routes/api.php +++ b/routes/api.php @@ -83,6 +83,7 @@ Route::get('pages/{type}/{name}', 'App\Http\Controllers\TechniqueController@byTy Route::get('protocol/{tournament}', 'App\Http\Controllers\ProtocolController@forTournament'); Route::get('protocol/{tournament}/{round}', 'App\Http\Controllers\ProtocolController@forRound'); +Route::get('protocol/{tournament}/{round}/{runner}', 'App\Http\Controllers\ProtocolController@forRoundAndRunner'); Route::post('results', 'App\Http\Controllers\ResultController@create'); Route::post('results/{result}/modify', 'App\Http\Controllers\ResultController@modify'); -- 2.47.3
{t('results.runner')}{t('results.placement')}
+ {result ? + + : null} +