Added contact request logic and connected it to the backend

This commit is contained in:
Franklin 2023-04-14 18:00:19 -04:00
parent 49e7712407
commit 89fe0495cb
7 changed files with 101 additions and 13 deletions

2
Cargo.lock generated
View File

@ -721,6 +721,7 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-logger", "wasm-logger",
"web-sys",
"yew", "yew",
"yew-router", "yew-router",
"yew-utils", "yew-utils",
@ -734,6 +735,7 @@ dependencies = [
"chrono", "chrono",
"chrono-tz", "chrono-tz",
"format_num", "format_num",
"rand",
"serde", "serde",
"serde_json", "serde_json",
"uuid", "uuid",

View File

@ -20,6 +20,7 @@ wasm-bindgen = "0.2.84"
wasm-bindgen-futures = "0.4.34" wasm-bindgen-futures = "0.4.34"
stdweb = "0.4.20" stdweb = "0.4.20"
js-sys = "0.3" js-sys = "0.3"
web-sys = "0.3.61"
# other libs # other libs
reqwest = { version = "0.11.11", features = ["rustls-tls", "json", "blocking"], default-features = false } reqwest = { version = "0.11.11", features = ["rustls-tls", "json", "blocking"], default-features = false }

View File

@ -1,6 +1,6 @@
use std::collections::HashSet; use std::collections::HashSet;
use jl_types::{dto::{filters::Filter, listing::Listing, project_card::ProjectCardDto}, domain::agent::Agent}; use jl_types::{dto::{filters::Filter, listing::Listing, project_card::ProjectCardDto, payloads::contact::ContactPayload}, domain::{agent::Agent, count::Count, contact::Contact}};
use reqwest::Method; use reqwest::Method;
use uuid::Uuid; use uuid::Uuid;
@ -27,3 +27,16 @@ pub async fn get_project_listing(project_id: &Uuid) -> Result<Listing, err::Erro
pub async fn get_all_agents() -> Result<Vec<Agent>, err::Error> { pub async fn get_all_agents() -> Result<Vec<Agent>, err::Error> {
perform_request_without_client::<String, Vec<Agent>>(BASE_URL.into(), Method::GET, format!("read/agent"), None, 200, Vec::new(), None).await perform_request_without_client::<String, Vec<Agent>>(BASE_URL.into(), Method::GET, format!("read/agent"), None, 200, Vec::new(), None).await
} }
pub async fn get_all_page_visits_count() -> Result<Count, err::Error> {
perform_request_without_client::<String, Count>(BASE_URL.into(), Method::GET, format!("admin/visits/count"), None, 200, Vec::new(), None).await
}
pub async fn get_all_contacts_count() -> Result<Count, err::Error> {
perform_request_without_client::<String, Count>(BASE_URL.into(), Method::GET, format!("admin/contacts/count"), None, 200, Vec::new(), None).await
}
pub async fn get_all_contacts() -> Result<Vec<Contact>, err::Error> {
perform_request_without_client::<String, Vec<Contact>>(BASE_URL.into(), Method::GET, format!("admin/contacts"), None, 200, Vec::new(), None).await
}
pub async fn create_new_contact_request(contact: ContactPayload) -> Result<(), err::Error> {
perform_request_without_client(BASE_URL.into(), Method::POST, format!("read/contact"), Some(contact), 200, Vec::new(), None).await
}

View File

@ -1,10 +1,62 @@
use jl_types::dto::payloads::contact::ContactPayload;
use yew::prelude::*; use yew::prelude::*;
use crate::components::{nav_bar::NavigationBar, footer::PageFooter}; use crate::{components::{nav_bar::NavigationBar, footer::PageFooter}, utils::input::{get_value_from_input_event, get_value_from_textarea_event}, api::backend::create_new_contact_request};
#[function_component(ContactPage)] #[function_component(ContactPage)]
pub fn contact_page() -> Html { pub fn contact_page() -> Html {
let first_name = use_state(|| String::new());
let last_name = use_state(|| String::new());
let credential = use_state(|| String::new());
let messsage = use_state(|| String::new());
//TODO: Think about how this renders each time an input is typed onto. (Pretty sure it does, as use_state re-renders the whole component it's in when called)
let on_fn_input_changed = {
let first_name = first_name.clone();
Callback::from(move |e: InputEvent| {
first_name.set(get_value_from_input_event(e));
})
};
let on_ln_input_changed = {
let last_name = last_name.clone();
Callback::from(move |e: InputEvent| {
last_name.set(get_value_from_input_event(e));
})
};
let on_credential_input_changed = {
let credential = credential.clone();
Callback::from(move |e: InputEvent| {
credential.set(get_value_from_input_event(e));
})
};
let on_message_input_changed = {
let messsage = messsage.clone();
Callback::from(move |e: InputEvent| {
messsage.set(get_value_from_textarea_event(e));
})
};
let onclick_button = {
let first_name = first_name.clone();
let last_name = last_name.clone();
let credential = credential.clone();
let messsage = messsage.clone();
Callback::from(move |_| {
let contact = ContactPayload {
first_name: (*first_name).clone(),
last_name: (*last_name).clone(),
credential: (*credential).clone(),
message: (*messsage).clone()
};
wasm_bindgen_futures::spawn_local(async move {
match create_new_contact_request(contact).await {
Ok(_) => {},
Err(error) => log::error!("Error in sending a contact request to the backend: {error}")
};
});
})
};
html! { html! {
<> <>
<NavigationBar/> <NavigationBar/>
@ -23,25 +75,25 @@ pub fn contact_page() -> Html {
<div class={"contact-us-name-container"}> <div class={"contact-us-name-container"}>
<div class={"contact-us-textfield-container"}> // First name <div class={"contact-us-textfield-container"}> // First name
<div class={"contact-us-textfield-label"}>{"Nombre"}</div> <div class={"contact-us-textfield-label"}>{"Nombre"}</div>
<input class={"contact-us-textfield"}/> <input class={"contact-us-textfield"} oninput={on_fn_input_changed}/>
</div> </div>
<div class={"contact-us-textfield-container"}> // Last name <div class={"contact-us-textfield-container"}> // Last name
<div class={"contact-us-textfield-label"}>{"Apellido"}</div> <div class={"contact-us-textfield-label"}>{"Apellido"}</div>
<input class={"contact-us-textfield"}/> <input class={"contact-us-textfield"} oninput={on_ln_input_changed}/>
</div> </div>
</div> </div>
<div class={"contact-us-textfield-container"}> // Email or Phone number <div class={"contact-us-textfield-container"}> // Email or Phone number
<div class={"contact-us-textfield-label"}>{"Número de Teléfono o Correo"}</div> <div class={"contact-us-textfield-label"}>{"Número de Teléfono o Correo"}</div>
<input class={"contact-us-textfield"}/> <input class={"contact-us-textfield"} oninput={on_credential_input_changed}/>
</div> </div>
<div class={"contact-us-textfield-container"}> // Message <div class={"contact-us-textfield-container"}> // Message
<div class={"contact-us-textfield-label"}>{"Mensaje"}</div> <div class={"contact-us-textfield-label"}>{"Mensaje"}</div>
<textarea class={"contact-us-textarea"}/> <textarea class={"contact-us-textarea"} oninput={on_message_input_changed}/>
</div> </div>
<div class={"contact-us-button"}> <div class={"contact-us-button"} onclick={onclick_button}>
{"Enviar"} {"Enviar"}
</div> </div>
</div> </div>

View File

@ -32,14 +32,14 @@ pub fn search_page() -> Html {
cities.insert(0, OptionWrapper::new(None)); cities.insert(0, OptionWrapper::new(None));
cities_handle.set(cities); cities_handle.set(cities);
}, },
Err(error) => info!("Error in loading cities: {error}") Err(error) => log::error!("Error in loading cities: {error}")
}; };
match get_all_projects_with_filters_paged(&(*page_counter), filters).await { match get_all_projects_with_filters_paged(&(*page_counter), filters).await {
Ok(projects) => { Ok(projects) => {
search_results_handle.set(projects); search_results_handle.set(projects);
finished_loading.set(true); finished_loading.set(true);
}, },
Err(error) => info!("Error in loading projects: {error}"), Err(error) => log::error!("Error in loading projects: {error}"),
}; };
}); });
}); });
@ -120,7 +120,7 @@ pub fn search_page() -> Html {
districts_vec.insert(0, OptionWrapper::new(None)); districts_vec.insert(0, OptionWrapper::new(None));
districts_handle.set(districts_vec); districts_handle.set(districts_vec);
}, },
Err(error) => info!("Error in dropdown callback: {}", error), Err(error) => log::error!("Error in dropdown callback: {}", error),
}; };
}); });
} }
@ -182,6 +182,10 @@ pub fn search_page() -> Html {
Some(project_district) => filters.push(Filter::InDistrict(project_district.clone())), Some(project_district) => filters.push(Filter::InDistrict(project_district.clone())),
None => {}, None => {},
}; };
match &(*unit_rooms_filter).option {
Some(rooms_filter) => filters.push(Filter::ByRoomCount(*rooms_filter as i32)),
None => {},
};
let search_results_handle = search_results_handle.clone(); let search_results_handle = search_results_handle.clone();
let page_counter = page_counter.clone(); let page_counter = page_counter.clone();
@ -190,9 +194,8 @@ pub fn search_page() -> Html {
Ok(projects) => { Ok(projects) => {
search_results_handle.set(projects) search_results_handle.set(projects)
}, },
Err(error) => info!("Error in loading projects: {error}"), Err(error) => log::error!("Error in loading projects: {error}"),
}; };
info!("done");
}); });
})}; })};

16
src/utils/input.rs Normal file
View File

@ -0,0 +1,16 @@
use wasm_bindgen::{JsCast, UnwrapThrowExt};
use web_sys::{Event, HtmlInputElement, InputEvent, HtmlTextAreaElement};
pub fn get_value_from_input_event(e: InputEvent) -> String {
let event: Event = e.dyn_into().unwrap_throw();
let event_target = event.target().unwrap_throw();
let target: HtmlInputElement = event_target.dyn_into().unwrap_throw();
target.value()
}
pub fn get_value_from_textarea_event(e: InputEvent) -> String {
let event: Event = e.dyn_into().unwrap_throw();
let event_target = event.target().unwrap_throw();
let target: HtmlTextAreaElement = event_target.dyn_into().unwrap_throw();
target.value()
}

View File

@ -1 +1,2 @@
pub mod get_value; pub mod get_value;
pub mod input;