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

@@ -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