diff --git a/app/Console/Commands/UpdateDepartedFlights.php b/app/Console/Commands/UpdateDepartedFlights.php
index c143a03..864f287 100644
--- a/app/Console/Commands/UpdateDepartedFlights.php
+++ b/app/Console/Commands/UpdateDepartedFlights.php
@@ -203,6 +203,7 @@ class UpdateDepartedFlights extends Command
'user_id' => $flight->user_id,
'title' => "Flight {$airlineCode}{$flightNumber} updated",
'body' => implode("\n", $changeDescriptions),
+ 'url' => '/u/'. $flight->user->name . '/flight/'. $flight->id,
]);
} else {
$this->info("No changes for {$airlineCode}{$flightNumber}");
@@ -211,6 +212,7 @@ class UpdateDepartedFlights extends Command
'user_id' => $flight->user_id,
'title' => "Flight {$airlineCode}{$flightNumber} updated — no changes",
'body' => "Your flight was completed and no updates were made to aircraft, registration, or departure/arrival times.",
+ 'url' => '/u/'. $flight->user->name . '/flight/'. $flight->id,
]);
}
diff --git a/app/Http/Controllers/AchievementController.php b/app/Http/Controllers/AchievementController.php
index 325ecb2..be5c780 100644
--- a/app/Http/Controllers/AchievementController.php
+++ b/app/Http/Controllers/AchievementController.php
@@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Models\Achievement;
+use App\Models\Country;
use App\Models\User;
use Illuminate\Http\Request;
use Inertia\Inertia;
@@ -30,4 +31,25 @@ class AchievementController extends Controller
'userAchievements' => $userAchievements,
]);
}
+
+ public function specific(User $user, Achievement $achievement)
+ {
+ $regions = match($achievement->internal_name){
+ 'fun_challenges.australian_states' => Country::where('code', 'AU')->first()->regions->toArray(),
+ 'fun_challenges.chinese_provinces' => Country::where('code', 'CN')->first()->regions->toArray(),
+ 'fun_challenges.canadian_provinces' => Country::where('code', 'CA')->first()->regions->toArray(),
+ 'fun_challenges.us_states' => Country::where('code', 'US')->first()->regions->toArray(),
+ default => [],
+ };
+
+ return Inertia::render('Profile/UserAchievement', [
+ 'user' => $user,
+ 'achievement' => $achievement,
+ 'userAchievement' => $user->achievements()->where('achievement_id', $achievement->id)->first(),
+ 'isFollowing' => auth()->check() && auth()->user()->isFollowing($user),
+ 'flight_api_url' => FlightProfileController::getUserFlightApiURL($user),
+ 'regions' => $regions,
+ ]);
+ }
+
}
diff --git a/app/Http/Controllers/FlightProfileController.php b/app/Http/Controllers/FlightProfileController.php
index 079bc9a..8bab328 100644
--- a/app/Http/Controllers/FlightProfileController.php
+++ b/app/Http/Controllers/FlightProfileController.php
@@ -10,13 +10,17 @@ use Inertia\Inertia;
class FlightProfileController extends Controller
{
+ public static function getUserFlightApiURL(User $user){
+ return '/data/user/'.$user->name.'/flights';
+ }
+
public function profileData(User $user, string $view, ?int $selectedFlightId = null) : array {
return [
'user' => $user,
'canEdit' => auth()->check() && auth()->id() === $user->id,
'initialView' => $view,
'selectedFlightId' => $selectedFlightId,
- 'flight_api_url' => '/data/user/'.$user->name.'/flights',
+ 'flight_api_url' => self::getUserFlightApiURL($user),
'isFollowing' => auth()->check() && auth()->user()->isFollowing($user),
];
}
diff --git a/app/Models/Achievement.php b/app/Models/Achievement.php
index 1f57d62..ca13693 100644
--- a/app/Models/Achievement.php
+++ b/app/Models/Achievement.php
@@ -39,13 +39,21 @@ class Achievement extends Model
'achievement_category_id',
'achievement_difficulty_id',
'threshold',
+ 'has_page',
];
protected $casts = [
+ 'has_page' => 'boolean',
'progressive' => 'boolean',
'threshold' => 'integer',
];
+
+ public function getRouteKeyName(): string
+ {
+ return 'internal_name';
+ }
+
// ---------------------------------------------------------------
// Relationships
// ---------------------------------------------------------------
diff --git a/database/migrations/2026_05_11_051100_add_achievement_pages.php b/database/migrations/2026_05_11_051100_add_achievement_pages.php
new file mode 100644
index 0000000..1f3fe5b
--- /dev/null
+++ b/database/migrations/2026_05_11_051100_add_achievement_pages.php
@@ -0,0 +1,47 @@
+boolean('has_page')->default(false);
+ });
+
+ $achievements = [
+ 'airlines_alliances.all_skyteam',
+ 'airlines_alliances.all_oneworld',
+ 'airlines_alliances.all_star_alliance',
+ 'airlines_alliances.all_vanilla_alliance',
+ 'fun_challenges.airline_alphabet',
+ 'fun_challenges.airport_alphabet',
+ 'fun_challenges.brazilian_states',
+ 'fun_challenges.us_states',
+ 'fun_challenges.australian_states',
+ 'fun_challenges.chinese_provinces',
+ 'fun_challenges.canadian_provinces',
+ 'countries_continents.all_continent_pairs_one_way',
+ 'countries_continents.all_continent_pairs_both_ways',
+ ];
+
+ foreach($achievements as $achievement) {
+ Achievement::where('internal_name', $achievement)->update(['has_page' => true]);
+ }
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ //
+ }
+};
diff --git a/resources/js/Components/FlightsGoneBy/AchievementCard.vue b/resources/js/Components/FlightsGoneBy/AchievementCard.vue
index fe8a7be..49971e5 100644
--- a/resources/js/Components/FlightsGoneBy/AchievementCard.vue
+++ b/resources/js/Components/FlightsGoneBy/AchievementCard.vue
@@ -1,13 +1,15 @@
-
+
@@ -54,6 +55,7 @@ const size = computed(() => props.size ? props.size + 'px' : '30px');
+
diff --git a/resources/js/Components/FlightsGoneBy/FlightToolTip.vue b/resources/js/Components/FlightsGoneBy/FlightToolTip.vue
new file mode 100644
index 0000000..8fdbf9e
--- /dev/null
+++ b/resources/js/Components/FlightsGoneBy/FlightToolTip.vue
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ flight.departure_airport.display_code }}
+ →
+ {{ flight.arrival_airport.display_code }}
+
+
+
+
+
+
+
+
+
diff --git a/resources/js/Components/FlightsGoneBy/Panels/PanelHeader.vue b/resources/js/Components/FlightsGoneBy/Panels/PanelHeader.vue
index 2e3ec70..22e30e1 100644
--- a/resources/js/Components/FlightsGoneBy/Panels/PanelHeader.vue
+++ b/resources/js/Components/FlightsGoneBy/Panels/PanelHeader.vue
@@ -1,9 +1,11 @@
-
+
diff --git a/resources/js/Components/FlightsGoneBy/ProfileHeader.vue b/resources/js/Components/FlightsGoneBy/ProfileHeader.vue
index e4909f4..0c92f44 100644
--- a/resources/js/Components/FlightsGoneBy/ProfileHeader.vue
+++ b/resources/js/Components/FlightsGoneBy/ProfileHeader.vue
@@ -2,6 +2,7 @@
import { usePage } from "@inertiajs/vue3";
import { computed, ref } from "vue";
import type { Flight, User, SharedProps } from "@/Types/types";
+import { Link } from "@inertiajs/vue3";
const props = defineProps<{
user: User
@@ -42,7 +43,11 @@ const follow = async () => {
FLIGHT HISTORY
-
{{ user.name }}
+
+
+ {{ user.name }}
+
+