Added contact request logic and connected it to the backend
This commit is contained in:
parent
49e7712407
commit
89fe0495cb
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -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",
|
||||||
|
@ -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 }
|
||||||
|
@ -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
|
||||||
|
}
|
@ -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>
|
||||||
|
@ -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
16
src/utils/input.rs
Normal 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()
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
pub mod get_value;
|
pub mod get_value;
|
||||||
|
pub mod input;
|
Loading…
Reference in New Issue
Block a user