Skip to main content

edc_web_components/components/
request_verifiable_credential.rs

1use crate::contexts::use_edc_identity_hub_context;
2use edc_identity_hub_client::models::{
3  CredentialFormat, CredentialQuery, RequestCredentialBody, RequestCredentialState,
4};
5use patternfly_yew::prelude::*;
6use uuid::Uuid;
7use yew::platform::spawn_local;
8use yew::platform::time::sleep;
9use yew::prelude::*;
10
11#[derive(Clone, Debug, PartialEq, Properties)]
12pub struct RequestVerifiableCredentialProps {
13  #[prop_or_default]
14  pub on_create: Callback<()>,
15}
16
17#[component]
18pub fn RequestVerifiableCredential(props: &RequestVerifiableCredentialProps) -> Html {
19  let requesting = use_state(|| false);
20  let issuer_did = use_state(String::new);
21  let holder_pid = use_state(|| Uuid::new_v4().to_string());
22  let r#type = use_state(String::new);
23  let id = use_state(String::new);
24
25  let onchange_issuer_did = use_callback(
26    issuer_did.setter(),
27    move |issuer_did: String, issuer_did_setter| {
28      issuer_did_setter.set(issuer_did);
29    },
30  );
31
32  let onchange_holder_pid = use_callback(
33    holder_pid.setter(),
34    move |holder_pid: String, holder_pid_setter| {
35      holder_pid_setter.set(holder_pid);
36    },
37  );
38
39  let onchange_type = use_callback(r#type.setter(), move |r#type: String, type_setter| {
40    type_setter.set(r#type);
41  });
42
43  let onchange_id = use_callback(id.setter(), move |id: String, id_setter| {
44    id_setter.set(id);
45  });
46
47  let edc_identity_hub_context = use_edc_identity_hub_context();
48
49  let onsubmit = use_callback(
50    (
51      issuer_did.clone(),
52      holder_pid.clone(),
53      r#type.clone(),
54      id.clone(),
55      props.on_create.clone(),
56      edc_identity_hub_context.clone(),
57      requesting.clone(),
58    ),
59    |event: SubmitEvent,
60     (issuer_did, holder_pid, r#type, id, on_create, edc_identity_hub_context, requesting)| {
61      event.prevent_default();
62      let edc_identity_hub_context = edc_identity_hub_context.clone();
63      let on_create = on_create.clone();
64      let issuer_did = (**issuer_did).clone();
65      let holder_pid = (**holder_pid).clone();
66      let r#type = (**r#type).clone();
67      let id = (**id).clone();
68      let requesting = requesting.clone();
69
70      spawn_local(async move {
71        requesting.set(true);
72
73        let body = RequestCredentialBody {
74          issuer_did,
75          holder_pid: holder_pid.clone(),
76          credentials: vec![CredentialQuery {
77            format: CredentialFormat::Vc10Jwt,
78            r#type,
79            id,
80          }],
81        };
82
83        let identity_hub_client = edc_identity_hub_context.get_client();
84
85        if let Err(error) = identity_hub_client
86          .request_verifiable_credential(edc_identity_hub_context.participant_id(), &body)
87          .await
88        {
89          log::error!("Error requesting verifiable credential: {:?}", error);
90        }
91
92        loop {
93          sleep(std::time::Duration::from_millis(500)).await;
94          log::info!("Waiting for verifiable credential status to be updated...");
95
96          match identity_hub_client
97            .get_request_verifiable_credential_status(
98              edc_identity_hub_context.participant_id(),
99              &holder_pid,
100            )
101            .await
102          {
103            Ok(status) if status.status == RequestCredentialState::Issued => {
104              break;
105            }
106            Ok(status) if status.status == RequestCredentialState::Error => {
107              break;
108            }
109            _ => {}
110          }
111        }
112
113        on_create.emit(());
114        requesting.set(false);
115      });
116    },
117  );
118
119  let disabled = (*issuer_did).is_empty()
120    || (*holder_pid).is_empty()
121    || (*r#type).is_empty()
122    || (*id).is_empty()
123    || *requesting;
124
125  html!(
126    <Form {onsubmit}>
127      <FormGroup label="Issuer DID" required=true>
128        <TextInput required=true value={(*issuer_did).to_string()} onchange={onchange_issuer_did} />
129      </FormGroup>
130      <FormGroup label="Holder PID" required=true>
131        <TextInput required=true value={(*holder_pid).to_string()} onchange={onchange_holder_pid} />
132      </FormGroup>
133      <FormGroup label="Credential Type" required=true>
134        <TextInput required=true value={(*r#type).to_string()} onchange={onchange_type} />
135      </FormGroup>
136      <FormGroup label="Credential ID" required=true>
137        <TextInput required=true value={(*id).to_string()} onchange={onchange_id} />
138      </FormGroup>
139      <ActionGroup>
140        <Button
141          variant={ButtonVariant::Primary}
142          label="Submit"
143          r#type={ButtonType::Submit}
144          {disabled}
145        />
146        <Button
147          variant={ButtonVariant::Secondary}
148          label="Reset"
149          r#type={ButtonType::Reset}
150          disabled={*requesting}
151        />
152      </ActionGroup>
153    </Form>
154  )
155}