feat: implement tour listing with sorting and pagination

This commit is contained in:
2026-08-17 16:37:11 +03:30
parent 5350cd1742
commit 9dc27863e2
8 changed files with 392 additions and 2 deletions
+33
View File
@@ -0,0 +1,33 @@
<?php
namespace App\Http\Controllers;
use App\Models\Tour;
use Illuminate\Http\Request;
class TourController extends Controller
{
public function index(Request $request)
{
$title = 'تورها';
$sort = $request->query('sort', 'default');
$tours = Tour::with([
'originCity',
'city',
'tourDepartures',
])
->applySort($sort)
->paginate(3)
->withQueryString();
return view('tours.index', compact('title', 'tours', 'sort'));
}
public function show(Tour $tour)
{
$title= 'جزئیات تور';
return view('tours.show', compact('title'));
}
}
+22
View File
@@ -7,6 +7,8 @@
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
@@ -50,6 +52,26 @@ class Tour extends Model
'file_id',
'tour_type'
];
#[Scope]
protected function applySort(Builder $query, ?string $sort = null): void
{
switch ($sort) {
case 'lowest':
$query->withMin('tourDepartures', 'price')
->orderBy('tour_departures_min_price');
break;
case 'highest':
$query->withMax('tourDepartures', 'price')
->orderByDesc('tour_departures_max_price');
break;
default:
$query->orderByDesc('id');
break;
}
}
public function flight()
{
+2 -1
View File
@@ -2,6 +2,7 @@
namespace App\Providers;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
@@ -19,6 +20,6 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot(): void
{
//
Paginator::useBootstrapFive();
}
}
+36
View File
@@ -1,5 +1,8 @@
<?php
use App\Models\Tour;
use Carbon\Carbon;
if (!function_exists('generateSortRouteParameter')) {
function generateSortRouteParameter(string $sortKey): array
{
@@ -21,3 +24,36 @@ if (!function_exists('activeSort')) {
return 'text-gray-600 dark:text-gray-300 hover:text-blue-500';
}
}
if (!function_exists('tourDuration')) {
function tourDuration(Tour $tour): string
{
$departure = $tour->tourDepartures->first();
if (!$departure) {
return 'نامشخص';
}
$start = Carbon::parse($departure->start_date);
$end = Carbon::parse($departure->end_date);
$nights = $start->diffInDays($end);
$days = $nights + 1;
return "{$days} روز و {$nights} شب";
}
}
if (!function_exists('tourDateRange')) {
function tourDateRange(Tour $tour): string
{
$departure = $tour->tourDepartures->first();
if (!$departure) {
return 'تاریخ نامشخص';
}
$start = Verta::instance($departure->start_date);
$end = Verta::instance($departure->end_date);
return $start->format('Y/m/d') . ' - ' . $end->format('Y/m/d');
}
}