From f446d5bcf3b87bd9443a060e27e9c0601c96fbb9 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Wed, 27 Apr 2022 15:36:02 +0200 Subject: [PATCH] tournament settings --- app/Http/Controllers/TournamentController.php | 16 ++++ app/Models/Protocol.php | 12 +++ ..._27_115504_tournament_discord_settings.php | 32 +++++++ .../js/components/tournament/DiscordForm.js | 83 +++++++++++++++++ .../components/tournament/SettingsDialog.js | 91 ++++++++++++------- resources/js/i18n/de.js | 4 + resources/js/i18n/en.js | 4 + routes/api.php | 1 + 8 files changed, 208 insertions(+), 35 deletions(-) create mode 100644 database/migrations/2022_04_27_115504_tournament_discord_settings.php create mode 100644 resources/js/components/tournament/DiscordForm.js diff --git a/app/Http/Controllers/TournamentController.php b/app/Http/Controllers/TournamentController.php index 7f6c913..e2fbe94 100644 --- a/app/Http/Controllers/TournamentController.php +++ b/app/Http/Controllers/TournamentController.php @@ -60,6 +60,22 @@ class TournamentController extends Controller return $tournament->toJson(); } + public function discordSettings(Request $request, Tournament $tournament) { + $this->authorize('update', $tournament); + $validatedData = $request->validate([ + 'round_template' => 'string|nullable', + ]); + if (array_key_exists('round_template', $validatedData)) { + $tournament->discord_round_template = $validatedData['round_template']; + } + $tournament->save(); + if ($tournament->wasChanged()) { + TournamentChanged::dispatch($tournament); + Protocol::tournamentDiscordSettings($tournament, $request->user()); + } + return $tournament->toJson(); + } + public function open(Request $request, Tournament $tournament) { $this->authorize('update', $tournament); $tournament->accept_applications = true; diff --git a/app/Models/Protocol.php b/app/Models/Protocol.php index 67fb1ce..9aaa5b0 100644 --- a/app/Models/Protocol.php +++ b/app/Models/Protocol.php @@ -168,6 +168,18 @@ class Protocol extends Model ProtocolAdded::dispatch($protocol); } + public static function tournamentDiscordSettings(Tournament $tournament, User $user = null) { + $protocol = static::create([ + 'tournament_id' => $tournament->id, + 'user_id' => $user ? $user->id : null, + 'type' => 'tournament.discordSettings', + 'details' => [ + 'tournament' => static::tournamentMemo($tournament), + ], + ]); + ProtocolAdded::dispatch($protocol); + } + public static function tournamentLocked(Tournament $tournament, User $user = null) { $protocol = static::create([ 'tournament_id' => $tournament->id, diff --git a/database/migrations/2022_04_27_115504_tournament_discord_settings.php b/database/migrations/2022_04_27_115504_tournament_discord_settings.php new file mode 100644 index 0000000..8dab17c --- /dev/null +++ b/database/migrations/2022_04_27_115504_tournament_discord_settings.php @@ -0,0 +1,32 @@ +string('discord_round_template')->default(''); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('tournaments', function(Blueprint $table) { + $table->dropColumn('discord_round_template'); + }); + } +}; diff --git a/resources/js/components/tournament/DiscordForm.js b/resources/js/components/tournament/DiscordForm.js new file mode 100644 index 0000000..f9eba93 --- /dev/null +++ b/resources/js/components/tournament/DiscordForm.js @@ -0,0 +1,83 @@ +import axios from 'axios'; +import { withFormik } from 'formik'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { Button, Col, Form, Row } from 'react-bootstrap'; +import { withTranslation } from 'react-i18next'; +import toastr from 'toastr'; + +import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik'; +import i18n from '../../i18n'; +import yup from '../../schema/yup'; + +const DiscordForm = ({ + errors, + handleBlur, + handleChange, + handleSubmit, + touched, + values, +}) => +
+
+ {i18n.t('tournaments.discordSettings')} + + + {i18n.t('tournaments.discordRoundTemplate')} + + + + +
+
; + +DiscordForm.propTypes = { + errors: PropTypes.shape({ + round_template: PropTypes.string, + }), + handleBlur: PropTypes.func, + handleChange: PropTypes.func, + handleSubmit: PropTypes.func, + touched: PropTypes.shape({ + round_template: PropTypes.bool, + }), + values: PropTypes.shape({ + round_template: PropTypes.string, + }), +}; + +export default withFormik({ + displayName: 'DiscordForm', + enableReinitialize: true, + handleSubmit: async (values, actions) => { + const { round_template } = values; + const { setErrors } = actions; + const { tournament } = actions.props; + try { + await axios.post(`/api/tournaments/${tournament.id}/discord-settings`, { + round_template, + }); + toastr.success(i18n.t('tournaments.discordSettingsSuccess')); + } catch (e) { + toastr.error(i18n.t('tournaments.discordSettingsError')); + if (e.response && e.response.data && e.response.data.errors) { + setErrors(laravelErrorsToFormik(e.response.data.errors)); + } + } + }, + mapPropsToValues: ({ tournament }) => ({ + round_template: tournament.discord_round_template || '', + }), + validationSchema: yup.object().shape({ + round_template: yup.string(), + }), +})(withTranslation()(DiscordForm)); diff --git a/resources/js/components/tournament/SettingsDialog.js b/resources/js/components/tournament/SettingsDialog.js index 995c07b..af4d664 100644 --- a/resources/js/components/tournament/SettingsDialog.js +++ b/resources/js/components/tournament/SettingsDialog.js @@ -1,10 +1,11 @@ import axios from 'axios'; import PropTypes from 'prop-types'; import React from 'react'; -import { Button, Modal } from 'react-bootstrap'; +import { Button, Col, Modal, Row } from 'react-bootstrap'; import { withTranslation } from 'react-i18next'; import toastr from 'toastr'; +import DiscordForm from './DiscordForm'; import DiscordSelect from '../common/DiscordSelect'; import Icon from '../common/Icon'; import ToggleSwitch from '../common/ToggleSwitch'; @@ -55,52 +56,72 @@ const setDiscord = async (tournament, guild_id) => { } }; +const inviteUrl = 'https://discordapp.com/oauth2/authorize?client_id=951113702839549982&scope=bot'; + const SettingsDialog = ({ onHide, show, tournament, }) => - + {i18n.t('tournaments.settings')} -
- {i18n.t('tournaments.open')} - value ? open(tournament) : close(tournament)} - value={tournament.accept_applications} - /> -
-
- {i18n.t('tournaments.locked')} - value ? lock(tournament) : unlock(tournament)} - value={tournament.locked} - /> -
-
-
-

{i18n.t('tournaments.discord')}

-
- + + +
+ {i18n.t('tournaments.open')} + value + ? open(tournament) : close(tournament)} + value={tournament.accept_applications} + /> +
+
+ {i18n.t('tournaments.locked')} + value + ? lock(tournament) : unlock(tournament)} + value={tournament.locked} + /> +
+
+
+

{i18n.t('tournaments.discord')}

+ {!tournament.discord ? +
+ +
+ : null} +
+ setDiscord(tournament, value)} + value={tournament.discord} + />
-
- setDiscord(tournament, value)} - value={tournament.discord} - /> -
+ + {tournament.discord ? + + + + : null} +