feat: Implement rides management with CRUD functionality

- Added rides index view with search and filter options.
- Created rides show view to display ride details.
- Implemented API routes for rides.
- Developed authentication routes for user registration, login, and email verification.
- Created tests for authentication, email verification, password reset, and user profile management.
- Added feature tests for rides and operators, including creation, updating, deletion, and searching.
- Implemented soft deletes and caching for rides and operators.
- Enhanced manufacturer and operator model tests for various functionalities.
This commit is contained in:
pacnpal
2025-06-19 22:34:10 -04:00
parent 86263db9d9
commit cc33781245
148 changed files with 14026 additions and 2482 deletions

View File

@@ -1,114 +1,3 @@
@import 'alerts.css';
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Custom base styles */
@layer base {
html {
scroll-behavior: smooth;
}
body {
@apply font-sans text-gray-900 bg-white dark:text-gray-100 dark:bg-gray-900 transition-colors duration-200;
}
h1, h2, h3, h4, h5, h6 {
@apply font-semibold text-gray-900 dark:text-white;
}
}
/* Custom components */
@layer components {
/* Navigation */
.nav-link {
@apply flex items-center gap-2 px-3 py-2 rounded-lg transition-all duration-200
text-gray-600 hover:text-primary-600 hover:bg-gray-100
dark:text-gray-300 dark:hover:text-primary-400 dark:hover:bg-gray-800;
}
.nav-link.active {
@apply text-primary-600 bg-primary-50 dark:text-primary-400 dark:bg-gray-800;
}
.site-logo {
@apply text-2xl font-bold text-primary-600 dark:text-primary-400;
}
/* Menu Items */
.menu-item {
@apply flex items-center gap-3 px-4 py-2 rounded-lg transition-all duration-200
text-gray-600 hover:text-primary-600 hover:bg-gray-100
dark:text-gray-300 dark:hover:text-primary-400 dark:hover:bg-gray-800;
}
/* Forms */
.form-input {
@apply w-full px-4 py-2 rounded-lg transition-all duration-200
text-gray-900 bg-white border border-gray-200
focus:border-primary-500 focus:ring-2 focus:ring-primary-500/20
dark:text-gray-100 dark:bg-gray-800 dark:border-gray-700
dark:focus:border-primary-400 dark:focus:ring-primary-400/20
disabled:opacity-50 disabled:cursor-not-allowed;
}
.form-label {
@apply block mb-2 text-sm font-medium text-gray-700 dark:text-gray-300;
}
/* Buttons */
.btn {
@apply inline-flex items-center justify-center px-4 py-2 rounded-lg font-semibold
transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed
focus:outline-none focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900;
}
.btn-primary {
@apply btn bg-gradient-to-r from-primary-600 to-primary-500 text-white
hover:from-primary-700 hover:to-primary-600
focus:ring-primary-500/50
dark:from-primary-500 dark:to-primary-400
dark:hover:from-primary-600 dark:hover:to-primary-500;
}
.btn-secondary {
@apply btn bg-white text-gray-700 border border-gray-200
hover:bg-gray-50 hover:text-gray-900
focus:ring-gray-500/50
dark:bg-gray-800 dark:text-gray-300 dark:border-gray-700
dark:hover:bg-gray-700 dark:hover:text-gray-100;
}
/* Cards */
.card {
@apply bg-white border border-gray-200 rounded-lg shadow-sm
dark:bg-gray-800 dark:border-gray-700;
}
.card-header {
@apply px-6 py-4 border-b border-gray-200 dark:border-gray-700;
}
.card-body {
@apply p-6;
}
.card-footer {
@apply px-6 py-4 border-t border-gray-200 dark:border-gray-700;
}
}
/* Custom utilities */
@layer utilities {
.text-gradient {
@apply text-transparent bg-clip-text bg-gradient-to-r
from-primary-600 to-secondary-500
dark:from-primary-400 dark:to-secondary-400;
}
.bg-gradient {
@apply bg-gradient-to-r from-primary-600 to-secondary-500
dark:from-primary-500 dark:to-secondary-400;
}
}

View File

@@ -0,0 +1,10 @@
@props(['on'])
<div x-data="{ shown: false, timeout: null }"
x-init="@this.on('{{ $on }}', () => { clearTimeout(timeout); shown = true; timeout = setTimeout(() => { shown = false }, 2000); })"
x-show.transition.out.opacity.duration.1500ms="shown"
x-transition:leave.opacity.duration.1500ms
style="display: none;"
{{ $attributes->merge(['class' => 'text-sm text-gray-600']) }}>
{{ $slot->isEmpty() ? __('Saved.') : $slot }}
</div>

View File

@@ -0,0 +1,3 @@
<svg viewBox="0 0 316 316" xmlns="http://www.w3.org/2000/svg" {{ $attributes }}>
<path d="M305.8 81.125C305.77 80.995 305.69 80.885 305.65 80.755C305.56 80.525 305.49 80.285 305.37 80.075C305.29 79.935 305.17 79.815 305.07 79.685C304.94 79.515 304.83 79.325 304.68 79.175C304.55 79.045 304.39 78.955 304.25 78.845C304.09 78.715 303.95 78.575 303.77 78.475L251.32 48.275C249.97 47.495 248.31 47.495 246.96 48.275L194.51 78.475C194.33 78.575 194.19 78.725 194.03 78.845C193.89 78.955 193.73 79.045 193.6 79.175C193.45 79.325 193.34 79.515 193.21 79.685C193.11 79.815 192.99 79.935 192.91 80.075C192.79 80.285 192.71 80.525 192.63 80.755C192.58 80.875 192.51 80.995 192.48 81.125C192.38 81.495 192.33 81.875 192.33 82.265V139.625L148.62 164.795V52.575C148.62 52.185 148.57 51.805 148.47 51.435C148.44 51.305 148.36 51.195 148.32 51.065C148.23 50.835 148.16 50.595 148.04 50.385C147.96 50.245 147.84 50.125 147.74 49.995C147.61 49.825 147.5 49.635 147.35 49.485C147.22 49.355 147.06 49.265 146.92 49.155C146.76 49.025 146.62 48.885 146.44 48.785L93.99 18.585C92.64 17.805 90.98 17.805 89.63 18.585L37.18 48.785C37 48.885 36.86 49.035 36.7 49.155C36.56 49.265 36.4 49.355 36.27 49.485C36.12 49.635 36.01 49.825 35.88 49.995C35.78 50.125 35.66 50.245 35.58 50.385C35.46 50.595 35.38 50.835 35.3 51.065C35.25 51.185 35.18 51.305 35.15 51.435C35.05 51.805 35 52.185 35 52.575V232.235C35 233.795 35.84 235.245 37.19 236.025L142.1 296.425C142.33 296.555 142.58 296.635 142.82 296.725C142.93 296.765 143.04 296.835 143.16 296.865C143.53 296.965 143.9 297.015 144.28 297.015C144.66 297.015 145.03 296.965 145.4 296.865C145.5 296.835 145.59 296.775 145.69 296.745C145.95 296.655 146.21 296.565 146.45 296.435L251.36 236.035C252.72 235.255 253.55 233.815 253.55 232.245V174.885L303.81 145.945C305.17 145.165 306 143.725 306 142.155V82.265C305.95 81.875 305.89 81.495 305.8 81.125ZM144.2 227.205L100.57 202.515L146.39 176.135L196.66 147.195L240.33 172.335L208.29 190.625L144.2 227.205ZM244.75 114.995V164.795L226.39 154.225L201.03 139.625V89.825L219.39 100.395L244.75 114.995ZM249.12 57.105L292.81 82.265L249.12 107.425L205.43 82.265L249.12 57.105ZM114.49 184.425L96.13 194.995V85.305L121.49 70.705L139.85 60.135V169.815L114.49 184.425ZM91.76 27.425L135.45 52.585L91.76 77.745L48.07 52.585L91.76 27.425ZM43.67 60.135L62.03 70.705L87.39 85.305V202.545V202.555V202.565C87.39 202.735 87.44 202.895 87.46 203.055C87.49 203.265 87.49 203.485 87.55 203.695V203.705C87.6 203.875 87.69 204.035 87.76 204.195C87.84 204.375 87.89 204.575 87.99 204.745C87.99 204.745 87.99 204.755 88 204.755C88.09 204.905 88.22 205.035 88.33 205.175C88.45 205.335 88.55 205.495 88.69 205.635L88.7 205.645C88.82 205.765 88.98 205.855 89.12 205.965C89.28 206.085 89.42 206.225 89.59 206.325C89.6 206.325 89.6 206.325 89.61 206.335C89.62 206.335 89.62 206.345 89.63 206.345L139.87 234.775V285.065L43.67 229.705V60.135ZM244.75 229.705L148.58 285.075V234.775L219.8 194.115L244.75 179.875V229.705ZM297.2 139.625L253.49 164.795V114.995L278.85 100.395L297.21 89.825V139.625H297.2Z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1,7 @@
@props(['status'])
@if ($status)
<div {{ $attributes->merge(['class' => 'font-medium text-sm text-green-600']) }}>
{{ $status }}
</div>
@endif

View File

@@ -0,0 +1,3 @@
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 transition ease-in-out duration-150']) }}>
{{ $slot }}
</button>

View File

@@ -0,0 +1 @@
<a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out']) }}>{{ $slot }}</a>

View File

@@ -0,0 +1,35 @@
@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white'])
@php
$alignmentClasses = match ($align) {
'left' => 'ltr:origin-top-left rtl:origin-top-right start-0',
'top' => 'origin-top',
default => 'ltr:origin-top-right rtl:origin-top-left end-0',
};
$width = match ($width) {
'48' => 'w-48',
default => $width,
};
@endphp
<div class="relative" x-data="{ open: false }" @click.outside="open = false" @close.stop="open = false">
<div @click="open = ! open">
{{ $trigger }}
</div>
<div x-show="open"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="absolute z-50 mt-2 {{ $width }} rounded-md shadow-lg {{ $alignmentClasses }}"
style="display: none;"
@click="open = false">
<div class="rounded-md ring-1 ring-black ring-opacity-5 {{ $contentClasses }}">
{{ $content }}
</div>
</div>
</div>

View File

@@ -0,0 +1,9 @@
@props(['messages'])
@if ($messages)
<ul {{ $attributes->merge(['class' => 'text-sm text-red-600 space-y-1']) }}>
@foreach ((array) $messages as $message)
<li>{{ $message }}</li>
@endforeach
</ul>
@endif

View File

@@ -0,0 +1,5 @@
@props(['value'])
<label {{ $attributes->merge(['class' => 'block font-medium text-sm text-gray-700']) }}>
{{ $value ?? $slot }}
</label>

View File

@@ -58,9 +58,9 @@
@stack('styles')
</head>
<body class="flex flex-col min-h-screen text-gray-900 bg-gradient-to-br from-white via-blue-50 to-indigo-50 dark:from-gray-950 dark:via-indigo-950 dark:to-purple-950 dark:text-white">
<body class="flex flex-col min-h-screen text-gray-900 bg-gradient-to-br from-white via-blue-50 to-indigo-50">
<!-- Header -->
<header class="sticky top-0 z-40 border-b shadow-lg bg-white/90 dark:bg-gray-800/90 backdrop-blur-lg border-gray-200/50 dark:border-gray-700/50">
<header class="sticky top-0 z-40 border-b shadow-lg bg-white/90 backdrop-blur-lg border-gray-200/50">
<nav class="container mx-auto nav-container">
<div class="flex items-center justify-between">
<!-- Logo -->
@@ -132,15 +132,15 @@
</main>
<!-- Footer -->
<footer class="mt-auto border-t bg-white/90 dark:bg-gray-800/90 backdrop-blur-lg border-gray-200/50 dark:border-gray-700/50">
<footer class="mt-auto border-t bg-white/90 backdrop-blur-lg border-gray-200/50">
<div class="container px-6 py-6 mx-auto">
<div class="flex items-center justify-between">
<div class="text-gray-600 dark:text-gray-400">
<div class="text-gray-600">
<p>&copy; {{ date('Y') }} ThrillWiki. All rights reserved.</p>
</div>
<div class="space-x-4">
<a href="{{ route('terms') }}" class="text-gray-600 transition-colors hover:text-primary dark:text-gray-400 dark:hover:text-primary">Terms</a>
<a href="{{ route('privacy') }}" class="text-gray-600 transition-colors hover:text-primary dark:text-gray-400 dark:hover:text-primary">Privacy</a>
<a href="{{ route('terms') }}" class="text-gray-600 transition-colors hover:text-primary">Terms</a>
<a href="{{ route('privacy') }}" class="text-gray-600 transition-colors hover:text-primary">Privacy</a>
</div>
</div>
</div>

View File

@@ -0,0 +1,78 @@
@props([
'name',
'show' => false,
'maxWidth' => '2xl'
])
@php
$maxWidth = [
'sm' => 'sm:max-w-sm',
'md' => 'sm:max-w-md',
'lg' => 'sm:max-w-lg',
'xl' => 'sm:max-w-xl',
'2xl' => 'sm:max-w-2xl',
][$maxWidth];
@endphp
<div
x-data="{
show: @js($show),
focusables() {
// All focusable element types...
let selector = 'a, button, input:not([type=\'hidden\']), textarea, select, details, [tabindex]:not([tabindex=\'-1\'])'
return [...$el.querySelectorAll(selector)]
// All non-disabled elements...
.filter(el => ! el.hasAttribute('disabled'))
},
firstFocusable() { return this.focusables()[0] },
lastFocusable() { return this.focusables().slice(-1)[0] },
nextFocusable() { return this.focusables()[this.nextFocusableIndex()] || this.firstFocusable() },
prevFocusable() { return this.focusables()[this.prevFocusableIndex()] || this.lastFocusable() },
nextFocusableIndex() { return (this.focusables().indexOf(document.activeElement) + 1) % (this.focusables().length + 1) },
prevFocusableIndex() { return Math.max(0, this.focusables().indexOf(document.activeElement)) -1 },
}"
x-init="$watch('show', value => {
if (value) {
document.body.classList.add('overflow-y-hidden');
{{ $attributes->has('focusable') ? 'setTimeout(() => firstFocusable().focus(), 100)' : '' }}
} else {
document.body.classList.remove('overflow-y-hidden');
}
})"
x-on:open-modal.window="$event.detail == '{{ $name }}' ? show = true : null"
x-on:close-modal.window="$event.detail == '{{ $name }}' ? show = false : null"
x-on:close.stop="show = false"
x-on:keydown.escape.window="show = false"
x-on:keydown.tab.prevent="$event.shiftKey || nextFocusable().focus()"
x-on:keydown.shift.tab.prevent="prevFocusable().focus()"
x-show="show"
class="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50"
style="display: {{ $show ? 'block' : 'none' }};"
>
<div
x-show="show"
class="fixed inset-0 transform transition-all"
x-on:click="show = false"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
>
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<div
x-show="show"
class="mb-6 bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full {{ $maxWidth }} sm:mx-auto"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
{{ $slot }}
</div>
</div>

View File

@@ -0,0 +1,11 @@
@props(['active'])
@php
$classes = ($active ?? false)
? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out'
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out';
@endphp
<a {{ $attributes->merge(['class' => $classes]) }}>
{{ $slot }}
</a>

View File

@@ -0,0 +1,3 @@
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150']) }}>
{{ $slot }}
</button>

View File

