diff --git a/app/Http/Controllers/Account/CommentController.php b/app/Http/Controllers/Account/CommentController.php index 87ef53e..dbdc3ea 100644 --- a/app/Http/Controllers/Account/CommentController.php +++ b/app/Http/Controllers/Account/CommentController.php @@ -17,7 +17,7 @@ class CommentController extends Controller $tour->comments()->create([ 'user_id' => auth()->id(), 'body' => $request->validated('body'), - 'status' => 1, // در انتظار تایید (طبق قرارداد: 1 = پیشنویس/فعال، 2 = منتشرشده) + 'status' => 1, ]); return back()->with('success', 'نظر شما با موفقیت ثبت شد.'); diff --git a/app/Http/Controllers/Account/FavoriteController.php b/app/Http/Controllers/Account/FavoriteController.php index 9094841..db20b84 100644 --- a/app/Http/Controllers/Account/FavoriteController.php +++ b/app/Http/Controllers/Account/FavoriteController.php @@ -15,7 +15,7 @@ class FavoriteController extends Controller $user = Auth::user(); - $favorites = Favorite::with('favoritable') // لود پلیمورفیک + $favorites = Favorite::with('favoritable') ->where('user_id', $user->id) ->orderByDesc('id') ->paginate(9); @@ -23,10 +23,6 @@ class FavoriteController extends Controller return view('account.favorites', compact('favorites')); } - /** - * افزودن/حذف به صورت toggle (اگر موجود بود حذف کن، اگر نبود بساز). - * این متد با پلیمورفیک بودن Favorite از هر دو مدل تور و پرواز پشتیبانی میکنه. - */ public function toggle(Request $request) { // چک اینکه کاربر ورود شدهست @@ -42,7 +38,7 @@ class FavoriteController extends Controller $type = $data['favoritable_type']; $id = $data['favoritable_id']; - // بررسی اینکه مدل درخواستی واقعاً وجود داره (مثلاً Tour یا Flight) + if (!class_exists($type)) { return back()->with('error', 'مدل معتبر نیست'); } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 3cf089e..fe88ded 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -13,9 +13,7 @@ use Illuminate\Support\Facades\Hash; class RegisterController extends Controller { - /** - * نمایش فرم ثبت نام - */ + public function index() { $provinces = Province::orderBy('name')->get(); @@ -24,9 +22,7 @@ class RegisterController extends Controller } - /** - * ثبت نام کاربر - */ + public function post(RegisterPostRequest $request) { @@ -86,9 +82,6 @@ class RegisterController extends Controller } - /** - * دریافت شهرستانهای یک استان - */ public function cities(Province $province) { $cities = City::where('province_id', $province->id) diff --git a/app/Http/Controllers/FlightController.php b/app/Http/Controllers/FlightController.php index ebb4e5d..c3d15ec 100644 --- a/app/Http/Controllers/FlightController.php +++ b/app/Http/Controllers/FlightController.php @@ -8,9 +8,7 @@ use Illuminate\Http\Request; class FlightController extends Controller { - /** - * لیست پروازهای فعال - */ + public function index(Request $request) { $query = Flight::query() @@ -56,9 +54,7 @@ class FlightController extends Controller } - /** - * جستجوی پروازها - */ + public function search(Request $request) { $query = Flight::query() @@ -108,15 +104,9 @@ class FlightController extends Controller } - /** - * جزئیات پرواز - */ + public function show(Flight $flight) { -// // فقط پرواز فعال قابل مشاهده باشد -// if (!$flight->isActive()) { -// abort(404); -// } $flight->load([ 'travelType', diff --git a/app/Http/Controllers/IndexController.php b/app/Http/Controllers/IndexController.php index 5527857..486663a 100644 --- a/app/Http/Controllers/IndexController.php +++ b/app/Http/Controllers/IndexController.php @@ -13,12 +13,12 @@ class IndexController extends Controller $tours = Tour::query() ->where('status', 1) ->orderByDesc('created_at') - ->paginate(6, ['*'], 'tours_page'); + ->paginate(3, ['*'], 'tours_page'); $flights = Flight::query() ->where('status', 1) ->orderByDesc('created_at') - ->paginate(6, ['*'], 'flights_page'); + ->paginate(3, ['*'], 'flights_page'); $latestTours= Tour::latest()->limit(6)->get(); $latestFlights = Flight::latest()->limit(6)->get(); diff --git a/app/Http/Controllers/TourController.php b/app/Http/Controllers/TourController.php index 0506838..49534c6 100644 --- a/app/Http/Controllers/TourController.php +++ b/app/Http/Controllers/TourController.php @@ -13,15 +13,15 @@ use Illuminate\Http\Request; class TourController extends Controller { - /** - * لیست / آرشیو تورها با قابلیت فیلتر - */ + public function index(Request $request) { $query = Tour::query() ->where('status', 1) ->with(['travelType', 'flights']); + + if ($request->filled('travel_type')) { $query->where('travel_type_id', $request->input('travel_type')); } @@ -44,15 +44,18 @@ class TourController extends Controller $query->latest(); } - $tours = $query->paginate(9); - $travelTypes = TravelType::where('status', 1)->get(); + if ($request->routeIs('index')) { - return view('tours.index', compact('tours', 'travelTypes')); + $tours = $query->latest()->limit(4)->get(); + return view('index', compact('tours')); + } else { + + $tours = $query->latest()->paginate(2); + $travelTypes = TravelType::where('status', 1)->get(); + return view('tours.index', compact('tours', 'travelTypes')); + } } - /** - * نمایش جزئیات یک تور - */ public function show(Tour $tour) { if ($tour->status != 1) { @@ -75,7 +78,7 @@ class TourController extends Controller ->where('travel_type_id', $tour->travel_type_id) ->where('id', '!=', $tour->id) ->latest() - ->limit(4) + ->limit(3) ->get(); $isFav = false; @@ -117,160 +120,3 @@ class TourController extends Controller ); } } - -// -//namespace App\Http\Controllers; -// -//use App\Models\Favorite; -//use App\Models\Tour; -//use App\Models\TravelType; -//use Illuminate\Http\Request; -// -//class TourController extends Controller -//{ -// /** -// * لیست / آرشیو تورها با قابلیت فیلتر -// */ -// public function index(Request $request) -// { -// $query = Tour::query() -// ->where('status', 1) -// ->with(['travelType', 'flights']); -// -// // فیلتر بر اساس نوع سفر -// if ($request->filled('travel_type')) { -// $query->where( -// 'travel_type_id', -// $request->input('travel_type') -// ); -// } -// -// // جستجو بر اساس عنوان -// if ($request->filled('q')) { -// $query->where( -// 'title', -// 'like', -// '%' . $request->input('q') . '%' -// ); -// } -// -// // حداقل قیمت -// if ($request->filled('price_min')) { -// $query->where( -// 'price', -// '>=', -// $request->input('price_min') -// ); -// } -// -// // حداکثر قیمت -// if ($request->filled('price_max')) { -// $query->where( -// 'price', -// '<=', -// $request->input('price_max') -// ); -// } -// -// // مرتبسازی -// if ($request->filled('sort')) { -// $query->orderBy( -// 'price', -// $request->input('sort') === 'desc' -// ? 'desc' -// : 'asc' -// ); -// } else { -// $query->latest(); -// } -// -// // صفحهبندی -// $tours = $query->paginate(9); -// -// // انواع سفر -// $travelTypes = TravelType::where('status', 1)->get(); -// -// return view( -// 'tours.index', -// compact('tours', 'travelTypes') -// ); -// } -// -// -// /** -// * حذف فیلترها -// */ -// public function removeFilters() -// { -// return redirect()->route('tours.index'); -// } -// -// -// /** -// * نمایش جزئیات یک تور -// */ -// public function show(Tour $tour) -// { -// // فقط تورهای فعال قابل مشاهده باشند -// if ($tour->status != 1) { -// abort(404); -// } -// -// // افزایش تعداد بازدید -// $tour->increment('views_count'); -// -// // بارگذاری اطلاعات مورد نیاز -// $tour->load([ -// 'flights', -// 'travelType', -// ]); -// -// // تورهای مرتبط -// $relatedTours = Tour::where('status', 1) -// ->where('travel_type_id', $tour->travel_type_id) -// ->where('id', '!=', $tour->id) -// ->latest() -// ->limit(4) -// ->get(); -// -// $isFav = false; -// -// if (auth()->check()) { -// $isFav = Favorite::where('user_id', auth()->id()) -// ->where('favoritable_type', Tour::class) -// ->where('favoritable_id', $tour->id) -// ->exists(); -// } -// -// -// return view( -// 'tours.show', -// compact('tour', 'relatedTours', 'isFav') -// ); -// } -// -// -// /** -// * جستجوی پیشنهادی -// */ -// public function searchSuggestion(Request $request) -// { -// $q = $request->input('q', ''); -// -// $tours = Tour::where('status', 1) -// ->where( -// 'title', -// 'like', -// '%' . $q . '%' -// ) -// ->limit(8) -// ->get([ -// 'id', -// 'title', -// 'slug', -// 'price' -// ]); -// -// return response()->json($tours); -// } -//} diff --git a/app/Http/Controllers/admin/AdminController.php b/app/Http/Controllers/admin/AdminController.php index 56e557f..98e4b25 100644 --- a/app/Http/Controllers/admin/AdminController.php +++ b/app/Http/Controllers/admin/AdminController.php @@ -67,8 +67,9 @@ class AdminController extends Controller public function update( AdminUpdateRequest $request, - Admin $admin - ) { + Admin $admin + ) + { $data = $request->validated(); $permissions = $data['permissions'] ?? []; @@ -96,7 +97,6 @@ class AdminController extends Controller ->with('success', 'مدیر با موفقیت ویرایش شد.'); } - public function destroy(Admin $admin) { $admin->permissions()->detach(); diff --git a/app/Http/Controllers/admin/CommentController.php b/app/Http/Controllers/admin/CommentController.php index 47d76bf..5bbb487 100644 --- a/app/Http/Controllers/admin/CommentController.php +++ b/app/Http/Controllers/admin/CommentController.php @@ -4,7 +4,6 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Http\Requests\CommentUpdateRequest; -use App\Http\Requests\UpdateCommentRequest; use App\Models\Comment; class CommentController extends Controller @@ -23,10 +22,6 @@ class CommentController extends Controller return view('admin.comments.show', compact('comment')); } -// public function edit(Comment $comment) -// { -// return view('admin.comments.edit', compact('comment')); -// } public function update(CommentUpdateRequest $request, Comment $comment) { diff --git a/app/Http/Controllers/admin/FlightController.php b/app/Http/Controllers/admin/FlightController.php index 3a56067..3332b8a 100644 --- a/app/Http/Controllers/admin/FlightController.php +++ b/app/Http/Controllers/admin/FlightController.php @@ -78,9 +78,7 @@ class FlightController extends Controller return view('admin.flights.show', compact('flight')); } - /** - * نمایش فرم ویرایش پرواز - */ + public function edit(Flight $flight) { abort_unless(auth('admin')->user()?->canManageFlights('update'), 403); @@ -90,9 +88,7 @@ class FlightController extends Controller return view('admin.flights.edit', compact('flight', 'travelTypes')); } - /** - * بروزرسانی پرواز - */ + public function update(FlightUpdateRequest $request, Flight $flight) { abort_unless(auth('admin')->user()?->canManageFlights('update'), 403); diff --git a/app/Http/Controllers/admin/TourController.php b/app/Http/Controllers/admin/TourController.php index d5330fd..ba4ba02 100644 --- a/app/Http/Controllers/admin/TourController.php +++ b/app/Http/Controllers/admin/TourController.php @@ -14,13 +14,9 @@ use Illuminate\Support\Str; class TourController extends Controller { - /** - * لیست تورها - */ + public function index() { - // همه تورها نمایش داده میشوند - // اگر فقط تورهای تایید شده را میخواهی: // ->where('status', 2) $tours = Tour::latest()->paginate(20); @@ -57,15 +53,6 @@ class TourController extends Controller $data['slug'] = Str::slug($data['title']); } - /* - * وضعیت تور - * - * 1 = در انتظار - * 2 = تایید شده - * - * اگر میخواهی تور بلافاصله در لیست نمایش داده شود، - * مقدار 2 قرار میدهیم. - */ $data['status'] = 2; // ایجاد تور @@ -114,17 +101,13 @@ class TourController extends Controller } } - /** - * نمایش جزئیات تور - */ + public function show(Tour $tour) { return view('admin.tours.show', compact('tour')); } - /** - * فرم ویرایش تور - */ + public function edit(Tour $tour) { $travelTypes = TravelType::all(); @@ -135,9 +118,7 @@ class TourController extends Controller ); } - /** - * بروزرسانی تور - */ + public function update( TourStoreRequest $request, Tour $tour @@ -153,10 +134,6 @@ class TourController extends Controller $data['slug'] = Str::slug($data['title']); } - /* - * اگر status از فرم ارسال نشده باشد، - * وضعیت فعلی تور حفظ شود. - */ if (!isset($data['status'])) { $data['status'] = $tour->status ?? 2; } @@ -217,9 +194,6 @@ class TourController extends Controller } } - /** - * حذف تصویر تور - */ public function removeImage(Tour $tour) { try { @@ -251,9 +225,7 @@ class TourController extends Controller } } - /** - * حذف تور - */ + public function destroy(Tour $tour) { try { diff --git a/app/Http/Controllers/admin/TravelTypeController.php b/app/Http/Controllers/admin/TravelTypeController.php index 48eae31..20c5ee8 100644 --- a/app/Http/Controllers/admin/TravelTypeController.php +++ b/app/Http/Controllers/admin/TravelTypeController.php @@ -10,9 +10,7 @@ use Illuminate\Http\Request; class TravelTypeController extends Controller { - /** - * لیست + جستجو + صفحهبندی انواع سفر - */ + public function index(Request $request) { abort_unless(auth('admin')->user()->canManageTravelTypes('view'), 403); @@ -27,7 +25,7 @@ class TravelTypeController extends Controller }); } - // فیلتر وضعیت (1=فعال، 0=غیرفعال) + // فیلتر وضعیت if ($request->filled('status')) { $query->where('status', $request->status); } diff --git a/app/Http/Controllers/admin/UserController.php b/app/Http/Controllers/admin/UserController.php index fb24212..002407e 100644 --- a/app/Http/Controllers/admin/UserController.php +++ b/app/Http/Controllers/admin/UserController.php @@ -16,7 +16,7 @@ class UserController extends Controller public function index(Request $request) { // چک دسترسی: فقط مدیرانی که مجوز «مشاهده کاربران» دارند - abort_unless(auth('admin')->user()->canManageUsers('view'), 403); +// abort_unless(auth('admin')->user()->canManageUsers('view'), 403); $query = User::query(); @@ -57,7 +57,7 @@ class UserController extends Controller public function update(UserUpdateRequest $request, User $user) { - abort_unless(auth('admin')->user()->canManageUsers('edit'), 403); +// abort_unless(auth('admin')->user()->canManageUsers('edit'), 403); $data = $request->validated(); @@ -82,14 +82,14 @@ class UserController extends Controller public function changePassword(User $user) { - abort_unless(auth('admin')->user()->canManageUsers('password'), 403); +// abort_unless(auth('admin')->user()->canManageUsers('password'), 403); return view('admin.users.change-password', compact('user')); } - public function updatePassword(UserUpdateRequest $request, User $user) + public function updatePassword(UserPasswordUpdateRequest $request, User $user) { - abort_unless(auth('admin')->user()->canManageUsers('password'), 403); +// abort_unless(auth('admin')->user()->canManageUsers('password'), 403); $user->update([ 'password' => Hash::make($request->password), diff --git a/app/Http/Requests/AirportStoreRequest.php b/app/Http/Requests/AirportStoreRequest.php index e1898ef..6f2584f 100644 --- a/app/Http/Requests/AirportStoreRequest.php +++ b/app/Http/Requests/AirportStoreRequest.php @@ -14,6 +14,7 @@ class AirportStoreRequest extends FormRequest { return true; } + protected function prepareForValidation(): void { // کد فرودگاه همیشه با حروف بزرگ ذخیره شود (IATA) @@ -68,18 +69,4 @@ class AirportStoreRequest extends FormRequest 'code' => 'کد فرودگاه', ]; } - -// public function messages(): array -// { -// return [ -// 'name.required' => 'نام فرودگاه الزامی است.', -// 'name.max' => 'نام فرودگاه حداکثر ۱۵۰ کاراکتر باشد.', -// 'city.required' => 'نام شهر الزامی است.', -// 'city.max' => 'نام شهر حداکثر ۱۰۰ کاراکتر باشد.', -// 'country.required' => 'نام کشور الزامی است.', -// 'country.max' => 'نام کشور حداکثر ۱۰۰ کاراکتر باشد.', -// 'code.required' => 'کد فرودگاه (IATA) الزامی است.', -// 'code.max' => 'کد فرودگاه حداکثر ۱۰ کاراکتر باشد.', -// ]; -// } } diff --git a/app/Http/Requests/Auth/RegisterPostRequest.php b/app/Http/Requests/Auth/RegisterPostRequest.php index 71b87cf..80b586a 100644 --- a/app/Http/Requests/Auth/RegisterPostRequest.php +++ b/app/Http/Requests/Auth/RegisterPostRequest.php @@ -30,8 +30,7 @@ class RegisterPostRequest extends FormRequest 'persian_alpha', 'string', 'min:3', - 'max:100', -// 'regex:/^[\x{0600}-\x{06FF}\x{200C}\s]+$/u', + 'max:100' ], @@ -39,8 +38,7 @@ class RegisterPostRequest extends FormRequest 'required', 'persian_alpha', 'string', - 'max:100', -// 'regex:/^[\x{0600}-\x{06FF}\x{200C}\s]+$/u', + 'max:100' ], @@ -70,8 +68,7 @@ class RegisterPostRequest extends FormRequest 'nullable', 'string', 'max:200', - 'required_if:marital_status,2', -// 'regex:/^[\x{0600}-\x{06FF}\x{200C}\s]+$/u', + 'required_if:marital_status,2' ], @@ -79,7 +76,6 @@ class RegisterPostRequest extends FormRequest 'required', 'digits:11', 'ir_mobile:zero', -// 'regex:/^09\d{9}$/', 'unique:users,mobile', ], @@ -98,7 +94,6 @@ class RegisterPostRequest extends FormRequest 'string', 'min:3', 'max:50', -// 'regex:/^[A-Za-z0-9]+$/', 'unique:users,username', ], diff --git a/app/Http/Requests/SettingUpdateRequest.php b/app/Http/Requests/SettingUpdateRequest.php index 00b2916..5a0b543 100644 --- a/app/Http/Requests/SettingUpdateRequest.php +++ b/app/Http/Requests/SettingUpdateRequest.php @@ -29,9 +29,7 @@ class SettingUpdateRequest extends FormRequest $this->merge($filtered); } - /** - * قوانین اعتبارسنجی. - */ + public function rules(): array { $codes = Setting::pluck('code')->all(); diff --git a/app/Http/Requests/UserStoreRequest.php b/app/Http/Requests/UserStoreRequest.php index f09db4a..da0a726 100644 --- a/app/Http/Requests/UserStoreRequest.php +++ b/app/Http/Requests/UserStoreRequest.php @@ -47,15 +47,4 @@ class UserStoreRequest extends FormRequest ], ]; } -// public function messages(): array -// { -// return [ -// 'name.required' => 'نام و نام خانوادگی الزامی است.', -// 'email.required' => 'ایمیل الزامی است.', -// 'email.email' => 'فرمت ایمیل معتبر نیست.', -// 'email.unique' => 'این ایمیل قبلاً ثبت شده است.', -// 'password.required' => 'رمز عبور الزامی است.', -// 'password.confirmed' => 'تکرار رمز عبور مطابقت ندارد.', -// ]; -// } } diff --git a/app/Http/Requests/UserUpdateRequest.php b/app/Http/Requests/UserUpdateRequest.php index 5e002ac..7118d01 100644 --- a/app/Http/Requests/UserUpdateRequest.php +++ b/app/Http/Requests/UserUpdateRequest.php @@ -23,19 +23,24 @@ class UserUpdateRequest extends FormRequest public function rules(): array { return [ - 'name' => + 'first_name' => [ 'required', 'string', - 'max:255' + 'max:100' + ], + 'last_name' => + [ + 'required', + 'string', + 'max:100' ], 'email' => [ - 'required', + 'nullable', 'email', 'max:255', - 'unique:users', - 'email,' . $this->user->id + 'unique:users,email,' . $this->user->id, ], 'mobile' => diff --git a/app/Models/Admin.php b/app/Models/Admin.php index fe5c62d..d678984 100644 --- a/app/Models/Admin.php +++ b/app/Models/Admin.php @@ -86,96 +86,3 @@ class Admin extends Authenticatable return $this->status == 1; } } -// -///** -// * Created by Reliese Model. -// */ -// -//namespace App\Models; -// -//use App\Enums\AdminStatus; -//use Carbon\Carbon; -//use Illuminate\Auth\Middleware\Authenticate; -//use Illuminate\Database\Eloquent\Factories\HasFactory; -//use Illuminate\Database\Eloquent\Model; -// -////use Illuminate\Foundation\Auth\Admin as User; -////use Illuminate\Foundation\Auth\Admin as Authenticate; -// -// -///** -// * Class Admin -// * -// * @property int $id -// * @property string $full_name -// * @property string $username -// * @property string $email -// * @property string $mobile -// * @property string $password -// * @property int $status -// * @property Carbon $created_at -// * @property Carbon $updated_at -// * -// * @package App\Models -// */ -//class Admin extends Authenticate -//{ -// protected $table = 'admins'; -// -// public static $snakeAttributes = false; -// -// protected $casts = [ -// 'status' => 'int', -// ]; -// -// protected $hidden = [ -// 'password', -// ]; -// -// protected $fillable = [ -// 'full_name', -// 'username', -// 'email', -// 'mobile', -// 'password', -// 'status', -// ]; -// -// public function permissions() -// { -// return $this->belongsToMany( -// Permission::class, -// 'admin_permission', -// 'admin_id', -// 'permission_id' -// ); -// } -// -// -// /** -// * بررسی دسترسی مدیر به ماژول مدیریت کاربران -// * -// * @param string $action view|edit|delete|password -// */ -// public function canManageUsers(string $action): bool -// { -// // مدیریت کاربران فقط برای مدیر فعال مجاز است -// return $this->status == 1; -// } -// -// -// public function canManageTravelTypes(string $action): bool -// { -// return $this->status == 1; -// } -// -// public function canManageFlights(string $action): bool -// { -// return $this->status == 1; -// } -// -// public function canManageTours(string $action): bool -// { -// return $this->status == 1; -// } -//} diff --git a/app/Models/Comment.php b/app/Models/Comment.php index 5fa55a0..4cf91a2 100644 --- a/app/Models/Comment.php +++ b/app/Models/Comment.php @@ -53,19 +53,9 @@ class Comment extends Model return $this->belongsTo(User::class); } - // ✅ رابطه پلیمورفیک: نظر میتونه متعلق به محصول، خبر، پست و... باشه + // رابطه پلیمورفیک public function commentable(): MorphTo { return $this->morphTo(); } - -// public function comment() -// { -// return $this->belongsTo(Comment::class, 'commentable_id'); -// } -// -// public function comments() -// { -// return $this->hasMany(Comment::class, 'commentable_id'); -// } } diff --git a/app/Models/Favorite.php b/app/Models/Favorite.php index c055108..ff6c853 100644 --- a/app/Models/Favorite.php +++ b/app/Models/Favorite.php @@ -47,7 +47,7 @@ class Favorite extends Model return $this->belongsTo(User::class); } - // رابطه پلیمورفیک: علاقهمندی میتونه به محصول، خبر، پست و... وصل باشه + // رابطه پلیمورفیک public function favoritable(): MorphTo { return $this->morphTo(); diff --git a/app/Models/Tour.php b/app/Models/Tour.php index ae878a1..71f1765 100644 --- a/app/Models/Tour.php +++ b/app/Models/Tour.php @@ -36,45 +36,45 @@ use Illuminate\Database\Eloquent\Model; */ class Tour extends Model { - protected $table = 'tours'; - public static $snakeAttributes = false; + protected $table = 'tours'; + public static $snakeAttributes = false; - protected $casts = [ - 'travel_type_id' => 'int', - 'start_date' => 'datetime', - 'end_date' => 'datetime', - 'price' => 'float', - 'capacity' => 'int', - 'views_count' => 'int', - 'status' => 'int' - ]; + protected $casts = [ + 'travel_type_id' => 'int', + 'start_date' => 'datetime', + 'end_date' => 'datetime', + 'price' => 'float', + 'capacity' => 'int', + 'views_count' => 'int', + 'status' => 'int' + ]; - protected $fillable = [ - 'travel_type_id', - 'title', - 'slug', - 'image', - 'description', - 'duration', - 'start_date', - 'end_date', - 'price', - 'capacity', - 'views_count', - 'status' - ]; + protected $fillable = [ + 'travel_type_id', + 'title', + 'slug', + 'image', + 'description', + 'duration', + 'start_date', + 'end_date', + 'price', + 'capacity', + 'views_count', + 'status' + ]; - public function travelType() - { - return $this->belongsTo(TravelType::class); - } + public function travelType() + { + return $this->belongsTo(TravelType::class); + } - public function flights() - { - return $this->belongsToMany(Flight::class, 'tour_flights') - ->withPivot('id') - ->withTimestamps(); - } + public function flights() + { + return $this->belongsToMany(Flight::class, 'tour_flights') + ->withPivot('id') + ->withTimestamps(); + } // در فایل App\Models\Tour.php و App\Models\Flight.php @@ -83,6 +83,23 @@ class Tour extends Model return $this->morphMany(Comment::class, 'commentable'); } + public function favorites() + { + return $this->morphMany(\App\Models\Favorite::class, 'favoritable'); + } + + + public function isFavoritedBy($user) + { + if (!$user) return false; + + // استفاده از فیلدهای پلیمورفیک به جای tour_id + return $this->favorites() + ->where('user_id', $user->id) + ->where('favoritable_id', $this->id) + ->where('favoritable_type', Tour::class) + ->exists(); + } protected static function booted() @@ -93,7 +110,8 @@ class Tour extends Model $tour->views_count = 0; } if (is_null($tour->status)) { - $tour->status = 0; // فرض بر اینکه 0 یعنی غیرفعال/پیشنویس + // فرض بر اینکه 0 یعنی غیرفعال یا پیشنویس + $tour->status = 0; } }); } diff --git a/public/assets/css/custom.css b/public/assets/css/custom.css index d68af3b..4816399 100644 --- a/public/assets/css/custom.css +++ b/public/assets/css/custom.css @@ -1,606 +1,178 @@ /* ========================================================= - Travel Agency - Home Page + تایپوگرافی و تنظیمات پایه (یکپارچه) ========================================================= */ - -.travel-page { - background: #f6f8fb; - min-height: 100vh; - padding: 60px 0; - direction: rtl; +body, html { + font-family: 'Tahoma', 'Arial', sans-serif !important; + /*font-size: 13px !important; !* متن اصلی خواناتر *!*/ + line-height: 1.8 !important; + color: #374151 !important; + /*background: #f5f7fa;*/ } -.travel-page .section-heading { - text-align: center; - margin-bottom: 35px; +h1, h2, h3, h4, h5 { + font-family: 'Tahoma', sans-serif !important; + color: #1f2937 !important; } -.travel-page .section-heading h2 { - font-size: 28px; - font-weight: 700; - color: #1f2937; - margin-bottom: 10px; +/* اصلاح فرمها */ +.form-control, input, select, textarea { + font-size: 12px !important; + padding: 10px 14px !important; } -.travel-page .section-heading p { - color: #7b8494; - font-size: 14px; - margin: 0; -} - - /* ========================================================= - Tour Cards + استایلهای کارتها (مشترک بین همه صفحات) ========================================================= */ - -.travel-page .travel-card { - background: #fff; - border-radius: 14px; - overflow: hidden; - border: 1px solid #edf0f4; - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.06); - transition: all .25s ease; - height: 100%; -} - -.travel-page .travel-card:hover { - transform: translateY(-6px); - box-shadow: 0 14px 30px rgba(0, 0, 0, 0.10); -} - - -/* تصویر کارت */ - -.travel-page .travel-card-image { - width: 100%; - height: 210px; - overflow: hidden; - background: #eef1f5; -} - -.travel-page .travel-card-image img { - width: 100%; - height: 100%; - display: block; - object-fit: cover; - transition: transform .35s ease; -} - -.travel-page .travel-card:hover .travel-card-image img { - transform: scale(1.05); -} - - -/* بدنه کارت */ - -.travel-page .travel-card-body { - padding: 20px; -} - -.travel-page .travel-card-title { - font-size: 19px; - font-weight: 700; - color: #202936; - margin: 0 0 12px; -} - -.travel-page .travel-card-summary { - color: #737d8d; - font-size: 14px; - line-height: 1.9; - min-height: 52px; - margin-bottom: 15px; -} - -.travel-page .travel-date { - color: #555f70; - font-size: 13px; - margin-bottom: 18px; -} - -.travel-page .travel-date i { - margin-left: 6px; - color: #1687d9; -} - - -/* ========================================================= - Buttons - ========================================================= */ - -.travel-page .travel-btn { - display: block; - text-align: center; - text-decoration: none !important; - background: #1687d9; - color: #fff !important; - border-radius: 8px; - padding: 10px 15px; - font-size: 14px; - transition: .2s; -} - -.travel-page .travel-btn:hover { - background: #0d6fae; -} - - -/* ========================================================= - Empty State - ========================================================= */ - -.travel-page .empty-box { - background: #fff; - border: 1px dashed #d9dee7; - border-radius: 12px; - padding: 35px; - text-align: center; - color: #8a93a1; -} - - -/* ========================================================= - Pagination - ========================================================= */ - -.travel-page .pagination-wrapper { - display: flex; - justify-content: center; - margin-top: 30px; - direction: rtl; -} - -.travel-page .pagination-wrapper nav { - margin: 0; -} - - -/* ========================================================= - Flights - ========================================================= */ - -.travel-page .flights-section { - margin-top: 80px; -} - -.travel-page .flight-card { - background: #fff; - border-radius: 14px; - border: 1px solid #edf0f4; - padding: 22px; - height: 100%; - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.05); - transition: all .25s ease; -} - -.travel-page .flight-card:hover { - transform: translateY(-5px); - box-shadow: 0 14px 30px rgba(0, 0, 0, 0.09); -} - -.travel-page .flight-icon { - width: 50px; - height: 50px; - border-radius: 50%; - background: #e9f5ff; - color: #1687d9; - display: flex; - align-items: center; - justify-content: center; - font-size: 21px; - margin-bottom: 17px; -} - -.travel-page .flight-title { - font-size: 19px; - font-weight: 700; - color: #202936; - margin-bottom: 12px; -} - -.travel-page .flight-summary { - color: #737d8d; - font-size: 14px; - line-height: 1.9; - min-height: 52px; - margin-bottom: 14px; -} - -.travel-page .flight-date { - color: #555f70; - font-size: 13px; - margin-bottom: 18px; -} - - -/* ========================================================= - Responsive - ========================================================= */ - -@media (max-width: 767px) { - - .travel-page { - padding: 35px 15px; - } - - .travel-page .section-heading h2 { - font-size: 23px; - } - - .travel-page .travel-card-image { - height: 190px; - } - - .travel-page .flights-section { - margin-top: 55px; - } - -} - - -.tour-details-page { - direction: rtl; - padding: 50px 0; - background: #f7f8fa; -} - -.tour-details-card { - max-width: 1050px; - margin: auto; +.travel-card, .flight-card, .tour-card, .tour-details-card { background: #fff; border-radius: 16px; - overflow: hidden; - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08); + border: 1px solid #eef0f5; + transition: all .3s ease; } +.travel-card:hover, .flight-card:hover, .tour-details-card:hover { + box-shadow: 0 10px 25px rgba(20, 50, 90, .10); +} + +/* دکمههای اصلی */ +.travel-btn { + display: inline-block; + background: #1687d9; + color: #fff !important; + font-size: 12px; + font-weight: 400; + padding: 10px 20px; + border-radius: 8px; + text-decoration: none; +} +.travel-btn:hover { background: #0e6bb0; } + +/* دکمه علاقهمندی */ +.travel-favorite-btn { + display: inline-flex; + align-items: center; + gap: 8px; + background: transparent; + border: 1px solid #e0245e; + color: #e0245e; + border-radius: 25px; + padding: 8px 20px; + font-size: 12px; + cursor: pointer; + transition: all .2s ease; +} +.travel-favorite-btn:hover, .travel-favorite-btn.active { + background: #e0245e; + color: #fff; +} + +/* ========================================================= + بخش اختصاصی جزئیات تور (tour-details-page) + ========================================================= */ +.tour-details-page { padding: 30px 0; } + +.tour-details-card { padding: 30px; margin-bottom: 30px; } + .tour-details-image { width: 100%; - height: 400px; + height: 350px; overflow: hidden; + border-radius: 12px; + margin-bottom: 20px; } - -.tour-details-image img { - width: 100%; - height: 100%; - object-fit: cover; - display: block; -} - -.tour-no-image { - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - background: #eeeeee; - color: #777; -} - -.tour-details-content { - padding: 35px; -} - -.tour-details-title { - margin: 0 0 25px; - font-size: 32px; - font-weight: 700; - color: #222; -} +.tour-details-image img { width: 100%; height: 100%; object-fit: cover; } .tour-details-info { display: grid; - grid-template-columns: repeat(4, 1fr); + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 15px; - margin-bottom: 35px; + margin: 25px 0; } .tour-info-box { - padding: 20px; - background: #f7f8fa; - border-radius: 12px; + background: #f8fafc; + padding: 15px; + border-radius: 10px; text-align: center; + border: 1px solid #eef0f5; } .tour-info-label { display: block; - color: #888; - font-size: 13px; - margin-bottom: 8px; -} - -.tour-info-box strong { - color: #222; - font-size: 15px; -} - -.tour-description { - border-top: 1px solid #eee; - padding-top: 30px; -} - -.tour-description h2, -.tour-flights h2, -.related-tours h2 { - margin-bottom: 20px; - font-size: 22px; -} - -.tour-description p { - color: #555; - line-height: 2.2; - font-size: 15px; -} - -.tour-flights { - margin-top: 35px; - padding-top: 30px; - border-top: 1px solid #eee; -} - -.flight-item { - display: flex; - justify-content: space-between; - gap: 20px; - padding: 18px; - margin-bottom: 10px; - background: #f7f8fa; - border-radius: 10px; -} - -.flight-item span { - display: block; - color: #888; - font-size: 13px; + font-size: 12px; + color: #8a93a3; margin-bottom: 5px; } -.related-tours { - margin-top: 40px; - padding-top: 30px; - border-top: 1px solid #eee; -} - -.related-tours-grid { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 15px; -} - -.related-tour-card { +.tour-info-box strong { + font-size: 13px; + color: #1f2937; display: block; - overflow: hidden; - background: #f7f8fa; +} + +.tour-flights .flight-item { + background: #f8fafc; + padding: 15px; border-radius: 10px; - color: inherit; - text-decoration: none; -} - -.related-tour-card img { - width: 100%; - height: 130px; - object-fit: cover; - display: block; -} - -.related-tour-card div { - padding: 12px; -} - -.related-tour-card h3 { - margin: 0 0 8px; - font-size: 15px; -} - -.related-tour-card span { - color: #888; - font-size: 12px; -} - -.tour-back { - margin-top: 35px; -} - -.tour-back-button { - display: inline-block; - padding: 12px 25px; - background: #222; - color: #fff; - border-radius: 8px; - text-decoration: none; -} - -.tour-back-button:hover { - color: #fff; - text-decoration: none; - opacity: .9; -} - -@media (max-width: 768px) { - - .tour-details-page { - padding: 20px 10px; - } - - .tour-details-image { - height: 250px; - } - - .tour-details-content { - padding: 20px; - } - - .tour-details-title { - font-size: 25px; - } - - .tour-details-info { - grid-template-columns: 1fr 1fr; - } - - .related-tours-grid { - grid-template-columns: 1fr 1fr; - } - - .flight-item { - flex-direction: column; - } + margin-bottom: 10px; + display: flex; + justify-content: space-between; } /* ========================================================= - Main Navbar - RTL Fix -========================================================= */ - -#main-nav { - direction: rtl; - width: 100%; + عنوان بخشها (Global Header Style) + ========================================================= */ +h2 { + font-size: 15px !important; + font-weight: 500 !important; + padding-right: 15px; position: relative; - z-index: 1000; + margin-bottom: 20px !important; } - -#main-nav .container { - width: 100%; -} - -#main-nav .navbar-inner { - display: flex; - align-items: center; - min-height: 80px; -} - -/* لوگو */ -#main-nav .navbar-header { - float: none; - flex-shrink: 0; -} - -#main-nav .navbar-brand { - display: flex; - align-items: center; - height: 80px; - padding: 10px 0 10px 30px; -} - -#main-nav .navbar-brand img { - max-height: 55px; - width: auto; -} - - -/* بخش منو */ -#main-nav .navbar-collapse { - display: flex !important; - align-items: center; - justify-content: space-between; - flex: 1; - border: 0; - box-shadow: none; -} - - -/* منوی اصلی */ -#main-nav .navbar-nav { - float: none !important; - display: flex; - align-items: center; - margin: 0; -} - -#main-nav .navbar-nav > li { - float: none; -} - -#main-nav .navbar-nav > li > a { - display: flex; - align-items: center; - min-height: 80px; - padding: 0 16px; - white-space: nowrap; -} - - -/* منوی سمت راست */ -#main-nav .navbar-nav.navbar-right { - margin-right: auto; - margin-left: 0; -} - - -/* آیکون حساب */ -#main-nav .navbar-nav-item-user-icon { - margin-left: 7px; - font-size: 18px; -} - - -/* Dropdown */ -#main-nav .dropdown-menu { +h2::before { + content: ""; + position: absolute; right: 0; - left: auto; - min-width: 180px; - text-align: right; + top: 2px; + width: 5px; + height: 24px; + /*background: #1687d9;*/ + border-radius: 4px; +} +/* ========================================================= + حفظ رنگ سفید در هیرو (travel-hero) + این قانون باید بعد از قانون سراسری h1 قرار بگیرد + ========================================================= */ + +.travel-hero-content h1, +.travel-hero-content h1 span { + color: #ffffff !important; + text-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); } -#main-nav .navbar-right .dropdown-menu { - right: auto; - left: 0; +/* متنهای دیگر هیرو هم سفید و خوانا */ +.travel-hero-label, +.travel-hero-content p { + color: #ffffff !important; + text-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); } - -/* موبایل */ -@media (max-width: 767px) { - - #main-nav .navbar-inner { - display: block; - min-height: auto; - } - - #main-nav .navbar-header { - display: flex; - align-items: center; - justify-content: space-between; - min-height: 70px; - } - - #main-nav .navbar-brand { - height: 70px; - padding: 8px 0; - } - - #main-nav .navbar-toggle { - float: left; - margin-left: 0; - margin-right: 15px; - } - - #main-nav .navbar-collapse { - display: block !important; - width: 100%; - padding: 0; - } - - #main-nav .navbar-nav { - display: block; - width: 100%; - } - - #main-nav .navbar-nav > li { - display: block; - width: 100%; - } - - #main-nav .navbar-nav > li > a { - min-height: 45px; - padding: 12px 15px; - display: block; - } - - #main-nav .navbar-nav.navbar-right { - margin: 0; - } - - #main-nav .dropdown-menu { - position: static; - float: none; - width: 100%; - box-shadow: none; - } +.travel-card { + display: flex; + flex-direction: column; + border-radius: 8px; + overflow: hidden; + background: #fff; + transition: transform 0.3s ease; +} + +.travel-card-image img { + width: 100%; + height: 200px; + object-fit: cover; +} + +.travel-card-body { + padding: 15px; + flex-grow: 1; } diff --git a/resources/views/account/bookings.blade.php b/resources/views/account/bookings.blade.php deleted file mode 100644 index 2a24a5d..0000000 --- a/resources/views/account/bookings.blade.php +++ /dev/null @@ -1,3 +0,0 @@ -
+ دیدگاههایی که برای تورها و پروازها ثبت کردهاید +
++ بعد از خرید یا رزرو تور و پرواز، میتوانید نظر خود را ثبت کنید. +
+ + + + مشاهده تورها + + +هنوز کامنتی ثبت نکردهاید.
+ @endforelse +هنوز موردی به علاقهمندیها اضافه نکردهاید.
+ @endforelse +--}} -{{-- مدیریت مدیران و سطح دسترسی پنل--}} -{{--
--}} - -{{--| --}} -{{-- #--}} -{{-- | --}} - -{{----}} -{{-- مدیر--}} -{{-- | --}} - -{{----}} -{{-- نام کاربری--}} -{{-- | --}} - -{{----}} -{{-- اطلاعات تماس--}} -{{-- | --}} - -{{----}} -{{-- دسترسیها--}} -{{-- | --}} - -{{----}} -{{-- وضعیت--}} -{{-- | --}} - -{{----}} -{{-- تاریخ ایجاد--}} -{{-- | --}} - -{{----}} -{{-- عملیات--}} -{{-- | --}} - -{{--
|---|---|---|---|---|---|---|---|
| --}} -{{-- {{ $admin->id }}--}} -{{-- | --}} - - -{{-- --}}{{-- نام مدیر --}} - -{{----}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- --}}
-{{-- {{ $admin->full_name }}--}}
-{{-- --}}
-
-{{-- --}}
-{{-- مدیر پنل--}}
-{{-- --}}
-
-{{-- | --}}
-
-
-{{-- --}}{{-- username --}}
-
-{{-- --}} - -{{-- --}} - -{{-- --}} - -{{-- {{ $admin->username }}--}} - -{{-- --}} - -{{-- | --}} - - -{{-- --}}{{-- اطلاعات تماس --}} - -{{----}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- {{ $admin->email }}--}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- {{ $admin->mobile }}--}}
-
-{{-- --}}
-
-{{-- | --}}
-
-
-{{-- --}}{{-- Permissionها --}}
-
-{{-- --}} - -{{-- @forelse($admin->permissions as $permission)--}} - -{{-- --}} - -{{-- {{ $permission->name }}--}} - -{{-- --}} - -{{-- @empty--}} - -{{-- --}} - -{{-- بدون دسترسی--}} - -{{-- --}} - -{{-- @endforelse--}} - -{{-- | --}} - - -{{-- --}}{{-- وضعیت --}} - -{{----}} - -{{-- @if((int) $admin->status === 1)--}} - -{{-- --}} - -{{-- --}} - -{{-- فعال--}} - -{{-- --}} - -{{-- @else--}} - -{{-- --}} - -{{-- --}} - -{{-- غیرفعال--}} - -{{-- --}} - -{{-- @endif--}} - -{{-- | --}} - - -{{-- --}}{{-- تاریخ ایجاد --}} - -{{----}} - -{{-- @if($admin->created_at)--}} - -{{-- --}} - -{{-- {{ $admin->created_at->toJalali()->format('H:i Y/m/d') }}--}} - -{{-- --}} - -{{-- @else--}} - -{{-- ---}} - -{{-- @endif--}} - -{{-- | --}} - - -{{-- --}}{{-- عملیات --}} - -{{----}}
-
-{{-- --}}
-
-{{-- --}}{{-- ویرایش --}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- --}}
-
-
-{{-- --}}{{-- حذف --}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- | --}}
-
-{{--
| --}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- مدیری برای نمایش وجود ندارد.--}}
-
-{{-- --}}
-
-{{-- | --}}
-
-{{-- |||||||
--}} -{{-- مدیریت مدیران پنل آژانس هواپیمایی--}} -{{--
--}} - -{{--| --}} -{{-- #--}} -{{-- | --}} - -{{----}} -{{-- نام و نام خانوادگی--}} -{{-- | --}} - -{{----}} -{{-- نام کاربری--}} -{{-- | --}} - -{{----}} -{{-- ایمیل--}} -{{-- | --}} - -{{----}} -{{-- موبایل--}} -{{-- | --}} - -{{----}} -{{-- وضعیت--}} -{{-- | --}} - -{{----}} -{{-- تاریخ ایجاد--}} -{{-- | --}} - -{{----}} -{{-- عملیات--}} -{{-- | --}} - -{{--
|---|---|---|---|---|---|---|---|
| --}} -{{-- {{ $admin->id }}--}} -{{-- | --}} - - -{{----}} - -{{-- --}} -{{-- {{ $admin->full_name }}--}} -{{-- --}} - -{{-- | --}} - - -{{----}} - -{{-- --}} -{{-- {{ $admin->username }}--}} -{{-- --}} - -{{-- | --}} - - -{{----}} - -{{-- {{ $admin->email }}--}} - -{{-- | --}} - - -{{----}} - -{{-- {{ $admin->mobile }}--}} - -{{-- | --}} - - -{{----}} - -{{-- @if((int) $admin->status === 1)--}} - -{{-- --}} -{{-- فعال--}} -{{-- --}} - -{{-- @else--}} - -{{-- --}} -{{-- غیرفعال--}} -{{-- --}} - -{{-- @endif--}} - -{{-- | --}} - - -{{----}} - -{{-- {{ optional($admin->created_at)->format('Y/m/d') }}--}} - -{{-- | --}} - - -{{----}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- --}}
-
-
-{{-- --}}
-
-{{-- --}}
-
-{{-- | --}}
-
-{{--
| --}}
-
-{{-- --}}
-
-{{-- مدیری برای نمایش وجود ندارد.--}}
-
-{{-- --}}
-
-{{-- | --}}
-
-{{-- |||||||
- - به پنل مدیریت آژانس هواپیمایی خوش آمدید. - -
- ---}} - -{{-- به پنل مدیریت آژانس هواپیمایی خوش آمدید.--}} - -{{--
--}} - -{{----}} -{{-- از منوی سمت راست میتوانید بخشهای مختلف سیستم را مدیریت کنید.--}} -{{--
--}} - -{{----}} -{{-- به پنل مدیریت آژانس هواپیمایی خوش آمدید.--}} -{{--
--}} - -{{----}} -{{-- از منوی سمت راست میتوانید بخشهای مختلف سیستم را مدیریت کنید.--}} -{{--
--}} - -{{--
+ {{ $comment->commentable?->title ?? 'مورد حذفشده' }} +
+ + {{ class_basename($comment->commentable_type) }} + ++ {{ $comment->body }} +
+ + {{-- تاریخ ثبت --}} +