Add unified expertise tag system and round entry notifications
- ExpertiseSelect now fetches tags from database with category grouping - Tags set by admin during invitation are locked and cannot be removed - Onboarding merges user-selected tags with admin-preset tags - MENTOR role now goes through onboarding flow - Added migration for Round.entryNotificationType column - Added seed script with ~90 comprehensive expertise tags Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useMemo } from 'react'
|
||||
import { useState, useMemo, useEffect } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { trpc } from '@/lib/trpc/client'
|
||||
import { Button } from '@/components/ui/button'
|
||||
@@ -39,15 +39,44 @@ type Step = 'name' | 'phone' | 'tags' | 'preferences' | 'complete'
|
||||
export default function OnboardingPage() {
|
||||
const router = useRouter()
|
||||
const [step, setStep] = useState<Step>('name')
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
|
||||
// Form state
|
||||
const [name, setName] = useState('')
|
||||
const [phoneNumber, setPhoneNumber] = useState('')
|
||||
const [expertiseTags, setExpertiseTags] = useState<string[]>([])
|
||||
const [lockedTags, setLockedTags] = useState<string[]>([])
|
||||
const [notificationPreference, setNotificationPreference] = useState<
|
||||
'EMAIL' | 'WHATSAPP' | 'BOTH' | 'NONE'
|
||||
>('EMAIL')
|
||||
|
||||
// Fetch current user data to get admin-preset tags
|
||||
const { data: userData, isLoading: userLoading } = trpc.user.me.useQuery()
|
||||
|
||||
// Initialize form with user data
|
||||
useEffect(() => {
|
||||
if (userData && !initialized) {
|
||||
// Pre-fill name if available
|
||||
if (userData.name) {
|
||||
setName(userData.name)
|
||||
}
|
||||
// Pre-fill phone if available
|
||||
if (userData.phoneNumber) {
|
||||
setPhoneNumber(userData.phoneNumber)
|
||||
}
|
||||
// Set admin-preset tags as both locked and selected
|
||||
if (userData.expertiseTags && userData.expertiseTags.length > 0) {
|
||||
setLockedTags(userData.expertiseTags)
|
||||
setExpertiseTags(userData.expertiseTags)
|
||||
}
|
||||
// Pre-fill notification preference if available
|
||||
if (userData.notificationPreference) {
|
||||
setNotificationPreference(userData.notificationPreference)
|
||||
}
|
||||
setInitialized(true)
|
||||
}
|
||||
}, [userData, initialized])
|
||||
|
||||
// Fetch feature flags
|
||||
const { data: featureFlags } = trpc.settings.getFeatureFlags.useQuery()
|
||||
const whatsappEnabled = featureFlags?.whatsappEnabled ?? false
|
||||
@@ -95,15 +124,36 @@ export default function OnboardingPage() {
|
||||
setStep('complete')
|
||||
toast.success('Welcome to MOPC!')
|
||||
|
||||
// Redirect after a short delay
|
||||
// Redirect after a short delay based on user role
|
||||
setTimeout(() => {
|
||||
router.push('/jury')
|
||||
const role = userData?.role
|
||||
if (role === 'MENTOR') {
|
||||
router.push('/mentor')
|
||||
} else if (role === 'OBSERVER') {
|
||||
router.push('/observer')
|
||||
} else {
|
||||
router.push('/jury')
|
||||
}
|
||||
}, 2000)
|
||||
} catch (error) {
|
||||
toast.error(error instanceof Error ? error.message : 'Failed to complete onboarding')
|
||||
}
|
||||
}
|
||||
|
||||
// Show loading while fetching user data
|
||||
if (userLoading || !initialized) {
|
||||
return (
|
||||
<div className="absolute inset-0 -m-4 flex items-center justify-center p-4 md:p-8 bg-gradient-to-br from-[#053d57] to-[#557f8c]">
|
||||
<Card className="w-full max-w-lg shadow-2xl">
|
||||
<CardContent className="flex flex-col items-center justify-center py-12">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-primary mb-4" />
|
||||
<p className="text-muted-foreground">Loading your profile...</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="absolute inset-0 -m-4 flex items-center justify-center p-4 md:p-8 bg-gradient-to-br from-[#053d57] to-[#557f8c]">
|
||||
<Card className="w-full max-w-lg max-h-[85vh] overflow-y-auto shadow-2xl">
|
||||
@@ -219,6 +269,7 @@ export default function OnboardingPage() {
|
||||
value={expertiseTags}
|
||||
onChange={setExpertiseTags}
|
||||
maxTags={5}
|
||||
lockedTags={lockedTags}
|
||||
/>
|
||||
|
||||
<div className="flex gap-2">
|
||||
|
||||
Reference in New Issue
Block a user