@@ -0,0 +1,11 @@
@props(['active'])
@php
$classes = ($active ?? false)
? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 text-start text-base font-medium text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out'
: 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out';
@endphp
<a {{ $attributes->merge(['class' => $classes]) }}>
{{ $slot }}
</a>

View File

@@ -0,0 +1,3 @@
<button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center px-4 py-2 bg-white border border-gray-300 rounded-md font-semibold text-xs text-gray-700 uppercase tracking-widest shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25 transition ease-in-out duration-150']) }}>
{{ $slot }}
</button>

View File

@@ -0,0 +1,3 @@
@props(['disabled' => false])
<input @disabled($disabled) {{ $attributes->merge(['class' => 'border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm']) }}>

View File

@@ -0,0 +1,17 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Dashboard') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
{{ __("You're logged in!") }}
</div>
</div>
</div>
</div>
</x-app-layout>

View File

@@ -1,44 +1,36 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'ThrillWiki') }}</title>
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
<!-- Styles -->
@livewireStyles
</head>
<body class="font-sans antialiased bg-gray-100">
<div class="min-h-screen">
<nav class="bg-white border-b border-gray-100">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<div class="flex-shrink-0 flex items-center">
<a href="{{ route('home') }}" class="text-2xl font-bold text-gray-800">
ThrillWiki
</a>
</div>
<!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="font-sans antialiased">
<div class="min-h-screen bg-gray-100">
<livewire:layout.navigation />
<!-- Page Heading -->
@if (isset($header))
<header class="bg-white shadow">
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
{{ $header }}
</div>
</header>
@endif
<div class="flex items-center">
@livewire('auth-menu-component')
</div>
</div>
</div>
</nav>
<!-- Page Content -->
<main>
@yield('content')
</main>
</div>
@livewireScripts
</body>
<!-- Page Content -->
<main>
{{ $slot }}
</main>
</div>
</body>
</html>

View File

@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
<!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="font-sans text-gray-900 antialiased">
<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100">
<div>
<a href="/" wire:navigate>
<x-application-logo class="w-20 h-20 fill-current text-gray-500" />
</a>
</div>
<div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg">
{{ $slot }}
</div>
</div>
</body>
</html>

View File

@@ -72,21 +72,21 @@
@focus="open = true"
@keydown="onKeyDown($event)"
placeholder="Search..."
class="w-full px-4 py-2 border rounded-lg shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-800 dark:border-gray-700 dark:text-white"
class="w-full px-4 py-2 border rounded-lg shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<div
x-show="open"
x-ref="results"
class="absolute z-50 w-full mt-1 bg-white rounded-md shadow-lg dark:bg-gray-800"
class="absolute z-50 w-full mt-1 bg-white rounded-md shadow-lg"
x-cloak
>
@if(count($suggestions) > 0)
@foreach($suggestions as $suggestion)
<a
href="{{ $suggestion['url'] }}"
class="block px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-gray-200"
:class="{ 'bg-gray-100 dark:bg-gray-700': selectedIndex === {{ $loop->index }} }"
class="block px-4 py-2 text-sm hover:bg-gray-100"
:class="{ 'bg-gray-100': selectedIndex === {{ $loop->index }} }"
data-url="{{ $suggestion['url'] }}"
wire:key="{{ $suggestion['id'] }}"
>
@@ -95,7 +95,7 @@
@endforeach
@else
@if(strlen($query) >= 2)
<div class="px-4 py-2 text-sm text-gray-500 dark:text-gray-400">
<div class="px-4 py-2 text-sm text-gray-500">
No results found
</div>
@endif

View File

@@ -1,5 +1,5 @@
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 mb-6">
<h3 class="text-lg font-semibold mb-4 text-gray-900 dark:text-white">Featured Photo</h3>
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
<h3 class="text-lg font-semibold mb-4 text-gray-900">Featured Photo</h3>
@if ($isLoading)
<div class="flex justify-center items-center py-12">
@@ -9,11 +9,11 @@
</svg>
</div>
@elseif ($error)
<div class="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded relative dark:bg-red-900 dark:border-red-800 dark:text-red-200" role="alert">
<div class="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded relative" role="alert">
<span class="block sm:inline">{{ $error }}</span>
</div>
@elseif (count($photos) === 0)
<div class="text-center py-8 text-gray-500 dark:text-gray-400">
<div class="text-center py-8 text-gray-500">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 mx-auto mb-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
@@ -22,7 +22,7 @@
</div>
@else
@if ($success)
<div class="bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded relative mb-4 dark:bg-green-900 dark:border-green-800 dark:text-green-200" role="alert">
<div class="bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded relative mb-4" role="alert">
<span class="block sm:inline">Featured photo updated successfully!</span>
</div>
@endif
@@ -31,7 +31,7 @@
@foreach ($photos as $photo)
<div
wire:key="featured-photo-{{ $photo->id }}"
class="relative aspect-square overflow-hidden rounded-lg bg-gray-100 dark:bg-gray-700 {{ $featuredPhotoId === $photo->id ? 'ring-2 ring-yellow-500 ring-offset-2 dark:ring-offset-gray-800' : '' }}"
class="relative aspect-square overflow-hidden rounded-lg bg-gray-100 {{ $featuredPhotoId === $photo->id ? 'ring-2 ring-yellow-500 ring-offset-2' : '' }}"
>
<img
src="{{ $photo->url }}"

View File

@@ -0,0 +1,110 @@
<?php
use App\Livewire\Actions\Logout;
use Livewire\Volt\Component;
new class extends Component
{
/**
* Log the current user out of the application.
*/
public function logout(Logout $logout): void
{
$logout();
$this->redirect('/', navigate: true);
}
}; ?>
<nav x-data="{ open: false }" class="bg-white border-b border-gray-100">
<!-- Primary Navigation Menu -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<!-- Logo -->
<div class="shrink-0 flex items-center">
<a href="{{ route('dashboard') }}" wire:navigate>
<x-application-logo class="block h-9 w-auto fill-current text-gray-800" />
</a>
</div>
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')" wire:navigate>
{{ __('Dashboard') }}
</x-nav-link>
</div>
</div>
<!-- Settings Dropdown -->
<div class="hidden sm:flex sm:items-center sm:ms-6">
<x-dropdown align="right" width="48">
<x-slot name="trigger">
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
<div x-data="{{ json_encode(['name' => auth()->user()->name]) }}" x-text="name" x-on:profile-updated.window="name = $event.detail.name"></div>
<div class="ms-1">
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</div>
</button>
</x-slot>
<x-slot name="content">
<x-dropdown-link :href="route('profile')" wire:navigate>
{{ __('Profile') }}
</x-dropdown-link>
<!-- Authentication -->
<button wire:click="logout" class="w-full text-start">
<x-dropdown-link>
{{ __('Log Out') }}
</x-dropdown-link>
</button>
</x-slot>
</x-dropdown>
</div>
<!-- Hamburger -->
<div class="-me-2 flex items-center sm:hidden">
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out">
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
<path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
</div>
<!-- Responsive Navigation Menu -->
<div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
<div class="pt-2 pb-3 space-y-1">
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')" wire:navigate>
{{ __('Dashboard') }}
</x-responsive-nav-link>
</div>
<!-- Responsive Settings Options -->
<div class="pt-4 pb-1 border-t border-gray-200">
<div class="px-4">
<div class="font-medium text-base text-gray-800" x-data="{{ json_encode(['name' => auth()->user()->name]) }}" x-text="name" x-on:profile-updated.window="name = $event.detail.name"></div>
<div class="font-medium text-sm text-gray-500">{{ auth()->user()->email }}</div>
</div>
<div class="mt-3 space-y-1">
<x-responsive-nav-link :href="route('profile')" wire:navigate>
{{ __('Profile') }}
</x-responsive-nav-link>
<!-- Authentication -->
<button wire:click="logout" class="w-full text-start">
<x-responsive-nav-link>
{{ __('Log Out') }}
</x-responsive-nav-link>
</button>
</div>
</div>
</div>
</nav>

View File

@@ -56,7 +56,7 @@
<div class="location-display-component">
<div wire:ignore class="relative mb-4" style="z-index: 1;">
<div id="locationMap" class="h-[400px] w-full rounded-lg border border-gray-300 dark:border-gray-600"></div>
<div id="locationMap" class="h-[400px] w-full rounded-lg border border-gray-300"></div>
@if($showInfoWindow && $activeMarker)
<div class="location-info-window absolute top-4 right-4 z-10">

View File

@@ -0,0 +1,62 @@
<?php
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
use Livewire\Attributes\Layout;
use Livewire\Volt\Component;
new #[Layout('layouts.guest')] class extends Component
{
public string $password = '';
/**
* Confirm the current user's password.
*/
public function confirmPassword(): void
{
$this->validate([
'password' => ['required', 'string'],
]);
if (! Auth::guard('web')->validate([
'email' => Auth::user()->email,
'password' => $this->password,
])) {
throw ValidationException::withMessages([
'password' => __('auth.password'),
]);
}
session(['auth.password_confirmed_at' => time()]);
$this->redirectIntended(default: route('dashboard', absolute: false), navigate: true);
}
}; ?>
<div>
<div class="mb-4 text-sm text-gray-600">
{{ __('This is a secure area of the application. Please confirm your password before continuing.') }}
</div>
<form wire:submit="confirmPassword">
<!-- Password -->
<div>
<x-input-label for="password" :value="__('Password')" />
<x-text-input wire:model="password"
id="password"
class="block mt-1 w-full"
type="password"
name="password"
required autocomplete="current-password" />
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
<div class="flex justify-end mt-4">
<x-primary-button>
{{ __('Confirm') }}
</x-primary-button>
</div>
</form>
</div>

View File

@@ -0,0 +1,61 @@
<?php
use Illuminate\Support\Facades\Password;
use Livewire\Attributes\Layout;
use Livewire\Volt\Component;
new #[Layout('layouts.guest')] class extends Component
{
public string $email = '';
/**
* Send a password reset link to the provided email address.
*/
public function sendPasswordResetLink(): void
{
$this->validate([
'email' => ['required', 'string', 'email'],
]);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$status = Password::sendResetLink(
$this->only('email')
);
if ($status != Password::RESET_LINK_SENT) {
$this->addError('email', __($status));
return;
}
$this->reset('email');
session()->flash('status', __($status));
}
}; ?>
<div>
<div class="mb-4 text-sm text-gray-600">
{{ __('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.') }}
</div>
<!-- Session Status -->
<x-auth-session-status class="mb-4" :status="session('status')" />
<form wire:submit="sendPasswordResetLink">
<!-- Email Address -->
<div>
<x-input-label for="email" :value="__('Email')" />
<x-text-input wire:model="email" id="email" class="block mt-1 w-full" type="email" name="email" required autofocus />
<x-input-error :messages="$errors->get('email')" class="mt-2" />
</div>
<div class="flex items-center justify-end mt-4">
<x-primary-button>
{{ __('Email Password Reset Link') }}
</x-primary-button>
</div>
</form>
</div>

View File

@@ -0,0 +1,71 @@
<?php
use App\Livewire\Forms\LoginForm;
use Illuminate\Support\Facades\Session;
use Livewire\Attributes\Layout;
use Livewire\Volt\Component;
new #[Layout('layouts.guest')] class extends Component
{
public LoginForm $form;
/**
* Handle an incoming authentication request.
*/
public function login(): void
{
$this->validate();
$this->form->authenticate();
Session::regenerate();
$this->redirectIntended(default: route('dashboard', absolute: false), navigate: true);
}
}; ?>
<div>
<!-- Session Status -->
<x-auth-session-status class="mb-4" :status="session('status')" />
<form wire:submit="login">
<!-- Email Address -->
<div>
<x-input-label for="email" :value="__('Email')" />
<x-text-input wire:model="form.email" id="email" class="block mt-1 w-full" type="email" name="email" required autofocus autocomplete="username" />
<x-input-error :messages="$errors->get('form.email')" class="mt-2" />
</div>
<!-- Password -->
<div class="mt-4">
<x-input-label for="password" :value="__('Password')" />
<x-text-input wire:model="form.password" id="password" class="block mt-1 w-full"
type="password"
name="password"
required autocomplete="current-password" />
<x-input-error :messages="$errors->get('form.password')" class="mt-2" />
</div>
<!-- Remember Me -->
<div class="block mt-4">
<label for="remember" class="inline-flex items-center">
<input wire:model="form.remember" id="remember" type="checkbox" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500" name="remember">
<span class="ms-2 text-sm text-gray-600">{{ __('Remember me') }}</span>
</label>
</div>
<div class="flex items-center justify-end mt-4">
@if (Route::has('password.request'))
<a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('password.request') }}" wire:navigate>
{{ __('Forgot your password?') }}
</a>
@endif
<x-primary-button class="ms-3">
{{ __('Log in') }}
</x-primary-button>
</div>
</form>
</div>

View File

@@ -0,0 +1,88 @@
<?php
use App\Models\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules;
use Livewire\Attributes\Layout;
use Livewire\Volt\Component;
new #[Layout('layouts.guest')] class extends Component
{
public string $name = '';
public string $email = '';
public string $password = '';
public string $password_confirmation = '';
/**
* Handle an incoming registration request.
*/
public function register(): void
{
$validated = $this->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
'password' => ['required', 'string', 'confirmed', Rules\Password::defaults()],
]);
$validated['password'] = Hash::make($validated['password']);
event(new Registered($user = User::create($validated)));
Auth::login($user);
$this->redirect(route('dashboard', absolute: false), navigate: true);
}
}; ?>
<div>
<form wire:submit="register">
<!-- Name -->
<div>
<x-input-label for="name" :value="__('Name')" />
<x-text-input wire:model="name" id="name" class="block mt-1 w-full" type="text" name="name" required autofocus autocomplete="name" />
<x-input-error :messages="$errors->get('name')" class="mt-2" />
</div>
<!-- Email Address -->
<div class="mt-4">
<x-input-label for="email" :value="__('Email')" />
<x-text-input wire:model="email" id="email" class="block mt-1 w-full" type="email" name="email" required autocomplete="username" />
<x-input-error :messages="$errors->get('email')" class="mt-2" />
</div>
<!-- Password -->
<div class="mt-4">
<x-input-label for="password" :value="__('Password')" />
<x-text-input wire:model="password" id="password" class="block mt-1 w-full"
type="password"
name="password"
required autocomplete="new-password" />
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
<!-- Confirm Password -->
<div class="mt-4">
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
<x-text-input wire:model="password_confirmation" id="password_confirmation" class="block mt-1 w-full"
type="password"
name="password_confirmation" required autocomplete="new-password" />
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
</div>
<div class="flex items-center justify-end mt-4">
<a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('login') }}" wire:navigate>
{{ __('Already registered?') }}
</a>
<x-primary-button class="ms-4">
{{ __('Register') }}
</x-primary-button>
</div>
</form>
</div>

View File

