Skip to main content

shield_leptos/routes/
action.rs

1use leptos::prelude::*;
2use leptos_router::{hooks::use_params, params::Params};
3use serde_json::Value;
4use shield::ActionForms;
5
6use crate::ErasedLeptosStyle;
7
8#[derive(Params, PartialEq)]
9struct ActionParams {
10    action_id: Option<String>,
11}
12
13#[component]
14pub fn Action() -> impl IntoView {
15    let params = use_params::<ActionParams>();
16    let action_id = move || {
17        params
18            .read()
19            .as_ref()
20            .ok()
21            .and_then(|params| params.action_id.clone())
22            .unwrap_or("index".to_owned())
23    };
24
25    let resource = Resource::new(action_id, forms);
26    let style = expect_context::<ErasedLeptosStyle>();
27
28    view! {
29        <Transition>
30            {move || resource.get().map(|response| match response {
31                Ok(forms) => style.render(&forms),
32                Err(err) => format!("{err:?}").into_any()
33            })}
34        </Transition>
35    }
36}
37
38#[server]
39async fn forms(action_id: String) -> Result<ActionForms, ServerFnError> {
40    use crate::expect_server_integration;
41
42    let integration = expect_server_integration();
43    let shield = integration.extract_shield().await;
44    let session = integration.extract_session().await;
45
46    let forms = shield.action_forms(&action_id, session).await?;
47
48    Ok(forms)
49}
50
51#[server]
52pub async fn call(
53    action_id: String,
54    // TODO: Would be nice if this argument could fill up with all unknown keys instead of setting name to `data[...]`.
55    data: Value,
56) -> Result<(), ServerFnError> {
57    use serde_json::Value;
58    use shield::{Request, ResponseType};
59
60    use crate::expect_server_integration;
61
62    let integration = expect_server_integration();
63    let shield = integration.extract_shield().await;
64    let session = integration.extract_session().await;
65
66    tracing::info!("call data {data:#?}");
67
68    let response = shield
69        .call(
70            &action_id,
71            session,
72            Request {
73                query: Value::Null,
74                form_data: data,
75            },
76        )
77        .await?;
78
79    match response {
80        ResponseType::Default => todo!("default reponse"),
81        ResponseType::Redirect(to) => {
82            integration.redirect(&to);
83        }
84        ResponseType::RedirectToAction { action_id } => {
85            // TODO: Use actual router prefix instead of hardcoded `/auth`.
86            integration.redirect(&format!("/auth/{action_id}"));
87        }
88    }
89
90    Ok(())
91}
92
93#[server]
94pub async fn call_method(
95    action_id: String,
96    method_id: String,
97    provider_id: Option<String>,
98    // TODO: Would be nice if this argument could fill up with all unknown keys instead of setting name to `data[...]`.
99    data: Value,
100) -> Result<(), ServerFnError> {
101    use serde_json::Value;
102    use shield::{Request, ResponseType};
103
104    use crate::expect_server_integration;
105
106    let integration = expect_server_integration();
107    let shield = integration.extract_shield().await;
108    let session = integration.extract_session().await;
109
110    tracing::info!("call method data {data:#?}");
111
112    let response = shield
113        .call_method(
114            &action_id,
115            &method_id,
116            provider_id.as_deref(),
117            session,
118            Request {
119                query: Value::Null,
120                form_data: data,
121            },
122        )
123        .await?;
124
125    match response {
126        ResponseType::Default => todo!("default reponse"),
127        ResponseType::Redirect(to) => {
128            integration.redirect(&to);
129        }
130        ResponseType::RedirectToAction { action_id } => {
131            // TODO: Use actual router prefix instead of hardcoded `/auth`.
132            integration.redirect(&format!("/auth/{action_id}"));
133        }
134    }
135
136    Ok(())
137}