Update console releases admin

This commit is contained in:
DariusIII
2025-10-10 13:33:39 +02:00
parent 61af8a5a1a
commit 20a83c1003
4 changed files with 444 additions and 33 deletions
@@ -6,14 +6,17 @@ use App\Http\Controllers\BasePageController;
use Blacklight\Console;
use Blacklight\Genres;
use Blacklight\utility\Utility;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\View\View;
class AdminConsoleController extends BasePageController
{
/**
* @throws \Exception
* Display a listing of console games
*/
public function index(): void
public function index(): View
{
$this->setAdminPrefs();
@@ -21,21 +24,13 @@ class AdminConsoleController extends BasePageController
$consoleList = Utility::getRange('consoleinfo');
$this->smarty->assign('consolelist', $consoleList);
$content = $this->smarty->fetch('console-list.tpl');
$this->smarty->assign(compact('title', 'meta_title', 'content'));
$this->adminrender();
return view('admin.console.index', compact('consoleList', 'title', 'meta_title'));
}
/**
* @return \Illuminate\Http\RedirectResponse|void
*
* @throws \Exception
* Show the form for editing a console game
*/
public function edit(Request $request)
public function edit(Request $request): View|RedirectResponse
{
$this->setAdminPrefs();
$console = new Console(['Settings' => null]);
@@ -43,48 +38,57 @@ class AdminConsoleController extends BasePageController
$meta_title = $title = 'Console Edit';
// set the current action
$action = $request->input('action') ?? 'view';
$action = $request->input('action', 'view');
if ($request->has('id')) {
$id = $request->input('id');
$con = $console->getConsoleInfo($id);
if (! $con) {
$this->show404();
abort(404);
}
switch ($action) {
case 'submit':
$coverLoc = storage_path('covers/console/'.$id.'.jpg');
if ($_FILES['cover']['size'] > 0) {
$tmpName = $_FILES['cover']['tmp_name'];
$file_info = getimagesize($tmpName);
if ($request->hasFile('cover') && $request->file('cover')->isValid()) {
$uploadedFile = $request->file('cover');
$file_info = getimagesize($uploadedFile->getRealPath());
if (! empty($file_info)) {
move_uploaded_file($_FILES['cover']['tmp_name'], $coverLoc);
$uploadedFile->move(storage_path('covers/console'), $id.'.jpg');
}
}
$request->merge(['cover' => file_exists($coverLoc) ? 1 : 0]);
$request->merge(['salesrank' => (empty($request->input('salesrank')) || ! ctype_digit($request->input('salesrank'))) ? 'null' : $request->input('salesrank')]);
$request->merge(['releasedate' => (empty($request->input('releasedate')) || ! strtotime($request->input('releasedate'))) ? $con['releasedate'] : Carbon::parse($request->input('releasedate'))->timestamp]);
$hasCover = file_exists($coverLoc) ? 1 : 0;
$salesrank = (empty($request->input('salesrank')) || ! ctype_digit($request->input('salesrank'))) ? null : $request->input('salesrank');
$releasedate = (empty($request->input('releasedate')) || ! strtotime($request->input('releasedate')))
? $con['releasedate']
: Carbon::parse($request->input('releasedate'))->timestamp;
$console->update($id, $request->input('title'), $request->input('asin'), $request->input('url'), $request->input('salesrank'), $request->input('platform'), $request->input('publisher'), $request->input('releasedate'), $request->input('esrb'), $request->input('cover'), $request->input('genre'));
$console->update(
$id,
$request->input('title'),
$request->input('asin'),
$request->input('url'),
$salesrank,
$request->input('platform'),
$request->input('publisher'),
$releasedate,
$request->input('esrb'),
$hasCover,
$request->input('genre')
);
return redirect()->route('admin.console-list')->with('success', 'Console game updated successfully');
return redirect()->to('admin/console-list.');
break;
case 'view':
default:
$this->smarty->assign('console', $con);
$this->smarty->assign('genres', $gen->getGenres(Genres::CONSOLE_TYPE));
break;
$genres = $gen->getGenres(Genres::CONSOLE_TYPE);
return view('admin.console.edit', compact('con', 'genres', 'title', 'meta_title'));
}
}
$content = $this->smarty->fetch('console-edit.tpl');
$this->smarty->assign(compact('title', 'meta_title', 'content'));
$this->adminrender();
return redirect()->route('admin.console-list');
}
}
@@ -0,0 +1,260 @@
@extends('layouts.admin')
@section('content')
<div class="container mx-auto px-4 py-6">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm">
<!-- Header -->
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<div class="flex justify-between items-center">
<h1 class="text-2xl font-semibold text-gray-800 dark:text-gray-200">
<i class="fas fa-edit mr-2"></i>{{ $title }}
</h1>
<a href="{{ route('admin.console-list') }}" class="px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700">
<i class="fas fa-arrow-left mr-2"></i>Back to List
</a>
</div>
</div>
<!-- Edit Form -->
<div class="p-6">
<form method="POST" action="{{ url('admin/console-edit?id=' . $con['id']) }}" enctype="multipart/form-data">
@csrf
<input type="hidden" name="action" value="submit">
<input type="hidden" name="id" value="{{ $con['id'] }}">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Left Column -->
<div class="space-y-6">
<!-- Title -->
<div>
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Title <span class="text-red-500">*</span>
</label>
<input type="text"
id="title"
name="title"
value="{{ $con['title'] ?? '' }}"
required
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md focus:ring-blue-500 focus:border-blue-500">
</div>
<!-- Platform -->
<div>
<label for="platform" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Platform
</label>
<input type="text"
id="platform"
name="platform"
value="{{ $con['platform'] ?? '' }}"
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md focus:ring-blue-500 focus:border-blue-500">
</div>
<!-- Publisher -->
<div>
<label for="publisher" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Publisher
</label>
<input type="text"
id="publisher"
name="publisher"
value="{{ $con['publisher'] ?? '' }}"
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md focus:ring-blue-500 focus:border-blue-500">
</div>
<!-- Release Date -->
<div>
<label for="releasedate" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Release Date
</label>
<input type="date"
id="releasedate"
name="releasedate"
value="{{ isset($con['releasedate']) && $con['releasedate'] ? date('Y-m-d', $con['releasedate']) : '' }}"
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md focus:ring-blue-500 focus:border-blue-500">
</div>
<!-- ASIN -->
<div>
<label for="asin" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
ASIN
</label>
<input type="text"
id="asin"
name="asin"
value="{{ $con['asin'] ?? '' }}"
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md focus:ring-blue-500 focus:border-blue-500">
</div>
<!-- URL -->
<div>
<label for="url" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Amazon URL
</label>
<input type="url"
id="url"
name="url"
value="{{ $con['url'] ?? '' }}"
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md focus:ring-blue-500 focus:border-blue-500">
@if(!empty($con['url']))
<a href="{{ $con['url'] }}" target="_blank" class="text-sm text-blue-600 dark:text-blue-400 hover:underline mt-1 inline-block">
<i class="fas fa-external-link-alt mr-1"></i>View on Amazon
</a>
@endif
</div>
<!-- ESRB Rating -->
<div>
<label for="esrb" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
ESRB Rating
</label>
<select id="esrb"
name="esrb"
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md focus:ring-blue-500 focus:border-blue-500">
<option value="">Select Rating</option>
<option value="E" {{ isset($con['esrb']) && $con['esrb'] == 'E' ? 'selected' : '' }}>E - Everyone</option>
<option value="E10+" {{ isset($con['esrb']) && $con['esrb'] == 'E10+' ? 'selected' : '' }}>E10+ - Everyone 10+</option>
<option value="T" {{ isset($con['esrb']) && $con['esrb'] == 'T' ? 'selected' : '' }}>T - Teen</option>
<option value="M" {{ isset($con['esrb']) && $con['esrb'] == 'M' ? 'selected' : '' }}>M - Mature</option>
<option value="AO" {{ isset($con['esrb']) && $con['esrb'] == 'AO' ? 'selected' : '' }}>AO - Adults Only</option>
<option value="RP" {{ isset($con['esrb']) && $con['esrb'] == 'RP' ? 'selected' : '' }}>RP - Rating Pending</option>
</select>
</div>
<!-- Sales Rank -->
<div>
<label for="salesrank" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Sales Rank
</label>
<input type="number"
id="salesrank"
name="salesrank"
value="{{ $con['salesrank'] ?? '' }}"
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md focus:ring-blue-500 focus:border-blue-500">
</div>
<!-- Genre -->
<div>
<label for="genre" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Genre
</label>
<select id="genre"
name="genre"
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md focus:ring-blue-500 focus:border-blue-500">
<option value="">Select Genre</option>
@foreach($genres as $genre)
<option value="{{ $genre->id }}" {{ isset($con['genre_id']) && $con['genre_id'] == $genre->id ? 'selected' : '' }}>
{{ $genre->title }}
</option>
@endforeach
</select>
</div>
</div>
<!-- Right Column -->
<div class="space-y-6">
<!-- Current Cover -->
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Current Cover
</label>
<div class="border border-gray-300 dark:border-gray-600 rounded-lg p-4 bg-gray-50 dark:bg-gray-900">
@php
$coverPath = public_path('covers/console/' . $con['id'] . '.jpg');
$hasCover = file_exists($coverPath);
@endphp
@if($hasCover)
<img src="{{ asset('covers/console/' . $con['id'] . '.jpg') }}"
alt="{{ $con['title'] }}"
class="max-w-full h-auto mx-auto rounded shadow-lg"
style="max-height: 400px;">
@else
<div class="flex flex-col items-center justify-center py-12 text-gray-400 dark:text-gray-500">
<i class="fas fa-gamepad text-6xl mb-3"></i>
<p>No cover image available</p>
</div>
@endif
</div>
</div>
<!-- Upload New Cover -->
<div>
<label for="cover" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Upload New Cover
</label>
<div class="border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg p-4">
<input type="file"
id="cover"
name="cover"
accept="image/*"
class="w-full text-sm text-gray-500 dark:text-gray-400
file:mr-4 file:py-2 file:px-4
file:rounded-md file:border-0
file:text-sm file:font-semibold
file:bg-blue-50 file:text-blue-700
hover:file:bg-blue-100
dark:file:bg-blue-900 dark:file:text-blue-200">
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
PNG, JPG, GIF up to 10MB
</p>
</div>
</div>
<!-- Console Info -->
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">Console Information</h3>
<dl class="space-y-2 text-sm">
<div class="flex justify-between">
<dt class="text-gray-500 dark:text-gray-400">ID:</dt>
<dd class="text-gray-900 dark:text-gray-200 font-mono">{{ $con['id'] }}</dd>
</div>
@if(isset($con['created_at']))
<div class="flex justify-between">
<dt class="text-gray-500 dark:text-gray-400">Created:</dt>
<dd class="text-gray-900 dark:text-gray-200">{{ $con['created_at'] }}</dd>
</div>
@endif
@if(isset($con['updated_at']))
<div class="flex justify-between">
<dt class="text-gray-500 dark:text-gray-400">Updated:</dt>
<dd class="text-gray-900 dark:text-gray-200">{{ $con['updated_at'] }}</dd>
</div>
@endif
</dl>
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="mt-6 flex items-center justify-between border-t border-gray-200 dark:border-gray-700 pt-6">
<a href="{{ route('admin.console-list') }}" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600">
<i class="fas fa-times mr-2"></i>Cancel
</a>
<button type="submit" class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
<i class="fas fa-save mr-2"></i>Save Changes
</button>
</div>
</form>
</div>
</div>
</div>
@push('scripts')
<script>
// Preview image before upload
document.getElementById('cover')?.addEventListener('change', function(e) {
if (e.target.files && e.target.files[0]) {
const reader = new FileReader();
reader.onload = function(event) {
const img = document.querySelector('img[alt="{{ $con['title'] ?? '' }}"]');
if (img) {
img.src = event.target.result;
}
}
reader.readAsDataURL(e.target.files[0]);
}
});
</script>
@endpush
@endsection
@@ -0,0 +1,133 @@
@extends('layouts.admin')
@section('content')
<div class="container mx-auto px-4 py-6">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm">
<!-- Header -->
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<div class="flex justify-between items-center">
<h1 class="text-2xl font-semibold text-gray-800 dark:text-gray-200">
<i class="fas fa-gamepad mr-2"></i>{{ $title }}
</h1>
<div class="text-sm text-gray-600 dark:text-gray-400">
Total: {{ $consoleList->total() }} games
</div>
</div>
</div>
<!-- Console Table -->
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-900">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Cover</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Title</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Platform</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Publisher</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Release Date</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">ESRB</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
@forelse($consoleList as $console)
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-6 py-4 whitespace-nowrap">
@php
$coverPath = public_path('covers/console/' . $console->id . '.jpg');
$hasCover = file_exists($coverPath);
@endphp
@if($hasCover)
<img src="{{ asset('covers/console/' . $console->id . '.jpg') }}"
alt="{{ $console->title }}"
class="h-16 w-12 object-cover rounded shadow"
loading="lazy">
@else
<div class="h-16 w-12 bg-gray-200 dark:bg-gray-700 rounded flex items-center justify-center">
<i class="fas fa-gamepad text-gray-400 text-sm"></i>
</div>
@endif
</td>
<td class="px-6 py-4">
<div class="text-sm font-medium text-gray-900 dark:text-gray-200">
{{ $console->title }}
</div>
@if($console->asin)
<div class="text-xs text-gray-500 dark:text-gray-400">
ASIN: {{ $console->asin }}
</div>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap">
@if($console->platform)
<span class="px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200">
{{ $console->platform }}
</span>
@else
<span class="text-gray-400"></span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-200">
{{ $console->publisher ?? '—' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
@if($console->releasedate)
{{ date('Y-m-d', $console->releasedate) }}
@else
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap">
@if($console->esrb)
<span class="px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full
@if($console->esrb == 'E') bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200
@elseif($console->esrb == 'E10+') bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200
@elseif($console->esrb == 'T') bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200
@elseif($console->esrb == 'M') bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200
@elseif($console->esrb == 'AO') bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200
@else bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-200
@endif">
{{ $console->esrb }}
</span>
@else
<span class="text-gray-400"></span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium space-x-2">
<a href="{{ url('admin/console-edit?id=' . $console->id) }}"
class="text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300"
title="Edit">
<i class="fas fa-edit"></i>
</a>
@if($console->url)
<a href="{{ $console->url }}"
target="_blank"
class="text-green-600 dark:text-green-400 hover:text-green-900 dark:hover:text-green-300"
title="View on Amazon">
<i class="fas fa-external-link-alt"></i>
</a>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="7" class="px-6 py-8 text-center text-gray-500 dark:text-gray-400">
<div class="flex flex-col items-center">
<i class="fas fa-gamepad text-4xl mb-3"></i>
<p class="text-lg">No console games available</p>
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<!-- Pagination -->
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700">
{{ $consoleList->links() }}
</div>
</div>
</div>
@endsection
@@ -121,6 +121,20 @@
</div>
</div>
<!-- Console -->
<div class="mb-4">
<button type="button" class="flex items-center justify-between w-full text-left text-gray-300 dark:text-gray-400 hover:text-white dark:hover:text-white transition" onclick="toggleAdminSubmenu('console-menu')">
<div class="flex items-center space-x-3">
<i class="fas fa-gamepad"></i>
<span>Console</span>
</div>
<i class="fas fa-chevron-down text-sm transform transition-transform" id="console-menu-icon"></i>
</button>
<div id="console-menu" class="hidden mt-2 ml-6 space-y-1">
<a href="{{ url('/admin/console-list') }}" class="block py-2 px-3 text-gray-400 dark:text-gray-500 hover:text-white dark:hover:text-white hover:bg-gray-800 dark:hover:bg-gray-800 rounded transition">Console List</a>
</div>
</div>
<!-- Music -->
<div class="mb-4">
<button type="button" class="flex items-center justify-between w-full text-left text-gray-300 dark:text-gray-400 hover:text-white dark:hover:text-white transition" onclick="toggleAdminSubmenu('music-menu')">