@@ -0,0 +1,105 @@
<?php
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;
use Illuminate\Validation\Rules;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Locked;
use Livewire\Volt\Component;
new #[Layout('layouts.guest')] class extends Component
{
#[Locked]
public string $token = '';
public string $email = '';
public string $password = '';
public string $password_confirmation = '';
/**
* Mount the component.
*/
public function mount(string $token): void
{
$this->token = $token;
$this->email = request()->string('email');
}
/**
* Reset the password for the given user.
*/
public function resetPassword(): void
{
$this->validate([
'token' => ['required'],
'email' => ['required', 'string', 'email'],
'password' => ['required', 'string', 'confirmed', Rules\Password::defaults()],
]);
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$status = Password::reset(
$this->only('email', 'password', 'password_confirmation', 'token'),
function ($user) {
$user->forceFill([
'password' => Hash::make($this->password),
'remember_token' => Str::random(60),
])->save();
event(new PasswordReset($user));
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
if ($status != Password::PASSWORD_RESET) {
$this->addError('email', __($status));
return;
}
Session::flash('status', __($status));
$this->redirectRoute('login', navigate: true);
}
}; ?>
<div>
<form wire:submit="resetPassword">
<!-- Email Address -->
<div>
<x-input-label for="email" :value="__('Email')" />
<x-text-input wire:model="email" id="email" class="block mt-1 w-full" type="email" name="email" required autofocus autocomplete="username" />
<x-input-error :messages="$errors->get('email')" class="mt-2" />
</div>
<!-- Password -->
<div class="mt-4">
<x-input-label for="password" :value="__('Password')" />
<x-text-input wire:model="password" id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="new-password" />
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
<!-- Confirm Password -->
<div class="mt-4">
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
<x-text-input wire:model="password_confirmation" id="password_confirmation" class="block mt-1 w-full"
type="password"
name="password_confirmation" required autocomplete="new-password" />
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
</div>
<div class="flex items-center justify-end mt-4">
<x-primary-button>
{{ __('Reset Password') }}
</x-primary-button>
</div>
</form>
</div>

View File

@@ -0,0 +1,58 @@
<?php
use App\Livewire\Actions\Logout;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Livewire\Attributes\Layout;
use Livewire\Volt\Component;
new #[Layout('layouts.guest')] class extends Component
{
/**
* Send an email verification notification to the user.
*/
public function sendVerification(): void
{
if (Auth::user()->hasVerifiedEmail()) {
$this->redirectIntended(default: route('dashboard', absolute: false), navigate: true);
return;
}
Auth::user()->sendEmailVerificationNotification();
Session::flash('status', 'verification-link-sent');
}
/**
* Log the current user out of the application.
*/
public function logout(Logout $logout): void
{
$logout();
$this->redirect('/', navigate: true);
}
}; ?>
<div>
<div class="mb-4 text-sm text-gray-600">
{{ __('Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just emailed to you? If you didn\'t receive the email, we will gladly send you another.') }}
</div>
@if (session('status') == 'verification-link-sent')
<div class="mb-4 font-medium text-sm text-green-600">
{{ __('A new verification link has been sent to the email address you provided during registration.') }}
</div>
@endif
<div class="mt-4 flex items-center justify-between">
<x-primary-button wire:click="sendVerification">
{{ __('Resend Verification Email') }}
</x-primary-button>
<button wire:click="logout" type="submit" class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
{{ __('Log Out') }}
</button>
</div>
</div>

View File

@@ -2,7 +2,7 @@
<div class="space-y-6 sm:space-y-5">
<div class="sm:grid sm:grid-cols-2 sm:gap-4">
<div>
<label for="height_ft" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="height_ft" class="block text-sm font-medium text-gray-700">
Height (feet)
</label>
<div class="mt-1">
@@ -10,12 +10,12 @@
step="0.01"
id="height_ft"
wire:model="coasterStats.height_ft"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('coasterStats.height_ft') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
<div>
<label for="length_ft" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="length_ft" class="block text-sm font-medium text-gray-700">
Length (feet)
</label>
<div class="mt-1">
@@ -23,7 +23,7 @@
step="0.01"
id="length_ft"
wire:model="coasterStats.length_ft"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('coasterStats.length_ft') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
@@ -31,7 +31,7 @@
<div class="sm:grid sm:grid-cols-2 sm:gap-4">
<div>
<label for="speed_mph" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="speed_mph" class="block text-sm font-medium text-gray-700">
Speed (mph)
</label>
<div class="mt-1">
@@ -39,12 +39,12 @@
step="0.01"
id="speed_mph"
wire:model="coasterStats.speed_mph"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('coasterStats.speed_mph') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
<div>
<label for="max_drop_height_ft" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="max_drop_height_ft" class="block text-sm font-medium text-gray-700">
Max Drop Height (feet)
</label>
<div class="mt-1">
@@ -52,7 +52,7 @@
step="0.01"
id="max_drop_height_ft"
wire:model="coasterStats.max_drop_height_ft"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('coasterStats.max_drop_height_ft') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
@@ -63,13 +63,13 @@
<div class="space-y-6 sm:space-y-5 mt-6">
<div class="sm:grid sm:grid-cols-2 sm:gap-4">
<div>
<label for="track_material" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="track_material" class="block text-sm font-medium text-gray-700">
Track Material
</label>
<div class="mt-1">
<select id="track_material"
wire:model="coasterStats.track_material"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@foreach(App\Enums\TrackMaterial::cases() as $material)
<option value="{{ $material->value }}">{{ $material->label() }}</option>
@endforeach
@@ -78,13 +78,13 @@
</div>
</div>
<div>
<label for="roller_coaster_type" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="roller_coaster_type" class="block text-sm font-medium text-gray-700">
Coaster Type
</label>
<div class="mt-1">
<select id="roller_coaster_type"
wire:model="coasterStats.roller_coaster_type"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@foreach(App\Enums\RollerCoasterType::cases() as $type)
<option value="{{ $type->value }}">{{ $type->label() }}</option>
@endforeach
@@ -96,25 +96,25 @@
<div class="sm:grid sm:grid-cols-2 sm:gap-4">
<div>
<label for="inversions" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="inversions" class="block text-sm font-medium text-gray-700">
Number of Inversions
</label>
<div class="mt-1">
<input type="number"
id="inversions"
wire:model="coasterStats.inversions"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('coasterStats.inversions') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
<div>
<label for="launch_type" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="launch_type" class="block text-sm font-medium text-gray-700">
Launch Type
</label>
<div class="mt-1">
<select id="launch_type"
wire:model="coasterStats.launch_type"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@foreach(App\Enums\LaunchType::cases() as $type)
<option value="{{ $type->value }}">{{ $type->label() }}</option>
@endforeach
@@ -128,52 +128,52 @@
{{-- Train Configuration --}}
<div class="space-y-6 sm:space-y-5 mt-6">
<div>
<label for="train_style" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="train_style" class="block text-sm font-medium text-gray-700">
Train Style
</label>
<div class="mt-1">
<input type="text"
id="train_style"
wire:model="coasterStats.train_style"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('coasterStats.train_style') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
<div class="sm:grid sm:grid-cols-3 sm:gap-4">
<div>
<label for="trains_count" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="trains_count" class="block text-sm font-medium text-gray-700">
Number of Trains
</label>
<div class="mt-1">
<input type="number"
id="trains_count"
wire:model="coasterStats.trains_count"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('coasterStats.trains_count') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
<div>
<label for="cars_per_train" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="cars_per_train" class="block text-sm font-medium text-gray-700">
Cars per Train
</label>
<div class="mt-1">
<input type="number"
id="cars_per_train"
wire:model="coasterStats.cars_per_train"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('coasterStats.cars_per_train') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
<div>
<label for="seats_per_car" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="seats_per_car" class="block text-sm font-medium text-gray-700">
Seats per Car
</label>
<div class="mt-1">
<input type="number"
id="seats_per_car"
wire:model="coasterStats.seats_per_car"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('coasterStats.seats_per_car') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>

View File

@@ -1,12 +1,12 @@
<div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 mb-6">
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Photo Gallery</h3>
<h3 class="text-lg font-semibold text-gray-900">Photo Gallery</h3>
<div class="flex space-x-2">
<button
wire:click="toggleViewMode"
class="inline-flex items-center px-3 py-1.5 bg-gray-100 border border-gray-300 rounded-md font-medium text-xs text-gray-700 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition ease-in-out duration-150 dark:bg-gray-700 dark:border-gray-600 dark:text-gray-200 dark:hover:bg-gray-600"
class="inline-flex items-center px-3 py-1.5 bg-gray-100 border border-gray-300 rounded-md font-medium text-xs text-gray-700 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition ease-in-out duration-150"
>
@if ($viewMode === 'grid')
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -31,11 +31,11 @@
</svg>
</div>
@elseif ($error)
<div class="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded relative dark:bg-red-900 dark:border-red-800 dark:text-red-200" role="alert">
<div class="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded relative" role="alert">
<span class="block sm:inline">{{ $error }}</span>
</div>
@elseif (count($photos) === 0)
<div class="text-center py-12 text-gray-500 dark:text-gray-400">
<div class="text-center py-12 text-gray-500">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
@@ -48,7 +48,7 @@
@foreach ($photos as $photo)
<div
wire:key="photo-{{ $photo->id }}"
class="relative group aspect-square overflow-hidden rounded-lg bg-gray-100 dark:bg-gray-700"
class="relative group aspect-square overflow-hidden rounded-lg bg-gray-100"
>
<img
src="{{ $photo->url }}"
@@ -117,7 +117,7 @@
}"
class="relative"
>
<div class="relative aspect-video overflow-hidden rounded-lg bg-gray-100 dark:bg-gray-700">
<div class="relative aspect-video overflow-hidden rounded-lg bg-gray-100">
@foreach ($photos as $index => $photo)
<div
x-show="activeSlide === {{ $index }}"
@@ -176,7 +176,7 @@
@foreach ($photos as $index => $photo)
<button
@click="activeSlide = {{ $index }}"
:class="{'bg-blue-600': activeSlide === {{ $index }}, 'bg-gray-300 dark:bg-gray-600': activeSlide !== {{ $index }}}"
:class="{'bg-blue-600': activeSlide === {{ $index }}, 'bg-gray-300': activeSlide !== {{ $index }}}"
class="w-2.5 h-2.5 rounded-full transition-colors duration-200"
></button>
@endforeach
@@ -197,11 +197,11 @@
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 bg-gray-900 bg-opacity-75 transition-opacity" wire:click="closePhotoDetail"></div>
<div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full">
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full">
<div class="absolute top-0 right-0 pt-4 pr-4">
<button
wire:click="closePhotoDetail"
class="bg-white dark:bg-gray-800 rounded-md text-gray-400 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500"
class="bg-white rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<span class="sr-only">Close</span>
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -213,7 +213,7 @@
<div class="p-6">
<div class="flex flex-col md:flex-row gap-6">
<div class="md:w-2/3">
<div class="aspect-video bg-gray-100 dark:bg-gray-700 rounded-lg overflow-hidden">
<div class="aspect-video bg-gray-100 rounded-lg overflow-hidden">
<img
src="{{ $selectedPhoto->url }}"
alt="{{ $selectedPhoto->alt_text ?? $selectedPhoto->title ?? 'Park photo' }}"
@@ -223,29 +223,29 @@
</div>
<div class="md:w-1/3">
<h3 class="text-lg font-medium text-gray-900 dark:text-white">
<h3 class="text-lg font-medium text-gray-900">
{{ $selectedPhoto->title ?? 'Untitled Photo' }}
</h3>
@if ($selectedPhoto->description)
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
<p class="mt-2 text-sm text-gray-500">
{{ $selectedPhoto->description }}
</p>
@endif
<div class="mt-4 border-t border-gray-200 dark:border-gray-700 pt-4">
<div class="mt-4 border-t border-gray-200 pt-4">
<dl class="space-y-3 text-sm">
@if ($selectedPhoto->credit)
<div>
<dt class="font-medium text-gray-500 dark:text-gray-400">Credit:</dt>
<dd class="mt-1 text-gray-900 dark:text-white">{{ $selectedPhoto->credit }}</dd>
<dt class="font-medium text-gray-500">Credit:</dt>
<dd class="mt-1 text-gray-900">{{ $selectedPhoto->credit }}</dd>
</div>
@endif
@if ($selectedPhoto->source_url)
<div>
<dt class="font-medium text-gray-500 dark:text-gray-400">Source:</dt>
<dd class="mt-1 text-blue-600 dark:text-blue-400">
<dt class="font-medium text-gray-500">Source:</dt>
<dd class="mt-1 text-blue-600">
<a href="{{ $selectedPhoto->source_url }}" target="_blank" rel="noopener noreferrer" class="hover:underline">
{{ $selectedPhoto->source_url }}
</a>
@@ -254,13 +254,13 @@
@endif
<div>
<dt class="font-medium text-gray-500 dark:text-gray-400">Dimensions:</dt>
<dd class="mt-1 text-gray-900 dark:text-white">{{ $selectedPhoto->width }} × {{ $selectedPhoto->height }}</dd>
<dt class="font-medium text-gray-500">Dimensions:</dt>
<dd class="mt-1 text-gray-900">{{ $selectedPhoto->width }} × {{ $selectedPhoto->height }}</dd>
</div>
<div>
<dt class="font-medium text-gray-500 dark:text-gray-400">File Size:</dt>
<dd class="mt-1 text-gray-900 dark:text-white">{{ number_format($selectedPhoto->file_size / 1024, 2) }} KB</dd>
<dt class="font-medium text-gray-500">File Size:</dt>
<dd class="mt-1 text-gray-900">{{ number_format($selectedPhoto->file_size / 1024, 2) }} KB</dd>
</div>
</dl>
</div>
@@ -269,7 +269,7 @@
@if (!$selectedPhoto->is_featured)
<button
wire:click="setFeatured({{ $selectedPhoto->id }})"
class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600"
class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
@@ -281,7 +281,7 @@
<button
wire:click="deletePhoto({{ $selectedPhoto->id }})"
wire:confirm="Are you sure you want to delete this photo? This action cannot be undone."
class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600"
class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />

View File

@@ -1,12 +1,12 @@
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 mb-6">
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Manage Photos</h3>
<h3 class="text-lg font-semibold text-gray-900">Manage Photos</h3>
<div>
@if (!$reordering)
<button
wire:click="startReordering"
class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600"
class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" />
@@ -27,7 +27,7 @@
<button
wire:click="cancelReordering"
class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600"
class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
@@ -47,11 +47,11 @@
</svg>
</div>
@elseif ($error)
<div class="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded relative dark:bg-red-900 dark:border-red-800 dark:text-red-200" role="alert">
<div class="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded relative" role="alert">
<span class="block sm:inline">{{ $error }}</span>
</div>
@elseif (count($photos) === 0)
<div class="text-center py-12 text-gray-500 dark:text-gray-400">
<div class="text-center py-12 text-gray-500">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
@@ -67,7 +67,7 @@
@if ($photo)
<div
wire:key="photo-order-{{ $photo['id'] }}"
class="flex items-center bg-gray-50 dark:bg-gray-700 rounded-lg overflow-hidden"
class="flex items-center bg-gray-50 rounded-lg overflow-hidden"
>
<div class="w-20 h-20 flex-shrink-0">
<img
@@ -78,11 +78,11 @@
</div>
<div class="flex-1 min-w-0 px-4 py-2">
<p class="text-sm font-medium text-gray-900 dark:text-white truncate">
<p class="text-sm font-medium text-gray-900 truncate">
{{ $photo['title'] ?? 'Untitled Photo' }}
</p>
@if ($photo['description'])
<p class="text-xs text-gray-500 dark:text-gray-400 truncate">
<p class="text-xs text-gray-500 truncate">
{{ $photo['description'] }}
</p>
@endif
@@ -90,7 +90,7 @@
@if ($photo['is_featured'])
<div class="px-2">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800 dark:bg-yellow-800 dark:text-yellow-100">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
Featured
</span>
</div>
@@ -100,7 +100,7 @@
<div class="flex items-center space-x-1 px-4">
<button
wire:click="moveUp({{ $index }})"
class="p-1 text-gray-400 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200 {{ $index === 0 ? 'opacity-50 cursor-not-allowed' : '' }}"
class="p-1 text-gray-400 hover:text-gray-500 {{ $index === 0 ? 'opacity-50 cursor-not-allowed' : '' }}"
{{ $index === 0 ? 'disabled' : '' }}
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -110,7 +110,7 @@
<button
wire:click="moveDown({{ $index }})"
class="p-1 text-gray-400 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200 {{ $index === count($photoOrder) - 1 ? 'opacity-50 cursor-not-allowed' : '' }}"
class="p-1 text-gray-400 hover:text-gray-500 {{ $index === count($photoOrder) - 1 ? 'opacity-50 cursor-not-allowed' : '' }}"
{{ $index === count($photoOrder) - 1 ? 'disabled' : '' }}
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">

View File

@@ -1,9 +1,9 @@
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 mb-6">
<h3 class="text-lg font-semibold mb-4 text-gray-900 dark:text-white">Upload New Photo</h3>
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
<h3 class="text-lg font-semibold mb-4 text-gray-900">Upload New Photo</h3>
<form wire:submit.prevent="save" class="space-y-4">
<div class="space-y-2">
<label for="photo" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="photo" class="block text-sm font-medium text-gray-700">
Photo <span class="text-red-500">*</span>
</label>
<div
@@ -30,14 +30,14 @@
id="photo"
wire:model="photo"
x-on:change="handleFileSelect"
class="block w-full text-sm text-gray-500 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-gray-700 dark:file:text-gray-200"
class="block w-full text-sm text-gray-500 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"
/>
<div x-show="photoPreview" class="mt-2">
<img x-bind:src="photoPreview" class="h-32 w-auto object-cover rounded-md" />
</div>
<div x-show="isUploading" class="w-full bg-gray-200 rounded-full h-2.5 dark:bg-gray-700 mt-2">
<div x-show="isUploading" class="w-full bg-gray-200 rounded-full h-2.5 mt-2">
<div class="bg-blue-600 h-2.5 rounded-full" x-bind:style="`width: ${progress}%`"></div>
</div>
@@ -49,52 +49,52 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Title</label>
<input type="text" id="title" wire:model="title" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
<label for="title" class="block text-sm font-medium text-gray-700">Title</label>
<input type="text" id="title" wire:model="title" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
@error('title') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div>
<label for="alt_text" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Alt Text</label>
<input type="text" id="alt_text" wire:model="alt_text" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
<label for="alt_text" class="block text-sm font-medium text-gray-700">Alt Text</label>
<input type="text" id="alt_text" wire:model="alt_text" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
@error('alt_text') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
</div>
<div>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Description</label>
<textarea id="description" wire:model="description" rows="3" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"></textarea>
<label for="description" class="block text-sm font-medium text-gray-700">Description</label>
<textarea id="description" wire:model="description" rows="3" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"></textarea>
@error('description') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="credit" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Photo Credit</label>
<input type="text" id="credit" wire:model="credit" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
<label for="credit" class="block text-sm font-medium text-gray-700">Photo Credit</label>
<input type="text" id="credit" wire:model="credit" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
@error('credit') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div>
<label for="source_url" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Source URL</label>
<input type="url" id="source_url" wire:model="source_url" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
<label for="source_url" class="block text-sm font-medium text-gray-700">Source URL</label>
<input type="url" id="source_url" wire:model="source_url" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
@error('source_url') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
</div>
<div class="flex items-center">
<input type="checkbox" id="is_featured" wire:model="is_featured" class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600">
<label for="is_featured" class="ml-2 block text-sm text-gray-700 dark:text-gray-300">Set as featured photo</label>
<input type="checkbox" id="is_featured" wire:model="is_featured" class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-500 focus:ring-blue-500">
<label for="is_featured" class="ml-2 block text-sm text-gray-700">Set as featured photo</label>
@error('is_featured') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
@if ($uploadError)
<div class="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded relative dark:bg-red-900 dark:border-red-800 dark:text-red-200" role="alert">
<div class="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded relative" role="alert">
<span class="block sm:inline">{{ $uploadError }}</span>
</div>
@endif
@if ($uploadSuccess)
<div class="bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded relative dark:bg-green-900 dark:border-green-800 dark:text-green-200" role="alert">
<div class="bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded relative" role="alert">
<span class="block sm:inline">Photo uploaded successfully!</span>
</div>
@endif

View File

@@ -0,0 +1,79 @@
<?php
use App\Livewire\Actions\Logout;
use Illuminate\Support\Facades\Auth;
use Livewire\Volt\Component;
new class extends Component
{
public string $password = '';
/**
* Delete the currently authenticated user.
*/
public function deleteUser(Logout $logout): void
{
$this->validate([
'password' => ['required', 'string', 'current_password'],
]);
tap(Auth::user(), $logout(...))->delete();
$this->redirect('/', navigate: true);
}
}; ?>
<section class="space-y-6">
<header>
<h2 class="text-lg font-medium text-gray-900">
{{ __('Delete Account') }}
</h2>
<p class="mt-1 text-sm text-gray-600">
{{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.') }}
</p>
</header>
<x-danger-button
x-data=""
x-on:click.prevent="$dispatch('open-modal', 'confirm-user-deletion')"
>{{ __('Delete Account') }}</x-danger-button>
<x-modal name="confirm-user-deletion" :show="$errors->isNotEmpty()" focusable>
<form wire:submit="deleteUser" class="p-6">
<h2 class="text-lg font-medium text-gray-900">
{{ __('Are you sure you want to delete your account?') }}
</h2>
<p class="mt-1 text-sm text-gray-600">
{{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.') }}
</p>
<div class="mt-6">
<x-input-label for="password" value="{{ __('Password') }}" class="sr-only" />
<x-text-input
wire:model="password"
id="password"
name="password"
type="password"
class="mt-1 block w-3/4"
placeholder="{{ __('Password') }}"
/>
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-danger-button class="ms-3">
{{ __('Delete Account') }}
</x-danger-button>
</div>
</form>
</x-modal>
</section>

View File

@@ -0,0 +1,79 @@
<?php
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;
use Illuminate\Validation\ValidationException;
use Livewire\Volt\Component;
new class extends Component
{
public string $current_password = '';
public string $password = '';
public string $password_confirmation = '';
/**
* Update the password for the currently authenticated user.
*/
public function updatePassword(): void
{
try {
$validated = $this->validate([
'current_password' => ['required', 'string', 'current_password'],
'password' => ['required', 'string', Password::defaults(), 'confirmed'],
]);
} catch (ValidationException $e) {
$this->reset('current_password', 'password', 'password_confirmation');
throw $e;
}
Auth::user()->update([
'password' => Hash::make($validated['password']),
]);
$this->reset('current_password', 'password', 'password_confirmation');
$this->dispatch('password-updated');
}
}; ?>
<section>
<header>
<h2 class="text-lg font-medium text-gray-900">
{{ __('Update Password') }}
</h2>
<p class="mt-1 text-sm text-gray-600">
{{ __('Ensure your account is using a long, random password to stay secure.') }}
</p>
</header>
<form wire:submit="updatePassword" class="mt-6 space-y-6">
<div>
<x-input-label for="update_password_current_password" :value="__('Current Password')" />
<x-text-input wire:model="current_password" id="update_password_current_password" name="current_password" type="password" class="mt-1 block w-full" autocomplete="current-password" />
<x-input-error :messages="$errors->get('current_password')" class="mt-2" />
</div>
<div>
<x-input-label for="update_password_password" :value="__('New Password')" />
<x-text-input wire:model="password" id="update_password_password" name="password" type="password" class="mt-1 block w-full" autocomplete="new-password" />
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
<div>
<x-input-label for="update_password_password_confirmation" :value="__('Confirm Password')" />
<x-text-input wire:model="password_confirmation" id="update_password_password_confirmation" name="password_confirmation" type="password" class="mt-1 block w-full" autocomplete="new-password" />
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
</div>
<div class="flex items-center gap-4">
<x-primary-button>{{ __('Save') }}</x-primary-button>
<x-action-message class="me-3" on="password-updated">
{{ __('Saved.') }}
</x-action-message>
</div>
</form>
</section>

View File

@@ -0,0 +1,115 @@
<?php
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Illuminate\Validation\Rule;
use Livewire\Volt\Component;
new class extends Component
{
public string $name = '';
public string $email = '';
/**
* Mount the component.
*/
public function mount(): void
{
$this->name = Auth::user()->name;
$this->email = Auth::user()->email;
}
/**
* Update the profile information for the currently authenticated user.
*/
public function updateProfileInformation(): void
{
$user = Auth::user();
$validated = $this->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', Rule::unique(User::class)->ignore($user->id)],
]);
$user->fill($validated);
if ($user->isDirty('email')) {
$user->email_verified_at = null;
}
$user->save();
$this->dispatch('profile-updated', name: $user->name);
}
/**
* Send an email verification notification to the current user.
*/
public function sendVerification(): void
{
$user = Auth::user();
if ($user->hasVerifiedEmail()) {
$this->redirectIntended(default: route('dashboard', absolute: false));
return;
}
$user->sendEmailVerificationNotification();
Session::flash('status', 'verification-link-sent');
}
}; ?>
<section>
<header>
<h2 class="text-lg font-medium text-gray-900">
{{ __('Profile Information') }}
</h2>
<p class="mt-1 text-sm text-gray-600">
{{ __("Update your account's profile information and email address.") }}
</p>
</header>
<form wire:submit="updateProfileInformation" class="mt-6 space-y-6">
<div>
<x-input-label for="name" :value="__('Name')" />
<x-text-input wire:model="name" id="name" name="name" type="text" class="mt-1 block w-full" required autofocus autocomplete="name" />
<x-input-error class="mt-2" :messages="$errors->get('name')" />
</div>
<div>
<x-input-label for="email" :value="__('Email')" />
<x-text-input wire:model="email" id="email" name="email" type="email" class="mt-1 block w-full" required autocomplete="username" />
<x-input-error class="mt-2" :messages="$errors->get('email')" />
@if (auth()->user() instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && ! auth()->user()->hasVerifiedEmail())
<div>
<p class="text-sm mt-2 text-gray-800">
{{ __('Your email address is unverified.') }}
<button wire:click.prevent="sendVerification" class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
{{ __('Click here to re-send the verification email.') }}
</button>
</p>
@if (session('status') === 'verification-link-sent')
<p class="mt-2 font-medium text-sm text-green-600">
{{ __('A new verification link has been sent to your email address.') }}
</p>
@endif
</div>
@endif
</div>
<div class="flex items-center gap-4">
<x-primary-button>{{ __('Save') }}</x-primary-button>
<x-action-message class="me-3" on="profile-updated">
{{ __('Saved.') }}
</x-action-message>
</div>
</form>
</section>

View File

@@ -3,18 +3,18 @@
@if ($message)
<div @class([
'p-4 mb-4 rounded-lg',
'bg-green-100 dark:bg-green-800 text-green-700 dark:text-green-200' => !str_contains($message, 'error'),
'bg-red-100 dark:bg-red-800 text-red-700 dark:text-red-200' => str_contains($message, 'error'),
'bg-green-100 text-green-700' => !str_contains($message, 'error'),
'bg-red-100 text-red-700' => str_contains($message, 'error'),
])>
{{ $message }}
</div>
@endif
{{-- Controls --}}
<div class="bg-white dark:bg-gray-800 rounded-lg shadow">
<div class="bg-white rounded-lg shadow">
<div class="p-4 space-y-4">
{{-- Status Tabs --}}
<div class="border-b border-gray-200 dark:border-gray-700">
<div class="border-b border-gray-200">
<nav class="-mb-px flex space-x-8">
<button
wire:click="filterByStatus('{{ ReviewStatus::PENDING->value }}')"
@@ -60,14 +60,14 @@
<label for="search" class="sr-only">Search reviews</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<span class="text-gray-500 dark:text-gray-400">
<span class="text-gray-500">
🔍
</span>
</div>
<input
type="search"
wire:model.live.debounce.300ms="search"
class="block w-full pl-10 pr-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md leading-5 bg-white dark:bg-gray-700 placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
placeholder="Search reviews..."
>
</div>
@@ -75,7 +75,7 @@
@if (count($selected) > 0)
<div class="flex items-center space-x-3">
<span class="text-sm text-gray-700 dark:text-gray-300">
<span class="text-sm text-gray-700">
{{ count($selected) }} selected
</span>
<button
@@ -97,8 +97,8 @@
</div>
{{-- Reviews List --}}
<div class="bg-white dark:bg-gray-800 shadow rounded-lg">
<ul role="list" class="divide-y divide-gray-200 dark:divide-gray-700">
<div class="bg-white shadow rounded-lg">
<ul role="list" class="divide-y divide-gray-200">
@forelse ($reviews as $review)
<li class="p-4">
<div class="flex items-start space-x-4">
@@ -115,7 +115,7 @@
{{-- Content --}}
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between">
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">
<div class="text-sm font-medium text-gray-900">
{{ $review->user->name }}
</div>
<div class="text-sm text-gray-500">
@@ -130,12 +130,12 @@
@endfor
</div>
@if ($review->title)
<span class="text-gray-900 dark:text-gray-100 font-medium">
<span class="text-gray-900 font-medium">
{{ $review->title }}
</span>
@endif
</div>
<p class="mt-1 text-gray-600 dark:text-gray-400">
<p class="mt-1 text-gray-600">
{{ $review->content }}
</p>
<div class="mt-2 text-sm text-gray-500">
@@ -148,7 +148,7 @@
<div class="flex-shrink-0 flex items-center space-x-2">
<button
wire:click="editReview({{ $review->id }})"
class="inline-flex items-center p-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
class="inline-flex items-center p-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
>
✏️
</button>
@@ -168,14 +168,14 @@
</div>
</li>
@empty
<li class="p-4 text-center text-gray-500 dark:text-gray-400">
<li class="p-4 text-center text-gray-500">
No reviews found.
</li>
@endforelse
</ul>
{{-- Pagination --}}
<div class="p-4 border-t border-gray-200 dark:border-gray-700">
<div class="p-4 border-t border-gray-200">
{{ $reviews->links() }}
</div>
</div>
@@ -196,13 +196,13 @@
></div>
{{-- Modal panel --}}
<div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<form wire:submit="saveEdit">
<div class="bg-white dark:bg-gray-800 px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="space-y-4">
{{-- Rating --}}
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label class="block text-sm font-medium text-gray-700">
Rating
</label>
<div class="mt-1 flex items-center space-x-2">
@@ -214,50 +214,50 @@
>
<span @class([
'text-yellow-400' => $i <= $form['rating'],
'text-gray-300 dark:text-gray-600' => $i > $form['rating'],
'text-gray-300' => $i > $form['rating'],
])></span>
</button>
@endfor
</div>
@error('form.rating')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
{{-- Title --}}
<div>
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="title" class="block text-sm font-medium text-gray-700">
Title
</label>
<input
type="text"
wire:model="form.title"
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm dark:bg-gray-700"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
>
@error('form.title')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
{{-- Content --}}
<div>
<label for="content" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="content" class="block text-sm font-medium text-gray-700">
Content
</label>
<textarea
wire:model="form.content"
rows="4"
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm dark:bg-gray-700"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
></textarea>
@error('form.content')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
</div>
</div>
{{-- Modal footer --}}
<div class="bg-gray-50 dark:bg-gray-700 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
type="submit"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-primary-600 text-base font-medium text-white hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 sm:ml-3 sm:w-auto sm:text-sm"
@@ -267,7 +267,7 @@
<button
type="button"
wire:click="$set('showEditModal', false)"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 dark:border-gray-600 shadow-sm px-4 py-2 bg-white dark:bg-gray-800 text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
Cancel
</button>

View File

@@ -1,12 +1,12 @@
<div class="bg-white dark:bg-gray-800 shadow overflow-hidden sm:rounded-lg">
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
{{-- Header --}}
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700">
<div class="px-4 py-5 sm:px-6 border-b border-gray-200">
<div class="flex justify-between items-start">
<div>
<h3 class="text-2xl font-bold leading-6 text-gray-900 dark:text-white">
<h3 class="text-2xl font-bold leading-6 text-gray-900">
{{ $ride->name }}
</h3>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
<p class="mt-1 text-sm text-gray-500">
{{ $ride->park->name }}
@if($ride->parkArea)
<span class="px-2"></span>
@@ -21,77 +21,77 @@
</div>
{{-- Basic Information --}}
<div class="px-4 py-5 sm:p-6 border-b border-gray-200 dark:border-gray-700">
<div class="px-4 py-5 sm:p-6 border-b border-gray-200">
<dl class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-8">
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Category</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->category->label() }}</dd>
<dt class="text-sm font-medium text-gray-500">Category</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->category->label() }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Operating Period</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $this->operatingPeriod }}</dd>
<dt class="text-sm font-medium text-gray-500">Operating Period</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $this->operatingPeriod }}</dd>
</div>
@if($ride->manufacturer)
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Manufacturer</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->manufacturer->name }}</dd>
<dt class="text-sm font-medium text-gray-500">Manufacturer</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->manufacturer->name }}</dd>
</div>
@endif
@if($ride->designer)
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Designer</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->designer->name }}</dd>
<dt class="text-sm font-medium text-gray-500">Designer</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->designer->name }}</dd>
</div>
@endif
@if($ride->rideModel)
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Model</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->rideModel->name }}</dd>
<dt class="text-sm font-medium text-gray-500">Model</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->rideModel->name }}</dd>
</div>
@endif
</dl>
@if($ride->description)
<div class="mt-8">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Description</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white whitespace-pre-line">{{ $ride->description }}</dd>
<dt class="text-sm font-medium text-gray-500">Description</dt>
<dd class="mt-1 text-sm text-gray-900 whitespace-pre-line">{{ $ride->description }}</dd>
</div>
@endif
</div>
{{-- Technical Details --}}
<div class="px-4 py-5 sm:p-6 border-b border-gray-200 dark:border-gray-700">
<h4 class="text-lg font-medium text-gray-900 dark:text-white mb-4">Technical Specifications</h4>
<div class="px-4 py-5 sm:p-6 border-b border-gray-200">
<h4 class="text-lg font-medium text-gray-900 mb-4">Technical Specifications</h4>
<dl class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-4 gap-y-8">
@if($ride->min_height_in)
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Minimum Height</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->min_height_in }} inches</dd>
<dt class="text-sm font-medium text-gray-500">Minimum Height</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->min_height_in }} inches</dd>
</div>
@endif
@if($ride->max_height_in)
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Maximum Height</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->max_height_in }} inches</dd>
<dt class="text-sm font-medium text-gray-500">Maximum Height</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->max_height_in }} inches</dd>
</div>
@endif
@if($ride->capacity_per_hour)
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Hourly Capacity</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ number_format($ride->capacity_per_hour) }} riders</dd>
<dt class="text-sm font-medium text-gray-500">Hourly Capacity</dt>
<dd class="mt-1 text-sm text-gray-900">{{ number_format($ride->capacity_per_hour) }} riders</dd>
</div>
@endif
@if($ride->ride_duration_seconds)
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Ride Duration</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->ride_duration_seconds }} seconds</dd>
<dt class="text-sm font-medium text-gray-500">Ride Duration</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->ride_duration_seconds }} seconds</dd>
</div>
@endif
</dl>
@@ -101,10 +101,10 @@
@if($ride->coasterStats)
<div class="px-4 py-5 sm:p-6">
<div class="flex items-center justify-between mb-4">
<h4 class="text-lg font-medium text-gray-900 dark:text-white">Roller Coaster Statistics</h4>
<h4 class="text-lg font-medium text-gray-900">Roller Coaster Statistics</h4>
<button type="button"
wire:click="toggleCoasterStats"
class="inline-flex items-center px-3 py-1.5 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600">
class="inline-flex items-center px-3 py-1.5 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">
{{ $showCoasterStats ? 'Hide Details' : 'Show Details' }}
</button>
</div>
@@ -113,67 +113,67 @@
<dl class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-4 gap-y-8">
{{-- Track Details --}}
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Track Type</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->coasterStats->track_material->label() }}</dd>
<dt class="text-sm font-medium text-gray-500">Track Type</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->coasterStats->track_material->label() }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Coaster Type</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->coasterStats->roller_coaster_type->label() }}</dd>
<dt class="text-sm font-medium text-gray-500">Coaster Type</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->coasterStats->roller_coaster_type->label() }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Launch Type</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->coasterStats->launch_type->label() }}</dd>
<dt class="text-sm font-medium text-gray-500">Launch Type</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->coasterStats->launch_type->label() }}</dd>
</div>
{{-- Physical Measurements --}}
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Height</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $this->formatMeasurement($ride->coasterStats->height_ft, 'ft') }}</dd>
<dt class="text-sm font-medium text-gray-500">Height</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $this->formatMeasurement($ride->coasterStats->height_ft, 'ft') }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Length</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $this->formatMeasurement($ride->coasterStats->length_ft, 'ft') }}</dd>
<dt class="text-sm font-medium text-gray-500">Length</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $this->formatMeasurement($ride->coasterStats->length_ft, 'ft') }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Speed</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $this->formatMeasurement($ride->coasterStats->speed_mph, 'mph') }}</dd>
<dt class="text-sm font-medium text-gray-500">Speed</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $this->formatMeasurement($ride->coasterStats->speed_mph, 'mph') }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Max Drop</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $this->formatMeasurement($ride->coasterStats->max_drop_height_ft, 'ft') }}</dd>
<dt class="text-sm font-medium text-gray-500">Max Drop</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $this->formatMeasurement($ride->coasterStats->max_drop_height_ft, 'ft') }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Inversions</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->coasterStats->inversions ?? 'N/A' }}</dd>
<dt class="text-sm font-medium text-gray-500">Inversions</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->coasterStats->inversions ?? 'N/A' }}</dd>
</div>
{{-- Train Configuration --}}
@if($ride->coasterStats->train_style)
<div class="col-span-full">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Train Style</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->coasterStats->train_style }}</dd>
<dt class="text-sm font-medium text-gray-500">Train Style</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->coasterStats->train_style }}</dd>
</div>
@endif
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Number of Trains</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->coasterStats->trains_count ?? 'N/A' }}</dd>
<dt class="text-sm font-medium text-gray-500">Number of Trains</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->coasterStats->trains_count ?? 'N/A' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Cars per Train</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->coasterStats->cars_per_train ?? 'N/A' }}</dd>
<dt class="text-sm font-medium text-gray-500">Cars per Train</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->coasterStats->cars_per_train ?? 'N/A' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Seats per Car</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $ride->coasterStats->seats_per_car ?? 'N/A' }}</dd>
<dt class="text-sm font-medium text-gray-500">Seats per Car</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $ride->coasterStats->seats_per_car ?? 'N/A' }}</dd>
</div>
</dl>
@endif
@@ -181,7 +181,7 @@
@endif
{{-- Actions --}}
<div class="px-4 py-3 bg-gray-50 dark:bg-gray-700 text-right sm:px-6">
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<a href="{{ route('rides.edit', $ride) }}"
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">
Edit Ride

