Initial commit of the complete City10 virtual city simulation platform. Backend (Laravel 13): - REST API with Sanctum tokens and session-based web authentication - Role-based access control (admin/user) with middleware protection - AI agent CRUD with OpenRouter.ai integration restricted to free models - Store management with 3D coordinates and AI shopkeeper assignment - Versioned legal documents (Terms, Privacy, Cookies) with LGPD audit trail - Math CAPTCHA on public forms and multi-language support (pt_BR, en, es) Frontend: - Responsive Blade templates with Tailwind CSS v4 - Three.js 3D city viewer with SSE chat streaming to AI agents - Admin panel for store and user administration Infrastructure: - MariaDB/MySQL database with comprehensive migrations - Database seeders for demo content and test accounts - PHPUnit test suite and Laravel Pint code styling - Vite build configuration with hot reload
80 lines
4.6 KiB
PHP
80 lines
4.6 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', __('admin.stores.title'))
|
|
|
|
@section('content')
|
|
<div style="max-width: 1100px; margin: 0 auto;">
|
|
<div style="display:flex; justify-content:space-between; align-items:center; gap:1rem; flex-wrap:wrap; margin-bottom:1.25rem;">
|
|
<h1 style="margin:0; color:#fff;">🏪 {{ __('admin.stores.title') }}</h1>
|
|
<a href="{{ route('admin.stores.create') }}" class="btn btn-primary">+ {{ __('admin.stores.new') }}</a>
|
|
</div>
|
|
|
|
<form method="GET" action="{{ route('admin.stores.index') }}" class="card" style="margin-bottom:1.25rem; padding:1rem;">
|
|
<div style="display:flex; gap:.75rem; flex-wrap:wrap; align-items:flex-end;">
|
|
<div class="field" style="margin:0; flex:1; min-width:180px;">
|
|
<label for="search">{{ __('Search') }}</label>
|
|
<input id="search" type="text" name="search" value="{{ $currentSearch }}" placeholder="{{ __('Search') }}">
|
|
</div>
|
|
<div class="field" style="margin:0; min-width:160px;">
|
|
<label for="type">{{ __('admin.stores.type') }}</label>
|
|
<select id="type" name="type">
|
|
<option value="">{{ __('Cancel') }}</option>
|
|
@foreach ($types as $t)
|
|
<option value="{{ $t }}" @selected($currentType === $t)>{{ $t }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">{{ __('Search') }}</button>
|
|
</div>
|
|
</form>
|
|
|
|
@if ($stores->isEmpty())
|
|
<div class="card" style="text-align:center; color:var(--muted);">{{ __('admin.stores.empty') }}</div>
|
|
@else
|
|
<div style="display:grid; grid-template-columns:repeat(auto-fill, minmax(300px, 1fr)); gap:1rem;">
|
|
@foreach ($stores as $store)
|
|
<div class="card" style="padding:1.15rem;">
|
|
<div style="display:flex; justify-content:space-between; gap:.5rem; align-items:flex-start;">
|
|
<div>
|
|
<h3 style="margin:0 0 .35rem; color:#fff; font-size:1.05rem;">{{ $store->name }}</h3>
|
|
<span class="badge {{ $store->is_open ? 'badge-user' : 'badge-admin' }}">{{ $store->type }}</span>
|
|
@if (! $store->is_open)
|
|
<span class="badge" style="background:rgba(239,68,68,.2); color:#fecaca;">{{ __('city.closed') }}</span>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<p style="color:var(--muted); font-size:.8rem; margin:.75rem 0 .35rem;">{{ __('admin.stores.coords') }}:</p>
|
|
<p style="margin:0; font-family:ui-monospace, monospace; font-size:.85rem; color:#7dd3fc;">
|
|
X {{ number_format($store->pos_x, 2) }} · Y {{ number_format($store->pos_y, 2) }} · Z {{ number_format($store->pos_z, 2) }}
|
|
</p>
|
|
<p style="margin:.25rem 0 0; font-family:ui-monospace, monospace; font-size:.8rem; color:var(--muted);">
|
|
{{ __('admin.stores.width') }} {{ number_format($store->width, 1) }} ·
|
|
{{ __('admin.stores.height') }} {{ number_format($store->height, 1) }} ·
|
|
{{ __('admin.stores.depth') }} {{ number_format($store->depth, 1) }}
|
|
</p>
|
|
|
|
<p style="color:var(--muted); font-size:.85rem; margin:.75rem 0 0;">
|
|
{{ __('admin.stores.owner') }}: {{ $store->owner?->name ?? __('admin.stores.no_owner') }}<br>
|
|
{{ __('admin.stores.agent') }}: {{ $store->agent?->name ?? __('admin.stores.no_agent') }}
|
|
</p>
|
|
|
|
<div style="display:flex; gap:.5rem; margin-top:1rem;">
|
|
<a href="{{ route('admin.stores.edit', $store) }}" class="btn" style="flex:1; text-align:center;">{{ __('Edit') }}</a>
|
|
<form method="POST" action="{{ route('admin.stores.destroy', $store) }}" style="margin:0;"
|
|
onsubmit="return confirm('{{ __('admin.stores.confirm_delete') }}')">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button type="submit" class="btn" style="color:var(--danger); border-color:rgba(239,68,68,.5);">{{ __('Delete') }}</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
|
|
<div style="margin-top:1.5rem; display:flex; justify-content:center; gap:.5rem; flex-wrap:wrap;">
|
|
{{ $stores->links() }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@endsection |