Skip to main content

edc_web_components/components/
list_contract_negotiations.rs

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