UI/UX audit fixes: clickable pipelines, broken links, isActive locking

- Make pipeline cards clickable on list page (navigate to detail view)
- Fix broken nav link: applicant /messages → /mentor
- Fix broken nav link: mentor /messages → /projects
- Add isActive field locking to all 7 wizard sections (intake, main-track,
  filtering, assignment, awards, live-finals, notifications)
- Add minLoad ≤ maxLoad cross-field validation in assignment section
- Add duplicate stage slug detection in main track section
- Add active pipeline warning banners in intake and main track sections

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 20:50:22 +01:00
parent 31225b099e
commit 7d1c87e938
11 changed files with 149 additions and 79 deletions

View File

@@ -31,6 +31,7 @@ import type { RoutingMode, DecisionMode, AwardScoringMode } from '@prisma/client
type AwardsSectionProps = {
tracks: WizardTrackConfig[]
onChange: (tracks: WizardTrackConfig[]) => void
isActive?: boolean
}
function slugify(name: string): string {
@@ -40,7 +41,7 @@ function slugify(name: string): string {
.replace(/^-|-$/g, '')
}
export function AwardsSection({ tracks, onChange }: AwardsSectionProps) {
export function AwardsSection({ tracks, onChange, isActive }: AwardsSectionProps) {
const awardTracks = tracks.filter((t) => t.kind === 'AWARD')
const nonAwardTracks = tracks.filter((t) => t.kind !== 'AWARD')
@@ -72,7 +73,7 @@ export function AwardsSection({ tracks, onChange }: AwardsSectionProps) {
<p className="text-sm text-muted-foreground">
Configure special award tracks that run alongside the main competition.
</p>
<Button type="button" variant="outline" size="sm" onClick={addAward}>
<Button type="button" variant="outline" size="sm" onClick={addAward} disabled={isActive}>
<Plus className="h-3.5 w-3.5 mr-1" />
Add Award Track
</Button>
@@ -100,6 +101,7 @@ export function AwardsSection({ tracks, onChange }: AwardsSectionProps) {
variant="ghost"
size="icon"
className="h-7 w-7 text-muted-foreground hover:text-destructive"
disabled={isActive}
>
<Trash2 className="h-3.5 w-3.5" />
</Button>
@@ -129,6 +131,7 @@ export function AwardsSection({ tracks, onChange }: AwardsSectionProps) {
<Input
placeholder="e.g., Innovation Award"
value={track.awardConfig?.name ?? track.name}
disabled={isActive}
onChange={(e) => {
const name = e.target.value
updateAward(index, {
@@ -151,6 +154,7 @@ export function AwardsSection({ tracks, onChange }: AwardsSectionProps) {
routingModeDefault: value as RoutingMode,
})
}
disabled={isActive}
>
<SelectTrigger className="text-sm">
<SelectValue />
@@ -178,6 +182,7 @@ export function AwardsSection({ tracks, onChange }: AwardsSectionProps) {
onValueChange={(value) =>
updateAward(index, { decisionMode: value as DecisionMode })
}
disabled={isActive}
>
<SelectTrigger className="text-sm">
<SelectValue />
@@ -203,6 +208,7 @@ export function AwardsSection({ tracks, onChange }: AwardsSectionProps) {
},
})
}
disabled={isActive}
>
<SelectTrigger className="text-sm">
<SelectValue />