diff --git a/src/app/Http/Controllers/Anime/AnimeController.php b/src/app/Http/Controllers/Anime/AnimeController.php
index 477d358..eb6b6c3 100644
--- a/src/app/Http/Controllers/Anime/AnimeController.php
+++ b/src/app/Http/Controllers/Anime/AnimeController.php
@@ -93,10 +93,14 @@ public function show(Request $request, Anime $anime): Response
'genres:name',
]);
- $animeListEntry = $this->userAnimeListService->findById($request->user(), $anime->id);
- $animeListStatuses = AnimeListStatusEnum::cases();
+ $animeListEntry = $this->userAnimeListService->findById($request->user(), $anime->id);
+ $animeListStatuses = AnimeListStatusEnum::cases();
+ $animeListStatistic = $this->userAnimeListService->animeStatistics($anime->id);
- return Inertia::render('Anime/Show', compact('anime', 'animeListEntry', 'animeListStatuses'));
+ return Inertia::render(
+ 'Anime/Show',
+ compact('anime', 'animeListEntry', 'animeListStatuses', 'animeListStatistic')
+ );
}
/**
diff --git a/src/app/Services/User/UserAnimeListService.php b/src/app/Services/User/UserAnimeListService.php
index eb2f266..7ac2c0d 100644
--- a/src/app/Services/User/UserAnimeListService.php
+++ b/src/app/Services/User/UserAnimeListService.php
@@ -8,6 +8,7 @@
use App\Enums\UserAnimeList\StatusEnum;
use App\Models\Pivots\UserAnimeList;
use App\Models\User;
+use Illuminate\Support\Facades\DB;
final class UserAnimeListService
{
@@ -17,6 +18,53 @@ public function findById(User $user, string $animeId): ?UserAnimeList
return $user->animeList()->where('anime_id', $animeId)->first()?->pivot;
}
+ /**
+ * @return array{status: string, user_count: int, percentage: float}
+ */
+ public function animeStatistics(string $animeId): array
+ {
+ $subQuery = UserAnimeList::query()->fromRaw(
+ "(
+ SELECT 'plan_to_watch' AS status
+ UNION ALL SELECT 'watching'
+ UNION ALL SELECT 'on_hold'
+ UNION ALL SELECT 'completed'
+ UNION ALL SELECT 'dropped'
+ ) as statuses"
+ );
+
+ // Not using model directly because of Model::shouldBeStrict()
+ return DB::table(UserAnimeList::class)
+ ->fromSub(
+ $subQuery->leftJoin(
+ 'user_anime_list as ual',
+ static fn($join) => $join->on(
+ 'statuses.status',
+ '=',
+ 'ual.status'
+ )->where('ual.anime_id', $animeId)
+ )
+ ->groupBy('statuses.status')
+ ->select([
+ 'statuses.status',
+ DB::raw('COUNT(ual.user_id) as user_count'),
+ DB::raw('SUM(COUNT(ual.user_id)) OVER() as total_count'),
+ ]),
+ 'sub'
+ )
+ ->select([
+ 'status',
+ 'user_count',
+ DB::raw('ROUND(user_count * 100 / total_count, 1) as percentage'),
+ ])
+ ->get()
+ ->map(static function (\stdClass $item) {
+ $item->percentage = (float) $item->percentage;
+ return (array) $item;
+ })
+ ->toArray();
+ }
+
public function addAnime(User $user, string $animeId): void
{
$user->animeList()->attach($animeId, ['status' => StatusEnum::PLAN_TO_WATCH]);
diff --git a/src/resources/js/entities/anime-list/model/index.ts b/src/resources/js/entities/anime-list/model/index.ts
index 8022df1..2aa6b88 100644
--- a/src/resources/js/entities/anime-list/model/index.ts
+++ b/src/resources/js/entities/anime-list/model/index.ts
@@ -1 +1,7 @@
-export { Status, type AnimeList, type AnimeListEntry } from './types';
+export {
+ Status,
+ type AnimeList,
+ type AnimeListEntry,
+ type AnimeListEntryStatistic,
+ type AnimeListStatistics,
+} from './types';
diff --git a/src/resources/js/entities/anime-list/model/types.ts b/src/resources/js/entities/anime-list/model/types.ts
index baea627..628729e 100644
--- a/src/resources/js/entities/anime-list/model/types.ts
+++ b/src/resources/js/entities/anime-list/model/types.ts
@@ -14,4 +14,18 @@ type AnimeListEntry = {
type AnimeList = AnimeListEntry[];
-export { Status, type AnimeListEntry, type AnimeList };
+type AnimeListEntryStatistic = {
+ status: Status;
+ user_count: number;
+ percentage: number;
+};
+
+type AnimeListStatistics = AnimeListEntryStatistic[];
+
+export {
+ Status,
+ type AnimeListEntry,
+ type AnimeList,
+ type AnimeListEntryStatistic,
+ type AnimeListStatistics,
+};
diff --git a/src/resources/js/features/anime/list-statistic/AnimeListStatistic.vue b/src/resources/js/features/anime/list-statistic/AnimeListStatistic.vue
new file mode 100644
index 0000000..3fff24b
--- /dev/null
+++ b/src/resources/js/features/anime/list-statistic/AnimeListStatistic.vue
@@ -0,0 +1,56 @@
+
+
+
+
+
+