Skip to main content

edc_web_components/components/
list_contract_negotiations.rs

1use crate::components::MultiStateSelector;
2use crate::models::ContractNegotiationItem;
3use patternfly_yew::prelude::*;
4use std::rc::Rc;
5use yew::prelude::*;
6
7#[derive(Clone, Debug, PartialEq, Properties)]
8pub struct ListContractNegotiationsProps {
9  pub contract_negotiation_items: Vec<ContractNegotiationItem>,
10  pub offset: usize,
11  pub limit: usize,
12  pub switch: bool,
13  pub statuses: Vec<(String, bool)>,
14  pub on_offset: Callback<usize>,
15  pub on_limit: Callback<usize>,
16  pub on_switch_view_consumer: Callback<bool>,
17  pub on_show_contract_negotiation: Callback<String>,
18  pub on_statuses: Callback<Vec<(String, bool)>>,
19}
20
21#[component]
22pub fn ListContractNegotiations(props: &ListContractNegotiationsProps) -> Html {
23  let header = html_nested! {
24    <TableHeader<Columns>>
25      <TableColumn<Columns> label="State" index={Columns::State} />
26      <TableColumn<Columns> label="Contract Agreement ID" index={Columns::ContractAgreementId} />
27      <TableColumn<Columns> label="Counter Party ID" index={Columns::CounterPartyId} />
28      <TableColumn<Columns> label="Protocol" index={Columns::Protocol} />
29      <TableColumn<Columns> label="Kind" index={Columns::Kind} />
30      <TableColumn<Columns> label="" index={Columns::Actions} />
31    </TableHeader<Columns>>
32  };
33
34  let total_entries: Option<usize> = None;
35
36  let nav_callback = use_callback(
37    (
38      props.offset,
39      props.limit,
40      total_entries,
41      props.on_offset.clone(),
42    ),
43    |page: Navigation, (offset, limit, total_entries, on_offset)| {
44      let offset = match page {
45        Navigation::First => 0,
46        Navigation::Last => (total_entries.unwrap_or_default().saturating_sub(1) / limit) * limit,
47        Navigation::Previous => *offset - limit,
48        Navigation::Next => *offset + limit,
49        Navigation::Page(n) => n * limit,
50      };
51      on_offset.emit(offset);
52    },
53  );
54
55  let rows = props
56    .contract_negotiation_items
57    .iter()
58    .map(
59      |contract_negotiation_item| ContractNegotiationItemRenderer {
60        item: contract_negotiation_item.clone(),
61        on_show_contract_negotiation: props.on_show_contract_negotiation.clone(),
62      },
63    )
64    .collect();
65
66  let (entries, _) = use_table_data(MemoizedTableModel::new(Rc::new(rows)));
67
68  let statuses_selector = {
69    html!(
70      <MultiStateSelector
71        selectable_items={props.statuses.clone()}
72        on_selected={props.on_statuses.clone()}
73      />
74    )
75  };
76
77  html!(
78    <>
79      <Toolbar>
80        <ToolbarContent>
81          <ToolbarItem r#type={ToolbarItemType::BulkSelect}>
82            { statuses_selector }
83            <Switch
84              label="as Consumer"
85              label_off="as Provider"
86              onchange={props.on_switch_view_consumer.clone()}
87            />
88          </ToolbarItem>
89          <ToolbarItem r#type={ToolbarItemType::Pagination}>
90            <Pagination
91              offset={props.offset}
92              entries_per_page_choices={vec![5, 10, 25, 50, 100]}
93              selected_choice={props.limit}
94              onlimit={&props.on_limit}
95              onnavigation={&nav_callback}
96            />
97          </ToolbarItem>
98        </ToolbarContent>
99      </Toolbar>
100      <Table<Columns, UseTableData<Columns, MemoizedTableModel<ContractNegotiationItemRenderer>>>
101        mode={TableMode::Compact}
102        {header}
103        {entries}
104      />
105    </>
106  )
107}
108
109#[derive(Clone, Debug, Eq, PartialEq)]
110enum Columns {
111  State,
112  ContractAgreementId,
113  CounterPartyId,
114  Protocol,
115  Kind,
116  Actions,
117}
118
119#[derive(Clone, Debug)]
120struct ContractNegotiationItemRenderer {
121  item: ContractNegotiationItem,
122  on_show_contract_negotiation: Callback<String>,
123}
124
125impl TableEntryRenderer<Columns> for ContractNegotiationItemRenderer {
126  fn render_cell(&self, context: CellContext<'_, Columns>) -> Cell {
127    match context.column {
128      Columns::State => {
129        let color = match self.item.state.as_str() {
130          "Finalized" => Color::Green,
131          "Terminated" => Color::Red,
132          _ => Color::Blue,
133        };
134
135        html! { <Label label={self.item.state.to_string()} {color} /> }
136      },
137      Columns::ContractAgreementId => html! { self.item.contract_agreement_id.to_string() },
138      Columns::CounterPartyId => html! { self.item.counter_party_id.to_string() },
139      Columns::Protocol => html! { self.item.protocol.to_string() },
140      Columns::Kind => html! { self.item.kind.to_string() },
141      Columns::Actions => {
142        let contract_negotiation_id = self.item.id.clone();
143        html! {
144          <Button
145            variant={ButtonVariant::Primary}
146            onclick={self.on_show_contract_negotiation.clone().reform(move |_| contract_negotiation_id.clone())}
147            icon={Icon::Eye}
148          >
149            { "Show" }
150          </Button>
151        }
152      },
153    }
154    .into()
155  }
156}