View File

@@ -1,10 +1,10 @@
<div class="space-y-6">
<form wire:submit="save" class="space-y-8 divide-y divide-gray-200 dark:divide-gray-700">
<form wire:submit="save" class="space-y-8 divide-y divide-gray-200">
{{-- Basic Information --}}
<div class="space-y-6 sm:space-y-5">
<div>
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-white">Basic Information</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500 dark:text-gray-400">
<h3 class="text-lg font-medium leading-6 text-gray-900">Basic Information</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500">
Provide the basic details about this ride.
</p>
</div>
@@ -12,27 +12,27 @@
<div class="space-y-6 sm:space-y-5">
{{-- Name --}}
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<label for="name" class="block text-sm font-medium text-gray-700 dark:text-gray-300 sm:mt-px sm:pt-2">
<label for="name" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
Name
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<input type="text"
id="name"
wire:model="state.name"
class="max-w-lg block w-full shadow-sm focus:ring-primary-500 focus:border-primary-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="max-w-lg block w-full shadow-sm focus:ring-primary-500 focus:border-primary-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md">
@error('state.name') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
{{-- Park --}}
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<label for="park_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300 sm:mt-px sm:pt-2">
<label for="park_id" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
Park
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<select id="park_id"
wire:model.live="state.park_id"
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md">
<option value="">Select a park</option>
@foreach($this->parks as $park)
<option value="{{ $park->id }}">{{ $park->name }}</option>
@@ -44,13 +44,13 @@
{{-- Park Area --}}
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<label for="park_area_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300 sm:mt-px sm:pt-2">
<label for="park_area_id" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
Park Area
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<select id="park_area_id"
wire:model="state.park_area_id"
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md">
<option value="">Select an area</option>
@foreach($this->parkAreas as $area)
<option value="{{ $area->id }}">{{ $area->name }}</option>
@@ -62,13 +62,13 @@
{{-- Category --}}
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<label for="category" class="block text-sm font-medium text-gray-700 dark:text-gray-300 sm:mt-px sm:pt-2">
<label for="category" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
Category
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<select id="category"
wire:model.live="state.category"
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md">
@foreach(App\Enums\RideCategory::cases() as $category)
<option value="{{ $category->value }}">{{ $category->label() }}</option>
@endforeach
@@ -79,13 +79,13 @@
{{-- Status --}}
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<label for="status" class="block text-sm font-medium text-gray-700 dark:text-gray-300 sm:mt-px sm:pt-2">
<label for="status" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
Status
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<select id="status"
wire:model="state.status"
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md">
@foreach(App\Enums\RideStatus::cases() as $status)
<option value="{{ $status->value }}">{{ $status->label() }}</option>
@endforeach
@@ -96,14 +96,14 @@
{{-- Description --}}
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300 sm:mt-px sm:pt-2">
<label for="description" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
Description
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<textarea id="description"
wire:model="state.description"
rows="3"
class="max-w-lg shadow-sm block w-full focus:ring-primary-500 focus:border-primary-500 sm:text-sm border border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white"></textarea>
class="max-w-lg shadow-sm block w-full focus:ring-primary-500 focus:border-primary-500 sm:text-sm border border-gray-300 rounded-md"></textarea>
@error('state.description') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
@@ -113,8 +113,8 @@
{{-- Technical Details --}}
<div class="pt-8 space-y-6 sm:space-y-5">
<div>
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-white">Technical Details</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500 dark:text-gray-400">
<h3 class="text-lg font-medium leading-6 text-gray-900">Technical Details</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500">
Specify the technical specifications and requirements.
</p>
</div>
@@ -122,13 +122,13 @@
<div class="space-y-6 sm:space-y-5">
{{-- Manufacturer --}}
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<label for="manufacturer_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300 sm:mt-px sm:pt-2">
<label for="manufacturer_id" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
Manufacturer
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<select id="manufacturer_id"
wire:model="state.manufacturer_id"
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md">
<option value="">Select a manufacturer</option>
@foreach($this->manufacturers as $manufacturer)
<option value="{{ $manufacturer->id }}">{{ $manufacturer->name }}</option>
@@ -140,13 +140,13 @@
{{-- Designer --}}
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<label for="designer_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300 sm:mt-px sm:pt-2">
<label for="designer_id" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
Designer
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<select id="designer_id"
wire:model="state.designer_id"
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="max-w-lg block focus:ring-primary-500 focus:border-primary-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md">
<option value="">Select a designer</option>
@foreach($this->designers as $designer)
<option value="{{ $designer->id }}">{{ $designer->name }}</option>
@@ -160,26 +160,26 @@
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<div class="col-span-3 grid grid-cols-2 gap-4">
<div>
<label for="min_height_in" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="min_height_in" class="block text-sm font-medium text-gray-700">
Minimum Height (inches)
</label>
<div class="mt-1">
<input type="number"
id="min_height_in"
wire:model="state.min_height_in"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('state.min_height_in') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
<div>
<label for="max_height_in" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="max_height_in" class="block text-sm font-medium text-gray-700">
Maximum Height (inches)
</label>
<div class="mt-1">
<input type="number"
id="max_height_in"
wire:model="state.max_height_in"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('state.max_height_in') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
@@ -190,26 +190,26 @@
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<div class="col-span-3 grid grid-cols-2 gap-4">
<div>
<label for="capacity_per_hour" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="capacity_per_hour" class="block text-sm font-medium text-gray-700">
Capacity (per hour)
</label>
<div class="mt-1">
<input type="number"
id="capacity_per_hour"
wire:model="state.capacity_per_hour"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('state.capacity_per_hour') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
<div>
<label for="ride_duration_seconds" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="ride_duration_seconds" class="block text-sm font-medium text-gray-700">
Duration (seconds)
</label>
<div class="mt-1">
<input type="number"
id="ride_duration_seconds"
wire:model="state.ride_duration_seconds"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('state.ride_duration_seconds') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
</div>
</div>
@@ -222,8 +222,8 @@
@if($state['category'] === App\Enums\RideCategory::ROLLER_COASTER->value)
<div class="pt-8 space-y-6 sm:space-y-5">
<div>
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-white">Roller Coaster Details</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500 dark:text-gray-400">
<h3 class="text-lg font-medium leading-6 text-gray-900">Roller Coaster Details</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500">
Additional specifications for roller coasters.
</p>
</div>
@@ -236,11 +236,11 @@
<div class="pt-5">
<div class="flex justify-end">
<a href="{{ route('rides.index') }}"
class="bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600">
class="bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">
Cancel
</a>
<button type="submit"
class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 dark:hover:bg-primary-500">
class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">
Save
</button>
</div>

