diff --git a/src/api/backend/mod.rs b/src/api/backend/mod.rs index bd73987..cc34441 100644 --- a/src/api/backend/mod.rs +++ b/src/api/backend/mod.rs @@ -1,17 +1,23 @@ use std::collections::HashSet; use jl_types::{ - domain::{agent::Agent, contact::Contact, count::Count}, + domain::{agent::Agent, contact::Contact, count::Count, location::Location, project::Project}, dto::{ - filters::Filter, listing::Listing, payloads::contact::ContactPayload, - project_card::ProjectCardDto, + filters::Filter, item::Item, + listing::Listing, + payloads::{ + contact::ContactPayload, + location::NewLocationPayload, + project::{NewProjectPayload, UpdateProjectPayload}, + }, + project_card::ProjectCardDto, }, }; use reqwest::Method; use uuid::Uuid; -use super::base::{perform_request_without_client, perform_multipart_request_without_client}; +use super::base::{perform_multipart_request_without_client, perform_request_without_client}; const BASE_URL: &str = "http://localhost:8095/"; @@ -150,6 +156,59 @@ pub async fn create_new_contact_request(contact: ContactPayload) -> Result<(), e .await } +pub async fn get_location_with_city_and_district( + city: String, + district: String, +) -> Result { + perform_request_without_client::( + BASE_URL.into(), + Method::GET, + format!("read/location/{city}/{district}"), + None, + 200, + Vec::new(), + None, + ) + .await +} + +pub async fn create_new_project(project: NewProjectPayload) -> Result { + perform_request_without_client( + BASE_URL.into(), + Method::POST, + format!("admin/project"), + Some(project), + 200, + Vec::new(), + None, + ) + .await +} +pub async fn create_location(location: NewLocationPayload) -> Result { + perform_request_without_client( + BASE_URL.into(), + Method::POST, + format!("admin/location"), + Some(location), + 200, + Vec::new(), + None, + ) + .await +} +pub async fn update_project(project: UpdateProjectPayload) -> Result { + perform_request_without_client( + BASE_URL.into(), + Method::PUT, + format!("admin/project"), + Some(project), + 200, + Vec::new(), + None, + ) + .await +} + pub async fn upload_image(item: Item, body: Vec) -> Result { perform_multipart_request_without_client( BASE_URL.into(), diff --git a/src/api/base.rs b/src/api/base.rs index ab35d1f..2883691 100644 --- a/src/api/base.rs +++ b/src/api/base.rs @@ -85,7 +85,7 @@ pub async fn perform_multipart_request_without_client( let part = reqwest::multipart::Part::bytes(body).file_name("image"); let form = reqwest::multipart::Form::new(); let form = form.part("image", part); - + match req_incomplete.multipart(form).send().await { // Error handling here Ok(res) => { diff --git a/src/components/admin_agent.rs b/src/components/admin_agent.rs index 58758c2..315a3af 100644 --- a/src/components/admin_agent.rs +++ b/src/components/admin_agent.rs @@ -1,4 +1,4 @@ -use jl_types::{domain::{agent::Agent}}; +use jl_types::domain::agent::Agent; use yew::prelude::*; use yew_router::prelude::use_navigator; diff --git a/src/components/admin_unit.rs b/src/components/admin_unit.rs index b3ada59..b58342b 100644 --- a/src/components/admin_unit.rs +++ b/src/components/admin_unit.rs @@ -11,17 +11,14 @@ use crate::{ #[function_component(AdminUnit)] pub fn admin_project(props: &AdminUnitProps) -> Html { let navigator = use_navigator().unwrap(); - let price_usd = format!( - "${}", - { - let price_separated = props.unit.price_usd.separate_with_commas(); - if price_separated.contains(".") { - price_separated - } else { - format!("{price_separated}.00") - } + let price_usd = format!("${}", { + let price_separated = props.unit.price_usd.separate_with_commas(); + if price_separated.contains(".") { + price_separated + } else { + format!("{price_separated}.00") } - ); + }); let is_attempting_delete = use_state(|| false); let delete_unit = { let is_attempting_delete = is_attempting_delete.clone(); diff --git a/src/components/media_picker.rs b/src/components/media_picker.rs index 01a5f39..1db6b41 100644 --- a/src/components/media_picker.rs +++ b/src/components/media_picker.rs @@ -3,7 +3,10 @@ use js_sys::Uint8Array; use wasm_bindgen_futures::JsFuture; use yew::prelude::*; -use crate::{components::textfield::{get_value_from_input_event, get_files_from_input_event}, api}; +use crate::{ + api, + components::textfield::{get_files_from_input_event, get_value_from_input_event}, +}; #[function_component(MediaPicker)] pub fn media_picker(props: &MediaPickerProps) -> Html { @@ -95,7 +98,6 @@ fn render_media_list(props: &MediaListProps) -> Html { let onchange_cb = props.onchange.clone(); let item = props.item.clone(); Callback::from(move |e: InputEvent| { - match onchange_cb.clone() { Some(cb) => cb.emit(String::new()), None => {} @@ -117,14 +119,18 @@ fn render_media_list(props: &MediaListProps) -> Html { let mut media = (*media_handle).clone(); media.media_list.push(Media::Photo(url)); media_handle.set(media); - }, - Err(error) => log::error!("Error uploading image to backend: {error}"), + } + Err(error) => { + log::error!("Error uploading image to backend: {error}") + } }; }); - }, - None => {log::error!("No files in first element of filelist...")} + } + None => { + log::error!("No files in first element of filelist...") + } }; - }, + } None => { log::error!("Something weird happened. No files after selecting files") } diff --git a/src/components/mod.rs b/src/components/mod.rs index 6fd1311..2ed3946 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,5 +1,7 @@ +pub mod admin_agent; pub mod admin_nav_bar; pub mod admin_project; +pub mod admin_unit; pub mod agent_card; pub mod datepicker; pub mod dropdown; @@ -12,5 +14,3 @@ pub mod nav_bar; pub mod new_widget; pub mod project_card; pub mod textfield; -pub mod admin_unit; -pub mod admin_agent; \ No newline at end of file diff --git a/src/pages/admin/agents.rs b/src/pages/admin/agents.rs index f361d12..3f48a9b 100644 --- a/src/pages/admin/agents.rs +++ b/src/pages/admin/agents.rs @@ -1,6 +1,12 @@ use yew::prelude::*; -use crate::{api::backend::get_all_agents, components::{admin_nav_bar::AdminNavigationBar, admin_agent::AdminAgent, new_widget::NewThingWidget}, pages::admin::edit::EditItem}; +use crate::{ + api::backend::get_all_agents, + components::{ + admin_agent::AdminAgent, admin_nav_bar::AdminNavigationBar, new_widget::NewThingWidget, + }, + pages::admin::edit::EditItem, +}; #[function_component(AdminAgents)] pub fn admin_agents() -> Html { diff --git a/src/pages/admin/contacts.rs b/src/pages/admin/contacts.rs index db4201b..6684832 100644 --- a/src/pages/admin/contacts.rs +++ b/src/pages/admin/contacts.rs @@ -20,14 +20,14 @@ pub fn admin_contacts() -> Html { }); }); html! { - <> - -
-
-
{"Solicitudes de Contacto"}
-//TODO: Finish this + <> + +
+
+
{"Solicitudes de Contacto"}
+ //TODO: Finish this +
-
- - } + + } } diff --git a/src/pages/admin/edit.rs b/src/pages/admin/edit.rs index 6cdc937..f4c57a7 100644 --- a/src/pages/admin/edit.rs +++ b/src/pages/admin/edit.rs @@ -1,25 +1,35 @@ use std::{fmt::Display, str::FromStr}; +use chrono::NaiveTime; use jl_types::{ domain::{ agent::Agent, media::MediaList, project_condition::ProjectCondition, project_state::ProjectState, project_type::ProjectType, unit::Unit, }, - dto::listing::Listing, + dto::{ + listing::Listing, + payloads::{project::{NewProjectPayload, UpdateProjectPayload}, location::NewLocationPayload}, + }, }; use uuid::Uuid; use yew::prelude::*; use yew_router::prelude::use_navigator; use crate::{ - api::backend::{get_all_agents, get_project_listing}, + api::backend::{ + create_location, create_new_project, get_all_agents, get_location_with_city_and_district, + get_project_listing, update_project, + }, components::{ admin_nav_bar::AdminNavigationBar, datepicker::DatePicker, dropdown::DropDown, media_picker::MediaPicker, - textfield::{TextField, TextFieldType}, new_widget::NewThingWidget, - }, pages::admin::units::AdminUnits, + new_widget::NewThingWidget, + textfield::{TextField, TextFieldType}, + }, + pages::admin::units::AdminUnits, + routes::main_router::Route, }; /// All of the editing actions of the admin panel will lead to here. This should take an id of anything. A unit, a project, an agent. And its corresponding ID. @@ -70,7 +80,7 @@ pub fn edit_page(props: &AdminEditPageProps) -> Html { { match props.edit_item { EditItem::Agent => {html! {}}, - EditItem::Project => {html! { }}, + EditItem::Project => {html! { }}, EditItem::Unit(_) => {html! {}}, } } @@ -104,11 +114,13 @@ pub struct AdminEditPageProps { #[derive(Properties, PartialEq, Clone)] pub struct ProjectFieldsProps { pub listing: Option, + pub edittype: EditType, } #[allow(unused)] #[function_component(ProjectFields)] pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html { + let navigator = use_navigator().unwrap(); let user_typed = use_state(|| false); let listing_opt = props.listing.clone(); @@ -228,6 +240,154 @@ pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html { }); } + let update_button_onclick = { + let navigator = navigator.clone(); + let edit_type = props.edittype.clone(); + + // All fields to be sent to the backend + let location_city = location_city.clone(); + let location_district = location_district.clone(); + let agent = agent.clone(); + let project_state = project_state.clone(); + let project_condition = project_condition.clone(); + let project_type = project_type.clone(); + let project_description = project_description.clone(); + let project_admin_tag = project_admin_tag.clone(); + let project_finish_date = project_finish_date.clone(); + let project_floors = project_floors.clone(); + let media = media.clone(); + Callback::from(move |_: MouseEvent| { + let navigator = navigator.clone(); + let edit_type = edit_type.clone(); + //TODO: Create the location first. + //TODO: Then send the updateprojectpayload. + let location_city_handle = location_city.clone(); + let location_district_handle = location_district.clone(); + let agent_handle = agent.clone(); + let project_state_handle = project_state.clone(); + let project_condition_handle = project_condition.clone(); + let project_type_handle = project_type.clone(); + let project_description_handle = project_description.clone(); + let project_admin_tag_handle = project_admin_tag.clone(); + let project_finish_date_handle = project_finish_date.clone(); + let project_floors_handle = project_floors.clone(); + let media_handle = media.clone(); + wasm_bindgen_futures::spawn_local(async move { + let location = match get_location_with_city_and_district( + (*location_city_handle).clone(), + (*location_district_handle).clone(), + ) + .await + { + Ok(location) => location, + Err(_) => { + // Create location + match create_location(NewLocationPayload {city: (*location_city_handle).clone(), district: (*location_district_handle).clone()}).await { + Ok(location) => location, + Err(error) => { + log::error!("Couldn't create location..: {error}"); + return; + } + } + } + }; + let agent_id = match (*agent_handle).clone() { + Some(selected_agent) => selected_agent.id, + None => { + log::error!("Missing Field agent."); + return; + } + }; + let project_state = match (*project_state_handle).clone() { + Some(selected_project_state) => selected_project_state, + None => { + log::error!("Missing Field project_state."); + return; + } + }; + let project_condition = match (*project_condition_handle).clone() { + Some(selected_project_condition) => selected_project_condition, + None => { + log::error!("Missing Field project_condition."); + return; + } + }; + let project_type = match (*project_type_handle).clone() { + Some(selected_project_type) => selected_project_type, + None => { + log::error!("Missing Field project_type."); + return; + } + }; + let description = (*project_description_handle).clone(); + let project_admin_tag = (*project_admin_tag_handle).clone(); + let admin_tag = if project_admin_tag.is_empty() { + None + } else { + Some(project_admin_tag) + }; + let finish_date = match (*project_finish_date_handle).clone() { + Some(finish_date) => finish_date.and_time(NaiveTime::default()), + None => { + log::error!("Missing Field finish_date."); + return; + } + }; + let floors = match i16::from_str(&(*project_floors_handle).clone()) { + Ok(floors) => floors, + Err(error) => { + log::error!("Could not parse floors correctly. {error}"); + return; + } + }; + let media = (*media_handle).clone(); + + match edit_type { + EditType::New => { + let payload = NewProjectPayload { + project_state, + project_type, + project_condition, + agent_id, + location_id: location.id, + title: None, + description, + admin_tag, + finish_date, + floors, + media, + }; + + match create_new_project(payload).await { + Ok(_) => navigator.clone().push(&Route::AdminProjects), + Err(error) => log::error!("Error creating new project: {error}"), + }; + } + EditType::Existing(id) => { + let payload = UpdateProjectPayload { + id, + project_state: Some(project_state), + project_type: Some(project_type), + project_condition: Some(project_condition), + agent_id: Some(agent_id), + location_id: Some(location.id), + title: None, + description: Some(description), + admin_tag: Some(admin_tag), + finish_date: Some(finish_date), + floors: Some(floors), + media: Some(media), + }; + + match update_project(payload).await { + Ok(_) => navigator.clone().push(&Route::AdminProjects), + Err(error) => log::error!("Error updating project: {error}"), + }; + } + } + }); + }) + }; html! { <> @@ -313,7 +473,7 @@ pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html { -
+
{"Actualizar"}
diff --git a/src/pages/admin/mod.rs b/src/pages/admin/mod.rs index 7bf65e2..4042ad5 100644 --- a/src/pages/admin/mod.rs +++ b/src/pages/admin/mod.rs @@ -4,4 +4,4 @@ pub mod edit; pub mod login; pub mod projects; pub mod start; -pub mod units; \ No newline at end of file +pub mod units; diff --git a/src/pages/admin/units.rs b/src/pages/admin/units.rs index 65ce641..b382f90 100644 --- a/src/pages/admin/units.rs +++ b/src/pages/admin/units.rs @@ -1,11 +1,7 @@ use jl_types::domain::unit::Unit; use yew::prelude::*; -use crate::{ - components::{ - admin_unit::AdminUnit, - }, -}; +use crate::components::admin_unit::AdminUnit; #[function_component(AdminUnits)] pub fn admin_units(props: &AdminUnitProps) -> Html { @@ -27,5 +23,5 @@ pub fn admin_units(props: &AdminUnitProps) -> Html { #[derive(PartialEq, Properties, Clone)] pub struct AdminUnitProps { - pub units: Vec -} \ No newline at end of file + pub units: Vec, +}