/**
* Admin Page
*
* User management + app settings page.
* - useUsers for listing all users
* - setRole for changing user roles
* - Admin-only settings collection
* - useQuery with admin permissions
*/
import { useState, useMemo } from 'react'
import { useUser } from 'deepspace'
import { useUsers } from 'deepspace'
import { useQuery } from 'deepspace'
import { useMutations } from 'deepspace'
import { Button, Badge, Avatar, AvatarFallback, useToast, type BadgeProps } from '@/components/ui'
import { ROLES, ROLE_CONFIG, type Role } from 'deepspace'
// ============================================================================
// Types
// ============================================================================
interface Setting {
key: string
value: string
}
// ============================================================================
// Main Page
// ============================================================================
export default function AdminPage() {
const { user } = useUser()
const isAdmin = user?.role === 'admin'
const { users, setRole } = useUsers()
const [activeTab, setActiveTab] = useState<'users' | 'settings'>('users')
const toast = useToast()
// Security: Don't render admin content if not an admin
if (!isAdmin) {
return (
Access Denied
You don't have permission to view this page.
)
}
return (
{/* Header */}
Admin Panel
Manage users and settings
{/* Tabs */}
{/* Content */}
{activeTab === 'users' ? (
{
setRole(userId, role)
toast.success('Role updated successfully')
}}
/>
) : (
)}
)
}
// ============================================================================
// Users Panel
// ============================================================================
interface UsersPanelProps {
users: Array<{
id: string
email?: string
name: string
imageUrl?: string
role: string
lastSeenAt?: string
}>
currentUserId?: string
onSetRole: (userId: string, role: string) => void
}
function UsersPanel({ users, currentUserId, onSetRole }: UsersPanelProps) {
// Sort users by last seen
const sortedUsers = useMemo(() => {
return [...users].sort((a, b) =>
new Date(b.lastSeenAt ?? '').getTime() - new Date(a.lastSeenAt ?? '').getTime()
)
}, [users])
return (
{sortedUsers.map(user => {
const roleConfig = ROLE_CONFIG[user.role as Role] ?? ROLE_CONFIG[ROLES.VIEWER]
const isCurrentUser = user.id === currentUserId
return (
{user.name?.[0]?.toUpperCase() ?? '?'}
{user.name}
{isCurrentUser && (
(you)
)}
{user.email}
Last seen: {user.lastSeenAt ? new Date(user.lastSeenAt).toLocaleDateString() : '—'}
{roleConfig.title}
)
})}
{users.length === 0 && (
No users found
)}
)
}
// ============================================================================
// Settings Panel
// ============================================================================
interface SettingsPanelProps {
toast: ReturnType
}
function SettingsPanel({ toast }: SettingsPanelProps) {
const [newKey, setNewKey] = useState('')
const [newValue, setNewValue] = useState('')
// Query settings (admin-only collection)
const { records: settings, status } = useQuery('settings')
const { create, remove } = useMutations('settings')
const handleCreate = async () => {
if (!newKey.trim() || !newValue.trim()) return
await create({ key: newKey.trim(), value: newValue.trim() })
setNewKey('')
setNewValue('')
toast.success('Setting created')
}
const handleDelete = async (id: string) => {
if (confirm('Are you sure you want to delete this setting?')) {
await remove(id)
toast.success('Setting deleted')
}
}
return (
{/* Add new setting */}
{/* Settings list */}
{status === 'loading' ? (
) : settings.length === 0 ? (
No settings configured
) : (
{settings.map(setting => (
{setting.data.key}
=
{setting.data.value}
))}
)}
)
}