View File

@@ -3,19 +3,19 @@
<div class="flex justify-end">
<button type="button"
wire:click="toggleUploadForm"
class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600">
class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">
{{ $showUploadForm ? 'Cancel Upload' : 'Upload Photo' }}
</button>
</div>
{{-- Upload Form --}}
@if($showUploadForm)
<div class="bg-white dark:bg-gray-800 shadow sm:rounded-lg p-6">
<div class="bg-white shadow sm:rounded-lg p-6">
<form wire:submit="save">
<div class="space-y-4">
{{-- Photo Upload --}}
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Photo</label>
<label class="block text-sm font-medium text-gray-700">Photo</label>
<div class="mt-1 flex items-center">
<input type="file"
wire:model="photo"
@@ -23,11 +23,11 @@
class="sr-only"
id="photo-upload">
<label for="photo-upload"
class="cursor-pointer inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600">
class="cursor-pointer inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">
Choose File
</label>
@if($photo)
<span class="ml-3 text-sm text-gray-500 dark:text-gray-400">{{ $photo->getClientOriginalName() }}</span>
<span class="ml-3 text-sm text-gray-500">{{ $photo->getClientOriginalName() }}</span>
@endif
</div>
@error('photo') <span class="mt-1 text-sm text-red-500">{{ $message }}</span> @enderror
@@ -35,12 +35,12 @@
{{-- Caption --}}
<div>
<label for="caption" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Caption</label>
<label for="caption" class="block text-sm font-medium text-gray-700">Caption</label>
<div class="mt-1">
<input type="text"
id="caption"
wire:model="caption"
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md">
@error('caption') <span class="mt-1 text-sm text-red-500">{{ $message }}</span> @enderror
</div>
</div>
@@ -61,7 +61,7 @@
@if($photos->count() > 0)
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
@foreach($photos as $photo)
<div class="relative group bg-white dark:bg-gray-800 p-2 rounded-lg shadow hover:shadow-lg transition-shadow">
<div class="relative group bg-white p-2 rounded-lg shadow hover:shadow-lg transition-shadow">
<div class="aspect-w-16 aspect-h-9">
<img src="{{ Storage::url($photo->path) }}"
alt="{{ $photo->caption }}"
@@ -70,7 +70,7 @@
{{-- Caption --}}
@if($photo->caption)
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">{{ $photo->caption }}</p>
<p class="mt-2 text-sm text-gray-500">{{ $photo->caption }}</p>
@endif
{{-- Actions --}}
@@ -115,7 +115,7 @@
</div>
@else
<div class="text-center py-12">
<p class="text-gray-500 dark:text-gray-400">No photos uploaded yet.</p>
<p class="text-gray-500">No photos uploaded yet.</p>
</div>
@endif
</div>

