Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make some minor datatable ux improvements #2734

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
48 changes: 2 additions & 46 deletions app/Community/Requests/UserGameListRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,12 @@

namespace App\Community\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Platform\Requests\GameListRequest;

class UserGameListRequest extends FormRequest
class UserGameListRequest extends GameListRequest
{
public function authorize(): bool
{
return true;
}

public function rules(): array
{
return [
'page.number' => 'integer|min:1',
'sort' => 'string|in:title,system,achievementsPublished,pointsTotal,retroRatio,lastUpdated,releasedAt,playersTotal,numVisibleLeaderboards,numUnresolvedTickets,progress,-title,-system,-achievementsPublished,-pointsTotal,-retroRatio,-lastUpdated,-releasedAt,-playersTotal,-numVisibleLeaderboards,-numUnresolvedTickets,-progress',
'filter.*' => 'string',
];
}

public function getPage(): int
{
return (int) $this->input('page.number', 1);
}

public function getSort(): array
{
$sortParam = $this->input('sort', 'title');
$sortDirection = 'asc';

if (str_starts_with($sortParam, '-')) {
$sortDirection = 'desc';
$sortParam = ltrim($sortParam, '-');
}

return [
'field' => $sortParam,
'direction' => $sortDirection,
];
}

public function getFilters(): array
{
$filters = [];
foreach ($this->query('filter', []) as $key => $value) {
$filters[$key] = explode(',', $value);
}

if (!isset($filters['achievementsPublished'])) {
$filters['achievementsPublished'] = ['has'];
}

return $filters;
}
}
4 changes: 3 additions & 1 deletion app/Helpers/render/game.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,13 @@ function renderGameBreadcrumb(array|int $data, bool $addLinkToLastCrumb = true):
return [$mainID, $renderedMain, $subsetID ?? null, $renderedSubset ?? null];
};

$allGamesHref = route('game.index');

$gameListHref = System::isGameSystem($consoleID)
? route('system.game.index', ['system' => $consoleID])
: '/gameList.php?c=' . $consoleID;

$html = "<a href='/gameList.php'>All Games</a>"
$html = "<a href='" . $allGamesHref . "'>All Games</a>"
. $nextCrumb($consoleName, $gameListHref);

[$mainID, $renderedMain, $subsetID, $renderedSubset] = $getSplitData($data);
Expand Down
4 changes: 4 additions & 0 deletions app/Models/Emulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ class Emulator extends BaseModel implements HasMedia
'source_url',
];

protected $casts = [
'active' => 'boolean',
];

public static function boot()
{
parent::boot();
Expand Down
4 changes: 4 additions & 0 deletions app/Models/System.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ protected static function newFactory(): SystemFactory
'active',
];

protected $casts = [
'active' => 'boolean',
];

// == constants

public const Arduboy = 71;
Expand Down
11 changes: 10 additions & 1 deletion app/Platform/Actions/BuildGameListAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use App\Models\Game;
use App\Models\Leaderboard;
use App\Models\PlayerGame;
use App\Models\System;
use App\Models\Ticket;
use App\Models\User;
use App\Platform\Data\GameData;
Expand Down Expand Up @@ -156,6 +157,15 @@ private function buildBaseQuery(GameListType $listType, ?User $user = null): Bui
}

