Finished Unit edit
This commit is contained in:
parent
65395552e0
commit
7177823b14
@ -1,15 +1,20 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use jl_types::{
|
||||
domain::{agent::Agent, contact::Contact, count::Count, location::Location, project::Project, unit::Unit},
|
||||
domain::{
|
||||
agent::Agent, contact::Contact, count::Count, location::Location, project::Project,
|
||||
unit::Unit,
|
||||
},
|
||||
dto::{
|
||||
filters::Filter,
|
||||
item::Item,
|
||||
listing::Listing,
|
||||
payloads::{
|
||||
agent::{NewAgentPayload, UpdateAgentPayload},
|
||||
contact::ContactPayload,
|
||||
location::NewLocationPayload,
|
||||
project::{NewProjectPayload, UpdateProjectPayload}, unit::UpdateUnitPayload, agent::{UpdateAgentPayload, NewAgentPayload},
|
||||
project::{NewProjectPayload, UpdateProjectPayload},
|
||||
unit::{UpdateUnitPayload, NewUnitPayload},
|
||||
},
|
||||
project_card::ProjectCardDto,
|
||||
},
|
||||
@ -213,6 +218,20 @@ pub async fn create_new_agent(agent: NewAgentPayload) -> Result<Agent, err::Erro
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_new_unit(unit: NewUnitPayload) -> Result<Unit, err::Error> {
|
||||
perform_request_without_client(
|
||||
BASE_URL.into(),
|
||||
Method::POST,
|
||||
format!("admin/unit"),
|
||||
Some(unit),
|
||||
200,
|
||||
Vec::new(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_new_project(project: NewProjectPayload) -> Result<Project, err::Error> {
|
||||
perform_request_without_client(
|
||||
BASE_URL.into(),
|
||||
|
@ -3,8 +3,9 @@ use yew::prelude::*;
|
||||
use yew_router::prelude::use_navigator;
|
||||
|
||||
use crate::{
|
||||
api::backend::delete_agent,
|
||||
pages::admin::edit::{EditItem, EditType},
|
||||
routes::main_router::Route, api::backend::delete_agent,
|
||||
routes::main_router::Route,
|
||||
};
|
||||
|
||||
//TODO: Add admin tag
|
||||
|
@ -4,8 +4,9 @@ use yew::prelude::*;
|
||||
use yew_router::prelude::use_navigator;
|
||||
|
||||
use crate::{
|
||||
api::backend::delete_unit,
|
||||
pages::admin::edit::{EditItem, EditType},
|
||||
routes::main_router::Route, api::backend::delete_unit,
|
||||
routes::main_router::Route,
|
||||
};
|
||||
|
||||
#[function_component(AdminUnit)]
|
||||
@ -20,7 +21,7 @@ pub fn admin_unit(props: &AdminUnitProps) -> Html {
|
||||
format!("{price_separated}.00")
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let delete_unit = {
|
||||
let is_attempting_delete = is_attempting_delete.clone();
|
||||
let deletecb = props.deletecb.clone();
|
||||
@ -89,5 +90,5 @@ pub fn admin_unit(props: &AdminUnitProps) -> Html {
|
||||
pub struct AdminUnitProps {
|
||||
pub unit: Unit,
|
||||
pub index: usize,
|
||||
pub deletecb: Callback<usize>
|
||||
pub deletecb: Callback<usize>,
|
||||
}
|
||||
|
@ -15,8 +15,6 @@ pub struct DropDownProps<T: Display + std::cmp::PartialEq + Clone> {
|
||||
pub onchange: Option<Callback<Option<T>>>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[function_component(DropDown)]
|
||||
pub fn dropdown<T: Display + std::cmp::PartialEq + Clone + 'static>(
|
||||
props: &DropDownProps<T>,
|
||||
@ -33,19 +31,19 @@ pub fn dropdown<T: Display + std::cmp::PartialEq + Clone + 'static>(
|
||||
.collect();
|
||||
|
||||
options.insert(0, None);
|
||||
|
||||
|
||||
options
|
||||
},
|
||||
selection_changed: match props.onchange.clone() {
|
||||
Some(cb) => cb,
|
||||
None => Callback::from(|_| {})
|
||||
None => Callback::from(|_| {}),
|
||||
},
|
||||
class_css: Some("admin-dropdown".into()),
|
||||
none_str: props.unpicked_text.clone()
|
||||
none_str: props.unpicked_text.clone(),
|
||||
},
|
||||
);
|
||||
//if (*props.selected).is_none() {selection_changed_cb.emit( OptionWrapper::new((*props.selected).clone()));}
|
||||
html! {
|
||||
{drop_down}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use jl_types::domain::media::{Media, MediaList};
|
||||
use jl_types::{domain::media::{Media, MediaList}, dto::item::Item};
|
||||
use js_sys::Uint8Array;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use yew::prelude::*;
|
||||
@ -12,7 +12,11 @@ use crate::{
|
||||
pub fn media_picker(props: &MediaPickerProps) -> Html {
|
||||
html! {
|
||||
<>
|
||||
<div class={{"textfield-label-required"}}>{"Media del proyecto"}</div>
|
||||
<div class={{"textfield-label-required"}}>{format!("Media {}", match props.item {
|
||||
Item::Project => "del Proyecto",
|
||||
Item::Unit => "de la Unidad",
|
||||
Item::Agent => "del Agente"
|
||||
})}</div>
|
||||
<div class={"mediapicker-container"}>
|
||||
<MediaListRendered medialist={props.value.clone()} onchange={props.onchange.clone()} item={props.item.clone()}/>
|
||||
</div>
|
||||
|
@ -12,7 +12,7 @@ pub mod media_picker;
|
||||
pub mod media_slideshow;
|
||||
pub mod nav_bar;
|
||||
pub mod new_widget;
|
||||
pub mod number_textfield;
|
||||
pub mod project_card;
|
||||
pub mod textfield;
|
||||
pub mod single_media_picker;
|
||||
pub mod number_textfield;
|
||||
pub mod textfield;
|
||||
|
@ -1,8 +1,7 @@
|
||||
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||
use web_sys::{HtmlInputElement};
|
||||
use web_sys::HtmlInputElement;
|
||||
use yew::prelude::*;
|
||||
use std::{str::FromStr, fmt::{Display}};
|
||||
|
||||
#[derive(Properties, PartialEq, Clone)]
|
||||
pub struct NumberTextFieldProps<T: PartialEq + Clone + Display + Default + FromStr> {
|
||||
@ -14,23 +13,26 @@ pub struct NumberTextFieldProps<T: PartialEq + Clone + Display + Default + FromS
|
||||
}
|
||||
|
||||
#[function_component(NumberTextField)]
|
||||
pub fn number_textfield<T: PartialEq + Clone + Display + Default + FromStr + 'static>(props: &NumberTextFieldProps<T>) -> Html {
|
||||
pub fn number_textfield<T: PartialEq + Clone + Display + Default + FromStr + 'static>(
|
||||
props: &NumberTextFieldProps<T>,
|
||||
) -> Html {
|
||||
let on_input_changed = {
|
||||
let handle = props.value.clone();
|
||||
let onchange = props.onchange.clone();
|
||||
Callback::from(move |e: InputEvent| {
|
||||
let value = match get_number_value_from_input_event::<T>(e) {
|
||||
Ok(float) => float,
|
||||
Err(_) => {
|
||||
log::error!("Error ocurred attempting to parse number on input type number. This only happens in firefox browsers.");
|
||||
T::default()
|
||||
}};
|
||||
match onchange.clone() {
|
||||
Some(onchange) => onchange.emit(value.clone()),
|
||||
None => {}
|
||||
};
|
||||
handle.set(value);
|
||||
})
|
||||
let value = match get_number_value_from_input_event::<T>(e) {
|
||||
Ok(float) => float,
|
||||
Err(_) => {
|
||||
log::error!("Error ocurred attempting to parse number on input type number. This only happens in firefox browsers.");
|
||||
T::default()
|
||||
}
|
||||
};
|
||||
match onchange.clone() {
|
||||
Some(onchange) => onchange.emit(value.clone()),
|
||||
None => {}
|
||||
};
|
||||
handle.set(value);
|
||||
})
|
||||
};
|
||||
html! {
|
||||
<div class={"textfield-container"}>
|
||||
@ -48,4 +50,4 @@ pub fn get_number_value_from_input_event<T: FromStr>(e: InputEvent) -> Result<T,
|
||||
Ok(t) => Ok(t),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,7 @@ use js_sys::Uint8Array;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use yew::prelude::*;
|
||||
|
||||
use crate::{
|
||||
api,
|
||||
components::textfield::{get_files_from_input_event},
|
||||
};
|
||||
use crate::{api, components::textfield::get_files_from_input_event};
|
||||
|
||||
#[derive(PartialEq, Properties, Clone)]
|
||||
pub struct SingleMediaPickerProps {
|
||||
@ -102,9 +99,8 @@ pub fn single_media_picker(props: &SingleMediaPickerProps) -> Html {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,13 +5,9 @@ use yew::prelude::*;
|
||||
use yew_router::prelude::use_navigator;
|
||||
|
||||
use crate::{
|
||||
api::backend::{
|
||||
get_project_listing, get_agent_with_id, get_unit_with_id,
|
||||
},
|
||||
components::{
|
||||
admin_nav_bar::AdminNavigationBar,
|
||||
},
|
||||
pages::admin::{fields::{project::ProjectFields, unit::UnitFields, agent::AgentFields}},
|
||||
api::backend::{get_agent_with_id, get_project_listing},
|
||||
components::admin_nav_bar::AdminNavigationBar,
|
||||
pages::admin::fields::{agent::AgentFields, project::ProjectFields, unit::UnitFields},
|
||||
};
|
||||
|
||||
/// 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.
|
||||
@ -20,11 +16,9 @@ pub fn edit_page(props: &AdminEditPageProps) -> Html {
|
||||
let _navigator = use_navigator().unwrap();
|
||||
let listing = use_state(|| None);
|
||||
let agent = use_state(|| None);
|
||||
let unit = use_state(|| None);
|
||||
use_state(|| {
|
||||
let listing = listing.clone();
|
||||
let agent = agent.clone();
|
||||
let unit = unit.clone();
|
||||
match props.edit_item {
|
||||
EditItem::Agent => {
|
||||
match props.edit_type {
|
||||
@ -61,17 +55,7 @@ pub fn edit_page(props: &AdminEditPageProps) -> Html {
|
||||
EditItem::Unit(_) => {
|
||||
match props.edit_type {
|
||||
EditType::New => {}
|
||||
EditType::Existing(uid) => {
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let unit_result = get_unit_with_id(&uid).await;
|
||||
match unit_result {
|
||||
Ok(unit_persisted) => {
|
||||
unit.set(Some(unit_persisted));
|
||||
}
|
||||
Err(error) => log::error!("Error loading unit: {error}"),
|
||||
};
|
||||
});
|
||||
}
|
||||
EditType::Existing(_) => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -97,7 +81,7 @@ pub fn edit_page(props: &AdminEditPageProps) -> Html {
|
||||
match props.edit_item {
|
||||
EditItem::Agent => { html! { <AgentFields agent={(*agent).clone()} edittype={props.edit_type.clone()} /> } },
|
||||
EditItem::Project => { html! { <ProjectFields listing={(*listing).clone()} edittype={props.edit_type.clone()}/> } },
|
||||
EditItem::Unit(project_id) => { html! { <UnitFields edittype={props.edit_type.clone()} unit={(*unit).clone()} projectid={project_id}/> } },
|
||||
EditItem::Unit(project_id) => { html! { <UnitFields edittype={props.edit_type.clone()} projectid={project_id}/> } },
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
@ -1,8 +1,18 @@
|
||||
use jl_types::{domain::{agent::Agent, credential::CredentialType}, dto::payloads::agent::{NewAgentPayload, UpdateAgentPayload}};
|
||||
use jl_types::{
|
||||
domain::{agent::Agent, credential::CredentialType},
|
||||
dto::payloads::agent::{NewAgentPayload, UpdateAgentPayload},
|
||||
};
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::use_navigator;
|
||||
|
||||
use crate::{pages::admin::edit::{EditType}, components::{textfield::TextField, dropdown::DropDown, single_media_picker::SingleMediaPicker}, api::backend::{update_agent, create_new_agent}, routes::main_router::Route, };
|
||||
use crate::{
|
||||
api::backend::{create_new_agent, update_agent},
|
||||
components::{
|
||||
dropdown::DropDown, single_media_picker::SingleMediaPicker, textfield::TextField,
|
||||
},
|
||||
pages::admin::edit::EditType,
|
||||
routes::main_router::Route,
|
||||
};
|
||||
|
||||
#[derive(Properties, PartialEq, Clone)]
|
||||
pub struct AgentFieldsProps {
|
||||
@ -47,14 +57,12 @@ pub fn agent_fields(props: &AgentFieldsProps) -> Html {
|
||||
None => String::new(),
|
||||
});
|
||||
profile_picture_url_handle.set(match agent_opt.clone() {
|
||||
Some(agent) => {
|
||||
agent.profile_picture_url
|
||||
},
|
||||
Some(agent) => agent.profile_picture_url,
|
||||
None => String::new(),
|
||||
});
|
||||
credential_type.set(match agent_opt.clone() {
|
||||
Some(agent) => Some(agent.credential_type),
|
||||
None => None
|
||||
None => None,
|
||||
});
|
||||
credential_handle.set(match agent_opt.clone() {
|
||||
Some(agent) => agent.credential,
|
||||
@ -96,48 +104,48 @@ pub fn agent_fields(props: &AgentFieldsProps) -> Html {
|
||||
let agent_name = (*agent_name_handle).clone();
|
||||
let profile_picture_url = (*profile_picture_url_handle).clone();
|
||||
let credential = (*credential_handle).clone();
|
||||
let credential_type = if let Some(credential_type) = (*credential_type_handle).clone(){
|
||||
credential_type
|
||||
} else {
|
||||
log::error!("Missing field credential_type");
|
||||
return;
|
||||
};
|
||||
let credential_type =
|
||||
if let Some(credential_type) = (*credential_type_handle).clone() {
|
||||
credential_type
|
||||
} else {
|
||||
log::error!("Missing field credential_type");
|
||||
return;
|
||||
};
|
||||
match edit_type {
|
||||
EditType::New => {
|
||||
let agent = NewAgentPayload {
|
||||
credential,
|
||||
credential_type,
|
||||
full_name: agent_name,
|
||||
profile_picture_url
|
||||
profile_picture_url,
|
||||
};
|
||||
match create_new_agent(agent).await {
|
||||
Ok(_) => navigator.push(&Route::AdminAgents),
|
||||
Err(error) => log::error!("Error updating agent: {error}")
|
||||
Err(error) => log::error!("Error updating agent: {error}"),
|
||||
};
|
||||
},
|
||||
}
|
||||
EditType::Existing(id) => {
|
||||
let agent = UpdateAgentPayload {
|
||||
id,
|
||||
credential: Some(credential),
|
||||
credential_type: Some(credential_type),
|
||||
full_name: Some(agent_name),
|
||||
profile_picture_url: Some(profile_picture_url)
|
||||
profile_picture_url: Some(profile_picture_url),
|
||||
};
|
||||
match update_agent(agent).await {
|
||||
Ok(_) => navigator.push(&Route::AdminAgents),
|
||||
Err(error) => log::error!("Error updating agent: {error}")
|
||||
Err(error) => log::error!("Error updating agent: {error}"),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
})
|
||||
};
|
||||
html! {
|
||||
<>
|
||||
<SingleMediaPicker value={profile_picture_url_handle} onchange={ontype_cb.clone()} item={jl_types::dto::item::Item::Agent}/>
|
||||
<SingleMediaPicker value={profile_picture_url_handle} item={jl_types::dto::item::Item::Agent} onchange={ontype_cb.clone()} />
|
||||
<TextField label={"Nombre Completo"} value={agent_name_handle} required={true} onchange={ontype_cb.clone()}/>
|
||||
|
||||
|
||||
{if (*credential_type).clone().is_none() {
|
||||
match props.edittype.clone() {
|
||||
EditType::New => html! {
|
||||
@ -179,7 +187,7 @@ pub fn agent_fields(props: &AgentFieldsProps) -> Html {
|
||||
<div class={"admin-edit-submit-button"} onclick={update_button_onclick}>
|
||||
{"Actualizar"}
|
||||
</div>
|
||||
|
||||
|
||||
</>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
pub mod agent;
|
||||
pub mod project;
|
||||
pub mod unit;
|
||||
pub mod agent;
|
@ -1,10 +1,39 @@
|
||||
use chrono::NaiveTime;
|
||||
use jl_types::{dto::{listing::Listing, payloads::{location::NewLocationPayload, project::{UpdateProjectPayload, NewProjectPayload}}}, domain::{agent::Agent, media::MediaList, unit::Unit, project_condition::ProjectCondition, project_type::ProjectType, project_state::ProjectState}};
|
||||
use jl_types::{
|
||||
domain::{
|
||||
agent::Agent, media::MediaList, project_condition::ProjectCondition,
|
||||
project_state::ProjectState, project_type::ProjectType, unit::Unit,
|
||||
},
|
||||
dto::{
|
||||
listing::Listing,
|
||||
payloads::{
|
||||
location::NewLocationPayload,
|
||||
project::{NewProjectPayload, UpdateProjectPayload},
|
||||
},
|
||||
},
|
||||
};
|
||||
use std::str::FromStr;
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::use_navigator;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{pages::admin::{edit::{EditType, EditItem}, units::AdminUnits}, api::backend::{get_all_agents, get_location_with_city_and_district, create_location, create_new_project, update_project}, routes::main_router::Route, components::{new_widget::NewThingWidget, dropdown::DropDown, media_picker::MediaPicker, textfield::{TextField, TextFieldType}, datepicker::DatePicker}};
|
||||
use crate::{
|
||||
api::backend::{
|
||||
create_location, create_new_project, get_all_agents, get_location_with_city_and_district,
|
||||
update_project,
|
||||
},
|
||||
components::{
|
||||
datepicker::DatePicker,
|
||||
dropdown::DropDown,
|
||||
media_picker::MediaPicker,
|
||||
new_widget::NewThingWidget,
|
||||
textfield::{TextField, TextFieldType},
|
||||
},
|
||||
pages::admin::{
|
||||
edit::{EditItem, EditType},
|
||||
units::AdminUnits,
|
||||
},
|
||||
routes::main_router::Route,
|
||||
};
|
||||
|
||||
#[derive(Properties, PartialEq, Clone)]
|
||||
pub struct ProjectFieldsProps {
|
||||
@ -93,9 +122,7 @@ pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html {
|
||||
});
|
||||
project_state.set(match listing_opt.clone() {
|
||||
Some(listing) => Some(listing.project.project_state),
|
||||
None => {
|
||||
None
|
||||
},
|
||||
None => None,
|
||||
});
|
||||
project_condition.set(match listing_opt.clone() {
|
||||
Some(listing) => Some(listing.project.project_condition),
|
||||
@ -427,4 +454,4 @@ pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html {
|
||||
<AdminUnits units={units} onchange={ontype_cb.clone()}/>
|
||||
</>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,253 @@
|
||||
use jl_types::domain::{unit::Unit, unit_type::UnitType};
|
||||
use jl_types::{domain::{media::MediaList, unit_type::UnitType}, dto::payloads::unit::{NewUnitPayload, UpdateUnitPayload}};
|
||||
use uuid::Uuid;
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::use_navigator;
|
||||
|
||||
use crate::{pages::admin::edit::EditType, components::number_textfield::NumberTextField};
|
||||
use crate::{
|
||||
components::{dropdown::DropDown, number_textfield::NumberTextField, media_picker::MediaPicker, textfield::{TextField, TextFieldType}},
|
||||
pages::admin::edit::EditType, api::backend::{get_unit_with_id, create_new_unit, update_unit}, routes::main_router::Route,
|
||||
};
|
||||
|
||||
#[derive(Properties, PartialEq, Clone)]
|
||||
pub struct UnitFieldsProps {
|
||||
pub unit: Option<Unit>,
|
||||
pub edittype: EditType,
|
||||
pub projectid: Option<Uuid>,
|
||||
pub projectid: Uuid,
|
||||
}
|
||||
|
||||
#[function_component(UnitFields)]
|
||||
pub fn unit_fields(props: &UnitFieldsProps) -> Html {
|
||||
|
||||
let unit_opt = use_state(|| None);
|
||||
{
|
||||
let unit_opt = unit_opt.clone();
|
||||
use_state(move || {
|
||||
if let EditType::Existing(id) = props.edittype.clone() {
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let unit_result = get_unit_with_id(&id).await;
|
||||
match unit_result {
|
||||
Ok(unit_persisted) => {
|
||||
unit_opt.set(Some(unit_persisted));
|
||||
}
|
||||
Err(error) => log::error!("Error loading unit: {error}"),
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
let navigator = use_navigator().unwrap();
|
||||
let user_typed = use_state(|| false);
|
||||
let edit_type = props.edittype.clone();
|
||||
let project_id = props.projectid.clone();
|
||||
|
||||
let ontype_cb = {
|
||||
let user_typed = user_typed.clone();
|
||||
Callback::from(move |_: String| {
|
||||
user_typed.set(true);
|
||||
})
|
||||
};
|
||||
let onselect_cb = {
|
||||
let user_typed = user_typed.clone();
|
||||
Callback::from(move |_| {
|
||||
user_typed.set(true);
|
||||
})
|
||||
};
|
||||
let onchange_number_cb = {
|
||||
let user_typed = user_typed.clone();
|
||||
Callback::from(move |_| {
|
||||
user_typed.set(true);
|
||||
})
|
||||
};
|
||||
let onchange_number_cb_2 = {
|
||||
let user_typed = user_typed.clone();
|
||||
Callback::from(move |_| {
|
||||
user_typed.set(true);
|
||||
})
|
||||
};
|
||||
let onchange_number_cb_3 = {
|
||||
let user_typed = user_typed.clone();
|
||||
Callback::from(move |_| {
|
||||
user_typed.set(true);
|
||||
})
|
||||
};
|
||||
|
||||
// Fields
|
||||
let price_usd = use_state(|| 0.0);
|
||||
let unit_type_handle: UseStateHandle<Option<UnitType>> = use_state(|| None);
|
||||
let rooms_handle: UseStateHandle<i16> = use_state(|| 0);
|
||||
let bathrooms_handle: UseStateHandle<i16> = use_state(|| 0);
|
||||
let area_handle: UseStateHandle<f32> = use_state(|| 0.0);
|
||||
let a = 0.0;
|
||||
let b = a as i32;
|
||||
let price_usd = use_state_eq(|| 0.0);
|
||||
let unit_type_handle: UseStateHandle<Option<UnitType>> = use_state_eq(|| None);
|
||||
let rooms_handle: UseStateHandle<i16> = use_state_eq(|| 0);
|
||||
let bathrooms_handle: UseStateHandle<i16> = use_state_eq(|| 0);
|
||||
let area_handle: UseStateHandle<f32> = use_state_eq(|| 0.0);
|
||||
let media_handle: UseStateHandle<MediaList> = use_state_eq(|| MediaList {
|
||||
media_list: Vec::new(),
|
||||
});
|
||||
let unit_admin_tag_handle: UseStateHandle<String> = use_state_eq(|| String::new());
|
||||
let unit_description_handle = use_state_eq(|| String::new());
|
||||
|
||||
if !*user_typed {
|
||||
price_usd.set(match (*unit_opt).clone() {
|
||||
Some(unit) => unit.price_usd,
|
||||
None => 0.0,
|
||||
});
|
||||
unit_type_handle.set(match (*unit_opt).clone() {
|
||||
Some(unit) => Some(unit.unit_type),
|
||||
None => None
|
||||
});
|
||||
media_handle.set(match (*unit_opt).clone() {
|
||||
Some(unit) => unit.media,
|
||||
None => MediaList {
|
||||
media_list: Vec::new(),
|
||||
},
|
||||
});
|
||||
rooms_handle.set(match (*unit_opt).clone() {
|
||||
Some(unit) => unit.rooms,
|
||||
None => 0
|
||||
});
|
||||
bathrooms_handle.set(match (*unit_opt).clone() {
|
||||
Some(unit) => unit.bathrooms,
|
||||
None => 0
|
||||
});
|
||||
area_handle.set(match (*unit_opt).clone() {
|
||||
Some(unit) => unit.area,
|
||||
None => 0.0
|
||||
});
|
||||
unit_description_handle.set(match (*unit_opt).clone() {
|
||||
Some(unit) => unit.description,
|
||||
None => String::new(),
|
||||
});
|
||||
unit_admin_tag_handle.set(match (*unit_opt).clone() {
|
||||
Some(unit) => match unit.admin_tag {
|
||||
Some(admin_tag) => admin_tag,
|
||||
None => String::new()
|
||||
},
|
||||
None => String::new(),
|
||||
});
|
||||
}
|
||||
let update_button_onclick = {
|
||||
let navigator = navigator.clone();
|
||||
let edit_type = edit_type.clone();
|
||||
let project_id = project_id.clone();
|
||||
|
||||
let price_usd = price_usd.clone();
|
||||
let unit_type_handle: UseStateHandle<Option<UnitType>> = unit_type_handle.clone();
|
||||
let rooms_handle: UseStateHandle<i16> = rooms_handle.clone();
|
||||
let bathrooms_handle: UseStateHandle<i16> = bathrooms_handle.clone();
|
||||
let area_handle: UseStateHandle<f32> = area_handle.clone();
|
||||
let media_handle: UseStateHandle<MediaList> = media_handle.clone();
|
||||
let unit_admin_tag_handle: UseStateHandle<String> = unit_admin_tag_handle.clone();
|
||||
let unit_description_handle = unit_description_handle.clone();
|
||||
Callback::from(move |_: MouseEvent| {
|
||||
let navigator = navigator.clone();
|
||||
let edit_type = edit_type.clone();
|
||||
let project_id = project_id.clone();
|
||||
|
||||
let price_usd = price_usd.clone();
|
||||
let unit_type_handle: UseStateHandle<Option<UnitType>> = unit_type_handle.clone();
|
||||
let rooms_handle: UseStateHandle<i16> = rooms_handle.clone();
|
||||
let bathrooms_handle: UseStateHandle<i16> = bathrooms_handle.clone();
|
||||
let area_handle: UseStateHandle<f32> = area_handle.clone();
|
||||
let media_handle: UseStateHandle<MediaList> = media_handle.clone();
|
||||
let unit_admin_tag_handle: UseStateHandle<String> = unit_admin_tag_handle.clone();
|
||||
let unit_description_handle = unit_description_handle.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let price_usd = (*price_usd).clone();
|
||||
let unit_type = match (*unit_type_handle).clone() {
|
||||
Some(unit_type) => unit_type,
|
||||
None => {
|
||||
log::error!("Missing field unit_type");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let rooms = (*rooms_handle).clone();
|
||||
let bathrooms = (*bathrooms_handle).clone();
|
||||
let area = (*area_handle).clone();
|
||||
let media = (*media_handle).clone();
|
||||
let unit_admin_tag_val = (*unit_admin_tag_handle).clone();
|
||||
let admin_tag = if unit_admin_tag_val.is_empty() { None } else { Some(unit_admin_tag_val) };
|
||||
let description = (*unit_description_handle).clone();
|
||||
|
||||
match edit_type {
|
||||
EditType::New => {
|
||||
let payload = NewUnitPayload {
|
||||
project_id,
|
||||
price_usd,
|
||||
unit_type,
|
||||
rooms,
|
||||
bathrooms,
|
||||
area,
|
||||
admin_tag,
|
||||
media,
|
||||
description
|
||||
};
|
||||
match create_new_unit(payload).await {
|
||||
Ok(_) => navigator.clone().push(&Route::AdminProjects),
|
||||
Err(error) => log::error!("Error creating new unit: {error}"),
|
||||
};
|
||||
},
|
||||
EditType::Existing(id) => {
|
||||
let payload = UpdateUnitPayload {
|
||||
id,
|
||||
price_usd: Some(price_usd),
|
||||
unit_type: Some(unit_type),
|
||||
rooms: Some(rooms),
|
||||
bathrooms: Some(bathrooms),
|
||||
area: Some(area),
|
||||
admin_tag: Some(admin_tag),
|
||||
media: Some(media),
|
||||
description: Some(description)
|
||||
};
|
||||
match update_unit(payload).await {
|
||||
Ok(_) => navigator.clone().push(&Route::AdminProjects),
|
||||
Err(error) => log::error!("Error creating new unit: {error}"),
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
})
|
||||
};
|
||||
html! {
|
||||
<>
|
||||
<NumberTextField<f64> label={String::from("Precio en USD")} required={true} value={price_usd.clone()}/>
|
||||
<NumberTextField<f32> label={String::from("Area en m^2")} required={true} value={area_handle.clone()}/>
|
||||
<NumberTextField<i16> label={String::from("Cant. de habitaciones")} required={true} value={rooms_handle.clone()}/>
|
||||
<NumberTextField<i16> label={String::from("Cant. de baños")} required={true} value={bathrooms_handle.clone()}/>
|
||||
<NumberTextField<f64> label={String::from("Precio en USD")} required={true} value={price_usd.clone()} onchange={onchange_number_cb}/>
|
||||
<NumberTextField<f32> label={String::from("Area en m^2")} required={true} value={area_handle.clone()} onchange={onchange_number_cb_2}/>
|
||||
<NumberTextField<i16> label={String::from("Cant. de habitaciones")} required={true} value={rooms_handle.clone()} onchange={onchange_number_cb_3.clone()}/>
|
||||
<NumberTextField<i16> label={String::from("Cant. de baños")} required={true} value={bathrooms_handle.clone()} onchange={onchange_number_cb_3}/>
|
||||
<MediaPicker value={media_handle} onchange={ontype_cb.clone()} item={jl_types::dto::item::Item::Unit}/>
|
||||
|
||||
// Unit type dropdown
|
||||
{if (*unit_type_handle).clone().is_none() {
|
||||
match props.edittype.clone() {
|
||||
EditType::New => html! {
|
||||
<div class={"textfield-container"}>
|
||||
<div class={"textfield-label-required"}>{"Tipo de Unidad"}</div>
|
||||
<DropDown<UnitType> selected={unit_type_handle} options={vec![UnitType::ForSale, UnitType::NotForSale] } onchange={onselect_cb} />
|
||||
</div>
|
||||
},
|
||||
EditType::Existing(_) => if *user_typed {
|
||||
html! {
|
||||
<div class={"textfield-container"}>
|
||||
<div class={"textfield-label-required"}>{"Tipo de Unidad"}</div>
|
||||
<DropDown<UnitType> selected={unit_type_handle} options={vec![UnitType::ForSale, UnitType::NotForSale] } onchange={onselect_cb} />
|
||||
</div>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
html! {
|
||||
<div class={"textfield-container"}>
|
||||
<div class={"textfield-label-required"}>{"Tipo de Unidad"}</div>
|
||||
<DropDown<UnitType> selected={unit_type_handle} options={vec![UnitType::ForSale, UnitType::NotForSale] } onchange={onselect_cb} />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
<TextField label={"Descripción"} value={unit_description_handle} required={false} onchange={ontype_cb.clone()} fieldtype={TextFieldType::TextArea} />
|
||||
<TextField label={"Comentario interno"} value={unit_admin_tag_handle} required={false} onchange={ontype_cb.clone()} />
|
||||
<div class={"admin-edit-submit-button"} onclick={update_button_onclick}>
|
||||
{"Actualizar"}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
pub mod agents;
|
||||
pub mod contacts;
|
||||
pub mod edit;
|
||||
pub mod fields;
|
||||
pub mod login;
|
||||
pub mod projects;
|
||||
pub mod start;
|
||||
pub mod units;
|
||||
pub mod fields;
|
@ -5,7 +5,6 @@ use crate::components::admin_unit::AdminUnit;
|
||||
|
||||
#[function_component(AdminUnits)]
|
||||
pub fn admin_units(props: &AdminUnitProps) -> Html {
|
||||
|
||||
let units_handle = props.units.clone();
|
||||
html! {
|
||||
<div class={"admin-start-container"} style={"min-height: 10vh; margin-top: 10vh;"}>
|
||||
@ -38,5 +37,5 @@ pub fn admin_units(props: &AdminUnitProps) -> Html {
|
||||
#[derive(PartialEq, Properties, Clone)]
|
||||
pub struct AdminUnitProps {
|
||||
pub units: UseStateHandle<Vec<Unit>>,
|
||||
pub onchange: Option<Callback<String>>,
|
||||
pub onchange: Option<Callback<String>>,
|
||||
}
|
||||
|
@ -10,7 +10,9 @@ use crate::{
|
||||
api::backend::{
|
||||
get_all_cities, get_all_districts_in_city, get_all_projects_with_filters_paged,
|
||||
},
|
||||
components::{footer::PageFooter, nav_bar::NavigationBar, project_card::ProjectCard, dropdown::DropDown},
|
||||
components::{
|
||||
dropdown::DropDown, footer::PageFooter, nav_bar::NavigationBar, project_card::ProjectCard,
|
||||
},
|
||||
};
|
||||
|
||||
#[function_component(SearchPage)]
|
||||
@ -31,10 +33,7 @@ pub fn search_page() -> Html {
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
match get_all_cities().await {
|
||||
Ok(cities) => {
|
||||
let cities: Vec<String> = cities
|
||||
.into_iter()
|
||||
.map(|location| location)
|
||||
.collect();
|
||||
let cities: Vec<String> = cities.into_iter().map(|location| location).collect();
|
||||
cities_handle.set(cities);
|
||||
}
|
||||
Err(error) => log::error!("Error in loading cities: {error}"),
|
||||
@ -55,19 +54,14 @@ pub fn search_page() -> Html {
|
||||
});
|
||||
|
||||
// Dropdown
|
||||
let project_type_filter: UseStateHandle<Option<ProjectType>> =
|
||||
use_state(|| None);
|
||||
let project_type_filter: UseStateHandle<Option<ProjectType>> = use_state(|| None);
|
||||
// Dropdown
|
||||
let project_condition_filter: UseStateHandle<Option<ProjectCondition>> =
|
||||
use_state(|| None);
|
||||
let project_condition_filter: UseStateHandle<Option<ProjectCondition>> = use_state(|| None);
|
||||
// Dropdown
|
||||
let project_city_filter: UseStateHandle<Option<String>> =
|
||||
use_state(|| None);
|
||||
let project_city_filter: UseStateHandle<Option<String>> = use_state(|| None);
|
||||
// Dropdown
|
||||
let project_district_filter: UseStateHandle<Option<String>> =
|
||||
use_state(|| None);
|
||||
let unit_rooms_filter: UseStateHandle<Option<usize>> =
|
||||
use_state(|| None);
|
||||
let project_district_filter: UseStateHandle<Option<String>> = use_state(|| None);
|
||||
let unit_rooms_filter: UseStateHandle<Option<usize>> = use_state(|| None);
|
||||
|
||||
let search_onclick = {
|
||||
let search_results_handle = search_results_handle.clone();
|
||||
@ -167,7 +161,7 @@ pub fn search_page() -> Html {
|
||||
let cloned_project_type_filter = project_type_filter.clone();
|
||||
Callback::from(move |project_type: Option<ProjectType>| {
|
||||
cloned_project_type_filter.set(project_type)
|
||||
})}
|
||||
})}
|
||||
options={ vec![ProjectType::Apartamento, ProjectType::Casa, ProjectType::Oficina, ProjectType::Local, ProjectType::Solar]
|
||||
} />
|
||||
</div>
|
||||
@ -187,7 +181,7 @@ pub fn search_page() -> Html {
|
||||
let cloned_project_condition_filter = project_condition_filter.clone();
|
||||
Callback::from(move |project_condition: Option<ProjectCondition>| {
|
||||
cloned_project_condition_filter.set(project_condition)
|
||||
})}
|
||||
})}
|
||||
options={ vec![ProjectCondition::New, ProjectCondition::Resale]} />
|
||||
</div>
|
||||
|
||||
@ -226,7 +220,7 @@ pub fn search_page() -> Html {
|
||||
let project_district_filter = project_district_filter.clone();
|
||||
Callback::from(move |project_district: Option<String>| {
|
||||
project_district_filter.set(project_district)
|
||||
})}
|
||||
})}
|
||||
options={ (*districts_handle).clone() } />
|
||||
</div>
|
||||
|
||||
@ -238,7 +232,7 @@ pub fn search_page() -> Html {
|
||||
let unit_rooms_filter = unit_rooms_filter.clone();
|
||||
Callback::from(move |unit_rooms: Option<usize>| {
|
||||
unit_rooms_filter.set(unit_rooms)
|
||||
})}
|
||||
})}
|
||||
options={ (1..10).collect::<Vec<usize>>() } />
|
||||
</div>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user