View File

@@ -1,23 +1,23 @@
<div class="space-y-4">
{{-- Control Panel --}}
<div class="bg-white dark:bg-gray-800 shadow sm:rounded-lg p-4">
<div class="bg-white shadow sm:rounded-lg p-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
{{-- Search --}}
<div>
<label for="search" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Search</label>
<label for="search" class="block text-sm font-medium text-gray-700">Search</label>
<input type="search"
id="search"
wire:model.live="search"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white sm:text-sm"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
placeholder="Search rides...">
</div>
{{-- Category Filter --}}
<div>
<label for="category" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Category</label>
<label for="category" class="block text-sm font-medium text-gray-700">Category</label>
<select id="category"
wire:model.live="category"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white sm:text-sm">
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm">
<option value="">All Categories</option>
@foreach($this->categories as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@@ -29,7 +29,7 @@
<div class="flex items-end justify-end">
<button type="button"
wire:click="toggleView"
class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600">
class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
<span>{{ $viewMode === 'grid' ? 'Switch to List' : 'Switch to Grid' }}</span>
</button>
</div>
@@ -42,11 +42,11 @@
{{-- Grid View --}}
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
@foreach($rides as $ride)
<div class="bg-white dark:bg-gray-800 shadow overflow-hidden sm:rounded-lg">
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<div class="flex justify-between items-start">
<h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-white">
<a href="{{ route('rides.show', $ride) }}" class="hover:text-primary-600 dark:hover:text-primary-400">
<h3 class="text-lg leading-6 font-medium text-gray-900">
<a href="{{ route('rides.show', $ride) }}" class="hover:text-primary-600">
{{ $ride->name }}
</a>
</h3>
@@ -55,11 +55,11 @@
</span>
</div>
<div class="mt-2">
<p class="text-sm text-gray-500 dark:text-gray-400">
<p class="text-sm text-gray-500">
{{ $ride->park->name }}
</p>
@if($ride->parkArea)
<p class="text-sm text-gray-500 dark:text-gray-400">
<p class="text-sm text-gray-500">
{{ $ride->parkArea->name }}
</p>
@endif
@@ -83,19 +83,19 @@
</div>
@else
{{-- List View --}}
<div class="bg-white dark:bg-gray-800 shadow overflow-hidden sm:rounded-lg">
<ul class="divide-y divide-gray-200 dark:divide-gray-700">
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
<ul class="divide-y divide-gray-200">
@foreach($rides as $ride)
<li class="px-4 py-4 sm:px-6 hover:bg-gray-50 dark:hover:bg-gray-700">
<li class="px-4 py-4 sm:px-6 hover:bg-gray-50">
<div class="flex items-center justify-between">
<div class="flex-1 min-w-0">
<h3 class="text-sm font-medium text-gray-900 dark:text-white truncate">
<a href="{{ route('rides.show', $ride) }}" class="hover:text-primary-600 dark:hover:text-primary-400">
<h3 class="text-sm font-medium text-gray-900 truncate">
<a href="{{ route('rides.show', $ride) }}" class="hover:text-primary-600">
{{ $ride->name }}
</a>
</h3>
<div class="mt-2 flex">
<div class="flex items-center text-sm text-gray-500 dark:text-gray-400">
<div class="flex items-center text-sm text-gray-500">
{{ $ride->park->name }}
@if($ride->parkArea)
<span class="px-2"></span>

View File

@@ -1,10 +1,10 @@
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<div class="bg-white rounded-lg shadow p-6">
{{-- Show message if exists --}}
@if ($message)
<div @class([
'p-4 mb-4 rounded-lg',
'bg-green-100 dark:bg-green-800 text-green-700 dark:text-green-200' => !str_contains($message, 'error') && !str_contains($message, 'cannot'),
'bg-red-100 dark:bg-red-800 text-red-700 dark:text-red-200' => str_contains($message, 'error') || str_contains($message, 'cannot'),
'bg-green-100 text-green-700' => !str_contains($message, 'error') && !str_contains($message, 'cannot'),
'bg-red-100 text-red-700' => str_contains($message, 'error') || str_contains($message, 'cannot'),
])>
{{ $message }}
</div>
@@ -14,7 +14,7 @@
<form wire:submit="save" class="space-y-6">
{{-- Star Rating --}}
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
<label class="block text-sm font-medium text-gray-700 mb-2">
Rating <span class="text-red-500">*</span>
</label>
<div class="flex items-center space-x-2">
@@ -26,50 +26,50 @@
>
<span @class([
'text-yellow-400' => $i <= $rating,
'text-gray-300 dark:text-gray-600' => $i > $rating,
'text-gray-300' => $i > $rating,
])></span>
</button>
@endfor
</div>
@error('rating')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
{{-- Title Field --}}
<div>
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="title" class="block text-sm font-medium text-gray-700">
Title <span class="text-gray-500">(optional)</span>
</label>
<input
type="text"
id="title"
wire:model="title"
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 dark:bg-gray-700 shadow-sm focus:border-primary-500 focus:ring-primary-500"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500"
placeholder="Give your review a title"
>
@error('title')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
{{-- Content Field --}}
<div>
<label for="content" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="content" class="block text-sm font-medium text-gray-700">
Review <span class="text-red-500">*</span>
</label>
<textarea
id="content"
wire:model="content"
rows="4"
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 dark:bg-gray-700 shadow-sm focus:border-primary-500 focus:ring-primary-500"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500"
placeholder="Share your experience with this ride"
></textarea>
<p class="mt-1 text-sm text-gray-500">
{{ strlen($content) }}/2000 characters
</p>
@error('content')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>

View File

@@ -3,22 +3,22 @@
@if ($message)
<div @class([
'p-4 mb-4 rounded-lg',
'bg-green-100 dark:bg-green-800 text-green-700 dark:text-green-200' => !str_contains($message, 'error') && !str_contains($message, 'cannot'),
'bg-red-100 dark:bg-red-800 text-red-700 dark:text-red-200' => str_contains($message, 'error') || str_contains($message, 'cannot'),
'bg-green-100 text-green-700' => !str_contains($message, 'error') && !str_contains($message, 'cannot'),
'bg-red-100 text-red-700' => str_contains($message, 'error') || str_contains($message, 'cannot'),
])>
{{ $message }}
</div>
@endif
{{-- Statistics Panel --}}
<div x-data="{ open: @entangle('showStats') }" class="bg-white dark:bg-gray-800 rounded-lg shadow">
<div class="p-4 border-b border-gray-200 dark:border-gray-700">
<div x-data="{ open: @entangle('showStats') }" class="bg-white rounded-lg shadow">
<div class="p-4 border-b border-gray-200">
<button
type="button"
@click="open = !open"
class="flex justify-between items-center w-full"
>
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">
<h3 class="text-lg font-medium text-gray-900">
Review Statistics
</h3>
<span class="transform" :class="{ 'rotate-180': open }">
@@ -29,7 +29,7 @@
<div x-show="open" class="p-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="text-center">
<div class="text-3xl font-bold text-gray-900 dark:text-gray-100">
<div class="text-3xl font-bold text-gray-900">
{{ $statistics['average'] }}
</div>
<div class="text-sm text-gray-500">
@@ -37,7 +37,7 @@
</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-gray-900 dark:text-gray-100">
<div class="text-3xl font-bold text-gray-900">
{{ $statistics['total'] }}
</div>
<div class="text-sm text-gray-500">
@@ -47,12 +47,12 @@
<div class="col-span-1 md:col-span-1">
@foreach (range(5, 1) as $rating)
<div class="flex items-center">
<span class="w-8 text-sm text-gray-600 dark:text-gray-400">
<span class="w-8 text-sm text-gray-600">
{{ $rating }}
</span>
<div
x-data="{ width: '{{ $statistics['total'] > 0 ? number_format(($statistics['distribution'][$rating] / $statistics['total']) * 100, 1) : 0 }}%' }"
class="flex-1 h-4 mx-2 bg-gray-200 dark:bg-gray-700 rounded relative overflow-hidden"
class="flex-1 h-4 mx-2 bg-gray-200 rounded relative overflow-hidden"
>
@if ($statistics['total'] > 0)
<div
@@ -61,7 +61,7 @@
></div>
@endif
</div>
<span class="w-8 text-sm text-gray-600 dark:text-gray-400">
<span class="w-8 text-sm text-gray-600">
{{ $statistics['distribution'][$rating] }}
</span>
</div>
@@ -79,8 +79,8 @@
wire:click="sortBy('created_at')"
@class([
'px-3 py-2 text-sm font-medium rounded-md',
'bg-primary-100 text-primary-700 dark:bg-primary-800 dark:text-primary-200' => $sortField === 'created_at',
'text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700' => $sortField !== 'created_at',
'bg-primary-100 text-primary-700' => $sortField === 'created_at',
'text-gray-700 hover:bg-gray-100' => $sortField !== 'created_at',
])
>
Date
@@ -92,8 +92,8 @@
wire:click="sortBy('rating')"
@class([
'px-3 py-2 text-sm font-medium rounded-md',
'bg-primary-100 text-primary-700 dark:bg-primary-800 dark:text-primary-200' => $sortField === 'rating',
'text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700' => $sortField !== 'rating',
'bg-primary-100 text-primary-700' => $sortField === 'rating',
'text-gray-700 hover:bg-gray-100' => $sortField !== 'rating',
])
>
Rating
@@ -110,8 +110,8 @@
wire:click="filterByRating({{ $rating }})"
@class([
'px-3 py-2 text-sm font-medium rounded-md',
'bg-yellow-100 text-yellow-700 dark:bg-yellow-800 dark:text-yellow-200' => $ratingFilter === $rating,
'text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700' => $ratingFilter !== $rating,
'bg-yellow-100 text-yellow-700' => $ratingFilter === $rating,
'text-gray-700 hover:bg-gray-100' => $ratingFilter !== $rating,
])
>
{{ $rating }}
@@ -120,7 +120,7 @@
@if ($ratingFilter)
<button
wire:click="filterByRating(null)"
class="px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 rounded-md"
class="px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 rounded-md"
>
Clear
</button>
@@ -131,7 +131,7 @@
{{-- Reviews List --}}
<div class="space-y-4">
@forelse ($reviews as $review)
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<div class="bg-white rounded-lg shadow p-6">
<div class="flex justify-between items-start">
<div>
<div class="flex items-center gap-2">
@@ -141,12 +141,12 @@
@endfor
</div>
@if ($review->title)
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">
<h3 class="text-lg font-medium text-gray-900">
{{ $review->title }}
</h3>
@endif
</div>
<p class="mt-2 text-gray-600 dark:text-gray-400">
<p class="mt-2 text-gray-600">
{{ $review->content }}
</p>
</div>
@@ -162,8 +162,8 @@
wire:click="toggleHelpfulVote({{ $review->id }})"
@class([
'flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md',
'bg-green-100 text-green-700 dark:bg-green-800 dark:text-green-200' => $review->helpfulVotes->contains('user_id', Auth::id()),
'text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700' => !$review->helpfulVotes->contains('user_id', Auth::id()),
'bg-green-100 text-green-700' => $review->helpfulVotes->contains('user_id', Auth::id()),
'text-gray-700 hover:bg-gray-100' => !$review->helpfulVotes->contains('user_id', Auth::id()),
])
>
<span>Helpful</span>
@@ -172,7 +172,7 @@
</div>
</div>
@empty
<div class="text-center py-12 text-gray-500 dark:text-gray-400">
<div class="text-center py-12 text-gray-500">
@if ($ratingFilter)
No {{ $ratingFilter }}-star reviews yet.
@else

View File

@@ -2,12 +2,12 @@
<div class="flex flex-col lg:flex-row gap-8">
<!-- Filters Sidebar -->
<div class="lg:w-1/4">
<div class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow">
<h2 class="text-xl font-bold mb-4 dark:text-white">Filter Parks</h2>
<div class="bg-white p-6 rounded-lg shadow">
<h2 class="text-xl font-bold mb-4">Filter Parks</h2>
<div class="space-y-4">
<!-- Search with Autocomplete -->
<div class="flex flex-col">
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">
<label class="text-sm font-medium text-gray-700">
Search
</label>
<div class="mt-1">
@@ -20,42 +20,42 @@
<!-- Location -->
<div class="flex flex-col">
<label for="location" class="text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="location" class="text-sm font-medium text-gray-700">
Location
</label>
<div class="mt-1">
<input type="text"
wire:model.live="location"
id="location"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
placeholder="Filter by location...">
</div>
</div>
<!-- Rating Range -->
<div class="flex flex-col">
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">Rating Range</label>
<label class="text-sm font-medium text-gray-700">Rating Range</label>
<div class="flex gap-2 mt-1">
<input type="number"
wire:model.live="minRating"
min="0"
max="5"
step="0.1"
class="w-1/2 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"
class="w-1/2 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
placeholder="Min">
<input type="number"
wire:model.live="maxRating"
min="0"
max="5"
step="0.1"
class="w-1/2 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"
class="w-1/2 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
placeholder="Max">
</div>
</div>
<!-- Minimum Rides -->
<div class="flex flex-col">
<label for="minRides" class="text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="minRides" class="text-sm font-medium text-gray-700">
Minimum Rides
</label>
<div class="mt-1">
@@ -63,14 +63,14 @@
wire:model.live="minRides"
id="minRides"
min="0"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
placeholder="Minimum number of rides">
</div>
</div>
<!-- Minimum Coasters -->
<div class="flex flex-col">
<label for="minCoasters" class="text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="minCoasters" class="text-sm font-medium text-gray-700">
Minimum Coasters
</label>
<div class="mt-1">
@@ -78,7 +78,7 @@
wire:model.live="minCoasters"
id="minCoasters"
min="0"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
placeholder="Minimum number of coasters">
</div>
</div>
@@ -88,7 +88,7 @@
@if($filtersApplied)
<button wire:click="clearFilters"
type="button"
class="inline-flex justify-center py-2 px-4 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600">
class="inline-flex justify-center py-2 px-4 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
Clear Filters
</button>
@endif
@@ -99,27 +99,27 @@
<!-- Results Section -->
<div class="lg:w-3/4">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow">
<div class="p-6 border-b border-gray-200 dark:border-gray-700">
<div class="bg-white rounded-lg shadow">
<div class="p-6 border-b border-gray-200">
<div class="flex justify-between items-center">
<h2 class="text-xl font-bold dark:text-white">
<h2 class="text-xl font-bold">
Search Results
<span class="text-sm font-normal text-gray-500 dark:text-gray-400">({{ $results->total() }} found)</span>
<span class="text-sm font-normal text-gray-500">({{ $results->total() }} found)</span>
</h2>
</div>
</div>
<div class="divide-y divide-gray-200 dark:divide-gray-700">
<div class="divide-y divide-gray-200">
@forelse($results as $park)
<div class="p-6 flex flex-col md:flex-row gap-4">
<!-- Park Image -->
<div class="md:w-48 h-32 bg-gray-200 dark:bg-gray-700 rounded-lg overflow-hidden">
<div class="md:w-48 h-32 bg-gray-200 rounded-lg overflow-hidden">
@if($park->photos->isNotEmpty())
<img src="{{ $park->photos->first()->image_url }}"
alt="{{ $park->name }}"
class="w-full h-full object-cover">
@else
<div class="w-full h-full flex items-center justify-center text-gray-400 dark:text-gray-500">
<div class="w-full h-full flex items-center justify-center text-gray-400">
No Image
</div>
@endif
@@ -128,12 +128,12 @@
<!-- Park Details -->
<div class="flex-1">
<h3 class="text-lg font-semibold">
<a href="{{ route('parks.show', $park) }}" class="hover:text-blue-600 dark:text-white dark:hover:text-blue-400">
<a href="{{ route('parks.show', $park) }}" class="hover:text-blue-600">
{{ $park->name }}
</a>
</h3>
<div class="mt-2 text-sm text-gray-600 dark:text-gray-400">
<div class="mt-2 text-sm text-gray-600">
@if($park->formatted_location)
<p>{{ $park->formatted_location }}</p>
@endif
@@ -141,44 +141,44 @@
<div class="mt-2 flex flex-wrap gap-2">
@if($park->average_rating)
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-800 dark:text-green-100">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
{{ number_format($park->average_rating, 1) }}
</span>
@endif
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-800 dark:text-blue-100">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
{{ $park->status->label() }}
</span>
@if($park->ride_count)
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800 dark:bg-purple-800 dark:text-purple-100">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800">
{{ $park->ride_count }} Rides
</span>
@endif
@if($park->coaster_count)
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800 dark:bg-yellow-800 dark:text-yellow-100">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
{{ $park->coaster_count }} Coasters
</span>
@endif
</div>
@if($park->description)
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400 line-clamp-2">
<p class="mt-2 text-sm text-gray-600 line-clamp-2">
{{ $park->description }}
</p>
@endif
</div>
</div>
@empty
<div class="p-6 text-center text-gray-500 dark:text-gray-400">
<div class="p-6 text-center text-gray-500">
No parks found matching your criteria.
</div>
@endforelse
</div>
@if($results->hasPages())
<div class="px-6 py-4 border-t border-gray-200 dark:border-gray-700">
<div class="px-6 py-4 border-t border-gray-200">
{{ $results->links() }}
</div>
@endif

View File

@@ -10,7 +10,7 @@
>
<img
src="{{ auth()->user()->profile->avatar }}"
alt="{{ auth()->user()->username }}"
alt="{{ auth()->user()->name }}"
class="w-10 h-10 transition-all duration-200 rounded-full cursor-pointer ring-2 ring-primary/20 hover:scale-105 focus:outline-none focus:ring-2 focus:ring-primary/40"
/>
</button>
@@ -23,7 +23,7 @@
aria-label="User menu"
class="flex items-center justify-center w-10 h-10 text-lg font-semibold text-white transition-all duration-200 rounded-full cursor-pointer bg-gradient-to-br from-primary to-secondary hover:scale-105 focus:outline-none focus:ring-2 focus:ring-primary/40"
>
{{ ucfirst(auth()->user()->username[0]) }}
{{ ucfirst(auth()->user()->name[0]) }}
</button>
@endif
@@ -38,11 +38,11 @@
>
<div class="px-4 py-3 border-b border-gray-800/50">
<p class="text-sm text-gray-400">Signed in as</p>
<p class="text-sm font-medium text-white truncate">{{ auth()->user()->username }}</p>
<p class="text-sm font-medium text-white truncate">{{ auth()->user()->name }}</p>
</div>
<div class="py-1">
<a
href="{{ route('profile.show', auth()->user()->username) }}"
href="{{ route('profile') }}"
class="flex items-center w-full gap-3 px-4 py-2 text-gray-300 transition-colors hover:text-white hover:bg-gray-800/50 focus:outline-none focus:text-white focus:bg-gray-800/50"
role="menuitem"
>
@@ -50,14 +50,14 @@
<span>Profile</span>
</a>
<a
href="{{ route('settings') }}"
href="{{ route('profile') }}"
class="flex items-center w-full gap-3 px-4 py-2 text-gray-300 transition-colors hover:text-white hover:bg-gray-800/50 focus:outline-none focus:text-white focus:bg-gray-800/50"
role="menuitem"
>
<i class="w-5 fas fa-cog"></i>
<span>Settings</span>
</a>
@if(auth()->user()->can('access-admin'))
@if(auth()->user()->role === 'ADMIN')
<a
href="{{ route('admin.index') }}"
class="flex items-center w-full gap-3 px-4 py-2 text-gray-300 transition-colors hover:text-white hover:bg-gray-800/50 focus:outline-none focus:text-white focus:bg-gray-800/50"

View File

@@ -0,0 +1,26 @@
<nav class="-mx-3 flex flex-1 justify-end">
@auth
<a
href="{{ url('/dashboard') }}"
class="rounded-md px-3 py-2 text-black ring-1 ring-transparent transition hover:text-black/70 focus:outline-none focus-visible:ring-[#FF2D20] dark:text-white dark:hover:text-white/80 dark:focus-visible:ring-white"
>
Dashboard
</a>
@else
<a
href="{{ route('login') }}"
class="rounded-md px-3 py-2 text-black ring-1 ring-transparent transition hover:text-black/70 focus:outline-none focus-visible:ring-[#FF2D20] dark:text-white dark:hover:text-white/80 dark:focus-visible:ring-white"
>
Log in
</a>
@if (Route::has('register'))
<a
href="{{ route('register') }}"
class="rounded-md px-3 py-2 text-black ring-1 ring-transparent transition hover:text-black/70 focus:outline-none focus-visible:ring-[#FF2D20] dark:text-white dark:hover:text-white/80 dark:focus-visible:ring-white"
>
Register
</a>
@endif
@endauth
</nav>

View File

@@ -0,0 +1,62 @@
@extends('layouts.app')
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">Create New Operator</h1>
<a href="{{ route('operators.index') }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg">
Back to List
</a>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<form action="{{ route('operators.store') }}" method="POST">
@csrf
<div class="space-y-6">
<div>
<label for="name" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Name *
</label>
<input type="text" id="name" name="name" value="{{ old('name') }}" required
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
@error('name')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
<div>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Description
</label>
<textarea id="description" name="description" rows="4"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">{{ old('description') }}</textarea>
@error('description')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
<div>
<label class="flex items-center">
<input type="checkbox" name="is_active" value="1" {{ old('is_active', true) ? 'checked' : '' }}
class="rounded border-gray-300 text-blue-600 shadow-sm focus:ring-blue-500">
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">Active</span>
</label>
@error('is_active')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
</div>
<div class="flex justify-end space-x-2 mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
<a href="{{ route('operators.index') }}" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
Cancel
</a>
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Create Operator
</button>
</div>
</form>
</div>
</div>
@endsection

View File

@@ -0,0 +1,68 @@
@extends('layouts.app')
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">Edit Operator</h1>
<div class="flex space-x-2">
<a href="{{ route('operators.show', $operator) }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg">
View
</a>
<a href="{{ route('operators.index') }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg">
Back to List
</a>
</div>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<form action="{{ route('operators.update', $operator) }}" method="POST">
@csrf
@method('PUT')
<div class="space-y-6">
<div>
<label for="name" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Name *
</label>
<input type="text" id="name" name="name" value="{{ old('name', $operator->name) }}" required
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
@error('name')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
<div>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Description
</label>
<textarea id="description" name="description" rows="4"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">{{ old('description', $operator->description) }}</textarea>
@error('description')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
<div>
<label class="flex items-center">
<input type="checkbox" name="is_active" value="1" {{ old('is_active', $operator->is_active) ? 'checked' : '' }}
class="rounded border-gray-300 text-blue-600 shadow-sm focus:ring-blue-500">
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">Active</span>
</label>
@error('is_active')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
</div>
<div class="flex justify-end space-x-2 mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
<a href="{{ route('operators.show', $operator) }}" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
Cancel
</a>
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Update Operator
</button>
</div>
</form>
</div>
</div>
@endsection

View File

@@ -0,0 +1,77 @@
@extends('layouts.app')
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">Operators</h1>
<a href="{{ route('operators.create') }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Add New Operator
</a>
</div>
<!-- Search and Filters -->
<form method="GET" class="mb-6">
<div class="flex gap-4">
<input type="text" name="search" value="{{ request('search') }}"
placeholder="Search operators..."
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white">
<select name="status" class="px-4 py-2 border border-gray-300 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white">
<option value="">All Status</option>
<option value="active" {{ request('status') === 'active' ? 'selected' : '' }}>Active</option>
<option value="inactive" {{ request('status') === 'inactive' ? 'selected' : '' }}>Inactive</option>
</select>
<button type="submit" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg">
Search
</button>
</div>
</form>
<!-- Results -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden">
@forelse($operators as $operator)
<div class="p-6 border-b border-gray-200 dark:border-gray-700">
<div class="flex justify-between items-start">
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">
<a href="{{ route('operators.show', $operator) }}" class="hover:text-blue-600">
{{ $operator->name }}
</a>
</h3>
@if($operator->description)
<p class="text-gray-600 dark:text-gray-400 mt-2">{{ $operator->description }}</p>
@endif
<div class="flex items-center mt-2 space-x-4">
<span class="text-sm text-gray-500">
{{ $operator->created_at->format('M j, Y') }}
</span>
<span class="px-2 py-1 text-xs rounded-full {{ $operator->is_active ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' }}">
{{ $operator->is_active ? 'Active' : 'Inactive' }}
</span>
</div>
</div>
<div class="flex space-x-2">
<a href="{{ route('operators.edit', $operator) }}" class="text-blue-600 hover:text-blue-800">Edit</a>
<form action="{{ route('operators.destroy', $operator) }}" method="POST" class="inline">
@csrf
@method('DELETE')
<button type="submit" class="text-red-600 hover:text-red-800"
onclick="return confirm('Are you sure?')">Delete</button>
</form>
</div>
</div>
</div>
@empty
<div class="p-6 text-center text-gray-500 dark:text-gray-400">
No operators found.
</div>
@endforelse
</div>
<!-- Pagination -->
@if($operators->hasPages())
<div class="mt-6">
{{ $operators->links() }}
</div>
@endif
</div>
@endsection

View File

@@ -0,0 +1,73 @@
@extends('layouts.app')
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">{{ $operator->name }}</h1>
<div class="flex space-x-2">
<a href="{{ route('operators.edit', $operator) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Edit
</a>
<a href="{{ route('operators.index') }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg">
Back to List
</a>
</div>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Details</h3>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Name</label>
<p class="text-gray-900 dark:text-white">{{ $operator->name }}</p>
</div>
@if($operator->description)
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Description</label>
<p class="text-gray-900 dark:text-white">{{ $operator->description }}</p>
</div>
@endif
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Status</label>
<span class="px-2 py-1 text-xs rounded-full {{ $operator->is_active ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' }}">
{{ $operator->is_active ? 'Active' : 'Inactive' }}
</span>
</div>
</div>
</div>
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Metadata</h3>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Created</label>
<p class="text-gray-900 dark:text-white">{{ $operator->created_at->format('F j, Y \at g:i A') }}</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Last Updated</label>
<p class="text-gray-900 dark:text-white">{{ $operator->updated_at->format('F j, Y \at g:i A') }}</p>
</div>
</div>
</div>
</div>
<div class="flex justify-end space-x-2 mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
<form action="{{ route('operators.destroy', $operator) }}" method="POST" class="inline">
@csrf
@method('DELETE')
<button type="submit" class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg"
onclick="return confirm('Are you sure you want to delete this operator?')">
Delete Operator
</button>
</form>
</div>
</div>
</div>
@endsection

View File

@@ -0,0 +1,21 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Create New Park') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-4xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-medium text-gray-900">Add a New Theme Park</h3>
<p class="mt-1 text-sm text-gray-600">Create a new theme park entry with detailed information.</p>
</div>
<div class="p-6">
<livewire:park-form-component />
</div>
</div>
</div>
</div>
</x-app-layout>

View File

@@ -0,0 +1,21 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Edit Park: ') . $park->name }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-4xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-medium text-gray-900">Edit Park Information</h3>
<p class="mt-1 text-sm text-gray-600">Update the park details and information.</p>
</div>
<div class="p-6">
<livewire:park-form-component :park="$park" />
</div>
</div>
</div>
</div>
</x-app-layout>

View File

@@ -0,0 +1,13 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Parks') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<livewire:park-list-component />
</div>
</div>
</x-app-layout>

View File

@@ -1,163 +1,200 @@
<x-app-layout>
<x-slot name="title">{{ $park->name }}</x-slot>
<div class="container mx-auto px-4 py-8">
<div class="mb-6">
<div class="flex flex-wrap items-center justify-between">
<div>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">{{ $park->name }}</h1>
<div class="flex items-center mt-2 text-sm text-gray-600 dark:text-gray-300">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium {{ $park->status_classes }} mr-2">
{{ $park->status->name }}
</span>
@if ($park->operator)
<span>Operated by <a href="{{ route('operators.show', $park->operator) }}" class="text-blue-600 dark:text-blue-400 hover:underline">{{ $park->operator->name }}</a></span>
@endif
<x-slot name="header">
<div class="flex justify-between items-center">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ $park->name }}
</h2>
@auth
<div class="flex space-x-2">
<a href="{{ route('parks.edit', $park) }}"
class="inline-flex items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<svg class="-ml-1 mr-2 h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
Edit Park
</a>
</div>
</div>
<div class="mt-4 md:mt-0 flex space-x-2">
<a href="{{ route('parks.edit', $park) }}" class="inline-flex items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:bg-gray-600">
<svg class="-ml-1 mr-2 h-5 w-5 text-gray-500 dark:text-gray-300" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
</svg>
Edit Park
</a>
</div>
@endauth
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Main Content -->
<div class="lg:col-span-2 space-y-6">
<!-- Featured Photo -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden">
<div class="aspect-video bg-gray-100 dark:bg-gray-700">
<img
src="{{ $park->featured_photo_url }}"
alt="{{ $park->name }}"
class="w-full h-full object-cover"
>
</x-slot>
<div class="py-8">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<!-- Park Header -->
<div class="bg-white shadow rounded-lg mb-8">
<div class="px-6 py-8">
<div class="flex flex-col lg:flex-row lg:items-start lg:space-x-8">
<!-- Park Image Placeholder -->
<div class="w-full lg:w-1/3 mb-6 lg:mb-0">
<div class="aspect-video bg-gray-100 rounded-lg flex items-center justify-center">
@if($park->photos->count() > 0)
<img src="#" alt="{{ $park->name }}" class="w-full h-full object-cover rounded-lg">
@else
<div class="text-center">
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<p class="mt-2 text-sm text-gray-500">No photos available</p>
</div>
@endif
</div>
</div>
<!-- Park Details -->
<div class="flex-1">
<div class="flex flex-wrap gap-2 mb-4">
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium {{ $park->status_classes }}">
{{ $park->status->label() }}
</span>
@if($park->opening_date)
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-gray-100 text-gray-800">
Opened {{ date('F j, Y', strtotime($park->opening_date)) }}
</span>
@endif
</div>
@if($park->description)
<p class="text-gray-700 text-lg mb-6">{{ $park->description }}</p>
@endif
<!-- Park Stats -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
@if($park->ride_count)
<div class="text-center p-4 bg-blue-50 rounded-lg">
<div class="text-2xl font-bold text-blue-600">{{ $park->ride_count }}</div>
<div class="text-sm text-blue-600">Total Rides</div>
</div>
@endif
@if($park->coaster_count)
<div class="text-center p-4 bg-purple-50 rounded-lg">
<div class="text-2xl font-bold text-purple-600">{{ $park->coaster_count }}</div>
<div class="text-sm text-purple-600">Roller Coasters</div>
</div>
@endif
@if($park->size_acres)
<div class="text-center p-4 bg-green-50 rounded-lg">
<div class="text-2xl font-bold text-green-600">{{ number_format($park->size_acres) }}</div>
<div class="text-sm text-green-600">Acres</div>
</div>
@endif
@if($park->annual_attendance)
<div class="text-center p-4 bg-orange-50 rounded-lg">
<div class="text-2xl font-bold text-orange-600">{{ number_format($park->annual_attendance) }}</div>
<div class="text-sm text-orange-600">Annual Visitors</div>
</div>
@endif
</div>
<!-- Location and Operator -->
<div class="space-y-4">
@if($park->location)
<div class="flex items-start space-x-3">
<svg class="h-5 w-5 text-gray-400 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<div>
<div class="font-medium text-gray-900">Location</div>
<div class="text-gray-600">
{{ $park->location->city }}{{ $park->location->state ? ', ' . $park->location->state : '' }}{{ $park->location->country ? ', ' . $park->location->country : '' }}
</div>
</div>
</div>
@endif
@if($park->operator)
<div class="flex items-start space-x-3">
<svg class="h-5 w-5 text-gray-400 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
<div>
<div class="font-medium text-gray-900">Operator</div>
<div class="text-gray-600">{{ $park->operator->name }}</div>
</div>
</div>
@endif
@if($park->website)
<div class="flex items-start space-x-3">
<svg class="h-5 w-5 text-gray-400 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
</svg>
<div>
<div class="font-medium text-gray-900">Website</div>
<a href="{{ $park->website }}" target="_blank" class="text-blue-600 hover:text-blue-800">{{ $park->website }}</a>
</div>
</div>
@endif
</div>
</div>
</div>
</div>
</div>
<!-- Description -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-900 dark:text-white">About {{ $park->name }}</h2>
<div class="prose dark:prose-invert max-w-none">
@if ($park->description)
<p>{{ $park->description }}</p>
@else
<p class="text-gray-500 dark:text-gray-400">No description available.</p>
@endif
<!-- Park Areas and Rides -->
@if($park->areas->count() > 0)
<div class="bg-white shadow rounded-lg">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-medium text-gray-900">Park Areas & Attractions</h3>
</div>
<div class="p-6">
<div class="space-y-6">
@foreach($park->areas as $area)
<div class="border border-gray-200 rounded-lg p-4">
<div class="flex justify-between items-start mb-4">
<div>
<h4 class="text-lg font-semibold text-gray-900">{{ $area->name }}</h4>
@if($area->description)
<p class="text-gray-600 mt-1">{{ $area->description }}</p>
@endif
</div>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800">
{{ $area->type }}
</span>
</div>
@if($area->rides->count() > 0)
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
@foreach($area->rides as $ride)
<div class="border border-gray-100 rounded p-3 hover:bg-gray-50">
<div class="flex justify-between items-start">
<div class="flex-1">
<h5 class="font-medium text-gray-900">{{ $ride->name }}</h5>
<p class="text-sm text-gray-600">{{ $ride->category->label() }}</p>
@if($ride->opening_date)
<p class="text-xs text-gray-500">Opened {{ date('Y', strtotime($ride->opening_date)) }}</p>
@endif
</div>
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium {{ $ride->status_classes }}">
{{ $ride->status->label() }}
</span>
</div>
</div>
@endforeach
</div>
@else
<p class="text-gray-500 text-sm">No attractions listed for this area.</p>
@endif
</div>
@endforeach
</div>
</div>
</div>
</div>
<!-- Photo Gallery -->
<livewire:photo-gallery-component :park="$park" />
</div>
<!-- Sidebar -->
<div class="space-y-6">
<!-- Park Info -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6">
<h2 class="text-lg font-semibold mb-4 text-gray-900 dark:text-white">Park Information</h2>
<dl class="space-y-3 text-sm">
@if ($park->opening_date)
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Opened:</dt>
<dd class="text-gray-900 dark:text-white">{{ $park->opening_date->format('F j, Y') }}</dd>
</div>
@endif
@if ($park->closing_date)
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Closed:</dt>
<dd class="text-gray-900 dark:text-white">{{ $park->closing_date->format('F j, Y') }}</dd>
</div>
@endif
@if ($park->size_acres)
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Size:</dt>
<dd class="text-gray-900 dark:text-white">{{ $park->size_display }}</dd>
</div>
@endif
@if ($park->operating_season)
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Season:</dt>
<dd class="text-gray-900 dark:text-white">{{ $park->operating_season }}</dd>
</div>
@endif
@if ($park->website)
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Website:</dt>
<dd class="text-gray-900 dark:text-white">
<a href="{{ $park->website_url }}" target="_blank" rel="noopener noreferrer" class="text-blue-600 dark:text-blue-400 hover:underline">
Visit Website
</a>
</dd>
</div>
@endif
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Location:</dt>
<dd class="text-gray-900 dark:text-white">{{ $park->formatted_location ?: 'Unknown' }}</dd>
@else
<div class="bg-white shadow rounded-lg">
<div class="px-6 py-8 text-center">
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
</svg>
<h3 class="mt-2 text-sm font-medium text-gray-900">No areas or attractions</h3>
<p class="mt-1 text-sm text-gray-500">This park doesn't have any areas or attractions listed yet.</p>
</div>
</dl>
</div>
<!-- Statistics -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6">
<h2 class="text-lg font-semibold mb-4 text-gray-900 dark:text-white">Statistics</h2>
<dl class="space-y-3 text-sm">
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Total Rides:</dt>
<dd class="text-gray-900 dark:text-white">{{ $park->total_rides ?: 0 }}</dd>
</div>
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Roller Coasters:</dt>
<dd class="text-gray-900 dark:text-white">{{ $park->total_coasters ?: 0 }}</dd>
</div>
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Flat Rides:</dt>
<dd class="text-gray-900 dark:text-white">{{ $park->total_flat_rides ?: 0 }}</dd>
</div>
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Water Rides:</dt>
<dd class="text-gray-900 dark:text-white">{{ $park->total_water_rides ?: 0 }}</dd>
</div>
<div class="flex justify-between">
<dt class="font-medium text-gray-500 dark:text-gray-400">Areas:</dt>
<dd class="text-gray-900 dark:text-white">{{ $park->total_areas ?: 0 }}</dd>
</div>
</dl>
</div>
<!-- Location -->
@if ($park->location)
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden">
<livewire:location.location-map-component :location="$park->location" :height="300" />
</div>
@endif
<!-- Photo Upload -->
<livewire:photo-upload-component :park="$park" />
<!-- Photo Management -->
<livewire:photo-manager-component :park="$park" />
<!-- Featured Photo Selector -->
<livewire:featured-photo-selector-component :park="$park" />
</div>
</div>
</div>
</x-app-layout>
</x-app-layout>

