|
1 | 1 | 'use client' |
2 | 2 |
|
3 | | -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" |
4 | | -import { Button } from "@/components/ui/button" |
5 | | -import Link from 'next/link' |
6 | 3 | import { useParams } from 'next/navigation' |
7 | 4 | import { useDecision } from '@/hooks/useDecisions' |
8 | 5 | import { useStakeholders } from '@/hooks/useStakeholders' |
9 | | -import { SupportingMaterialIcon } from '@/components/supporting-material-icon' |
10 | | -import { StakeholderRole } from '@/lib/domain/Decision' |
| 6 | +import { DecisionSummary } from '@/components/decision-summary' |
| 7 | +import Link from 'next/link' |
| 8 | + |
| 9 | +function PublishedBanner() { |
| 10 | + return ( |
| 11 | + <div className="bg-sky-100 p-4 rounded-md"> |
| 12 | + <p className="text-slate-700">This decision has been published and can no longer be edited</p> |
| 13 | + </div> |
| 14 | + ) |
| 15 | +} |
11 | 16 |
|
12 | | -function StakeholderGroup({ title, stakeholders }: { title: string, stakeholders: { id: string, displayName: string, photoURL?: string }[] }) { |
| 17 | +function SupersededBanner({ supersedingDecisionId, supersedingDecisionTitle, organisationId }: { |
| 18 | + supersedingDecisionId: string |
| 19 | + supersedingDecisionTitle: string |
| 20 | + organisationId: string |
| 21 | +}) { |
13 | 22 | return ( |
14 | | - <div className="flex-1"> |
15 | | - <h3 className="text-lg font-semibold text-slate-700 mb-4">{title}</h3> |
16 | | - <div className="space-y-3"> |
17 | | - {stakeholders.map((stakeholder) => ( |
18 | | - <div key={`stakeholder-${stakeholder.id}`} className="flex items-center gap-2"> |
19 | | - <Avatar className="h-8 w-8"> |
20 | | - <AvatarImage src={stakeholder.photoURL} alt={stakeholder.displayName} /> |
21 | | - <AvatarFallback>{stakeholder.displayName[0]}</AvatarFallback> |
22 | | - </Avatar> |
23 | | - <span className="text-slate-600">{stakeholder.displayName}</span> |
24 | | - </div> |
25 | | - ))} |
26 | | - </div> |
| 23 | + <div className="bg-amber-100 p-4 rounded-md"> |
| 24 | + <p className="text-slate-700"> |
| 25 | + This decision has been superseded by{' '} |
| 26 | + <Link |
| 27 | + href={`/organisation/${organisationId}/decision/${supersedingDecisionId}/view`} |
| 28 | + className="text-amber-800 hover:text-amber-900 underline" |
| 29 | + > |
| 30 | + {supersedingDecisionTitle} |
| 31 | + </Link> |
| 32 | + </p> |
27 | 33 | </div> |
28 | 34 | ) |
29 | 35 | } |
30 | 36 |
|
31 | 37 | export default function DecisionView() { |
32 | 38 | const params = useParams() |
33 | | - const decisionId = params.id as string |
34 | | - const organisationId = params.organisationId as string |
35 | | - |
36 | | - const { decision, loading, error } = useDecision(decisionId, organisationId) |
| 39 | + const { decision, loading } = useDecision(params.id as string, params.organisationId as string) |
37 | 40 | const { stakeholders } = useStakeholders() |
38 | 41 |
|
39 | 42 | if (loading) { |
40 | 43 | return <div>Loading...</div> |
41 | 44 | } |
42 | 45 |
|
43 | | - if (error) { |
44 | | - return <div>Error: {error.message}</div> |
45 | | - } |
46 | | - |
47 | 46 | if (!decision) { |
48 | 47 | return <div>Decision not found</div> |
49 | 48 | } |
50 | 49 |
|
51 | | - const deciderStakeholders = stakeholders?.filter(s => |
52 | | - decision.stakeholders.find(ds => ds.stakeholder_id === s.id && ds.role === ('decider' as StakeholderRole)) |
53 | | - ) || [] |
54 | | - const consultedStakeholders = stakeholders?.filter(s => |
55 | | - decision.stakeholders.find(ds => ds.stakeholder_id === s.id && ds.role === ('consulted' as StakeholderRole)) |
56 | | - ) || [] |
57 | | - const informedStakeholders = stakeholders?.filter(s => |
58 | | - decision.stakeholders.find(ds => ds.stakeholder_id === s.id && ds.role === ('informed' as StakeholderRole)) |
59 | | - ) || [] |
| 50 | + const supersededByRelationship = decision.getSupersededByRelationship() |
60 | 51 |
|
61 | 52 | return ( |
62 | | - <> |
63 | | - <div className="space-y-8"> |
64 | | - <div className="space-y-4"> |
65 | | - <h1 className="text-2xl font-bold text-slate-900">{decision.title || 'Untitled Decision'}</h1> |
66 | | - <p className="text-slate-600">{decision.description}</p> |
67 | | - </div> |
68 | | - |
69 | | - <section className="space-y-2"> |
70 | | - <h2 className="text-xl font-semibold text-slate-800">Decision</h2> |
71 | | - <p className="text-slate-600">{decision.decision || 'No decision made yet'}</p> |
72 | | - </section> |
73 | | - |
74 | | - {decision.options.length > 0 && ( |
75 | | - <section className="space-y-4"> |
76 | | - <h2 className="text-xl font-semibold text-slate-800">Options considered</h2> |
77 | | - <ol className="list-decimal list-inside space-y-2"> |
78 | | - {decision.options.map((option, index) => ( |
79 | | - <li key={`option-${index}`} className="text-slate-600">{option}</li> |
80 | | - ))} |
81 | | - </ol> |
82 | | - </section> |
83 | | - )} |
84 | | - |
85 | | - {decision.criteria.length > 0 && ( |
86 | | - <section className="space-y-4"> |
87 | | - <h2 className="text-xl font-semibold text-slate-800">Criteria</h2> |
88 | | - <ol className="list-decimal list-inside space-y-2"> |
89 | | - {decision.criteria.map((criterion, index) => ( |
90 | | - <li key={`criterion-${index}`} className="text-slate-600">{criterion}</li> |
91 | | - ))} |
92 | | - </ol> |
93 | | - </section> |
94 | | - )} |
95 | | - |
96 | | - {decision.supportingMaterials.length > 0 && ( |
97 | | - <section className="space-y-4"> |
98 | | - <h2 className="text-xl font-semibold text-slate-800">Supporting Materials</h2> |
99 | | - <div className="space-y-2"> |
100 | | - {decision.supportingMaterials.map((material, index) => ( |
101 | | - <div key={`material-${index}`} className="flex items-center gap-2 text-slate-600"> |
102 | | - <SupportingMaterialIcon mimeType={material.mimeType} /> |
103 | | - <a |
104 | | - href={material.url} |
105 | | - target="_blank" |
106 | | - rel="noopener noreferrer" |
107 | | - className="hover:underline" |
108 | | - > |
109 | | - {material.title} |
110 | | - </a> |
111 | | - </div> |
112 | | - ))} |
113 | | - </div> |
114 | | - </section> |
115 | | - )} |
116 | | - |
117 | | - <section className="space-y-2"> |
118 | | - <h2 className="text-xl font-semibold text-slate-800">Method</h2> |
119 | | - <p className="text-slate-600">{decision.decisionMethod || 'No method selected'}</p> |
120 | | - </section> |
121 | | - |
122 | | - <section className="space-y-4"> |
123 | | - <h2 className="text-xl font-semibold text-slate-800">Stakeholders</h2> |
124 | | - <div className="grid md:grid-cols-3 gap-8"> |
125 | | - {deciderStakeholders.length > 0 && ( |
126 | | - <StakeholderGroup |
127 | | - title="Deciders" |
128 | | - stakeholders={deciderStakeholders} |
129 | | - /> |
130 | | - )} |
131 | | - {consultedStakeholders.length > 0 && ( |
132 | | - <StakeholderGroup |
133 | | - title="Consulted" |
134 | | - stakeholders={consultedStakeholders} |
135 | | - /> |
136 | | - )} |
137 | | - {informedStakeholders.length > 0 && ( |
138 | | - <StakeholderGroup |
139 | | - title="Informed" |
140 | | - stakeholders={informedStakeholders} |
141 | | - /> |
142 | | - )} |
143 | | - </div> |
144 | | - </section> |
145 | | - |
146 | | - {decision.status === 'published' && ( |
147 | | - <div className="bottom-0 right-0 bg-sky-100 p-4 flex items-center justify-between z-50"> |
148 | | - <p className="text-slate-700">This decision has been published and can no longer be edited</p> |
149 | | - <Button variant="default" className="bg-blue-600 hover:bg-blue-700"> |
150 | | - <Link href={`/organisation/${organisationId}/decision/${decisionId}/edit`}> |
151 | | - Un-publish |
152 | | - </Link> |
153 | | - </Button> |
154 | | - </div> |
155 | | - )} |
156 | | - |
157 | | - <div className="flex justify-between items-center mb-8"> |
158 | | - <Button variant="outline" asChild> |
159 | | - <Link href={`/organisation/${organisationId}`}> |
160 | | - Back to Decisions |
161 | | - </Link> |
162 | | - </Button> |
163 | | - </div> |
164 | | - </div> |
165 | | - </> |
| 53 | + <div className="space-y-8"> |
| 54 | + <h1 className="text-2xl font-bold text-slate-900">{decision.title}</h1> |
| 55 | + |
| 56 | + <DecisionSummary |
| 57 | + decision={decision} |
| 58 | + stakeholders={stakeholders} |
| 59 | + /> |
| 60 | + |
| 61 | + {decision.isPublished() && <PublishedBanner />} |
| 62 | + {supersededByRelationship && ( |
| 63 | + <SupersededBanner |
| 64 | + supersedingDecisionId={supersededByRelationship.targetDecision.id} |
| 65 | + supersedingDecisionTitle={supersededByRelationship.targetDecisionTitle} |
| 66 | + organisationId={params.organisationId as string} |
| 67 | + /> |
| 68 | + )} |
| 69 | + </div> |
166 | 70 | ) |
167 | 71 | } |
168 | 72 |
|
0 commit comments