diff --git a/app/Console/Commands/SyncEndorsementActivities.php b/app/Console/Commands/SyncEndorsementActivities.php
index 68e44330..60772eea 100644
--- a/app/Console/Commands/SyncEndorsementActivities.php
+++ b/app/Console/Commands/SyncEndorsementActivities.php
@@ -156,6 +156,9 @@ protected function updateEndorsementActivity(EndorsementActivity $endorsementAct
}
}
+ $eligibleSince = $this->activityService->calculateEligibleSince($endorsementData);
+ $endorsementActivity->eligible_since = $eligibleSince;
+
$endorsementActivity->save();
} catch (\Exception $e) {
diff --git a/app/Http/Controllers/EndorsementController.php b/app/Http/Controllers/EndorsementController.php
index 839511ee..ccb7db7b 100644
--- a/app/Http/Controllers/EndorsementController.php
+++ b/app/Http/Controllers/EndorsementController.php
@@ -198,6 +198,7 @@ public function mentorView(Request $request): Response
'activityHours' => $activity->activity_hours,
'status' => $activity->status,
'progress' => $activity->progress,
+ 'eligibleSince' => $activity->eligible_since,
'removalDate' => $activity->removal_date?->format('Y-m-d'),
'removalDays' => $activity->removal_date
? $activity->removal_date->diffInDays(now(), false)
@@ -305,6 +306,7 @@ public function mentorView(Request $request): Response
'userPermissions' => [
'canRemoveForPositions' => $canRemovePositions,
'canRemoveAny' => ($user->is_superuser || $user->is_admin) || (!empty($canRemovePositions) && count($canRemovePositions) > 0),
+ 'isAdmin' => $user->is_superuser || $user->is_admin,
],
]);
}
diff --git a/app/Models/EndorsementActivity.php b/app/Models/EndorsementActivity.php
index 3ec79b10..48d3c441 100644
--- a/app/Models/EndorsementActivity.php
+++ b/app/Models/EndorsementActivity.php
@@ -18,6 +18,7 @@ class EndorsementActivity extends Model
'last_updated',
'last_activity_date',
'removal_date',
+ 'eligible_since',
'removal_notified',
'created_at_vateud',
];
@@ -27,6 +28,7 @@ class EndorsementActivity extends Model
'last_updated' => 'datetime',
'last_activity_date' => 'date',
'removal_date' => 'date',
+ 'eligible_since' => 'datetime',
'removal_notified' => 'boolean',
'created_at_vateud' => 'datetime',
];
diff --git a/app/Services/VatsimActivityService.php b/app/Services/VatsimActivityService.php
index c8afef31..380bc6ea 100644
--- a/app/Services/VatsimActivityService.php
+++ b/app/Services/VatsimActivityService.php
@@ -280,4 +280,177 @@ public function getActivityProgress(float $activityMinutes): float
$minRequiredMinutes = config('services.vateud.min_activity_minutes', 180);
return min(($activityMinutes / $minRequiredMinutes) * 100, 100);
}
+
+ protected function getVatsimConnectionsTwoYears(int $vatsimId): array
+ {
+ $cacheKey = "vatsim_activity_2y:{$vatsimId}";
+
+ return Cache::remember($cacheKey, now()->addHours(6), function () use ($vatsimId) {
+ $start = Carbon::now()->subYears(2)->format('Y-m-d');
+ $apiUrl = "http://stats.vatsim-germany.org/api/atc/{$vatsimId}/sessions/?start_date={$start}";
+
+ try {
+ $response = Http::timeout(15)
+ ->retry(2, 1000)
+ ->get($apiUrl);
+
+ if (!$response->successful()) {
+ return [];
+ }
+
+ $data = $response->json();
+ return is_array($data) ? $data : [];
+
+ } catch (\Exception $e) {
+ Log::error('Error fetching 2y VATSIM connections', [
+ 'vatsim_id' => $vatsimId,
+ 'error' => $e->getMessage(),
+ ]);
+ return [];
+ }
+ });
+ }
+
+ protected function extractRelevantSessions(array $endorsement, array $connections): array
+ {
+ $sessions = [];
+ $position = $endorsement['position'];
+ $inTransition = Carbon::now()->lessThan(Carbon::parse($this->transitionEndDate));
+
+ foreach ($connections as $connection) {
+ $callsign = $connection['callsign'] ?? '';
+ $minutes = floatval($connection['minutes_online'] ?? 0);
+ $date = $this->parseConnectionDate($connection);
+
+ if (!$date || $minutes <= 0) {
+ continue;
+ }
+
+ $matches = false;
+
+ if (str_ends_with($position, '_CTR')) {
+ $ctrlPrefix = substr($position, 0, 6);
+
+ if (str_starts_with($callsign, $ctrlPrefix) ||
+ ($position === 'EDWW_W_CTR' && $callsign === 'EDWW_CTR')) {
+ $matches = true;
+ }
+ } else {
+ $parts = explode('_', $position);
+ if (count($parts) >= 2) {
+ $airport = $parts[0];
+ $station = end($parts);
+
+ $ctrStations = $this->ctrTopdown[$airport] ?? [];
+ $legacyCtrStations = $inTransition ? ($this->legacyCtrTopdown[$airport] ?? []) : [];
+ $appStations = $this->appTopdown[$airport] ?? [];
+
+ $matchesSuffix = $this->suffixCondition($airport, $station, $callsign);
+
+ $matchesCtr = false;
+
+ $ctrAllowedStations = ['APP', 'TWR', 'GNDDEL'];
+
+ if (in_array($station, $ctrAllowedStations, true)) {
+ $allCtrStations = array_unique(array_merge($ctrStations, $legacyCtrStations));
+
+ foreach ($allCtrStations as $ctrStation) {
+ if (str_starts_with($callsign, $ctrStation)) {
+ $matchesCtr = true;
+ break;
+ }
+ }
+
+ if (!$matchesCtr && $station !== 'APP') {
+ foreach ($appStations as $appStation) {
+ if (str_starts_with($callsign, $appStation)) {
+ $matchesCtr = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!$matchesCtr && $station === 'APP') {
+ foreach ($appStations as $appStation) {
+ if (str_starts_with($callsign, $appStation)) {
+ $matchesCtr = true;
+ break;
+ }
+ }
+ }
+
+ $matches = $matchesCtr || $matchesSuffix;
+ }
+ }
+
+ if ($matches) {
+ $sessions[] = [
+ 'date' => $date,
+ 'minutes' => $minutes,
+ ];
+ }
+ }
+
+ usort($sessions, fn($a, $b) => $a['date']->lt($b['date']) ? -1 : 1);
+
+ return $sessions;
+ }
+
+ public function calculateEligibleSince(array $endorsement): ?Carbon
+ {
+ $connections = $this->getVatsimConnectionsTwoYears($endorsement['user_cid']);
+ $sessions = $this->extractRelevantSessions($endorsement, $connections);
+
+ // No sessions in 2 years -> no value
+ if (empty($sessions)) {
+ return null;
+ }
+
+ $requiredMinutes = config('services.vateud.min_activity_minutes', 180);
+
+ $events = [];
+
+ foreach ($sessions as $session) {
+ $events[] = [
+ 'date' => $session['date']->copy(),
+ 'delta' => $session['minutes'],
+ ];
+
+ $events[] = [
+ 'date' => $session['date']->copy()->addDays(180),
+ 'delta' => -$session['minutes'],
+ ];
+ }
+
+ usort($events, function ($a, $b) {
+ return $a['date']->timestamp <=> $b['date']->timestamp;
+ });
+
+ $runningMinutes = 0;
+ $eligibleSince = null;
+
+ foreach ($events as $event) {
+ $before = $runningMinutes;
+
+ $runningMinutes += $event['delta'];
+
+ if (
+ $before >= $requiredMinutes &&
+ $runningMinutes < $requiredMinutes
+ ) {
+ $eligibleSince = $event['date']->copy();
+ }
+
+ if ($runningMinutes >= $requiredMinutes) {
+ $eligibleSince = null;
+ }
+ }
+
+ if ($runningMinutes < $requiredMinutes) {
+ return $eligibleSince;
+ }
+
+ return null;
+ }
}
diff --git a/database/migrations/2026_05_13_125344_add_eligible_since_to_endorsement_activities.php b/database/migrations/2026_05_13_125344_add_eligible_since_to_endorsement_activities.php
new file mode 100644
index 00000000..9f861982
--- /dev/null
+++ b/database/migrations/2026_05_13_125344_add_eligible_since_to_endorsement_activities.php
@@ -0,0 +1,30 @@
+timestamp('eligible_since')
+ ->nullable()
+ ->after('removal_date');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('endorsement_activities', function (Blueprint $table) {
+ $table->dropColumn('eligible_since');
+ });
+ }
+};
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index ff29950b..116a0b2a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,7 +5,7 @@
"packages": {
"": {
"dependencies": {
- "@emnapi/core": "1.9.1",
+ "@emnapi/core": "1.10.0",
"@emnapi/runtime": "1.10.0",
"@headlessui/react": "^2.2.9",
"@inertiajs/react": "^2.3.6",
@@ -48,7 +48,7 @@
"next-themes": "^0.4.6",
"react": "^19.2.5",
"react-day-picker": "^9.13.0",
- "react-dom": "^19.2.3",
+ "react-dom": "^19.2.5",
"recharts": "2.15.4",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
@@ -61,7 +61,7 @@
"zod": "^4.3.6"
},
"devDependencies": {
- "@biomejs/biome": "2.4.13",
+ "@biomejs/biome": "2.4.15",
"@laravel/vite-plugin-wayfinder": "^0.1.7",
"@types/node": "^22.19.3",
"@types/ziggy-js": "^1.8.0"
@@ -77,9 +77,9 @@
}
},
"node_modules/@biomejs/biome": {
- "version": "2.4.13",
- "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.13.tgz",
- "integrity": "sha512-gLXOwkOBBg0tr7bDsqlkIh4uFeKuMjxvqsrb1Tukww1iDmHcfr4Uu8MoQxp0Rcte+69+osRNWXwHsu/zxT6XqA==",
+ "version": "2.4.15",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.15.tgz",
+ "integrity": "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==",
"dev": true,
"license": "MIT OR Apache-2.0",
"bin": {
@@ -93,20 +93,20 @@
"url": "https://opencollective.com/biome"
},
"optionalDependencies": {
- "@biomejs/cli-darwin-arm64": "2.4.13",
- "@biomejs/cli-darwin-x64": "2.4.13",
- "@biomejs/cli-linux-arm64": "2.4.13",
- "@biomejs/cli-linux-arm64-musl": "2.4.13",
- "@biomejs/cli-linux-x64": "2.4.13",
- "@biomejs/cli-linux-x64-musl": "2.4.13",
- "@biomejs/cli-win32-arm64": "2.4.13",
- "@biomejs/cli-win32-x64": "2.4.13"
+ "@biomejs/cli-darwin-arm64": "2.4.15",
+ "@biomejs/cli-darwin-x64": "2.4.15",
+ "@biomejs/cli-linux-arm64": "2.4.15",
+ "@biomejs/cli-linux-arm64-musl": "2.4.15",
+ "@biomejs/cli-linux-x64": "2.4.15",
+ "@biomejs/cli-linux-x64-musl": "2.4.15",
+ "@biomejs/cli-win32-arm64": "2.4.15",
+ "@biomejs/cli-win32-x64": "2.4.15"
}
},
"node_modules/@biomejs/cli-darwin-arm64": {
- "version": "2.4.13",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.13.tgz",
- "integrity": "sha512-2KImO1jhNFBa2oWConyr0x6flxbQpGKv6902uGXpYM62Xyem8U80j441SyUJ8KyngsmKbQjeIv1q2CQfDkNnYg==",
+ "version": "2.4.15",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.15.tgz",
+ "integrity": "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==",
"cpu": [
"arm64"
],
@@ -121,9 +121,9 @@
}
},
"node_modules/@biomejs/cli-darwin-x64": {
- "version": "2.4.13",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.13.tgz",
- "integrity": "sha512-BKrJklbaFN4p1Ts4kPBczo+PkbsHQg57kmJ+vON9u2t6uN5okYHaSr7h/MutPCWQgg2lglaWoSmm+zhYW+oOkg==",
+ "version": "2.4.15",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.15.tgz",
+ "integrity": "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==",
"cpu": [
"x64"
],
@@ -138,9 +138,9 @@
}
},
"node_modules/@biomejs/cli-linux-arm64": {
- "version": "2.4.13",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.13.tgz",
- "integrity": "sha512-NzkUDSqfvMBrPplKgVr3aXLHZ2NEELvvF4vZxXulEylKWIGqlvNEcwUcj9OLrn75TD3lJ/GIqCVlBwd1MZCuYQ==",
+ "version": "2.4.15",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.15.tgz",
+ "integrity": "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==",
"cpu": [
"arm64"
],
@@ -155,9 +155,9 @@
}
},
"node_modules/@biomejs/cli-linux-arm64-musl": {
- "version": "2.4.13",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.13.tgz",
- "integrity": "sha512-U5MsuBQW25dXaYtqWWSPM3P96H6Y+fHuja3TQpMNnylocHW0tEbtFTDlUj6oM+YJLntvEkQy4grBvQNUD4+RCg==",
+ "version": "2.4.15",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.15.tgz",
+ "integrity": "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==",
"cpu": [
"arm64"
],
@@ -172,9 +172,9 @@
}
},
"node_modules/@biomejs/cli-linux-x64": {
- "version": "2.4.13",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.13.tgz",
- "integrity": "sha512-Az3ZZedYRBo9EQzNnD9SxFcR1G5QsGo6VEc2hIyVPZ1rdKwee/7E9oeBBZFpE8Z44ekxsDQBqbiWGW5ShOhUSQ==",
+ "version": "2.4.15",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.15.tgz",
+ "integrity": "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==",
"cpu": [
"x64"
],
@@ -189,9 +189,9 @@
}
},
"node_modules/@biomejs/cli-linux-x64-musl": {
- "version": "2.4.13",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.13.tgz",
- "integrity": "sha512-Z601MienRgTBDza/+u2CH3RSrWoXo9rtr8NK6A4KJzqGgfxx+H3VlyLgTJ4sRo40T3pIsqpTmiOQEvYzQvBRvQ==",
+ "version": "2.4.15",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.15.tgz",
+ "integrity": "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==",
"cpu": [
"x64"
],
@@ -206,9 +206,9 @@
}
},
"node_modules/@biomejs/cli-win32-arm64": {
- "version": "2.4.13",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.13.tgz",
- "integrity": "sha512-Px9PS2B5/Q183bUwy/5VHqp3J2lzdOCeVGzMpphYfl8oSa7VDCqenBdqWpy6DCy/en4Rbf/Y1RieZF6dJPcc9A==",
+ "version": "2.4.15",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.15.tgz",
+ "integrity": "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==",
"cpu": [
"arm64"
],
@@ -223,9 +223,9 @@
}
},
"node_modules/@biomejs/cli-win32-x64": {
- "version": "2.4.13",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.13.tgz",
- "integrity": "sha512-tTcMkXyBrmHi9BfrD2VNHs/5rYIUKETqsBlYOvSAABwBkJhSDVb5e7wPukftsQbO3WzQkXe6kaztC6WtUOXSoQ==",
+ "version": "2.4.15",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.15.tgz",
+ "integrity": "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==",
"cpu": [
"x64"
],
@@ -246,12 +246,12 @@
"license": "MIT"
},
"node_modules/@emnapi/core": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz",
- "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
"license": "MIT",
"dependencies": {
- "@emnapi/wasi-threads": "1.2.0",
+ "@emnapi/wasi-threads": "1.2.1",
"tslib": "^2.4.0"
}
},
@@ -265,9 +265,9 @@
}
},
"node_modules/@emnapi/wasi-threads": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz",
- "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+ "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
"license": "MIT",
"dependencies": {
"tslib": "^2.4.0"
@@ -4613,15 +4613,15 @@
}
},
"node_modules/react-dom": {
- "version": "19.2.4",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
- "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
+ "version": "19.2.5",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz",
+ "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==",
"license": "MIT",
"dependencies": {
"scheduler": "^0.27.0"
},
"peerDependencies": {
- "react": "^19.2.4"
+ "react": "^19.2.5"
}
},
"node_modules/react-is": {
diff --git a/package.json b/package.json
index a0186738..d188f5f7 100644
--- a/package.json
+++ b/package.json
@@ -9,13 +9,13 @@
"types": "tsc --noEmit"
},
"devDependencies": {
- "@biomejs/biome": "2.4.13",
+ "@biomejs/biome": "2.4.15",
"@laravel/vite-plugin-wayfinder": "^0.1.7",
"@types/node": "^22.19.3",
"@types/ziggy-js": "^1.8.0"
},
"dependencies": {
- "@emnapi/core": "1.9.1",
+ "@emnapi/core": "1.10.0",
"@emnapi/runtime": "1.10.0",
"@headlessui/react": "^2.2.9",
"@inertiajs/react": "^2.3.6",
@@ -58,7 +58,7 @@
"next-themes": "^0.4.6",
"react": "^19.2.5",
"react-day-picker": "^9.13.0",
- "react-dom": "^19.2.3",
+ "react-dom": "^19.2.5",
"recharts": "2.15.4",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
diff --git a/resources/js/pages/endorsements/manage.tsx b/resources/js/pages/endorsements/manage.tsx
index b3d89697..be725a86 100644
--- a/resources/js/pages/endorsements/manage.tsx
+++ b/resources/js/pages/endorsements/manage.tsx
@@ -57,6 +57,7 @@ interface EndorsementData {
activityHours: number
status: "active" | "warning" | "removal"
progress: number
+ eligibleSince: string
removalDate: string | null
removalDays: number
}
@@ -74,6 +75,7 @@ interface PageProps {
userPermissions: {
canRemoveForPositions: string[] | null
canRemoveAny: boolean
+ isAdmin: boolean
}
}
@@ -122,6 +124,8 @@ export default function ManageEndorsements({
const [isProcessing, setIsProcessing] = useState(false)
const [showActiveEndorsements, setShowActiveEndorsements] = useState(false)
+ const { isAdmin } = userPermissions
+
const canRemoveForPosition = (position: string): boolean => {
if (userPermissions.canRemoveForPositions === null) {
return true
@@ -478,6 +482,7 @@ export default function ManageEndorsements({
Controller
Activity
Status
+ {isAdmin && Eligible Since}
Actions
@@ -564,6 +569,20 @@ export default function ManageEndorsements({
)}
+ {isAdmin && (
+
+ {state !== "active"
+ ? (() => {
+ const date = new Date(
+ endorsement.eligibleSince,
+ )
+ return date.getFullYear() === 1970
+ ? "Unknown"
+ : date.toLocaleDateString("de")
+ })()
+ : null}
+
+ )}