Edit project screen done
This commit is contained in:
parent
c693287063
commit
39abe4caca
|
@ -5,3 +5,19 @@
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1rem;
|
letter-spacing: 0.1rem;
|
||||||
}
|
}
|
||||||
|
.admin-dropdown {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 150px;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 50px;
|
||||||
|
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.0);
|
||||||
|
background-color: rgba(0, 0, 0, 0.04);
|
||||||
|
border-radius: 5px;
|
||||||
|
font-family: Source Sans Pro;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
.textfield-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: start;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.textfield-label {
|
||||||
|
font-family: Space Grotesk;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 900;
|
||||||
|
letter-spacing: 0.1rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.textfield-label-required {
|
||||||
|
font-family: Space Grotesk;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 900;
|
||||||
|
letter-spacing: 0.1rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.textfield-label-required:after {
|
||||||
|
color: #e32;
|
||||||
|
content: '*';
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.textfield {
|
||||||
|
height: 50px;
|
||||||
|
background-color: white;
|
||||||
|
border: solid 0.5px #d8d8d8;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
text-indent: 10px;
|
||||||
|
}
|
||||||
|
.textarea {
|
||||||
|
height: 150px;
|
||||||
|
background-color: white;
|
||||||
|
border: solid 0.5px #d8d8d8;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
13
css/edit.css
13
css/edit.css
|
@ -1,11 +1,12 @@
|
||||||
.admin-project-fields-container {
|
.admin-project-fields-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: start;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
|
|
||||||
width: 90%;
|
width: 80%;
|
||||||
|
max-width: 750px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-project-field-container {
|
.admin-project-field-container {
|
||||||
|
@ -22,3 +23,11 @@
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
.admin-project-textfield {
|
||||||
|
height: 50px;
|
||||||
|
background-color: white;
|
||||||
|
border: solid 0.5px #d8d8d8;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
text-indent: 10px;
|
||||||
|
}
|
|
@ -25,6 +25,7 @@
|
||||||
<link data-trunk type="text/css" href="css/components/media_slideshow.css" rel="css" />
|
<link data-trunk type="text/css" href="css/components/media_slideshow.css" rel="css" />
|
||||||
<link data-trunk type="text/css" href="css/components/floating_widget.css" rel="css" />
|
<link data-trunk type="text/css" href="css/components/floating_widget.css" rel="css" />
|
||||||
<link data-trunk type="text/css" href="css/components/footer.css" rel="css" />
|
<link data-trunk type="text/css" href="css/components/footer.css" rel="css" />
|
||||||
|
<link data-trunk type="text/css" href="css/components/textfield.css" rel="css" />
|
||||||
<link data-trunk type="text/css" href="css/components/agent_card.css" rel="css" />
|
<link data-trunk type="text/css" href="css/components/agent_card.css" rel="css" />
|
||||||
<link data-trunk type="text/css" href="css/components/admin_nav_bar.css" rel="css" />
|
<link data-trunk type="text/css" href="css/components/admin_nav_bar.css" rel="css" />
|
||||||
<link data-trunk type="text/css" href="css/components/admin_project.css" rel="css" />
|
<link data-trunk type="text/css" href="css/components/admin_project.css" rel="css" />
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use jl_types::domain::{option_wrapper::OptionWrapper};
|
||||||
|
use yew::prelude::*;
|
||||||
|
use yew_utils::vdom::comp_with;
|
||||||
|
|
||||||
|
/// Give this component a list of options
|
||||||
|
#[function_component(DropDown)]
|
||||||
|
pub fn dropdown<T: Display + std::cmp::PartialEq + Clone + 'static>(props: &DropDownProps<T>) -> Html {
|
||||||
|
let selection_changed_cb = {
|
||||||
|
let onchange_cb = props.onchange.clone();
|
||||||
|
let selected = props.selected.clone();
|
||||||
|
Callback::from(move |option: OptionWrapper<T>| {
|
||||||
|
selected.set(option.option.clone());
|
||||||
|
match onchange_cb.clone() {
|
||||||
|
Some(additional_cb) => additional_cb.emit(option),
|
||||||
|
None => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let drop_down = comp_with::<yew_utils::components::drop_down::DropDown<OptionWrapper<T>>>(yew_utils::components::drop_down::DropDownProps {
|
||||||
|
initial: {
|
||||||
|
OptionWrapper::new((*props.selected).clone())},
|
||||||
|
options: {
|
||||||
|
let mut options: Vec<OptionWrapper<T>> = props.options.clone().into_iter().map(|option| OptionWrapper::new(Some(option))).collect();
|
||||||
|
if props.has_none { options.insert(0, OptionWrapper::new(None)); }
|
||||||
|
options
|
||||||
|
},
|
||||||
|
selection_changed: selection_changed_cb.clone(),
|
||||||
|
class_css: Some("admin-dropdown".into())
|
||||||
|
});
|
||||||
|
//if (*props.selected).is_none() {selection_changed_cb.emit( OptionWrapper::new((*props.selected).clone()));}
|
||||||
|
html! {
|
||||||
|
{drop_down}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Properties, Clone)]
|
||||||
|
pub struct DropDownProps<T: Display + std::cmp::PartialEq + Clone> {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub options: Vec<T>,
|
||||||
|
/// in case that there is no selected option, this will reflect a None variant
|
||||||
|
pub selected: UseStateHandle<Option<T>>,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub unpicked_text: String,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub onchange: Option<Callback<OptionWrapper<T>>>,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub has_none: bool
|
||||||
|
}
|
|
@ -7,3 +7,5 @@ pub mod footer;
|
||||||
pub mod agent_card;
|
pub mod agent_card;
|
||||||
pub mod admin_nav_bar;
|
pub mod admin_nav_bar;
|
||||||
pub mod admin_project;
|
pub mod admin_project;
|
||||||
|
pub mod textfield;
|
||||||
|
pub mod dropdown;
|
|
@ -0,0 +1,80 @@
|
||||||
|
// COMPONENTFORLIB
|
||||||
|
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||||
|
use web_sys::{HtmlInputElement, HtmlTextAreaElement};
|
||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
|
/// This component is a text
|
||||||
|
#[function_component(TextField)]
|
||||||
|
pub fn textfield(props: &TextFieldProps) -> Html {
|
||||||
|
let on_input_changed = {
|
||||||
|
let handle = props.value.clone();
|
||||||
|
let fieldtype = props.fieldtype.clone();
|
||||||
|
let onchange = props.onchange.clone();
|
||||||
|
Callback::from(move |e: InputEvent| {
|
||||||
|
match fieldtype {
|
||||||
|
TextFieldType::Input => {
|
||||||
|
let value = get_value_from_input_event(e);
|
||||||
|
match onchange.clone() {
|
||||||
|
Some(onchange) => { onchange.emit(value.clone()); },
|
||||||
|
None => {}
|
||||||
|
};
|
||||||
|
handle.set(value);
|
||||||
|
},
|
||||||
|
TextFieldType::TextArea => {
|
||||||
|
let value = get_value_from_input_event(e);
|
||||||
|
match onchange.clone() {
|
||||||
|
Some(onchange) => { onchange.emit(value.clone()); },
|
||||||
|
None => {}
|
||||||
|
};
|
||||||
|
handle.set(value);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
html! {
|
||||||
|
<div class={"textfield-container"}>
|
||||||
|
<div class={if props.required {"textfield-label-required"} else {"textfield-label"}}>{props.label.clone()}</div>
|
||||||
|
{
|
||||||
|
if props.fieldtype == TextFieldType::Input {
|
||||||
|
html! { <input class={"textfield"} oninput={on_input_changed} value={(*props.value).clone()}/> }
|
||||||
|
} else {
|
||||||
|
html! { <textarea class={"textarea"} oninput={on_input_changed} value={(*props.value).clone()}/> }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq, Clone)]
|
||||||
|
pub struct TextFieldProps {
|
||||||
|
pub label: String,
|
||||||
|
pub value: UseStateHandle<String>,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub fieldtype: TextFieldType,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub required: bool,
|
||||||
|
pub onchange: Option<Callback<String>>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Default)]
|
||||||
|
pub enum TextFieldType {
|
||||||
|
TextArea,
|
||||||
|
#[default]
|
||||||
|
Input,
|
||||||
|
}
|
||||||
|
|
||||||
|
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,19 +1,17 @@
|
||||||
use std::{fmt::Display, str::FromStr};
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use chrono::Utc;
|
use jl_types::{ domain::{agent::Agent, media::{MediaList}, unit::Unit, project_state::ProjectState, project_condition::ProjectCondition, project_type::ProjectType}, dto::listing::Listing};
|
||||||
use jl_types::{ domain::{agent::Agent, project_state::ProjectState, project_condition::ProjectCondition, project_type::ProjectType, media::{Media, MediaList}, unit::Unit}, dto::listing::Listing};
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::prelude::use_navigator;
|
use yew_router::prelude::use_navigator;
|
||||||
|
|
||||||
use crate::{components::admin_nav_bar::AdminNavigationBar, api::backend::get_project_listing};
|
use crate::{components::{admin_nav_bar::AdminNavigationBar, textfield::{TextField, TextFieldType}, dropdown::DropDown}, api::backend::{get_project_listing, get_all_agents}};
|
||||||
|
|
||||||
/// 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.
|
/// 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.
|
||||||
#[function_component(AdminEditPage)]
|
#[function_component(AdminEditPage)]
|
||||||
pub fn edit_page(props: &AdminEditPageProps) -> Html {
|
pub fn edit_page(props: &AdminEditPageProps) -> Html {
|
||||||
let navigator = use_navigator().unwrap();
|
let _navigator = use_navigator().unwrap();
|
||||||
let listing = use_state(|| None);
|
let listing = use_state(|| None);
|
||||||
|
|
||||||
use_state(|| {
|
use_state(|| {
|
||||||
let listing = listing.clone();
|
let listing = listing.clone();
|
||||||
match props.edit_item {
|
match props.edit_item {
|
||||||
|
@ -31,7 +29,7 @@ pub fn edit_page(props: &AdminEditPageProps) -> Html {
|
||||||
listing.set(Some(listing_persisted));
|
listing.set(Some(listing_persisted));
|
||||||
},
|
},
|
||||||
Err(error) => log::error!("Error loading listing: {error}")
|
Err(error) => log::error!("Error loading listing: {error}")
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -49,6 +47,7 @@ pub fn edit_page(props: &AdminEditPageProps) -> Html {
|
||||||
EditItem::Project => "Proyecto",
|
EditItem::Project => "Proyecto",
|
||||||
EditItem::Unit(_) => "Unidad",
|
EditItem::Unit(_) => "Unidad",
|
||||||
})}</div>
|
})}</div>
|
||||||
|
<div class={"admin-project-fields-container"}>
|
||||||
{
|
{
|
||||||
match props.edit_item {
|
match props.edit_item {
|
||||||
EditItem::Agent => {html! {}},
|
EditItem::Agent => {html! {}},
|
||||||
|
@ -58,6 +57,7 @@ pub fn edit_page(props: &AdminEditPageProps) -> Html {
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -84,34 +84,154 @@ pub struct AdminEditPageProps {
|
||||||
|
|
||||||
#[derive(Properties, PartialEq, Clone)]
|
#[derive(Properties, PartialEq, Clone)]
|
||||||
pub struct ProjectFieldsProps {
|
pub struct ProjectFieldsProps {
|
||||||
pub listing: Option<Listing>
|
pub listing: Option<Listing>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[function_component(ProjectFields)]
|
#[function_component(ProjectFields)]
|
||||||
pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html {
|
pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html {
|
||||||
|
let user_typed = use_state(|| false);
|
||||||
let listing_opt = props.listing.clone();
|
let listing_opt = props.listing.clone();
|
||||||
let location_city = use_state(|| listing_opt.clone().unwrap_or_default().location.city);
|
|
||||||
let location_district = use_state(|| listing_opt.clone().unwrap_or_default().location.district);
|
let location_city = use_state_eq(|| String::new());
|
||||||
let agent: UseStateHandle<Option<Agent>> = use_state(|| {
|
let location_district = use_state_eq(|| String::new());
|
||||||
match listing_opt.clone() {
|
let agent: UseStateHandle<Option<Agent>> = use_state_eq(|| None);
|
||||||
|
let project_state = use_state_eq(|| None);
|
||||||
|
let project_condition = use_state_eq(|| None);
|
||||||
|
let project_type = use_state_eq(|| None);
|
||||||
|
let project_description = use_state_eq(|| "".to_string());
|
||||||
|
let project_admin_tag: UseStateHandle<String> = use_state_eq(|| listing_opt.clone().unwrap_or_default().project.admin_tag.unwrap_or(String::new()));
|
||||||
|
let project_finish_date = use_state_eq(|| listing_opt.clone().unwrap_or_default().project.finish_date);
|
||||||
|
let project_floors = use_state_eq(|| listing_opt.clone().unwrap_or_default().project.floors.to_string());
|
||||||
|
let media: UseStateHandle<MediaList> = use_state_eq(|| listing_opt.clone().unwrap_or_default().project.media);
|
||||||
|
let units: UseStateHandle<Vec<Unit>> = use_state_eq(|| listing_opt.clone().unwrap_or_default().units);
|
||||||
|
|
||||||
|
let ontype_cb = {
|
||||||
|
let user_typed = user_typed.clone();
|
||||||
|
Callback::from(move |_| {
|
||||||
|
user_typed.set(true);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let onselect_cb = {
|
||||||
|
let user_typed = user_typed.clone();
|
||||||
|
Callback::from(move |_| {
|
||||||
|
user_typed.set(true);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let onselect_cb2 = {
|
||||||
|
let user_typed = user_typed.clone();
|
||||||
|
Callback::from(move |_| {
|
||||||
|
user_typed.set(true);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let onselect_cb3 = {
|
||||||
|
let user_typed = user_typed.clone();
|
||||||
|
Callback::from(move |_| {
|
||||||
|
user_typed.set(true);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let onselect_cb4 = {
|
||||||
|
let user_typed = user_typed.clone();
|
||||||
|
Callback::from(move |_| {
|
||||||
|
user_typed.set(true);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let all_agents = use_state(|| Vec::new());
|
||||||
|
|
||||||
|
use_state(|| {
|
||||||
|
let all_agents = all_agents.clone();
|
||||||
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
|
match get_all_agents().await {
|
||||||
|
Ok(persisted_agents) => all_agents.set(persisted_agents),
|
||||||
|
Err(error) => log::error!("Error fetching agents from admin panel edit screen: {error}"),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if !*user_typed {
|
||||||
|
location_city.set(listing_opt.clone().unwrap_or_default().location.city);
|
||||||
|
location_district.set(listing_opt.clone().unwrap_or_default().location.district);
|
||||||
|
agent.set(match listing_opt.clone() {
|
||||||
Some(listing) => Some(listing.agent),
|
Some(listing) => Some(listing.agent),
|
||||||
None => None,
|
None => None,
|
||||||
}
|
|
||||||
});
|
});
|
||||||
let project_state = use_state(|| listing_opt.clone().unwrap_or_default().project.project_state);
|
project_state.set(match listing_opt.clone() {
|
||||||
let project_condition = use_state(|| listing_opt.clone().unwrap_or_default().project.project_condition);
|
Some(listing) => Some(listing.project.project_state),
|
||||||
let project_type = use_state(|| listing_opt.clone().unwrap_or_default().project.project_type);
|
None => None,
|
||||||
let project_description = use_state(|| listing_opt.clone().unwrap_or_default().project.description);
|
});
|
||||||
let project_admin_tag: UseStateHandle<Option<String>> = use_state(|| listing_opt.clone().unwrap_or_default().project.admin_tag);
|
project_condition.set(match listing_opt.clone() {
|
||||||
let project_finish_date = use_state(|| listing_opt.clone().unwrap_or_default().project.finish_date);
|
Some(listing) => Some(listing.project.project_condition),
|
||||||
let project_floors = use_state(|| listing_opt.clone().unwrap_or_default().project.floors);
|
None => None,
|
||||||
let media: UseStateHandle<MediaList> = use_state(|| listing_opt.clone().unwrap_or_default().project.media);
|
});
|
||||||
let units: UseStateHandle<Vec<Unit>> = use_state(|| listing_opt.clone().unwrap_or_default().units);
|
project_type.set(match listing_opt.clone() {
|
||||||
|
Some(listing) => Some(listing.project.project_type),
|
||||||
|
None => None,
|
||||||
|
});
|
||||||
|
project_description.set(match listing_opt.clone() {
|
||||||
|
Some(listing) => listing.project.description,
|
||||||
|
None => "".into(),
|
||||||
|
});
|
||||||
|
project_floors.set(match listing_opt.clone() {
|
||||||
|
Some(listing) => listing.project.floors.to_string(),
|
||||||
|
None => "".into(),
|
||||||
|
});
|
||||||
|
project_admin_tag.set(match listing_opt.clone() {
|
||||||
|
Some(listing) => match listing.project.admin_tag {
|
||||||
|
Some(admin_tag) => admin_tag,
|
||||||
|
None => String::new(),
|
||||||
|
},
|
||||||
|
None => String::new(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
|
<>
|
||||||
|
<TextField label={"Ciudad"} value={location_city} required={true} onchange={ontype_cb.clone()}/>
|
||||||
|
<TextField label={"Distrito"} value={location_district} required={true} onchange={ontype_cb.clone()} />
|
||||||
|
{if (*agent).clone().is_none() { html! { } } else {
|
||||||
|
html! {
|
||||||
|
<div class={"textfield-container"}>
|
||||||
|
<div class={"textfield-label-required"}>{"Agente asignado"}</div>
|
||||||
|
<DropDown<Agent> options={(*all_agents).clone()} selected={agent} onchange={onselect_cb.clone()} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{if (*project_state).clone().is_none() { html! { } } else {
|
||||||
|
html! {
|
||||||
|
<div class={"textfield-container"}>
|
||||||
|
<div class={"textfield-label-required"}>{"Estado del Proyecto"}</div>
|
||||||
|
<DropDown<ProjectState> options={vec![ProjectState::Finished, ProjectState::InConstruction]} selected={project_state} onchange={onselect_cb2} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{if (*project_condition).clone().is_none() { html! { } } else {
|
||||||
|
html! {
|
||||||
|
<div class={"textfield-container"}>
|
||||||
|
<div class={"textfield-label-required"}>{"Condición del Proyecto"}</div>
|
||||||
|
<DropDown<ProjectCondition> options={vec![ProjectCondition::Resale, ProjectCondition::New]} selected={project_condition} onchange={onselect_cb3} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{if (*project_type).clone().is_none() { html! { } } else {
|
||||||
|
html! {
|
||||||
|
<div class={"textfield-container"}>
|
||||||
|
<div class={"textfield-label-required"}>{"Tipo de Proyecto"}</div>
|
||||||
|
<DropDown<ProjectType> options={vec![ProjectType::Apartamento, ProjectType::Casa, ProjectType::Oficina, ProjectType::Local, ProjectType::Solar]} selected={project_type} onchange={onselect_cb4} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<TextField label={"Pisos"} value={project_floors} required={true} />
|
||||||
|
<TextField label={"Descripción"} value={project_description} fieldtype={TextFieldType::TextArea}/>
|
||||||
|
<TextField label={"Comentario interno"} value={project_admin_tag} />
|
||||||
|
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub fn search_page() -> Html {
|
||||||
let finished_loading = use_state(|| false);
|
let finished_loading = use_state(|| false);
|
||||||
let project_state_filter_handle = use_state_eq(|| ProjectState::InConstruction);
|
let project_state_filter_handle = use_state_eq(|| ProjectState::InConstruction);
|
||||||
|
|
||||||
let filters = Vec::new();
|
let filters: Vec<Filter> = Vec::new();
|
||||||
|
|
||||||
// All code to execute on first render and never again
|
// All code to execute on first render and never again
|
||||||
use_state(|| {
|
use_state(|| {
|
||||||
|
@ -34,7 +34,7 @@ pub fn search_page() -> Html {
|
||||||
},
|
},
|
||||||
Err(error) => log::error!("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), vec![Filter::InConstruction]).await {
|
||||||
Ok(projects) => {
|
Ok(projects) => {
|
||||||
search_results_handle.set(projects);
|
search_results_handle.set(projects);
|
||||||
finished_loading.set(true);
|
finished_loading.set(true);
|
||||||
|
@ -165,6 +165,8 @@ pub fn search_page() -> Html {
|
||||||
let mut filters = Vec::new();
|
let mut filters = Vec::new();
|
||||||
if (*project_state_filter).eq(&ProjectState::Finished) {
|
if (*project_state_filter).eq(&ProjectState::Finished) {
|
||||||
filters.push(Filter::Finished);
|
filters.push(Filter::Finished);
|
||||||
|
} else {
|
||||||
|
filters.push(Filter::InConstruction);
|
||||||
}
|
}
|
||||||
match &(*project_type_filter).option {
|
match &(*project_type_filter).option {
|
||||||
Some(project_type) => filters.push(Filter::ByProjectType(project_type.clone())),
|
Some(project_type) => filters.push(Filter::ByProjectType(project_type.clone())),
|
||||||
|
|
Loading…
Reference in New Issue