edc_web_components/pages/
show_contract_negotiation.rs1use crate::components::{
2 AssetReference, ContractAgreementReference, ContractNegotiationStatus, DidLabel, Identifier,
3};
4use crate::contexts::use_edc_connector_context;
5#[cfg(feature = "contract-negotiation-review")]
6use edc_connector_client::types::contract_negotiation::{
7 ContractNegotiationKind, ContractNegotiationState,
8};
9use patternfly_yew::prelude::*;
10use yew::prelude::*;
11use yew::suspense::use_future_with;
12
13#[derive(Clone, Debug, PartialEq, Properties)]
14pub struct ShowContractNegotiationPageProps {
15 #[prop_or("Contract Negotiation".to_string())]
16 pub title: String,
17 #[prop_or(None)]
18 pub tag_line: Option<String>,
19 pub contract_negotiation_id: String,
20 #[prop_or_default]
21 pub on_contract_agreement_click: Callback<String>,
22}
23
24#[component]
25pub fn ShowContractNegotiationPage(props: &ShowContractNegotiationPageProps) -> Html {
26 let tag_line = props
27 .tag_line
28 .as_ref()
29 .map(|tag_line| html!(<p>{ tag_line }</p>))
30 .unwrap_or_default();
31
32 html!(
33 <>
34 <Title level={Level::H2} size={Size::XXXLarge}>{ &props.title }</Title>
35 { tag_line }
36 <Suspense fallback={html! {<Bullseye><Spinner /></Bullseye>}}>
37 <ShowContractNegotiationPageInner
38 contract_negotiation_id={props.contract_negotiation_id.clone()}
39 on_contract_agreement_click={props.on_contract_agreement_click.clone()}
40 />
41 </Suspense>
42 </>
43 )
44}
45
46#[component]
47pub fn ShowContractNegotiationPageInner(props: &ShowContractNegotiationPageProps) -> HtmlResult {
48 let edc_connector_client = use_edc_connector_context();
49
50 let refresh = use_state(|| 0usize);
51
52 let contract_negotiation = use_future_with(
53 (
54 props.contract_negotiation_id.clone(),
55 edc_connector_client.clone(),
56 refresh.clone(),
57 ),
58 |properties| async move {
59 let (contract_negotiation_id, edc_connector_client, _) = (*properties).clone();
60
61 if let Some(client) = edc_connector_client.get_client() {
62 client
63 .contract_negotiations(edc_connector_client::EdcConnectorApiVersion::V4)
64 .get(&contract_negotiation_id)
65 .await
66 .ok()
67 } else {
68 None
69 }
70 },
71 )?;
72
73 let on_finalized = use_callback(refresh.setter(), |_, refresh_setter| {
74 refresh_setter.set(1);
75 });
76
77 #[cfg(feature = "contract-negotiation-review")]
78 let on_reviewed = use_callback(refresh.setter(), |_, refresh_setter| {
79 refresh_setter.set(1);
80 });
81
82 let contract_negotiation = (*contract_negotiation).clone();
83
84 if let Some(contract_negotiation) = contract_negotiation {
85 let created_date = chrono::DateTime::from_timestamp_millis(contract_negotiation.created_at())
86 .unwrap_or_default()
87 .to_string();
88
89 let contract_agreement = contract_negotiation
90 .contract_agreement_id()
91 .map(|contract_agreement_id| {
92 html!(
93 <Card>
94 <CardBody>
95 <Split gutter=true>
96 <SplitItem>
97 <yew_icons::Icon data={yew_icons::IconData::LUCIDE_HEART_HANDSHAKE} />
98 </SplitItem>
99 <SplitItem fill=true>
100 <DescriptionGroup term="Contract Agreement">
101 <div class="pf-v6-u-font-weight-bold">
102 { format!("Signed {}", &created_date) }
103 </div>
104 <Identifier id={contract_agreement_id.clone()} />
105 </DescriptionGroup>
106 </SplitItem>
107 <SplitItem>
108 <ContractAgreementReference
109 contract_agreement_id={contract_agreement_id.clone()}
110 />
111 </SplitItem>
112 </Split>
113 </CardBody>
114 </Card>
115 )
116 })
117 .unwrap_or_default();
118
119 let state =
120 Some(crate::models::ContractNegotiationState::from(contract_negotiation.state()).to_string())
121 .map(|value| {
122 let color = match value.as_str() {
123 "Finalized" => Color::Green,
124 "Terminated" => Color::Red,
125 _ => Color::Blue,
126 };
127
128 html!(
129 <DescriptionGroup term="State">
130 <Label label={value} {color} />
131 </DescriptionGroup>
132 )
133 });
134
135 let kind =
136 crate::models::ContractNegotiationKind::from(contract_negotiation.kind()).to_string();
137
138 #[cfg(feature = "contract-negotiation-review")]
139 let review = if contract_negotiation.state() == &ContractNegotiationState::Requested
140 && contract_negotiation.kind() == &ContractNegotiationKind::Provider
141 {
142 let contract_negotiation_id = contract_negotiation.id().to_string();
143
144 html!(
145 <Alert title="Review the Contract Negotiation">
146 <Suspense fallback={html!(<Bullseye><Spinner /></Bullseye>)}>
147 <crate::components::ReviewContractNegotiation {contract_negotiation_id} {on_reviewed} />
148 </Suspense>
149 </Alert>
150 )
151 } else {
152 html!()
153 };
154
155 #[cfg(not(feature = "contract-negotiation-review"))]
156 let review = html!();
157
158 Ok(html!(
159 <Stack gutter=true>
160 <StackItem>
161 <Flex modifiers={[FlexModifier::Justify(Justify::Start)]}>
162 <FlexItem modifiers={[FlexModifier::Flex1, FlexModifier::Align(Alignment::Start)]}>
163 <Card>
164 <CardTitle>
165 <Title level={Level::H2}>{ "Negotiation Properties" }</Title>
166 </CardTitle>
167 <CardBody>
168 <DescriptionList mode={[DescriptionListMode::Horizontal]}>
169 <DescriptionGroup term="Id">
170 <Identifier id={contract_negotiation.id().to_string()} />
171 </DescriptionGroup>
172 { state }
173 <DescriptionGroup term="Kind">{ kind }</DescriptionGroup>
174 <DescriptionGroup term="Counter Party">
175 <DidLabel
176 did={contract_negotiation.counter_party_id().clone().unwrap_or_default()}
177 />
178 </DescriptionGroup>
179 <DescriptionGroup term="Protocol">
180 <Label label={contract_negotiation.protocol().to_string()} />
181 </DescriptionGroup>
182 <DescriptionGroup term="Created At">{ created_date }</DescriptionGroup>
183 </DescriptionList>
184 </CardBody>
185 </Card>
186 </FlexItem>
187 <FlexItem modifiers={[FlexModifier::Flex1, FlexModifier::Align(Alignment::Start)]}>
188 <Card>
189 <CardTitle>
190 <Title level={Level::H2}>{ "Outcome" }</Title>
191 </CardTitle>
192 <CardBody>
193 <Flex modifiers={[FlexModifier::Column.lg()]}>
194 <FlexItem>
195 <Card>
196 <CardBody>
197 <Split gutter=true>
198 <SplitItem>
199 <yew_icons::Icon data={yew_icons::IconData::LUCIDE_BOX} />
200 </SplitItem>
201 <SplitItem fill=true>
202 <DescriptionGroup term="Asset">
203 <AssetReference
204 asset_id={contract_negotiation.asset_id().clone().unwrap_or_default()}
205 />
206 <Identifier
207 id={contract_negotiation.asset_id().clone().unwrap_or_default()}
208 />
209 </DescriptionGroup>
210 </SplitItem>
211 </Split>
212 </CardBody>
213 </Card>
214 </FlexItem>
215 <FlexItem>{ contract_agreement }</FlexItem>
216 </Flex>
217 </CardBody>
218 </Card>
219 </FlexItem>
220 </Flex>
221 </StackItem>
222 <StackItem>
223 <Flex>
224 <FlexItem modifiers={[FlexModifier::Flex1, FlexModifier::Align(Alignment::Start)]}>
225 <Card>
226 <CardTitle>
227 <Title level={Level::H2}>{ "Negotiation Process" }</Title>
228 </CardTitle>
229 <CardBody>
230 <ContractNegotiationStatus
231 contract_negotiation_id={props.contract_negotiation_id.clone()}
232 {on_finalized}
233 />
234 </CardBody>
235 </Card>
236 </FlexItem>
237 </Flex>
238 </StackItem>
239 <StackItem>{ review }</StackItem>
240 </Stack>
241 ))
242 } else {
243 Ok(html!(
244 format!(
245 "Contract Negotiation with id {} not found.",
246 props.contract_negotiation_id
247 )
248 ))
249 }
250}