Skip to main content

edc_web_components/pages/
contract_negotiation_page.rs

1use crate::components::ListContractNegotiations;
2use crate::contexts::use_edc_connector_context;
3use crate::models::ContractNegotiationItem;
4use edc_connector_client::EdcConnectorApiVersion;
5use edc_connector_client::types::query::{Query, SortOrder};
6use patternfly_yew::prelude::*;
7use yew::prelude::*;
8use yew::suspense::use_future_with;
9
10#[derive(Clone, Debug, PartialEq, Properties)]
11pub struct ContractNegotiationPageProps {
12  pub on_show_contract_negotiation: Callback<String>,
13}
14
15#[component]
16pub fn ContractNegotiationPage(props: &ContractNegotiationPageProps) -> Html {
17  let refresh = use_state(|| 0usize);
18  let offset = use_state(|| 0usize);
19  let limit = use_state(|| 10usize);
20  let switch_view_consumer = use_state(|| false);
21  let statuses = use_state(|| {
22    vec![
23      ("Initial".to_string(), false),
24      ("Requesting".to_string(), false),
25      ("Requested".to_string(), false),
26      ("Offering".to_string(), false),
27      ("Offered".to_string(), false),
28      ("Accepting".to_string(), false),
29      ("Accepted".to_string(), false),
30      ("Agreeing".to_string(), false),
31      ("Agreed".to_string(), false),
32      ("Verifying".to_string(), false),
33      ("Verified".to_string(), false),
34      ("Finalizing".to_string(), false),
35      ("Finalized".to_string(), false),
36      ("Terminating".to_string(), false),
37      ("Terminated".to_string(), false),
38    ]
39  });
40
41  let on_offset = use_callback(
42    (refresh.clone(), offset.setter()),
43    |offset, (refresh, offset_setter)| {
44      offset_setter.set(offset);
45      refresh.set(**refresh + 1);
46    },
47  );
48
49  let on_limit = use_callback(
50    (refresh.clone(), limit.setter()),
51    |limit, (refresh, limit_setter)| {
52      limit_setter.set(limit);
53      refresh.set(**refresh + 1);
54    },
55  );
56
57  let on_switch_view_consumer = use_callback(
58    (refresh.clone(), switch_view_consumer.setter()),
59    |switch, (refresh, switch_setter)| {
60      switch_setter.set(switch);
61      refresh.set(**refresh + 1);
62    },
63  );
64
65  let on_statuses = use_callback(
66    (refresh.clone(), statuses.setter()),
67    |statuses, (refresh, statuses_setter)| {
68      statuses_setter.set(statuses);
69      refresh.set(**refresh + 1);
70    },
71  );
72
73  let fallback = html! {
74    <Bullseye>
75      <Spinner size={SpinnerSize::Lg} />
76    </Bullseye>
77  };
78
79  html!(
80    <Stack gutter=true>
81      <StackItem>
82        <Split gutter=true>
83          <SplitItem fill=true>
84            <Title level={Level::H3} size={Size::XXLarge}>{ "List Contract Negotiations" }</Title>
85            <p>
86              { "A contract negotiation represents the active, multi-step process between two parties to agree on data sharing terms." }
87            </p>
88          </SplitItem>
89        </Split>
90      </StackItem>
91      <StackItem>
92        <Suspense {fallback}>
93          <ContractNegotiationPageInner
94            offset={*offset}
95            limit={*limit}
96            switch_view_consumer={*switch_view_consumer}
97            statuses={(*statuses).clone()}
98            {on_offset}
99            {on_limit}
100            {on_switch_view_consumer}
101            {on_statuses}
102            force_refresh={*refresh}
103            on_show_contract_negotiation={props.on_show_contract_negotiation.clone()}
104          />
105        </Suspense>
106      </StackItem>
107    </Stack>
108  )
109}
110
111#[derive(Clone, Debug, PartialEq, Properties)]
112pub struct ContractNegotiationPageInnerProps {
113  pub offset: usize,
114  pub limit: usize,
115  pub switch_view_consumer: bool,
116  #[prop_or_default]
117  pub statuses: Vec<(String, bool)>,
118  pub on_offset: Callback<usize>,
119  pub on_limit: Callback<usize>,
120  pub on_switch_view_consumer: Callback<bool>,
121  pub on_statuses: Callback<Vec<(String, bool)>>,
122  pub force_refresh: usize,
123  pub on_show_contract_negotiation: Callback<String>,
124  #[prop_or(true)]
125  pub show_status_selector: bool,
126  #[prop_or(true)]
127  pub show_consumer_provider_switch: bool,
128}
129
130#[component]
131pub fn ContractNegotiationPageInner(props: &ContractNegotiationPageInnerProps) -> HtmlResult {
132  let edc_connector_context = use_edc_connector_context();
133
134  let contract_negotiation_items = use_future_with(
135    (
136      edc_connector_context,
137      props.limit,
138      props.offset,
139      props.switch_view_consumer,
140      props.statuses.clone(),
141      props.force_refresh,
142    ),
143    |parameters| async move {
144      let (edc_connector_context, limit, offset, switch_view_consumer, statuses, _) =
145        (*parameters).clone();
146
147      let query_builder = Query::builder()
148        .limit(limit as u32)
149        .offset(offset as u32)
150        .filter(
151          "type",
152          "=",
153          if switch_view_consumer {
154            "CONSUMER"
155          } else {
156            "PROVIDER"
157          },
158        );
159
160      let query_builder = if statuses.iter().all(|(_, selected)| *selected)
161        || statuses.iter().all(|(_, selected)| !*selected)
162      {
163        query_builder
164      } else {
165        let list = statuses
166          .iter()
167          .filter_map(|(label, selected)| {
168            if *selected {
169              Some(label.clone().to_uppercase())
170            } else {
171              None
172            }
173          })
174          .collect::<Vec<_>>();
175
176        query_builder.filter("state", "IN", list)
177      };
178
179      let query = query_builder.sort("createdAt", SortOrder::Desc).build();
180
181      if let Some(client) = edc_connector_context.get_client() {
182        client
183          .contract_negotiations(EdcConnectorApiVersion::V4)
184          .query(query)
185          .await
186          .unwrap_or_default()
187          .into_iter()
188          .map(ContractNegotiationItem::from)
189          .collect()
190      } else {
191        vec![]
192      }
193    },
194  )?;
195
196  let contract_negotiation_items = (*contract_negotiation_items).clone();
197
198  Ok(html!(
199    <ListContractNegotiations
200      contract_negotiation_items={contract_negotiation_items}
201      offset={props.offset}
202      limit={props.limit}
203      switch={props.switch_view_consumer}
204      statuses={props.statuses.clone()}
205      on_offset={props.on_offset.clone()}
206      on_limit={props.on_limit.clone()}
207      on_switch_view_consumer={props.on_switch_view_consumer.clone()}
208      on_show_contract_negotiation={props.on_show_contract_negotiation.clone()}
209      on_statuses={props.on_statuses.clone()}
210      show_status_selector={props.show_status_selector}
211      show_consumer_provider_switch={props.show_consumer_provider_switch}
212    />
213  ))
214}