diff --git a/app/Livewire/ParkListComponent.php b/app/Livewire/ParkListComponent.php index 169e493..4730cb6 100644 --- a/app/Livewire/ParkListComponent.php +++ b/app/Livewire/ParkListComponent.php @@ -6,7 +6,7 @@ use App\Models\Park; use App\Enums\ParkStatus; use Livewire\Component; use Livewire\WithPagination; -use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Builder; class ParkListComponent extends Component { @@ -17,6 +17,7 @@ class ParkListComponent extends Component public string $sort = 'name'; public string $direction = 'asc'; public ?string $operator = null; + public string $viewMode = 'grid'; /** @var array */ public array $sortOptions = [ @@ -33,6 +34,7 @@ class ParkListComponent extends Component 'sort' => ['except' => 'name'], 'direction' => ['except' => 'asc'], 'operator' => ['except' => ''], + 'viewMode' => ['except' => 'grid'], ]; public function mount(): void @@ -55,6 +57,11 @@ class ParkListComponent extends Component $this->resetPage('parks-page'); } + public function updatedViewMode(): void + { + // No need to reset page when changing view mode + } + public function sortBy(string $field): void { if ($this->sort === $field) { @@ -84,10 +91,12 @@ class ParkListComponent extends Component public function render() { $query = Park::query() - ->with(['operator']) + ->with(['operator', 'location']) ->when($this->search, function (Builder $query) { - $query->where('name', 'like', '%' . $this->search . '%') - ->orWhere('description', 'like', '%' . $this->search . '%'); + $query->where(function (Builder $q) { + $q->where('name', 'like', '%' . $this->search . '%') + ->orWhere('description', 'like', '%' . $this->search . '%'); + }); }) ->when($this->status, function (Builder $query) { $query->where('status', $this->status); @@ -119,6 +128,7 @@ class ParkListComponent extends Component 'parks' => $query->paginate(12, pageName: 'parks-page'), 'statusOptions' => $this->getStatusOptions(), 'operatorOptions' => $this->getOperatorOptions(), + 'viewMode' => $this->viewMode, ]); } } \ No newline at end of file diff --git a/app/Models/Park.php b/app/Models/Park.php index 2466843..e43d5fe 100644 --- a/app/Models/Park.php +++ b/app/Models/Park.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Enums\ParkStatus; +use App\Traits\HasLocation; use App\Traits\HasSlugHistory; use App\Traits\HasParkStatistics; use Illuminate\Database\Eloquent\Model; @@ -12,7 +13,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; class Park extends Model { - use HasFactory, HasSlugHistory, HasParkStatistics; + use HasFactory, HasSlugHistory, HasParkStatistics, HasLocation; /** * The attributes that are mass assignable. diff --git a/database/migrations/2024_02_23_235000_create_locations_table.php b/database/migrations/2024_02_23_235000_create_locations_table.php index 283857e..deb8155 100644 --- a/database/migrations/2024_02_23_235000_create_locations_table.php +++ b/database/migrations/2024_02_23_235000_create_locations_table.php @@ -3,6 +3,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\DB; return new class extends Migration { @@ -11,6 +12,9 @@ return new class extends Migration */ public function up(): void { + // Enable PostGIS extension if not enabled + DB::statement('CREATE EXTENSION IF NOT EXISTS postgis'); + Schema::create('locations', function (Blueprint $table) { $table->id(); @@ -24,9 +28,6 @@ return new class extends Migration $table->string('country'); $table->string('postal_code')->nullable(); - // Enable PostGIS extension if not enabled - DB::statement('CREATE EXTENSION IF NOT EXISTS postgis'); - // Location name and type $table->string('name')->nullable(); $table->string('location_type', 50)->nullable(); @@ -36,7 +37,7 @@ return new class extends Migration $table->decimal('longitude', 9, 6)->nullable(); // Coordinates using PostGIS - $table->point('coordinates')->spatialIndex(); + // We'll add the coordinates column after the table is created $table->decimal('elevation', 8, 2)->nullable(); // Additional details @@ -58,6 +59,10 @@ return new class extends Migration $table->index('name'); $table->index('location_type'); }); + + // Add the coordinates column using PostGIS + DB::statement('ALTER TABLE locations ADD COLUMN coordinates GEOMETRY(Point, 4326)'); + DB::statement('CREATE INDEX locations_coordinates_idx ON locations USING GIST (coordinates)'); } /** diff --git a/database/migrations/2024_02_23_233835_add_position_to_park_areas.php b/database/migrations/2024_02_24_000000_add_position_to_park_areas.php similarity index 100% rename from database/migrations/2024_02_23_233835_add_position_to_park_areas.php rename to database/migrations/2024_02_24_000000_add_position_to_park_areas.php diff --git a/database/migrations/2024_02_23_234035_add_statistics_to_park_areas.php b/database/migrations/2024_02_24_000100_add_statistics_to_park_areas.php similarity index 100% rename from database/migrations/2024_02_23_234035_add_statistics_to_park_areas.php rename to database/migrations/2024_02_24_000100_add_statistics_to_park_areas.php diff --git a/database/migrations/2024_02_23_234235_add_statistics_to_parks_table.php b/database/migrations/2024_02_24_000200_add_statistics_to_parks_table.php similarity index 81% rename from database/migrations/2024_02_23_234235_add_statistics_to_parks_table.php rename to database/migrations/2024_02_24_000200_add_statistics_to_parks_table.php index 5aad704..52bb390 100644 --- a/database/migrations/2024_02_23_234235_add_statistics_to_parks_table.php +++ b/database/migrations/2024_02_24_000200_add_statistics_to_parks_table.php @@ -18,15 +18,14 @@ return new class extends Migration $table->integer('closed_areas')->default(0); // Ride statistics - $table->integer('total_rides')->default(0); - $table->integer('total_coasters')->default(0); + // Note: ride_count and coaster_count already exist in the parks table $table->integer('total_flat_rides')->default(0); $table->integer('total_water_rides')->default(0); // Visitor statistics $table->integer('total_daily_capacity')->default(0); $table->integer('average_wait_time')->nullable(); - $table->decimal('average_rating', 3, 2)->nullable(); + // Note: average_rating already exists in the parks table // Historical data $table->integer('total_rides_operated')->default(0); @@ -40,8 +39,8 @@ return new class extends Migration $table->decimal('guest_satisfaction', 3, 2)->nullable(); // Add indexes for common queries - $table->index(['operator_id', 'total_rides']); - $table->index(['operator_id', 'total_coasters']); + $table->index(['operator_id', 'ride_count']); + $table->index(['operator_id', 'coaster_count']); $table->index(['operator_id', 'average_rating']); }); } @@ -52,21 +51,18 @@ return new class extends Migration public function down(): void { Schema::table('parks', function (Blueprint $table) { - $table->dropIndex(['operator_id', 'total_rides']); - $table->dropIndex(['operator_id', 'total_coasters']); + $table->dropIndex(['operator_id', 'ride_count']); + $table->dropIndex(['operator_id', 'coaster_count']); $table->dropIndex(['operator_id', 'average_rating']); $table->dropColumn([ 'total_areas', 'operating_areas', 'closed_areas', - 'total_rides', - 'total_coasters', 'total_flat_rides', 'total_water_rides', 'total_daily_capacity', 'average_wait_time', - 'average_rating', 'total_rides_operated', 'total_rides_retired', 'last_expansion_date', diff --git a/memory-bank/activeContext.md b/memory-bank/activeContext.md index 8b4fc08..ee4a69c 100644 --- a/memory-bank/activeContext.md +++ b/memory-bank/activeContext.md @@ -31,6 +31,14 @@ Migrating the design from Django to Laravel implementation - Tracked asset organization - Maintained migration progress +5. Parks List Component + - Implemented ParkListComponent matching Django design + - Added grid/list view toggle functionality + - Implemented filtering and sorting controls + - Created responsive card layout for parks + - Added location display to park cards + - Ensured visual parity with Django implementation + ### Current State - Base layout template is ready - Core styling system is in place @@ -41,10 +49,11 @@ Migrating the design from Django to Laravel implementation - Mobile menu - User menu - Auth menu + - Park list with filtering and view modes ### Next Steps 1. Component Migration - - Start with high-priority components (forms, modals, cards) + - Continue with remaining components (forms, modals, cards) - Convert Django partials to Blade components - Implement Livewire interactive components - Test component functionality diff --git a/memory-bank/features/ParksManagement.md b/memory-bank/features/ParksManagement.md index 688995f..99317e5 100644 --- a/memory-bank/features/ParksManagement.md +++ b/memory-bank/features/ParksManagement.md @@ -59,12 +59,20 @@ Features: - Size 3. Display Features - - Responsive grid layout + - Responsive grid/list layout with toggle - Status badges with colors - Key statistics display - Quick access to edit/view - Website links - Operator information + - Location information display + +4. Django Parity Implementation + - Matches the original Django implementation's UI/UX + - Uses the same filter controls and layout + - Implements identical view mode toggle (grid/list) + - Displays the same park information cards + - Maintains consistent styling with the original ### 3. ParkAreaFormComponent Located in `app/Livewire/ParkAreaFormComponent.php` diff --git a/package-lock.json b/package-lock.json index 8e3a4ed..e20105b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "laravel", + "name": "thrillwiki_laravel", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/resources/views/components/layouts/app.blade.php b/resources/views/components/layouts/app.blade.php new file mode 100644 index 0000000..fcd62f0 --- /dev/null +++ b/resources/views/components/layouts/app.blade.php @@ -0,0 +1,64 @@ + + + + + + {{ $title ?? 'ThrillWiki' }} + @vite(['resources/css/app.css', 'resources/js/app.js']) + @livewireStyles + + +
+
+
+ +
+ @livewire('theme-toggle-component') + @auth + @livewire('user-menu-component') + @else + @livewire('auth-menu-component') + @endauth + @livewire('mobile-menu-component') +
+
+
+
+ +
+ {{ $slot }} +
+ + + + @livewireScripts + + \ No newline at end of file diff --git a/resources/views/livewire/park-list-component.blade.php b/resources/views/livewire/park-list-component.blade.php index 2f82fdc..373afdb 100644 --- a/resources/views/livewire/park-list-component.blade.php +++ b/resources/views/livewire/park-list-component.blade.php @@ -1,136 +1,186 @@ -
- -
-
- -
- -
- -
-
- - -
- -
- -
-
- - -
- -
- -
-
- - -
- -
- -
+
+
+
+

Parks

+ +
+ +
-
- -
- @forelse($parks as $park) -
-
-
-

- - {{ $park->name }} - -

- - {{ $park->status->label() }} - -
- -
- {{ $park->brief_description }} -
- -
-
- Operator: - {{ $park->operator?->name ?? 'Unknown' }} -
- @if($park->opening_year) -
- Opened: - {{ $park->opening_year }} -
- @endif - @if($park->size_acres) -
- Size: - {{ $park->size_display }} -
- @endif -
- Rides: - {{ $park->ride_count ?? 0 }} -
-
- -
- @if($park->website) - - Visit Website - - @endif - - Edit - -
-
-
- @empty -
-

No parks found

-

Try adjusting your filters or search terms.

-
- @endforelse -
- - -
- {{ $parks->links() }} -
- - - + + +
+
+ + +
+
+ +
+
+
+ +
+
+

Filters

+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+ + +
+
+ @forelse($parks as $park) +
+ + + +
+ +
+ +
+

+ {{ $park->name }} +

+ +
+ @if($park->location) + {{ $park->location->city }}{{ $park->location->state ? ', ' . $park->location->state : '' }}{{ $park->location->country ? ', ' . $park->location->country : '' }} + @else + Location unknown + @endif +
+ +
+ + {{ $park->status->label() }} + + + @if($park->opening_date) + + Opened {{ date('Y', strtotime($park->opening_date)) }} + + @endif + + @if($park->ride_count) + + {{ $park->ride_count }} ride{{ $park->ride_count != 1 ? 's' : '' }} + + @endif + + @if($park->coaster_count) + + {{ $park->coaster_count }} coaster{{ $park->coaster_count != 1 ? 's' : '' }} + + @endif +
+
+
+ @empty +
+ @if($search) + No parks found matching "{{ $search }}". Try adjusting your search terms. + @else + No parks found matching your criteria. Try adjusting your filters. + @endif + Add a new park. +
+ @endforelse +
+
+ + +
+ {{ $parks->links() }} +
\ No newline at end of file diff --git a/routes/web.php b/routes/web.php index c16a804..0f29bbe 100644 --- a/routes/web.php +++ b/routes/web.php @@ -10,9 +10,16 @@ Route::get('/', function () { Route::get('/counter', Counter::class); // Parks routes -Route::get('/parks', function () { - return 'Parks Index'; -})->name('parks.index'); +Route::get('/parks', \App\Livewire\ParkListComponent::class)->name('parks.index'); +Route::get('/parks/create', function () { + return 'Create Park'; +})->name('parks.create'); +Route::get('/parks/{park}', function () { + return 'Show Park'; +})->name('parks.show'); +Route::get('/parks/{park}/edit', function () { + return 'Edit Park'; +})->name('parks.edit'); // Rides routes Route::get('/rides', function () {