feat: leaderboard with top (by period) and new tabs

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Doar Mihai
2026-10-17 16:39:28 +03:00
co-authored by Claude Sonnet 5.5
parent 25e1dd2413
commit 3f8fa9f22f
7 changed files with 343 additions and 0 deletions
+36
View File
@@ -284,6 +284,42 @@ class Product extends Model
return $query->withCount('upvotes')->orderBy('upvotes_count', 'desc');
}
/**
* Leaderboard periods: key => label.
*/
public const LEADERBOARD_PERIODS = [
'today' => 'Today',
'week' => 'This week',
'month' => 'This month',
'all' => 'All time',
];
/**
* Approved products ranked by the upvotes they received in the period,
* then by total upvotes, then newest. Products with no upvotes in the
* period are left out. Adds `period_upvotes_count` and `total_upvotes_count`.
*/
public function scopeTopFor(Builder $query, string $period): Builder
{
$since = match ($period) {
'today' => now()->startOfDay(),
'week' => now()->subDays(7),
'month' => now()->subDays(30),
default => null,
};
$inPeriod = fn (Builder $upvotes) => $since ? $upvotes->where('created_at', '>=', $since) : $upvotes;
return $query->approved()
->whereHas('upvotes', $inPeriod)
->withCount(['upvotes as period_upvotes_count' => $inPeriod])
->withCount('upvotes as total_upvotes_count')
->orderByDesc('period_upvotes_count')
->orderByDesc('total_upvotes_count')
->orderByDesc('products.created_at')
->orderByDesc('products.id');
}
/**
* Scope a query to sort products.
*/