about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2023-06-02T20·43+0300
committertazjin <tazjin@tvl.su>2023-06-06T11·43+0000
commit6fa6f3a7f4a72a74ce495609646d2dae3789cde3 (patch)
treeb5a673931267da0ad6682f0d9ae05567dba5cc58
parent20a671036586088578952f4958440f246decb06e (diff)
feat(corp/rih): submit form data to backend r/6236
Change-Id: I0c74deea8debf9acbcf6eabf225969dbfe9cc34c
Reviewed-on: https://cl.tvl.fyi/c/depot/+/8703
Tested-by: BuildkiteCI
Reviewed-by: tazjin <tazjin@tvl.su>
-rw-r--r--corp/rih/Cargo.lock1
-rw-r--r--corp/rih/Cargo.toml1
-rw-r--r--corp/rih/src/home.html9
-rw-r--r--corp/rih/src/main.rs66
4 files changed, 74 insertions, 3 deletions
diff --git a/corp/rih/Cargo.lock b/corp/rih/Cargo.lock
index 7e472e5fe1..b9d5c9c330 100644
--- a/corp/rih/Cargo.lock
+++ b/corp/rih/Cargo.lock
@@ -1093,6 +1093,7 @@ dependencies = [
  "serde_urlencoded",
  "static_markdown",
  "wasm-bindgen",
+ "wasm-bindgen-futures",
  "web-sys",
  "yew",
  "yew-router",
diff --git a/corp/rih/Cargo.toml b/corp/rih/Cargo.toml
index 2dd8cb7b97..1ef53bb5d3 100644
--- a/corp/rih/Cargo.toml
+++ b/corp/rih/Cargo.toml
@@ -16,6 +16,7 @@ serde_json = "1.0"
 serde_urlencoded = "*" # pinned by yew
 yew = { version = "0.20", features = ["csr"] }
 yew-router = "0.17"
+wasm-bindgen-futures = "0.4"
 
 # needs to be in sync with nixpkgs
 wasm-bindgen = "= 0.2.84"
diff --git a/corp/rih/src/home.html b/corp/rih/src/home.html
index df77ee1e88..697daf5148 100644
--- a/corp/rih/src/home.html
+++ b/corp/rih/src/home.html
@@ -99,6 +99,7 @@ html! {
         <p>{"Let's get started with you telling us a bit about what kind of job you would like!"}</p>
       </div>
 
+      if !self.submitted {
       <div class="mx-auto col-6 border rounded-3 shadow">
         <form class="m-3">
 
@@ -172,12 +173,18 @@ html! {
           <div id="captcha-container" class="smart-captcha mb-3" style="height: 100px" />
 
           <button type="submit" class="btn btn-primary"
-                  disabled={!(self.record.is_complete() && self.captcha_token.is_some())}>
+                  disabled={!(self.record.is_complete() && self.captcha_token.is_some())}
+                  onclick={link.callback(|_| Msg::Submit)}>
             {"Submit"}
           </button>
           <p class="pt-2"><i>{"This page is still under construction! Please reach out at contact@ if you have any questions."}</i></p>
         </form>
       </div>
+      } else {
+      <div class="mx-auto col-6 border rounded-3 shadow">
+        <p>{"Thank you for submitting your data! We will reach out to confirm your email address, and further if any matches are found. You can contact us at contact@russiaishiring.com with any questions you might have."}</p>
+      </div>
+      }
 
     </div>
   </div>
diff --git a/corp/rih/src/main.rs b/corp/rih/src/main.rs
index 02cb350d1a..9b7e38422a 100644
--- a/corp/rih/src/main.rs
+++ b/corp/rih/src/main.rs
@@ -2,7 +2,9 @@ use fuzzy_matcher::skim::SkimMatcherV2;
 use fuzzy_matcher::FuzzyMatcher;
 use gloo::console;
 use gloo::history::{BrowserHistory, History};
+use gloo::net::http;
 use gloo::storage::{LocalStorage, Storage};
+use gloo::utils::format::JsValueSerdeExt;
 use rand::seq::IteratorRandom;
 use rand::thread_rng;
 use serde::{Deserialize, Serialize};
@@ -24,6 +26,13 @@ const CAPTCHA_KEY: &'static str = "ysc1_K7iOi3FSmsyO8pZGu8Im2iQClCtPsVx7jSRyhyCV
 #[cfg(not(debug_assertions))]
 const CAPTCHA_KEY: &'static str = "ysc1_a3LVlaDRDMwU8CLSZ0WKENTI2exyOxz5J2c6x28P5339d410";
 
+// Form data is submitted to different endpoints in dev/prod.
+#[cfg(debug_assertions)]
+const SUBMIT_URL: &'static str = "http://localhost:9090/submit";
+
+#[cfg(not(debug_assertions))]
+const SUBMIT_URL: &'static str = "https://api.russiaishiring.com/submit";
+
 /// This code ends up being compiled for the native and for the
 /// webassembly architectures during the build & test process.
 /// However, the `rust_iso3166` crate exposes a different API (!)
@@ -83,7 +92,7 @@ enum Route {
 
 /// Represents a single record as filled in by a user. This is the
 /// primary data structure we want to populate and persist somewhere.
-#[derive(Default, Debug, Deserialize, Serialize)]
+#[derive(Clone, Default, Debug, Deserialize, Serialize)]
 struct Record {
     // Personal information
     name: String,
@@ -127,6 +136,9 @@ struct App {
     // Captcha callback closure which needs to be kept alive for the
     // lifecycle of the app.
     captcha_callback: Closure<dyn FnMut(String)>,
+
+    // Has data been submitted already by this user?
+    submitted: bool,
 }
 
 #[derive(Clone, Debug)]
@@ -146,7 +158,9 @@ enum Msg {
     SetPosition(String),
     SetJobDetails(String),
     SetWorkBackground(String),
+
     CaptchaSolved(String),
+    Submit,
 }
 
 /// Callback handler for adding a technology.
@@ -306,6 +320,42 @@ fn render_technologies(link: &Scope<App>, technologies: &BTreeSet<String>) -> Ht
     }
 }
 
+/// Submit the collected data to the backend service.
+async fn submit_data(captcha_token: &str, record: &Record) -> bool {
+    let response = http::Request::get(SUBMIT_URL)
+        .method(http::Method::POST)
+        .json(&serde_json::json!({
+            "captcha_token": captcha_token,
+            "record": record,
+        }))
+        .expect("serialising a serde_json::Value can not fail")
+        .send()
+        .await
+        .unwrap();
+
+    // currently there is nothing we can actually do with the response
+    // here, but we should add some way to communicate back some
+    // server errors etc., even if the whole thing should be as
+    // forgiving as possible.
+    response.ok()
+}
+
+/// Handle the submit event, if all data was successfully collected.
+fn handle_submit(app: &App, link: Scope<App>) -> Msg {
+    let token = app.captcha_token.as_ref().unwrap().clone();
+    let record = app.record.clone();
+
+    wasm_bindgen_futures::spawn_local(async move {
+        if !submit_data(&token, &record).await {
+            console::warn!("failed to submit data for some reason");
+        } else {
+            console::log!("submitted data successfully");
+        }
+    });
+
+    Msg::NoOp
+}
+
 impl Component for App {
     type Message = Msg;
     type Properties = ();
@@ -323,10 +373,11 @@ impl Component for App {
                     link.send_message(Msg::CaptchaSolved(val));
                 }))
             },
+            submitted: false,
         }
     }
 
-    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
+    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
         console::log!("handling ", format!("{:?}", msg));
         let (state_change, view_change) = match msg {
             Msg::NoOp => (false, false),
@@ -397,6 +448,17 @@ impl Component for App {
                 self.captcha_token = Some(token);
                 (false, true)
             }
+
+            Msg::Submit => {
+                if self.record.is_complete() && self.captcha_token.is_some() {
+                    self.submitted = true;
+                    handle_submit(self, ctx.link().clone());
+                    (false, true)
+                } else {
+                    console::warn!("submitted data, but form or captcha was not ready");
+                    (false, false)
+                }
+            }
         };
 
         if state_change {