Skip to content

Commit

Permalink
Optimize gameslist, add update/delete game
Browse files Browse the repository at this point in the history
  • Loading branch information
joeke committed Jan 30, 2024
1 parent 66b8bd5 commit f0b5bbe
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 52 deletions.
56 changes: 51 additions & 5 deletions app/Http/Controllers/GameController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Foundation\Http\FormRequest;
use Inertia\Inertia;
use Inertia\Response;
use Illuminate\Http\RedirectResponse;
Expand Down Expand Up @@ -69,6 +70,51 @@ public function store(Request $request): RedirectResponse
return redirect()->route('game.show', ['id' => $game->id]);
}

/**
* Handle updating a game.
*
* @throws \Illuminate\Validation\ValidationException
*/
public function update(FormRequest $request): RedirectResponse
{
$request->validate([
'id' => 'required',
'type_id' => 'required',
'player_id' => 'required',
'score_goal' => 'required',
]);

$game = Game::where('id', $request->id)->first();

if (!$request->user()->hasAccessToGame($game)) {
abort(403);
}

$game->fill($request->all());
$game->save();

return redirect()->route('games');
}

/**
* Delete a game.
*/
public function delete(Request $request)
{
$request->validate([
'id' => 'required'
]);

$game = Game::where('id', $request->id)->first();

if (!$request->user()->hasAccessToGame($game)) {
abort(403);
}

$game->scores()->delete();
$game->delete();
}

/**
* Display the game overview.
*/
Expand All @@ -79,15 +125,15 @@ public function overview(): Response
->orderBy('created_at', 'desc')
->get();

// $scores = [];
$scores = [];

// foreach ($games as $game) {
// $scores[$game->id] = $this->calculateScores($game);
// }
foreach ($games as $game) {
$scores[$game->id] = $this->calculateScores($game);
}

return Inertia::render('Game/Overview', [
'games' => $games,
// 'scores' => $scores
'scores' => $scores
]);
}

Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/GameScoreController.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function store(Request $request)
]);
}

/**
/**
* Delete a game score.
*/
public function delete(Request $request)
Expand Down
2 changes: 1 addition & 1 deletion app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ class User extends Authenticatable

