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