edc-web-components 0.1.0

A Rust Web Components with patternfly-yew client for EDC
Documentation
use crate::contexts::use_edc_identity_hub_context;
use edc_identity_hub_client::models::{
  CredentialFormat, CredentialQuery, RequestCredentialBody, RequestCredentialState,
};
use patternfly_yew::prelude::*;
use uuid::Uuid;
use yew::platform::spawn_local;
use yew::platform::time::sleep;
use yew::prelude::*;

#[derive(Clone, Debug, PartialEq, Properties)]
pub struct RequestVerifiableCredentialProps {
  #[prop_or_default]
  pub on_create: Callback<()>,
}

#[component]
pub fn RequestVerifiableCredential(props: &RequestVerifiableCredentialProps) -> Html {
  let requesting = use_state(|| false);
  let issuer_did = use_state(String::new);
  let holder_pid = use_state(|| Uuid::new_v4().to_string());
  let r#type = use_state(String::new);
  let id = use_state(String::new);

  let onchange_issuer_did = use_callback(
    issuer_did.setter(),
    move |issuer_did: String, issuer_did_setter| {
      issuer_did_setter.set(issuer_did);
    },
  );

  let onchange_holder_pid = use_callback(
    holder_pid.setter(),
    move |holder_pid: String, holder_pid_setter| {
      holder_pid_setter.set(holder_pid);
    },
  );

  let onchange_type = use_callback(r#type.setter(), move |r#type: String, type_setter| {
    type_setter.set(r#type);
  });

  let onchange_id = use_callback(id.setter(), move |id: String, id_setter| {
    id_setter.set(id);
  });

  let edc_identity_hub_context = use_edc_identity_hub_context();

  let onsubmit = use_callback(
    (
      issuer_did.clone(),
      holder_pid.clone(),
      r#type.clone(),
      id.clone(),
      props.on_create.clone(),
      edc_identity_hub_context.clone(),
      requesting.clone(),
    ),
    |event: SubmitEvent,
     (issuer_did, holder_pid, r#type, id, on_create, edc_identity_hub_context, requesting)| {
      event.prevent_default();
      let edc_identity_hub_context = edc_identity_hub_context.clone();
      let on_create = on_create.clone();
      let issuer_did = (**issuer_did).clone();
      let holder_pid = (**holder_pid).clone();
      let r#type = (**r#type).clone();
      let id = (**id).clone();
      let requesting = requesting.clone();

      spawn_local(async move {
        requesting.set(true);

        let body = RequestCredentialBody {
          issuer_did,
          holder_pid: holder_pid.clone(),
          credentials: vec![CredentialQuery {
            format: CredentialFormat::Vc10Jwt,
            r#type,
            id,
          }],
        };

        let identity_hub_client = edc_identity_hub_context.get_client();

        if let Err(error) = identity_hub_client
          .request_verifiable_credential(edc_identity_hub_context.participant_id(), &body)
          .await
        {
          log::error!("Error requesting verifiable credential: {:?}", error);
        }

        loop {
          sleep(std::time::Duration::from_millis(500)).await;
          log::info!("Waiting for verifiable credential status to be updated...");

          match identity_hub_client
            .get_request_verifiable_credential_status(
              edc_identity_hub_context.participant_id(),
              &holder_pid,
            )
            .await
          {
            Ok(status) if status.status == RequestCredentialState::Issued => {
              break;
            }
            Ok(status) if status.status == RequestCredentialState::Error => {
              break;
            }
            _ => {}
          }
        }

        on_create.emit(());
        requesting.set(false);
      });
    },
  );

  let disabled = (*issuer_did).is_empty()
    || (*holder_pid).is_empty()
    || (*r#type).is_empty()
    || (*id).is_empty()
    || *requesting;

  html!(
    <Form {onsubmit}>
      <FormGroup label="Issuer DID" required=true>
        <TextInput required=true value={(*issuer_did).to_string()} onchange={onchange_issuer_did} />
      </FormGroup>
      <FormGroup label="Holder PID" required=true>
        <TextInput required=true value={(*holder_pid).to_string()} onchange={onchange_holder_pid} />
      </FormGroup>
      <FormGroup label="Credential Type" required=true>
        <TextInput required=true value={(*r#type).to_string()} onchange={onchange_type} />
      </FormGroup>
      <FormGroup label="Credential ID" required=true>
        <TextInput required=true value={(*id).to_string()} onchange={onchange_id} />
      </FormGroup>
      <ActionGroup>
        <Button
          variant={ButtonVariant::Primary}
          label="Submit"
          r#type={ButtonType::Submit}
          {disabled}
        />
        <Button
          variant={ButtonVariant::Secondary}
          label="Reset"
          r#type={ButtonType::Reset}
          disabled={*requesting}
        />
      </ActionGroup>
    </Form>
  )
}