diff --git a/app/Http/Controllers/UserProfileController.php b/app/Http/Controllers/UserProfileController.php index eded32e..83bc82c 100644 --- a/app/Http/Controllers/UserProfileController.php +++ b/app/Http/Controllers/UserProfileController.php @@ -16,6 +16,10 @@ use Inertia\Inertia; class UserProfileController extends Controller { + public function currentUserCanEditProfile(User $profileUser){ + return auth()->check() && (auth()->id() === $profileUser->id || auth()->user()->hasRole('admin')); + } + public function index(){ if (auth()->check()) { $user = auth()->user(); @@ -39,7 +43,7 @@ class UserProfileController extends Controller return [ 'user' => $user, 'canView' => Gate::allows('viewProfileData', $user), - 'canEdit' => auth()->check() && (auth()->id() === $user->id || auth()->user()->hasRole('admin')), + 'canEdit' => $this->currentUserCanEditProfile($user), 'initialView' => $view, 'selectedFlightId' => $selectedFlightId, 'followStatus' => auth()->check() ? auth()->user()->followStatus($user) : 'none', @@ -85,10 +89,11 @@ class UserProfileController extends Controller return Inertia::render('UserFlight', [ 'flightCount' => $user->departedFlights()->count(), 'flight' => $userFlight->snapshot($userFlight->id), - 'canEdit' => auth()->check() && auth()->id() === $user->id, + 'canEdit' => $this->currentUserCanEditProfile($user), 'canView' => Gate::allows('viewProfileData', $user), 'user' => $user, 'followStatus' => auth()->check() ? auth()->user()->followStatus($user) : 'none', + 'otherUsersOnFlight' => $userFlight->otherUsersOnFlight(), ]); } @@ -128,6 +133,26 @@ class UserProfileController extends Controller ]); } + public function copyFlight(UserFlight $flight) + { + $loggedInUser = auth()->user(); + + $exists = UserFlight::where('user_id', $loggedInUser->id) + ->where('departure_airport_id', $flight->departure_airport_id) + ->where('arrival_airport_id', $flight->arrival_airport_id) + ->exists(); + + if ($exists) { + return back()->withErrors(['flight' => 'You already have a flight logged between these airports on this date.']); + } + + $newFlight = $flight->replicate(); + $newFlight->user_id = $loggedInUser->id; + $newFlight->save(); + + return redirect()->route('flights.edit', ['flight' => $newFlight->id]); + } + public function achievement(User $user, Achievement $achievement) { $regions = match($achievement->internal_name){ diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index d9cd4cc..b0d7d29 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -39,6 +39,10 @@ class HandleInertiaRequests extends Middleware 'permissions' => $request->user()?->getAllPermissions()->pluck('name') ?? [], 'apiToken' => session('api_token'), ], + 'flash' => [ + 'success' => $request->session()->get('success'), + 'error' => $request->session()->get('error'), + ], 'achievement_notifications' => fn() => $request->user() ? $request->user() ->notifications() diff --git a/app/Models/UserFlight.php b/app/Models/UserFlight.php index ed8e2d5..8b572ce 100644 --- a/app/Models/UserFlight.php +++ b/app/Models/UserFlight.php @@ -182,6 +182,20 @@ class UserFlight extends Model return !$this->isDomestic(); } + public function otherUsersOnFlight(){ + return UserFlight::where('user_id', '!=', $this->user_id) + ->where('departure_airport_id', $this->departure_airport_id) + ->where('arrival_airport_id', $this->arrival_airport_id) + ->where('flight_number', $this->flight_number) + ->where('airline_id', $this->airline_id) + ->whereRaw('DATE(departure_date AT TIME ZONE \'UTC\') = ?', [ + Carbon::parse($this->departure_date)->utc()->toDateString() + ]) + ->with('user') + ->get() + ->pluck('user.name'); + } + public static function snapshot($userFlightId): array { return UserFlight::with([ diff --git a/app/Observers/FlightObserver.php b/app/Observers/FlightObserver.php index 80a58a1..07234bd 100644 --- a/app/Observers/FlightObserver.php +++ b/app/Observers/FlightObserver.php @@ -14,7 +14,7 @@ class FlightObserver //Make queued task if the site gets big $flight->user->followers() ->get() - ->each(fn ($follower) => Cache::forget("user_following_flights_{$follower->id}")); + ->each(fn ($follower) => Cache::forget("user_following_flights_{$follower->user_id}")); } diff --git a/app/Settings/SettingsRegistry.php b/app/Settings/SettingsRegistry.php index 4b60348..ad23a45 100644 --- a/app/Settings/SettingsRegistry.php +++ b/app/Settings/SettingsRegistry.php @@ -79,7 +79,7 @@ class SettingsRegistry 'type' => 'checkbox', 'label' => 'Hide Map Filters By Default', 'category' => 'FlightsGoneBy Settings', - 'default' => false, + 'default' => true, ], [ 'key' => 'hide_impossible_achievements', @@ -111,8 +111,8 @@ class SettingsRegistry 'options' => [ ['value' => 'airline', 'label' => 'Airline'], ['value' => 'flight_number', 'label' => 'Flight Number'], - ['value' => 'from', 'label' => 'From'], - ['value' => 'to', 'label' => 'To'], + ['value' => 'departure_airport', 'label' => 'From'], + ['value' => 'arrival_airport', 'label' => 'To'], ['value' => 'departure_date', 'label' => 'Departure Date'], ['value' => 'departure_time', 'label' => 'Departure Time'], ['value' => 'arrival_time', 'label' => 'Arrival Time'], diff --git a/resources/js/Components/FlightsGoneBy/DepartureBoard.vue b/resources/js/Components/FlightsGoneBy/DepartureBoard.vue index cb0c24e..e4365df 100644 --- a/resources/js/Components/FlightsGoneBy/DepartureBoard.vue +++ b/resources/js/Components/FlightsGoneBy/DepartureBoard.vue @@ -24,8 +24,8 @@ const showColumn = (column: string) => columnsToShow.value.includes(column) const allHeaders = [ { title: '', key: 'airline', sortable: true }, { title: 'FLIGHT', key: 'flight_number', sortable: true }, - { title: 'FROM', key: 'from', sortable: true }, - { title: 'TO', key: 'to', sortable: true }, + { title: 'FROM', key: 'departure_airport', sortable: true }, + { title: 'TO', key: 'arrival_airport', sortable: true }, { title: 'DATE', key: 'departure_date', sortable: true }, { title: 'DEPART', key: 'departure_time', sortable: false }, { title: 'ARRIVE', key: 'arrival_time', sortable: false }, diff --git a/resources/js/Components/FlightsGoneBy/DepartureBoardTableRow.vue b/resources/js/Components/FlightsGoneBy/DepartureBoardTableRow.vue index 14d45ea..09e4ed8 100644 --- a/resources/js/Components/FlightsGoneBy/DepartureBoardTableRow.vue +++ b/resources/js/Components/FlightsGoneBy/DepartureBoardTableRow.vue @@ -49,14 +49,14 @@ const showColumn = (column: string) => props.columnsToShow.includes(column) - + {{ flight.departure_airport.display_code }}
{{ flight.departure_airport.municipality }} - + {{ flight.arrival_airport.display_code }}
diff --git a/resources/js/Components/FlightsGoneBy/Panels/AirlinePanel.vue b/resources/js/Components/FlightsGoneBy/Panels/AirlinePanel.vue index 50ae918..47c9835 100644 --- a/resources/js/Components/FlightsGoneBy/Panels/AirlinePanel.vue +++ b/resources/js/Components/FlightsGoneBy/Panels/AirlinePanel.vue @@ -40,26 +40,4 @@ defineProps<{ gap: 0.75rem; margin-bottom: 0.25rem; } - -.airline-logo-placeholder { - width: 42px; - height: 42px; - border-radius: 8px; - background: var(--accent-glow); - border: 1px solid rgba(56, 189, 248, 0.2); - display: flex; - align-items: center; - justify-content: center; - font-size: 0.75rem; - font-family: 'Share Tech Mono', monospace; - color: var(--accent); - flex-shrink: 0; -} - -.airline-name { - font-size: 1rem; - font-weight: 600; - color: var(--text); -} - diff --git a/resources/js/Components/FlightsGoneBy/Panels/Panel.vue b/resources/js/Components/FlightsGoneBy/Panels/Panel.vue index 44fe63f..dd7321c 100644 --- a/resources/js/Components/FlightsGoneBy/Panels/Panel.vue +++ b/resources/js/Components/FlightsGoneBy/Panels/Panel.vue @@ -1,4 +1,6 @@ + + + + diff --git a/resources/js/Components/FlightsGoneBy/StatusNotifications.vue b/resources/js/Components/FlightsGoneBy/StatusNotifications.vue new file mode 100644 index 0000000..597d105 --- /dev/null +++ b/resources/js/Components/FlightsGoneBy/StatusNotifications.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/resources/js/Components/FlightsGoneBy/ToastNotifications.vue b/resources/js/Components/FlightsGoneBy/ToastNotifications.vue new file mode 100644 index 0000000..144eb8b --- /dev/null +++ b/resources/js/Components/FlightsGoneBy/ToastNotifications.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/resources/js/Components/FlightsGoneBy/UserFlightContextMenu.vue b/resources/js/Components/FlightsGoneBy/UserFlightContextMenu.vue index 228df94..15af63e 100644 --- a/resources/js/Components/FlightsGoneBy/UserFlightContextMenu.vue +++ b/resources/js/Components/FlightsGoneBy/UserFlightContextMenu.vue @@ -1,9 +1,11 @@ + -