From: Daniel Karbach Date: Fri, 25 Mar 2022 14:06:25 +0000 (+0100) Subject: result comments X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=a4260a00251cef4ad806c9d5c44d4c444d6ab831;p=alttp.git result comments --- diff --git a/app/Http/Controllers/ResultController.php b/app/Http/Controllers/ResultController.php index 5102c8a..ab1759d 100644 --- a/app/Http/Controllers/ResultController.php +++ b/app/Http/Controllers/ResultController.php @@ -14,44 +14,54 @@ class ResultController extends Controller public function create(Request $request) { $validatedData = $request->validate([ + 'comment' => 'string', 'forfeit' => 'boolean', 'participant_id' => 'required|exists:App\\Models\\Participant,id', 'round_id' => 'required|exists:App\\Models\\Round,id', - 'time' => 'required_if:forfeit,false|numeric', + 'time' => 'numeric', ]); - error_log(var_export($validatedData, true)); $participant = Participant::findOrFail($validatedData['participant_id']); $round = Round::findOrFail($validatedData['round_id']); - if (!$round || $round->locked) { - abort(403); - } $user = $request->user(); if ($user->id != $participant->user->id) { $this->authorize('create', Result::class); } - $result = Result::updateOrCreate([ + $result = Result::firstOrCreate([ 'round_id' => $validatedData['round_id'], 'user_id' => $participant->user_id, - ], [ - 'forfeit' => $validatedData['forfeit'], - 'time' => isset($validatedData['time']) ? $validatedData['time'] : 0, ]); + if (!$round->locked) { + if (isset($validatedData['forfeit'])) $result->forfeit = $validatedData['forfeit']; + if (isset($validatedData['time'])) $result->time = $validatedData['time']; + } + $result->comment = $validatedData['comment'] ? $validatedData['comment'] : null; + $result->save(); + if ($result->wasChanged()) { ResultChanged::dispatch($result); } + + if ($result->wasChanged(['forfeit', 'time'])) { + Protocol::resultReported( + $round->tournament, + $result, + $request->user(), + ); + } else if ($result->wasChanged('comment')) { + Protocol::resultCommented( + $round->tournament, + $result, + $request->user(), + ); + } + $round->load('results'); $round->updatePlacement(); $round->tournament->updatePlacement(); - Protocol::resultReported( - $round->tournament, - $result, - $request->user(), - ); - return $result->toJson(); } diff --git a/app/Models/Protocol.php b/app/Models/Protocol.php index 4659665..995f9c0 100644 --- a/app/Models/Protocol.php +++ b/app/Models/Protocol.php @@ -10,6 +10,20 @@ class Protocol extends Model { use HasFactory; + public static function resultCommented(Tournament $tournament, Result $result, User $user) { + $protocol = static::create([ + 'tournament_id' => $tournament->id, + 'user_id' => $user->id, + 'type' => 'result.comment', + 'details' => [ + 'tournament' => static::tournamentMemo($tournament), + 'result' => static::resultMemo($result), + 'round' => static::roundMemo($result->round), + ], + ]); + ProtocolAdded::dispatch($protocol); + } + public static function resultReported(Tournament $tournament, Result $result, User $user) { $protocol = static::create([ 'tournament_id' => $tournament->id, @@ -18,6 +32,7 @@ class Protocol extends Model 'details' => [ 'tournament' => static::tournamentMemo($tournament), 'result' => static::resultMemo($result), + 'round' => static::roundMemo($result->round), ], ]); ProtocolAdded::dispatch($protocol); @@ -103,6 +118,7 @@ class Protocol extends Model protected static function resultMemo(Result $result) { return [ 'id' => $result->id, + 'comment' => $result->comment, 'forfeit' => $result->forfeit, 'time' => $result->time, ]; @@ -111,6 +127,8 @@ class Protocol extends Model protected static function roundMemo(Round $round) { return [ 'id' => $round->id, + 'locked' => $round->locked, + 'no_record' => $round->no_record, 'number' => $round->number, 'seed' => $round->seed, ]; @@ -119,6 +137,8 @@ class Protocol extends Model protected static function tournamentMemo(Tournament $tournament) { return [ 'id' => $tournament->id, + 'locked' => $tournament->locked, + 'no_record' => $tournament->no_record, 'title' => $tournament->title, ]; } diff --git a/app/Models/Result.php b/app/Models/Result.php index cdb86c7..308b9e9 100644 --- a/app/Models/Result.php +++ b/app/Models/Result.php @@ -43,6 +43,11 @@ class Result extends Model } + protected $casts = [ + 'forfeit' => 'boolean', + 'time' => 'double', + ]; + protected $appends = [ 'has_finished', ]; diff --git a/app/Models/Round.php b/app/Models/Round.php index 2232a0e..2c1a439 100644 --- a/app/Models/Round.php +++ b/app/Models/Round.php @@ -65,6 +65,7 @@ class Round extends Model protected $casts = [ 'code' => 'array', 'locked' => 'boolean', + 'no_record' => 'boolean', ]; protected $fillable = [ diff --git a/app/Models/Tournament.php b/app/Models/Tournament.php index a38e9bd..56ffe78 100644 --- a/app/Models/Tournament.php +++ b/app/Models/Tournament.php @@ -73,4 +73,10 @@ class Tournament extends Model return $this->hasMany(Round::class)->orderBy('number', 'DESC'); } + + protected $casts = [ + 'locked' => 'boolean', + 'no_record' => 'boolean', + ]; + } diff --git a/database/migrations/2022_03_25_123528_result_comment.php b/database/migrations/2022_03_25_123528_result_comment.php new file mode 100644 index 0000000..b5d5b05 --- /dev/null +++ b/database/migrations/2022_03_25_123528_result_comment.php @@ -0,0 +1,33 @@ +decimal('time', 6, 2)->unsigned()->default(0)->change(); + $table->text('comment')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('results', function(Blueprint $table) { + $table->dropColumn('comment'); + }); + } +}; diff --git a/resources/js/components/protocol/Item.js b/resources/js/components/protocol/Item.js index 2eaae5b..74bfa50 100644 --- a/resources/js/components/protocol/Item.js +++ b/resources/js/components/protocol/Item.js @@ -44,6 +44,7 @@ const getEntryDescription = entry => { number: getEntryRoundNumber(entry), }, ); + case 'result.comment': case 'tournament.lock': return i18n.t( `protocol.description.${entry.type}`, diff --git a/resources/js/components/results/Item.js b/resources/js/components/results/Item.js index 8439522..0781cca 100644 --- a/resources/js/components/results/Item.js +++ b/resources/js/components/results/Item.js @@ -41,6 +41,19 @@ const getTime = (result, maySee) => { return '?'; }; +const getClassName = result => { + const classNames = ['status']; + if (result && result.has_finished) { + classNames.push('finished'); + if (result.comment) { + classNames.push('has-comment'); + } + } else { + classNames.push('pending'); + } + return classNames.join(' '); +}; + const Item = ({ participant, round, @@ -51,7 +64,10 @@ const Item = ({ const maySee = maySeeResults(user, tournament, round); return
-
+
{getTime(result, maySee)} diff --git a/resources/js/components/results/ReportButton.js b/resources/js/components/results/ReportButton.js index d88c1a1..0a8c139 100644 --- a/resources/js/components/results/ReportButton.js +++ b/resources/js/components/results/ReportButton.js @@ -8,6 +8,23 @@ import Icon from '../common/Icon'; import { findResult } from '../../helpers/Participant'; import i18n from '../../i18n'; +const getButtonLabel = (participant, round) => { + const result = findResult(participant, round); + if (round.locked) { + if (result && result.comment) { + return i18n.t('results.editComment'); + } else { + return i18n.t('results.addComment'); + } + } else { + if (result && (result.time || result.forfeit)) { + return i18n.t('results.edit'); + } else { + return i18n.t('results.report'); + } + } +}; + const ReportButton = ({ participant, round }) => { const [showDialog, setShowDialog] = useState(false); @@ -16,7 +33,7 @@ const ReportButton = ({ participant, round }) => { onClick={() => setShowDialog(true)} variant="secondary" > - {i18n.t(findResult(participant, round) ? 'results.edit' : 'results.report')} + {getButtonLabel(participant, round)} {' '} diff --git a/resources/js/components/results/ReportForm.js b/resources/js/components/results/ReportForm.js index 28a757a..942869d 100644 --- a/resources/js/components/results/ReportForm.js +++ b/resources/js/components/results/ReportForm.js @@ -19,47 +19,63 @@ const ReportForm = ({ handleChange, handleSubmit, onCancel, + round, touched, values, }) =>
+ {!round.locked ? + + + {i18n.t('results.reportTime')} + + {touched.time && errors.time ? + + {i18n.t(errors.time)} + + : + + {parseTime(values.time) ? + i18n.t( + 'results.reportPreview', + { time: formatTime({ time: parseTime(values.time) })}, + ) + : null} + + } + + + {i18n.t('results.forfeit')} + + + + : null} - - {i18n.t('results.reportTime')} + + {i18n.t('results.comment')} - {touched.time && errors.time ? - - {i18n.t(errors.time)} - - : - - {parseTime(values.time) ? - i18n.t( - 'results.reportPreview', - { time: formatTime({ time: parseTime(values.time) })}, - ) - : null} - - } - - - {i18n.t('results.forfeit')} - @@ -78,6 +94,7 @@ const ReportForm = ({ ReportForm.propTypes = { errors: PropTypes.shape({ + comment: PropTypes.string, forfeit: PropTypes.string, time: PropTypes.string, }), @@ -85,11 +102,16 @@ ReportForm.propTypes = { handleChange: PropTypes.func, handleSubmit: PropTypes.func, onCancel: PropTypes.func, + round: PropTypes.shape({ + locked: PropTypes.bool, + }), touched: PropTypes.shape({ + comment: PropTypes.bool, forfeit: PropTypes.bool, time: PropTypes.bool, }), values: PropTypes.shape({ + comment: PropTypes.string, forfeit: PropTypes.bool, time: PropTypes.string, }), @@ -99,11 +121,12 @@ export default withFormik({ displayName: 'ReportForm', enableReinitialize: true, handleSubmit: async (values, actions) => { - const { forfeit, participant_id, round_id, time } = values; + const { comment, forfeit, participant_id, round_id, time } = values; const { setErrors } = actions; const { onCancel } = actions.props; try { await axios.post('/api/results', { + comment, forfeit, participant_id, round_id, @@ -123,6 +146,7 @@ export default withFormik({ mapPropsToValues: ({ participant, round }) => { const result = findResult(participant, round); return { + comment: result && result.comment ? result.comment : '', forfeit: result ? !!result.forfeit : false, participant_id: participant.id, round_id: round.id, @@ -130,6 +154,7 @@ export default withFormik({ }; }, validationSchema: yup.object().shape({ + comment: yup.string(), forfeit: yup.boolean().required(), time: yup.string().time().when('forfeit', { is: false, diff --git a/resources/js/components/rounds/Item.js b/resources/js/components/rounds/Item.js index f85492d..52b989d 100644 --- a/resources/js/components/rounds/Item.js +++ b/resources/js/components/rounds/Item.js @@ -57,7 +57,7 @@ const Item = ({ tournament={tournament} />

- {!round.locked && isParticipant(user, tournament) ? + {isParticipant(user, tournament) ?

{{time}} eingetragen', }, round: { @@ -140,12 +141,15 @@ export default { heading: 'Protokoll', }, results: { + addComment: 'Kommentieren', + comment: 'Kommentar', edit: 'Ergebnis ändern', + editComment: 'Kommentar ändern', forfeit: 'Aufgegeben', report: 'Ergebnis eintragen', reportError: 'Fehler beim Eintragen :(', reportPreview: 'Wird als {{ time }} festgehalten', - reportSuccess: 'Ergebnis festgehalten', + reportSuccess: 'Festgehalten', reportTime: 'Zeit', time: 'Zeit: {{ time }}', }, diff --git a/resources/js/i18n/en.js b/resources/js/i18n/en.js index 856aa56..6aa5cc8 100644 --- a/resources/js/i18n/en.js +++ b/resources/js/i18n/en.js @@ -124,6 +124,7 @@ export default { protocol: { description: { result: { + comment: 'Result commented: "{{details.result.comment}}"', report: 'Result of {{time}} reported', }, round: { @@ -140,12 +141,15 @@ export default { heading: 'Protocol', }, results: { + addComment: 'Comment', + comment: 'Comment', edit: 'Change result', + editComment: 'Edit comment', forfeit: 'Forfeit', report: 'Report result', - reportError: 'Error saving result :(', + reportError: 'Error saving :(', reportPreview: 'Will be recorded as {{ time }}', - reportSuccess: 'Result stored, thanks :)', + reportSuccess: 'Stored, thanks :)', reportTime: 'Time', time: 'Time: {{ time }}', }, diff --git a/resources/sass/form.scss b/resources/sass/form.scss index b44ae81..ee2ee5f 100644 --- a/resources/sass/form.scss +++ b/resources/sass/form.scss @@ -1,3 +1,7 @@ +label { + margin-top: 1ex; +} + .custom-check { display: table; width: auto; diff --git a/resources/sass/results.scss b/resources/sass/results.scss index b07fdeb..d78ebc5 100644 --- a/resources/sass/results.scss +++ b/resources/sass/results.scss @@ -17,6 +17,10 @@ background: $dark; color: $light; + &.has-comment { + box-shadow: 0 0.5ex 0 $info; + } + .time { min-width: 9ex; height: 1.4em;