UI polish: grouped dropdowns, analytics readability, invite tag picker

- Messages: group users by role in recipient dropdown (SelectGroup)
- Analytics: full country names via Intl.DisplayNames, format SNAKE_CASE
  labels to Title Case, custom tooltips, increased font sizes
- Invite: replace free-text tag input with grouped dropdown from DB tags
  using Command/Popover, showing tags organized by category with colors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-06 00:06:47 +01:00
parent 4830c0638c
commit 98fe658c33
3 changed files with 283 additions and 156 deletions

View File

@@ -21,7 +21,9 @@ import { Switch } from '@/components/ui/switch'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
@@ -321,11 +323,44 @@ export default function MessagesPage() {
<SelectValue placeholder="Choose a user..." />
</SelectTrigger>
<SelectContent>
{(users as { users: Array<{ id: string; name: string | null; email: string }> } | undefined)?.users?.map((u) => (
<SelectItem key={u.id} value={u.id}>
{u.name || u.email}
</SelectItem>
))}
{(() => {
const userList = (users as { users: Array<{ id: string; name: string | null; email: string; role: string }> } | undefined)?.users
if (!userList) return null
const grouped = userList.reduce<Record<string, typeof userList>>((acc, u) => {
const role = u.role || 'OTHER'
if (!acc[role]) acc[role] = []
acc[role].push(u)
return acc
}, {})
const roleLabels: Record<string, string> = {
SUPER_ADMIN: 'Super Admins',
PROGRAM_ADMIN: 'Program Admins',
JURY_MEMBER: 'Jury Members',
MENTOR: 'Mentors',
OBSERVER: 'Observers',
APPLICANT: 'Applicants',
OTHER: 'Other',
}
const roleOrder = ['SUPER_ADMIN', 'PROGRAM_ADMIN', 'JURY_MEMBER', 'MENTOR', 'OBSERVER', 'APPLICANT', 'OTHER']
return roleOrder
.filter((role) => grouped[role]?.length)
.map((role) => (
<SelectGroup key={role}>
<SelectLabel>{roleLabels[role] || role}</SelectLabel>
{grouped[role]
.sort((a, b) => (a.name || a.email).localeCompare(b.name || b.email))
.map((u) => (
<SelectItem key={u.id} value={u.id}>
{u.name || u.email}
</SelectItem>
))}
</SelectGroup>
))
})()}
</SelectContent>
</Select>
</div>