edc-web-components 0.4.1

A Rust Web Components with patternfly-yew client for EDC
Documentation
use crate::contexts::use_edc_connector_context;
use edc_connector_client::types::contract_negotiation::{
  ContractNegotiation, ContractNegotiationState,
};
use patternfly_yew::prelude::*;
use std::time::Duration;
use yew::platform::spawn_local;
use yew::platform::time::sleep;
use yew::prelude::*;

const HAPPY_PATH_STATES: [(&str, ContractNegotiationState); 7] = [
  ("Initial", ContractNegotiationState::Initial),
  ("Requested", ContractNegotiationState::Requested),
  ("Offered", ContractNegotiationState::Offered),
  ("Accepted", ContractNegotiationState::Accepted),
  ("Agreed", ContractNegotiationState::Agreed),
  ("Verifier", ContractNegotiationState::Verified),
  ("Finalized", ContractNegotiationState::Finalized),
];

#[derive(Clone, Debug, PartialEq, Properties)]
pub struct ContractNegotiationStatusProps {
  pub contract_negotiation_id: String,
  pub on_finalized: Callback<()>,
}

#[component]
pub fn ContractNegotiationStatus(props: &ContractNegotiationStatusProps) -> Html {
  let edc_connector_client = use_edc_connector_context();

  let contract_negotiation_state = use_state(|| None);

  use_effect_with(
    (
      props.contract_negotiation_id.clone(),
      edc_connector_client.clone(),
      contract_negotiation_state.setter(),
      props.on_finalized.clone(),
    ),
    |(
      contract_negotiation_id,
      edc_connector_client,
      contract_negotiation_state_setter,
      on_finalized,
    )| {
      let contract_negotiation_id = contract_negotiation_id.clone();
      let edc_connector_client = edc_connector_client.clone();
      let contract_negotiation_state_setter = contract_negotiation_state_setter.clone();
      let on_finalized = on_finalized.clone();

      spawn_local(async move {
        loop {
          let contract_negotiation = if let Some(client) = edc_connector_client.get_client() {
            client
              .contract_negotiations(edc_connector_client::EdcConnectorApiVersion::V4)
              .get(&contract_negotiation_id)
              .await
              .ok()
          } else {
            None
          };

          let state = contract_negotiation
            .as_ref()
            .map(|contract_negotiation| contract_negotiation.state().clone());

          contract_negotiation_state_setter.set(contract_negotiation);

          if state == Some(ContractNegotiationState::Finalized) {
            on_finalized.emit(());
            break;
          }

          sleep(Duration::from_secs(1)).await;
        }
      });
    },
  );

  if let Some(contract_negotiation) = (*contract_negotiation_state).clone() {
    let contract_negotiation: ContractNegotiation = contract_negotiation;

    let current_state_index = HAPPY_PATH_STATES
      .iter()
      .position(|(_, state)| state == contract_negotiation.state())
      .unwrap_or_default();

    let steps = HAPPY_PATH_STATES
      .iter()
      .enumerate()
      .map(|(index, (state_label, _))| {
        let status = if index < current_state_index {
          ProgressStepperStepStatus::Success
        } else if index == current_state_index {
          if index == HAPPY_PATH_STATES.len() - 1 {
            ProgressStepperStepStatus::Success
          } else {
            ProgressStepperStepStatus::Default
          }
        } else {
          ProgressStepperStepStatus::Pending
        };

        html_nested!(
          <ProgressStepperStep {status}>
            <div>{ state_label.to_string() }</div>
          </ProgressStepperStep>
        )
      });

    html!(<ProgressStepper>{ for steps }</ProgressStepper>)
  } else {
    html!()
  }
}