switch ($listType) {
case GameListType::AllGames:
// Exclude non game systems, inactive systems, and subsets.
$query
->whereHas('system', function ($q) {
return $q->gameSystems()->active();
})
->where('GameData.Title', 'not like', "%[Subset -%");
break;

case GameListType::UserPlay:
$query->whereHas('gameListEntries', function ($query) use ($user) {
$query->where('user_id', $user->id)
Expand All @@ -165,7 +175,6 @@ private function buildBaseQuery(GameListType $listType, ?User $user = null): Bui

// TODO implement these other use cases
case GameListType::UserDevelop:
case GameListType::AllGames:
case GameListType::System:
case GameListType::Hub:
case GameListType::DeveloperSets:
Expand Down
52 changes: 52 additions & 0 deletions app/Platform/Controllers/Api/GameApiController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace App\Platform\Controllers\Api;

use App\Http\Controller;
use App\Models\Game;
use App\Platform\Actions\BuildGameListAction;
use App\Platform\Enums\GameListType;
use App\Platform\Requests\GameListRequest;
use Illuminate\Http\JsonResponse;

class GameApiController extends Controller
{
public function index(GameListRequest $request): JsonResponse
{
$this->authorize('viewAny', Game::class);

$paginatedData = (new BuildGameListAction())->execute(
GameListType::AllGames,
user: $request->user(),
page: $request->getPage(),
filters: $request->getFilters(),
sort: $request->getSort(),
);

return response()->json($paginatedData);
}

public function create(): void
{
}

public function store(): void
{
}

public function show(): void
{
}

public function edit(): void
{
}

public function update(): void
{
}

public function destroy(): void
{
}
}
48 changes: 39 additions & 9 deletions app/Platform/Controllers/GameController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@

namespace App\Platform\Controllers;

use App\Data\UserPermissionsData;
use App\Http\Controller;
use App\Models\Game;
use App\Models\System;
use App\Models\User;
use App\Platform\Actions\BuildGameListAction;
use App\Platform\Data\GameListPagePropsData;
use App\Platform\Data\SystemData;
use App\Platform\Enums\GameListType;
use App\Platform\Requests\GameListRequest;
use App\Platform\Requests\GameRequest;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response as InertiaResponse;

class GameController extends Controller
{
Expand All @@ -19,16 +28,37 @@ protected function resourceName(): string
return 'game';
}

public function index(): View
public function index(GameListRequest $request): InertiaResponse
{
$this->authorize('viewAny', $this->resourceClass());

/*
* TODO: if slug is empty or does not match -> redirect to correctly slugged url
*/

return view('resource.index')
->with('resource', $this->resourceName());
/** @var ?User $user */
$user = $request->user();

$this->authorize('viewAny', [Game::class, $user]);

$paginatedData = (new BuildGameListAction())->execute(
GameListType::AllGames,
user: $user,
page: $request->getPage(),
filters: $request->getFilters(),
sort: $request->getSort(),
);

$filterableSystemOptions = System::active()
->gameSystems()
->get()
->map(fn ($system) => SystemData::fromSystem($system)->include('nameShort'))
->values()
->all();

$can = UserPermissionsData::fromUser($user)->include('develop');

$props = new GameListPagePropsData(
paginatedGameListEntries: $paginatedData,
filterableSystemOptions: $filterableSystemOptions,
can: $can,
);

return Inertia::render('game-list/index', $props);
}

public function popular(): void
Expand Down
24 changes: 24 additions & 0 deletions app/Platform/Data/GameListPagePropsData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace App\Platform\Data;

use App\Data\PaginatedData;
use App\Data\UserPermissionsData;
use Spatie\LaravelData\Data;
use Spatie\TypeScriptTransformer\Attributes\TypeScript;

#[TypeScript('GameListPageProps<TItems = App.Platform.Data.GameListEntry>')]
class GameListPagePropsData extends Data
{
/**
* @param SystemData[] $filterableSystemOptions
*/
public function __construct(
public PaginatedData $paginatedGameListEntries,
public array $filterableSystemOptions,
public UserPermissionsData $can,
) {
}
}
54 changes: 54 additions & 0 deletions app/Platform/Requests/GameListRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

namespace App\Platform\Requests;

use Illuminate\Foundation\Http\FormRequest;

class GameListRequest extends FormRequest
{
public function rules(): array
{
return [
'page.number' => 'integer|min:1',
'sort' => 'string|in:title,system,achievementsPublished,pointsTotal,retroRatio,lastUpdated,releasedAt,playersTotal,numVisibleLeaderboards,numUnresolvedTickets,progress,-title,-system,-achievementsPublished,-pointsTotal,-retroRatio,-lastUpdated,-releasedAt,-playersTotal,-numVisibleLeaderboards,-numUnresolvedTickets,-progress',
'filter.*' => 'string',
];
}

public function getPage(): int
{
return (int) $this->input('page.number', 1);
}

public function getSort(): array
{
$sortParam = $this->input('sort', 'title');
$sortDirection = 'asc';

if (str_starts_with($sortParam, '-')) {
$sortDirection = 'desc';
$sortParam = ltrim($sortParam, '-');
}

return [
'field' => $sortParam,
'direction' => $sortDirection,
];
}

public function getFilters(): array
{
$filters = [];
foreach ($this->query('filter', []) as $key => $value) {
$filters[$key] = explode(',', $value);
}

if (!isset($filters['achievementsPublished'])) {
$filters['achievementsPublished'] = ['has'];
}

return $filters;
}
}
8 changes: 7 additions & 1 deletion app/Platform/RouteServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use App\Models\GameHash;
use App\Platform\Controllers\AchievementController;
use App\Platform\Controllers\Api\GameApiController;
use App\Platform\Controllers\GameController;
use App\Platform\Controllers\GameHashController;
use App\Platform\Controllers\PlayerAchievementController;
Expand Down Expand Up @@ -44,8 +45,14 @@ public function map(): void
protected function mapWebRoutes(): void
{
Route::middleware(['web', 'csp'])->group(function () {
Route::group(['prefix' => 'internal-api'], function () {
Route::get('games', [GameApiController::class, 'index'])->name('api.game.index');
});

Route::middleware(['inertia'])->group(function () {
Route::get('game/{game}/hashes', [GameHashController::class, 'index'])->name('game.hashes.index');

Route::get('games', [GameController::class, 'index'])->name('game.index');
});

// Route::get('achievement/{achievement}{slug?}', [AchievementController::class, 'show'])->name('achievement.show');
Expand All @@ -65,7 +72,6 @@ protected function mapWebRoutes(): void
// ->name('system.achievement.index');

// Route::get('game/{game}{slug?}', [GameController::class, 'show'])->name('game.show');
// Route::resource('games', GameController::class)->only('index')->names(['index' => 'game.index']);
// Route::get('games/popular', [GameController::class, 'popular'])->name('games.popular');
// Route::get('game/{game}/badges', [GameBadgeController::class, 'index'])->name('game.badge.index');
// Route::get('game/{game}/assets', [GameAssetsController::class, 'index'])->name('game.asset.index');
Expand Down
1 change: 0 additions & 1 deletion app/Providers/RouteServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ protected function mapWebRoutes(): void

Route::middleware(['web', 'csp'])->group(function () {
Route::get('download.php', fn () => $this->handlePageRequest('download'))->name('download.index');
Route::get('gameList.php', fn () => $this->handlePageRequest('gameList'))->name('game.index');
Route::get('{path}.php', fn (string $path) => $this->handlePageRequest($path))->where('path', '(.*)');
Route::get('user/{user}', fn (string $user) => $this->handlePageRequest('userInfo', $user))->name('user.show');
Route::get('achievement/{achievement}{slug?}', fn ($achievement) => $this->handlePageRequest('achievementInfo', $achievement))->name('achievement.show');
Expand Down
7 changes: 5 additions & 2 deletions resources/js/common/components/+vendor/BaseBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import * as React from 'react';
import { cn } from '@/utils/cn';

const baseBadgeVariants = cva(
'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
cn(
'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold',
'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
),
{
variants: {
variant: {
default: 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
secondary:
'border-transparent bg-neutral-800 text-secondary-foreground hover:bg-secondary/80',
'border-transparent bg-neutral-800 light:bg-neutral-200 text-secondary-foreground hover:bg-secondary/80',
destructive:
'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
outline: 'text-foreground',
Expand Down
2 changes: 1 addition & 1 deletion resources/js/common/components/+vendor/BaseCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const BaseCheckbox = React.forwardRef<
'peer h-4 w-4 shrink-0 rounded-sm border light:border-neutral-900',
'focus-visible:outline-none focus-visible:ring-2 light:ring-offset-white light:focus-visible:ring-neutral-950',
'focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
'border-neutral-600 light:data-[state=checked]:bg-text light:data-[state=checked]:text-neutral-50',
'border-neutral-600 light:data-[state=checked]:bg-text',
'ring-offset-neutral-950 focus-visible:ring-neutral-300 data-[state=checked]:bg-neutral-700',
'data-[state=checked]:border-neutral-50 data-[state=checked]:text-neutral-50',
className,
Expand Down
Loading