View File

@@ -0,0 +1,23 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ $title }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
<div class="text-center">
<h3 class="text-lg font-medium text-gray-900 mb-4">{{ $message }}</h3>
<p class="text-gray-600 mb-6">This feature is part of the planned ThrillWiki application.</p>
<a href="{{ route('home') }}" class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150">
Back to Home
</a>
</div>
</div>
</div>
</div>
</div>
</x-app-layout>

View File

@@ -0,0 +1,29 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Profile') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
<div class="max-w-xl">
<livewire:profile.update-profile-information-form />
</div>
</div>
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
<div class="max-w-xl">
<livewire:profile.update-password-form />
</div>
</div>
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
<div class="max-w-xl">
<livewire:profile.delete-user-form />
</div>
</div>
</div>
</div>
</x-app-layout>

View File

@@ -0,0 +1,62 @@
@extends('layouts.app')
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">Create New Ride</h1>
<a href="{{ route('rides.index') }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg">
Back to List
</a>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<form action="{{ route('rides.store') }}" method="POST">
@csrf
<div class="space-y-6">
<div>
<label for="name" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Name *
</label>
<input type="text" id="name" name="name" value="{{ old('name') }}" required
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
@error('name')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
<div>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Description
</label>
<textarea id="description" name="description" rows="4"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">{{ old('description') }}</textarea>
@error('description')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
<div>
<label class="flex items-center">
<input type="checkbox" name="is_active" value="1" {{ old('is_active', true) ? 'checked' : '' }}
class="rounded border-gray-300 text-blue-600 shadow-sm focus:ring-blue-500">
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">Active</span>
</label>
@error('is_active')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
</div>
<div class="flex justify-end space-x-2 mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
<a href="{{ route('rides.index') }}" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
Cancel
</a>
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Create Ride
</button>
</div>
</form>
</div>
</div>
@endsection

