edc_web_components/components/
list_contract_negotiations.rs1use 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}