feat: forgot password flow, member page fixes, country name display
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m7s

Password reset:
- /forgot-password page: enter email, receive reset link via email
- /reset-password?token=xxx page: set new password with validation
- user.requestPasswordReset: generates token, sends styled email
- user.resetPassword: validates token, hashes new password
- Does NOT trigger re-onboarding — only resets the password
- 30-minute token expiry, cleared after use
- Added passwordResetToken/passwordResetExpiresAt to User model

Member detail page fixes:
- Hide "Expertise & Capacity" card for applicants/audience roles
- Show country names with flag emojis instead of raw ISO codes
- Login "Forgot password?" now links to /forgot-password page

Project detail page:
- Team member details show full country names with flags

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 13:49:43 +01:00
parent b6ba5d7145
commit ee8e90132e
10 changed files with 606 additions and 29 deletions

View File

@@ -62,10 +62,10 @@ import {
ThumbsDown,
Globe,
Building2,
Flag,
FileText,
FolderOpen,
} from 'lucide-react'
import { getCountryName, getCountryFlag } from '@/lib/countries'
export default function MemberDetailPage() {
const params = useParams()
@@ -266,19 +266,19 @@ export default function MemberDetailPage() {
<div className="grid gap-4 sm:grid-cols-2">
{user.nationality && (
<div className="flex items-start gap-2">
<Flag className="h-4 w-4 mt-0.5 text-muted-foreground shrink-0" />
<span className="text-lg mt-0.5 shrink-0" role="img">{getCountryFlag(user.nationality)}</span>
<div>
<p className="text-xs font-medium text-muted-foreground">Nationality</p>
<p className="text-sm">{user.nationality}</p>
<p className="text-sm">{getCountryName(user.nationality)}</p>
</div>
</div>
)}
{user.country && (
<div className="flex items-start gap-2">
<Globe className="h-4 w-4 mt-0.5 text-muted-foreground shrink-0" />
<span className="text-lg mt-0.5 shrink-0" role="img">{getCountryFlag(user.country)}</span>
<div>
<p className="text-xs font-medium text-muted-foreground">Country of Residence</p>
<p className="text-sm">{user.country}</p>
<p className="text-sm">{getCountryName(user.country)}</p>
</div>
</div>
)}
@@ -447,7 +447,8 @@ export default function MemberDetailPage() {
</CardContent>
</Card>
{/* Expertise & Capacity */}
{/* Expertise & Capacity — only for jury/mentor/observer/admin roles */}
{!['APPLICANT', 'AUDIENCE'].includes(user.role) && (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
@@ -494,6 +495,7 @@ export default function MemberDetailPage() {
)}
</CardContent>
</Card>
)}
</div>
{/* Mentor Assignments Section */}