View File

@@ -0,0 +1,68 @@
@extends('layouts.app')
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">Edit Ride</h1>
<div class="flex space-x-2">
<a href="{{ route('rides.show', $ride) }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg">
View
</a>
<a href="{{ route('rides.index') }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg">
Back to List
</a>
</div>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<form action="{{ route('rides.update', $ride) }}" method="POST">
@csrf
@method('PUT')
<div class="space-y-6">
<div>
<label for="name" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Name *
</label>
<input type="text" id="name" name="name" value="{{ old('name', $ride->name) }}" required
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
@error('name')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
<div>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Description
</label>
<textarea id="description" name="description" rows="4"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">{{ old('description', $ride->description) }}</textarea>
@error('description')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
<div>
<label class="flex items-center">
<input type="checkbox" name="is_active" value="1" {{ old('is_active', $ride->is_active) ? 'checked' : '' }}
class="rounded border-gray-300 text-blue-600 shadow-sm focus:ring-blue-500">
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">Active</span>
</label>
@error('is_active')
<p class="text-red-600 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
</div>
<div class="flex justify-end space-x-2 mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
<a href="{{ route('rides.show', $ride) }}" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
Cancel
</a>
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Update Ride
</button>
</div>
</form>
</div>
</div>
@endsection

View File

@@ -0,0 +1,77 @@
@extends('layouts.app')
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">Rides</h1>
<a href="{{ route('rides.create') }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Add New Ride
</a>
</div>
<!-- Search and Filters -->
<form method="GET" class="mb-6">
<div class="flex gap-4">
<input type="text" name="search" value="{{ request('search') }}"
placeholder="Search rides..."
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white">
<select name="status" class="px-4 py-2 border border-gray-300 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white">
<option value="">All Status</option>
<option value="active" {{ request('status') === 'active' ? 'selected' : '' }}>Active</option>
<option value="inactive" {{ request('status') === 'inactive' ? 'selected' : '' }}>Inactive</option>
</select>
<button type="submit" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg">
Search
</button>
</div>
</form>
<!-- Results -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden">
@forelse($rides as $ride)
<div class="p-6 border-b border-gray-200 dark:border-gray-700">
<div class="flex justify-between items-start">
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">
<a href="{{ route('rides.show', $ride) }}" class="hover:text-blue-600">
{{ $ride->name }}
</a>
</h3>
@if($ride->description)
<p class="text-gray-600 dark:text-gray-400 mt-2">{{ $ride->description }}</p>
@endif
<div class="flex items-center mt-2 space-x-4">
<span class="text-sm text-gray-500">
{{ $ride->created_at->format('M j, Y') }}
</span>
<span class="px-2 py-1 text-xs rounded-full {{ $ride->is_active ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' }}">
{{ $ride->is_active ? 'Active' : 'Inactive' }}
</span>
</div>
</div>
<div class="flex space-x-2">
<a href="{{ route('rides.edit', $ride) }}" class="text-blue-600 hover:text-blue-800">Edit</a>
<form action="{{ route('rides.destroy', $ride) }}" method="POST" class="inline">
@csrf
@method('DELETE')
<button type="submit" class="text-red-600 hover:text-red-800"
onclick="return confirm('Are you sure?')">Delete</button>
</form>
</div>
</div>
</div>
@empty
<div class="p-6 text-center text-gray-500 dark:text-gray-400">
No rides found.
</div>
@endforelse
</div>
<!-- Pagination -->
@if($rides->hasPages())
<div class="mt-6">
{{ $rides->links() }}
</div>
@endif
</div>
@endsection

View File

@@ -0,0 +1,73 @@
@extends('layouts.app')
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">{{ $ride->name }}</h1>
<div class="flex space-x-2">
<a href="{{ route('rides.edit', $ride) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Edit
</a>
<a href="{{ route('rides.index') }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg">
Back to List
</a>
</div>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Details</h3>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Name</label>
<p class="text-gray-900 dark:text-white">{{ $ride->name }}</p>
</div>
@if($ride->description)
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Description</label>
<p class="text-gray-900 dark:text-white">{{ $ride->description }}</p>
</div>
@endif
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Status</label>
<span class="px-2 py-1 text-xs rounded-full {{ $ride->is_active ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' }}">
{{ $ride->is_active ? 'Active' : 'Inactive' }}
</span>
</div>
</div>
</div>
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Metadata</h3>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Created</label>
<p class="text-gray-900 dark:text-white">{{ $ride->created_at->format('F j, Y \at g:i A') }}</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Last Updated</label>
<p class="text-gray-900 dark:text-white">{{ $ride->updated_at->format('F j, Y \at g:i A') }}</p>
</div>
</div>
</div>
</div>
<div class="flex justify-end space-x-2 mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
<form action="{{ route('rides.destroy', $ride) }}" method="POST" class="inline">
@csrf
@method('DELETE')
<button type="submit" class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg"
onclick="return confirm('Are you sure you want to delete this ride?')">
Delete Ride
</button>
</form>
</div>
</div>
</div>
@endsection

File diff suppressed because one or more lines are too long