Skip to main content

edc_web_components/pages/
show_contract_negotiation.rs

1use 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}