use App\Models\Round;
use App\Models\Tournament;
+use App\Models\User;
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
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 <Button onClick={onClick} variant="outline-secondary">
- <Icon.SWAP />
+ const { t } = useTranslation();
+
+ return <Button onClick={onClick} title={t('groups.swapGroup')} variant="outline-secondary">
+ <Icon.SWAP title="" />
</Button>;
};
--- /dev/null
+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 (
+ <>
+ <Button
+ onClick={() => setShowDialog(true)}
+ size="sm"
+ title={t('button.protocol')}
+ variant="outline-info"
+ >
+ <Icon.PROTOCOL title="" />
+ </Button>
+ <Dialog
+ onHide={() => setShowDialog(false)}
+ protocol={protocol}
+ show={showDialog}
+ />
+ </>
+ );
+};
+
+ResultProtocol.propTypes = {
+ roundId: PropTypes.number,
+ tournamentId: PropTypes.number,
+ userId: PropTypes.number,
+};
+
+export default ResultProtocol;
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';
() => maySeeResults(user, tournament, round),
[round, tournament, user],
);
+ const mayProtocol = React.useMemo(
+ () => mayViewProtocol(user, tournament, round),
+ [round, tournament, user],
+ );
return <Table className="result-table" striped hover>
<thead>
<tr>
+ {mayProtocol ?
+ <th className="result-protocol"><Icon.PROTOCOL /></th>
+ : null}
<th className="result-runner">{t('results.runner')}</th>
{maySee ?
<th className="result-placement">{t('results.placement')}</th>
key={result.id}
round={round}
showPlacement={maySee}
+ showProtocol={mayProtocol}
tournament={tournament}
user={result.user}
/>
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';
actions,
round,
showPlacement = false,
+ showProtocol = false,
tournament,
user,
}) => {
);
return <tr>
+ {showProtocol ?
+ <td className="result-protocol">
+ {result ?
+ <ResultProtocol
+ roundId={result.round_id}
+ tournamentId={tournament.id}
+ userId={result.user_id}
+ />
+ : null}
+ </td>
+ : null}
<td className="result-runner">
<Box user={user} />
</td>
round: PropTypes.shape({
}),
showPlacement: PropTypes.bool,
+ showProtocol: PropTypes.bool,
tournament: PropTypes.shape({
+ id: PropTypes.number,
}),
user: PropTypes.shape({
}),
verify: 'Ergebnis in Runde {{number}} von {{runner}} (<2>{{time}}</2>) 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',
verify: 'Verified round {{number}} result of {{runner}} (<2>{{time}}</2>)',
},
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',
.result-table {
width: 100%;
+ td {
+ vertical-align: middle;
+ }
+
+ .result-protocol {
+ text-align: center;
+ width: 5ex;
+ }
+
.result-time,
.result-vod {
text-align: right;
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');