fix(voice): proper shadcn select dropdowns + top reactors leaderboard
- ui/select: trigger default w-full h-9 (was w-fit h-8 — selects rendered tiny/misaligned); callers keep size override via className - VoiceConnectionCard: labeled full-width h-10 selects (Server/Guild + Voice Channel), guild icon + name in options, channel type icon + 'no akses' tag, empty states, htmlFor/id a11y wiring - GuildSelector sidebar + messages channel filter bumped to match - Backend GET /api/dashboard/reactors: top users by net reactions given (adds-removes) + messages_reacted + emojis_used - Reactions tab: second 'Top reaktor' leaderboard panel
This commit is contained in:
@@ -395,6 +395,36 @@ export class DashboardRepository {
|
||||
}));
|
||||
}
|
||||
|
||||
async getTopReactors(limit: number) {
|
||||
const db = getDatabase();
|
||||
const cap = Math.min(Math.max(limit || 20, 1), 50);
|
||||
|
||||
// Top users by net reactions given (adds minus removes)
|
||||
const result = await db.execute(sql`
|
||||
SELECT
|
||||
user_id,
|
||||
username,
|
||||
(COUNT(*) FILTER (WHERE reaction_type = 'add')
|
||||
- COUNT(*) FILTER (WHERE reaction_type = 'remove'))::int AS net_count,
|
||||
COUNT(*) FILTER (WHERE reaction_type = 'add')::int AS adds_count,
|
||||
COUNT(DISTINCT message_id)::int AS messages_reacted,
|
||||
COUNT(DISTINCT emoji)::int AS emojis_used
|
||||
FROM message_reactions
|
||||
GROUP BY user_id, username
|
||||
ORDER BY net_count DESC
|
||||
LIMIT ${cap}
|
||||
`);
|
||||
|
||||
return ((result.rows as Record<string, unknown>[]) || []).map((r) => ({
|
||||
user_id: String(r.user_id),
|
||||
username: String(r.username ?? "unknown"),
|
||||
net_count: Number(r.net_count),
|
||||
adds_count: Number(r.adds_count),
|
||||
messages_reacted: Number(r.messages_reacted),
|
||||
emojis_used: Number(r.emojis_used),
|
||||
}));
|
||||
}
|
||||
|
||||
async getUserDetail(userId: string) {
|
||||
const db = getDatabase();
|
||||
|
||||
|
||||
@@ -97,5 +97,15 @@ export function createDashboardRouter(): Router {
|
||||
}),
|
||||
);
|
||||
|
||||
// GET /api/dashboard/reactors — top users by reactions given
|
||||
router.get(
|
||||
"/dashboard/reactors",
|
||||
asyncHandler(async (req: Request, res: Response) => {
|
||||
const limit = Number(req.query.limit) || 20;
|
||||
const reactors = await dashboardService.getTopReactors(limit);
|
||||
res.json(reactors);
|
||||
}),
|
||||
);
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,11 @@ export class DashboardService {
|
||||
logger.debug({ limit }, "Fetching top reactions");
|
||||
return dashboardRepository.getTopReactions(limit);
|
||||
}
|
||||
|
||||
async getTopReactors(limit: number) {
|
||||
logger.debug({ limit }, "Fetching top reactors");
|
||||
return dashboardRepository.getTopReactors(limit);
|
||||
}
|
||||
}
|
||||
|
||||
export const dashboardService = new DashboardService();
|
||||
|
||||
Reference in New Issue
Block a user