public function hasAccessToGame(Game $game): bool
{
return $this->id === $game->player_id || $this->id === $game->opponent_id;
return in_array($this->id, [$game->player_id, $game->opponent_id, $game->created_by]);
}
}
16 changes: 11 additions & 5 deletions resources/js/Pages/Game/Game.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,24 @@ const isCreate = game ? false : true;
const title = isCreate ? 'New game' : 'Edit game';
const buttonTitle = isCreate ? 'Start game' : 'Save game';
const form = game || useForm({
const form = useForm(game || {
type_id: gameTypes[0]?.id || 0,
score_goal: 100,
player_id: usePage().props.auth.user.id || 0,
opponent_id: 0,
});
const submit = () => {
const endpoint = isCreate ? 'game.store' : 'game.update';
form.post(route(endpoint), {
onFinish: () => form.reset()
});
if (isCreate) {
form.post(route('game.store'), {
onFinish: () => form.reset()
});
} else {
form.patch(route('game.update'), {
onFinish: () => form.reset()
});
}
};
</script>
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Pages/Game/Overview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const games = usePage().props.games;
<Link :href="route('game.new')" class="btn btn-primary"><i class="bi bi-plus-lg"></i> New game</Link>

<div class="mt-4">
<GamesList :games="games" :showRowEditButton="true" />
<GamesList :games="games" :showRowEditButton="true" :showRowDeleteButton="true" />
</div>

</AuthenticatedLayout>
Expand Down
129 changes: 90 additions & 39 deletions resources/js/Pages/Game/Partials/GamesList.vue
Original file line number Diff line number Diff line change
@@ -1,48 +1,99 @@
<script setup>
import { Link } from '@inertiajs/vue3';
const props = defineProps({
games: {
type: Array,
default: () => [],
},
showMoreButton: {
type: Boolean,
default: false,
},
showRowEditButton: {
type: Boolean,
default: false,
},
});
import { useForm, Link, router } from '@inertiajs/vue3';
import { defineProps, onMounted, ref } from 'vue';
const props = defineProps({
games: {
type: Array,
default: () => [],
},
showMoreButton: {
type: Boolean,
default: false,
},
showRowEditButton: {
type: Boolean,
default: false,
},
showRowDeleteButton: {
type: Boolean,
default: false,
}
});
let selectedGame = ref(null);
let deleteModal = ref(null);
onMounted(() => {
deleteModal = new Modal('#deleteModal');
})
const showDeleteModal = (game) => {
selectedGame.value = game;
deleteModal.show();
}
const deleteGame = () => {
const form = useForm({
id: selectedGame.value.id,
});
form.delete(route('game.delete'), {
onSuccess: () => {
router.visit(route('games'));
deleteModal.hide();
}
});
}
</script>

<template>
<div class="table-list" v-if="games.length > 0">
<div class="table-list-row table-list-header">
<div>ID</div>
<div>Date</div>
<div>Type</div>
<div>Race to</div>
<div>Player(s)</div>
<div v-if="showRowEditButton"></div>
</div>
<section>
<div class="table-list" v-if="games.length > 0">
<div class="table-list-row table-list-header">
<div>Date</div>
<div>Type</div>
<div>Race to</div>
<div>Player(s)</div>
<div></div>
</div>

<Link :href="route('game.show', game.id)" class="table-list-row" aria-current="true" v-for="game in games" :key="game.id">
<div>#{{ game.id }}</div>
<div>{{ game.start_date_formatted }}</div>
<div>{{ game.type.name }}</div>
<div>{{ game.score_goal }}</div>
<div>{{ game.player.name }}<span v-if="game.opponent.name"> vs {{ game.opponent.name }}</span></div>
<div v-if="showRowEditButton">
<Link :href="route('game.edit', game.id)" class="btn btn-sm btn-gray-700"><i class="bi bi-pencil"></i></Link>
<div class="table-list-row" aria-current="true" v-for="game in games" :key="game.id">
<div><div class="label">Date:</div> {{ game.start_date_formatted }}</div>
<div><div class="label">Type:</div>{{ game.type.name }}</div>
<div><div class="label">Race to:</div>{{ game.score_goal }}</div>
<div><div class="label">Player(s):</div>{{ game.player.name }}<span v-if="game.opponent.name"> vs {{ game.opponent.name }}</span></div>
<div class="actions">
<Link :href="route('game.show', game.id)" class="btn btn-sm btn-outline-primary"><i class="bi bi-search"></i> View</Link>
<Link v-if="showRowEditButton" :href="route('game.edit', game.id)" class="btn btn-sm btn-outline-gray-500"><i class="bi bi-pencil"></i> Edit</Link>
<button v-if="showRowDeleteButton" @click="showDeleteModal(game)" class="btn btn-sm btn-danger"><i class="bi bi-trash-fill"></i> Delete</button>
</div>
</div>
</Link>

<Link :href="route('games')" class="btn btn-gray-600 mt-3" v-if="showMoreButton">View all games</Link>
</div>
<Link :href="route('games')" class="btn btn-gray-600 mt-3" v-if="showMoreButton">View all games</Link>
</div>

<div v-else class="py-2">
<em>No games found. <a :href="route('game.new')">Create a new game</a></em>
</div>

<div v-else class="py-2">
<em>No games found. <a :href="route('game.new')">Create a new game</a></em>
</div>
<div class="modal" id="deleteModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Delete game #{{ selectedGame?.id }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Are you sure you want to delete this game?</p>
<p><b>{{ selectedGame?.start_date_formatted }} - {{ selectedGame?.player.name }}<span v-if="selectedGame?.opponent.name"> vs {{ selectedGame?.opponent.name }}</span></b></p>

<div class="mt-4 d-flex">
<button class="btn btn-danger ms-auto" @click="deleteGame"><i class="bi bi-check-lg"></i> Yes, delete this game</button>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
46 changes: 46 additions & 0 deletions resources/scss/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@
display: table-cell;
padding: .5rem;
border-bottom: 1px solid var(--bs-border-color);
vertical-align: middle;

.label {
display: none;
}

&.actions {
display: flex;
justify-content: flex-end;
gap: .8rem;
width: 100%;
margin: 0;
grid-column: 1 / -1;
}
}

&:hover {
Expand All @@ -121,5 +135,37 @@
}
}
}

@include media-breakpoint-down(sm) {
display: grid;
grid-template-columns: 1fr 1fr;
gap: .25rem;
padding: .5rem 0;

> div {
border-bottom: 0;
padding: .25rem .5rem;

.label {
display: block;
font-size: .75rem;
color: $gray-500;
text-transform: uppercase;
}

&.actions {
width: 100%;
justify-content: center;

> * {
flex: 1;
}
}
}

&.table-list-header {
display: none;
}
}
}
}
1 change: 1 addition & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
Route::get('/game/{id}/show', [GameController::class, 'show'])->name('game.show');
Route::post('/game', [GameController::class, 'store'])->name('game.store');
Route::patch('/game', [GameController::class, 'update'])->name('game.update');
Route::delete('/game', [GameController::class, 'delete'])->name('game.delete');
Route::post('/game/score', [GameScoreController::class, 'store'])->name('game.score.store');
Route::delete('/game/score', [GameScoreController::class, 'delete'])->name('game.score.delete');
Route::get('/games', [GameController::class, 'overview'])->name('games');
Expand Down

0 comments on commit f0b5bbe

Please sign in to comment.