return $this->hasMany(Result::class);
}
+ public function rolled_by_user() {
+ return $this->belongsTo(User::class, 'rolled_by');
+ }
+
public function tournament() {
return $this->belongsTo(Tournament::class);
}
'tournament_id',
];
+ protected $with = [
+ 'rolled_by_user',
+ ];
+
}
--- /dev/null
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::table('rounds', function(Blueprint $table) {
+ $table->foreignId('rolled_by')->nullable()->default(null)->constrained('users');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('rounds', function(Blueprint $table) {
+ $table->dropColumn('rolled_by');
+ });
+ }
+};
import LockButton from './LockButton';
import SeedButton from './SeedButton';
import SeedCode from './SeedCode';
+import SeedRolledBy from './SeedRolledBy';
import List from '../results/List';
import ReportButton from '../results/ReportButton';
import { isRunner } from '../../helpers/permissions';
round={round}
tournament={tournament}
/>
+ {' '}
+ <SeedRolledBy round={round} />
</p>
{isRunner(user, tournament) ?
<p className="report">
--- /dev/null
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import { getAvatarUrl, getUserName } from '../../helpers/User';
+import i18n from '../../i18n';
+
+const SeedRolledBy = ({ round }) => round.rolled_by_user ?
+ <span
+ className="rolled-by"
+ title={i18n.t('rounds.rolledBy', { name: getUserName(round.rolled_by_user) })}
+ >
+ <img alt={getUserName(round.rolled_by_user)} src={getAvatarUrl(round.rolled_by_user)} />
+ </span>
+: null;
+
+SeedRolledBy.propTypes = {
+ round: PropTypes.shape({
+ rolled_by_user: PropTypes.shape({
+ }),
+ }),
+};
+
+export default SeedRolledBy;
return round.results.find(result => result.user_id == user.id);
};
-export const getAvatarUrl = user => user.avatar
+export const getAvatarUrl = user => user && user.avatar
? `//cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png`
: '/default-avatar.png';
+export const getUserName = user => (user && (user.nickname || user.username)) || '';
+
export const hasFinishedRound = (user, round) => {
const result = findResult(user, round);
return result && result.has_finished;
lockError: 'Fehler beim Sperren',
lockIncompleteWarning: 'Achtung: Noch nicht alle Runner haben ihr Ergebnis für diese Runde eingereicht!',
lockSuccess: 'Runde gesperrt',
+ rolledBy: 'Gerollt von {{name}}',
seed: 'Seed',
setSeed: 'Seed eintragen',
setSeedError: 'Seed konnte nicht eintragen werden',
lockError: 'Error locking round',
lockIncompleteWarning: 'Warning: Not all runners have submitted their results for this round yet!',
lockSuccess: 'Round locked',
+ rolledBy: 'Rolled by {{name}}',
seed: 'Seed',
setSeed: 'Set seed',
setSeedError: 'Seed could not be set',
font-size: 125%;
}
- .seed-code, .btn {
+ .rolled-by {
+ display: inline-block;
+ vertical-align: middle;
+
+ img {
+ max-height: 2rem;
+ width: auto;
+ border-radius: 50%;
+ }
+ }
+
+ .seed-code, .btn, .rolled-by {
margin-bottom: 1ex;
}
}