diff --git a/Cargo.toml b/Cargo.toml index debeb7f..30e3dcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,5 @@ err = { git = "https://git.franklinblanco.dev/franklinblanco/err.git" } thousands = "0.2.0" chrono = "0.4.23" - # Core jl-types = { path = "../jl-types", features = ["wasm"] } diff --git a/css/components/mediapicker.css b/css/components/mediapicker.css new file mode 100644 index 0000000..9171b72 --- /dev/null +++ b/css/components/mediapicker.css @@ -0,0 +1,77 @@ +.mediapicker-container { + display: flex; + flex-direction: row; + flex-flow: row wrap; + justify-content: start; + align-items: center; + gap: 10px; + + width: 100%; +} +.mediapicker-media { + display: flex; + object-fit: cover; + width: 240px; + height: 240px; +} +.mediapicker-new { + display: flex; + flex-direction: column; + justify-content: space-evenly; + align-items: center; + width: 240px; + height: 240px; + + font-size: 40px; + background-color: gainsboro; + color: white; +} +.mediapicker-new:hover { + cursor: pointer; +} +.mediapicker-delete { + position: relative; + right: 25px; + top: 10px; + + color: grey; + font-size: 18px; + width: fit-content; + height: fit-content; +} +.mediapicker-delete:hover { + cursor: pointer; +} +.mediapicker-new-photo-section { + width: 90%; + height: 30px; + font-size: 13px; + font-family: Source Sans Pro; + background-color: white; + color: black; + + padding: 3px; + display: flex; + justify-content: center; + align-items: center; +} +.mediapicker-new-video-section { + width: 90%; + height: 30px; + background-color: white; + color: black; + + padding: 3px; + display: flex; + justify-content: center; + align-items: center; +} +.mediapicker-new-video-section-input { + height: 100%; + background-color: white; + border: solid 0.5px #d8d8d8; + + width: 100%; + text-indent: 10px; + font-family: Source Sans Pro; +} \ No newline at end of file diff --git a/index.html b/index.html index 4e0dea7..4d391ee 100644 --- a/index.html +++ b/index.html @@ -30,6 +30,7 @@ + diff --git a/src/api/backend/mod.rs b/src/api/backend/mod.rs index e9c0699..ea93164 100644 --- a/src/api/backend/mod.rs +++ b/src/api/backend/mod.rs @@ -1,6 +1,12 @@ use std::collections::HashSet; -use jl_types::{dto::{filters::Filter, listing::Listing, project_card::ProjectCardDto, payloads::contact::ContactPayload}, domain::{agent::Agent, count::Count, contact::Contact}}; +use jl_types::{ + domain::{agent::Agent, contact::Contact, count::Count}, + dto::{ + filters::Filter, listing::Listing, payloads::contact::ContactPayload, + project_card::ProjectCardDto, + }, +}; use reqwest::Method; use uuid::Uuid; @@ -9,38 +15,140 @@ use super::base::perform_request_without_client; const BASE_URL: &str = "http://localhost:8095/"; pub async fn get_all_cities() -> Result, err::Error> { - perform_request_without_client::>(BASE_URL.into(), Method::GET, "read/locations".into(), None, 200, Vec::new(), None).await + perform_request_without_client::>( + BASE_URL.into(), + Method::GET, + "read/locations".into(), + None, + 200, + Vec::new(), + None, + ) + .await } pub async fn get_all_districts_in_city(city: &String) -> Result, err::Error> { - perform_request_without_client::>(BASE_URL.into(), Method::GET, format!("read/locations/{city}"), None, 200, Vec::new(), None).await + perform_request_without_client::>( + BASE_URL.into(), + Method::GET, + format!("read/locations/{city}"), + None, + 200, + Vec::new(), + None, + ) + .await } -pub async fn get_all_projects_with_filters_paged(page: &i64, filters: Vec) -> Result, err::Error> { - perform_request_without_client::>(BASE_URL.into(), Method::GET, format!("read/projects/{page}"), None, 200, Vec::new(), Some(filters.into_iter().map(|filter| filter.to_param()).collect())).await +pub async fn get_all_projects_with_filters_paged( + page: &i64, + filters: Vec, +) -> Result, err::Error> { + perform_request_without_client::>( + BASE_URL.into(), + Method::GET, + format!("read/projects/{page}"), + None, + 200, + Vec::new(), + Some( + filters + .into_iter() + .map(|filter| filter.to_param()) + .collect(), + ), + ) + .await } pub async fn get_project_listing(project_id: &Uuid) -> Result { - perform_request_without_client::(BASE_URL.into(), Method::GET, format!("read/project/{project_id}"), None, 200, Vec::new(), None).await + perform_request_without_client::( + BASE_URL.into(), + Method::GET, + format!("read/project/{project_id}"), + None, + 200, + Vec::new(), + None, + ) + .await } pub async fn get_all_agents() -> Result, err::Error> { - perform_request_without_client::>(BASE_URL.into(), Method::GET, format!("read/agent"), None, 200, Vec::new(), None).await + perform_request_without_client::>( + BASE_URL.into(), + Method::GET, + format!("read/agent"), + None, + 200, + Vec::new(), + None, + ) + .await } pub async fn get_agent_with_shortcode(shortcode: &String) -> Result { - perform_request_without_client::(BASE_URL.into(), Method::GET, format!("read/agent/{shortcode}"), None, 200, Vec::new(), None).await + perform_request_without_client::( + BASE_URL.into(), + Method::GET, + format!("read/agent/{shortcode}"), + None, + 200, + Vec::new(), + None, + ) + .await } pub async fn get_all_page_visits_count() -> Result { - perform_request_without_client::(BASE_URL.into(), Method::GET, format!("admin/visits/count"), None, 200, Vec::new(), None).await + perform_request_without_client::( + BASE_URL.into(), + Method::GET, + format!("admin/visits/count"), + None, + 200, + Vec::new(), + None, + ) + .await } pub async fn get_all_contacts_count() -> Result { - perform_request_without_client::(BASE_URL.into(), Method::GET, format!("admin/contacts/count"), None, 200, Vec::new(), None).await + perform_request_without_client::( + BASE_URL.into(), + Method::GET, + format!("admin/contacts/count"), + None, + 200, + Vec::new(), + None, + ) + .await } pub async fn get_all_contacts() -> Result, err::Error> { - perform_request_without_client::>(BASE_URL.into(), Method::GET, format!("admin/contacts"), None, 200, Vec::new(), None).await + perform_request_without_client::>( + 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 -} \ No newline at end of file + perform_request_without_client( + BASE_URL.into(), + Method::POST, + format!("read/contact"), + Some(contact), + 200, + Vec::new(), + None, + ) + .await +} +/* +pub async fn upload_image() -> Result { + perform_request_without_client(BASE_URL.into(), Method::POST, format!("images/"), Some(), 200, Vec::new(), None).await +}*/ diff --git a/src/api/base.rs b/src/api/base.rs index fba6f08..4615576 100644 --- a/src/api/base.rs +++ b/src/api/base.rs @@ -1,7 +1,6 @@ use err::{Error, MessageResource}; use reqwest::Client; -use serde::{Serialize, de::DeserializeOwned}; - +use serde::{de::DeserializeOwned, Serialize}; /// This function is mainly for when you don't have a client in your application and just want to get it over with. /// This shouldn't be used as it takes more resource consumption than the above method. @@ -12,7 +11,7 @@ pub async fn perform_request_without_client( body: Option, expected_status_code: u16, headers: Vec<(String, String)>, - params: Option> + params: Option>, ) -> Result { let client = Client::new(); let mut req_incomplete = @@ -25,7 +24,7 @@ pub async fn perform_request_without_client( if let Some(parameters) = params { req_incomplete = req_incomplete.query(¶meters) } - + let req_complete = match body { Some(b) => req_incomplete.json(&b), None => req_incomplete.header("content-length", 0), @@ -60,4 +59,4 @@ pub async fn perform_request_without_client( Err(Error::Network(MessageResource::from(e))) } } -} \ No newline at end of file +} diff --git a/src/api/mod.rs b/src/api/mod.rs index f36d941..a57ca5e 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,2 +1,2 @@ +pub mod backend; pub mod base; -pub mod backend; \ No newline at end of file diff --git a/src/components/admin_nav_bar.rs b/src/components/admin_nav_bar.rs index c673a1e..1d5f003 100644 --- a/src/components/admin_nav_bar.rs +++ b/src/components/admin_nav_bar.rs @@ -1,10 +1,9 @@ use yew::prelude::*; use yew_router::prelude::{use_navigator, use_route}; -use crate::{routes::main_router::Route}; +use crate::routes::main_router::Route; //use yew_router::prelude::use_navigator; - #[function_component(AdminNavigationBar)] pub fn admin_navigation_bar() -> Html { let current_route: Option = use_route(); @@ -13,7 +12,7 @@ pub fn admin_navigation_bar() -> Html { let cloned_navigator_2 = navigator.clone(); let cloned_navigator_3 = navigator.clone(); let cloned_navigator_4 = navigator.clone(); - + html! {
@@ -27,8 +26,8 @@ pub fn admin_navigation_bar() -> Html {
{"Mensajes"}
- - + +
} -} \ No newline at end of file +} diff --git a/src/components/admin_project.rs b/src/components/admin_project.rs index 3cc0195..9d66840 100644 --- a/src/components/admin_project.rs +++ b/src/components/admin_project.rs @@ -1,8 +1,11 @@ -use jl_types::{dto::project_card::ProjectCardDto, domain::project_state::ProjectState}; +use jl_types::{domain::project_state::ProjectState, dto::project_card::ProjectCardDto}; use yew::prelude::*; -use yew_router::{prelude::use_navigator}; +use yew_router::prelude::use_navigator; -use crate::{routes::main_router::Route, pages::admin::edit::{EditType, EditItem}}; +use crate::{ + pages::admin::edit::{EditItem, EditType}, + routes::main_router::Route, +}; #[function_component(AdminProject)] pub fn admin_project(props: &AdminProjectProps) -> Html { @@ -24,7 +27,10 @@ pub fn admin_project(props: &AdminProjectProps) -> Html { let onclick_item = { let props = props.clone(); Callback::from(move |_| { - navigator.push(&Route::AdminEdit { edit_type: EditType::Existing(props.project.id), edit_item: EditItem::Project }); + navigator.push(&Route::AdminEdit { + edit_type: EditType::Existing(props.project.id), + edit_item: EditItem::Project, + }); }) }; html! { @@ -59,4 +65,4 @@ pub fn admin_project(props: &AdminProjectProps) -> Html { pub struct AdminProjectProps { pub project: ProjectCardDto, pub index: usize, -} \ No newline at end of file +} diff --git a/src/components/agent_card.rs b/src/components/agent_card.rs index 24e25e4..625fc7f 100644 --- a/src/components/agent_card.rs +++ b/src/components/agent_card.rs @@ -30,4 +30,4 @@ pub fn agent_card(props: &AgentCardProps) -> Html { #[derive(Properties, PartialEq)] pub struct AgentCardProps { pub agent: Agent, -} \ No newline at end of file +} diff --git a/src/components/datepicker.rs b/src/components/datepicker.rs index d86f341..53de246 100644 --- a/src/components/datepicker.rs +++ b/src/components/datepicker.rs @@ -1,25 +1,25 @@ use std::str::FromStr; -use chrono::{NaiveDate}; +use chrono::NaiveDate; use yew::prelude::*; use crate::components::textfield::get_value_from_input_event; -/// The input type date field in html will always guarantee a valid date string. +/// The input type date field in html will always guarantee a valid date string. #[function_component(DatePicker)] pub fn datepicker(props: &DatePickerProps) -> Html { let date_handle = props.value.clone(); let optional_cb = props.onchange.clone(); let cb = Callback::from(move |e: InputEvent| { match parse_date(get_value_from_input_event(e)) { - Ok(date) => { + Ok(date) => { match optional_cb.clone() { Some(callback) => callback.emit(Some(date.clone())), - None => {}, + None => {} }; date_handle.set(Some(date)); - }, - Err(_) => {}, + } + Err(_) => {} }; }); let date_handle = props.value.clone(); @@ -40,7 +40,7 @@ pub struct DatePickerProps { pub value: UseStateHandle>, #[prop_or_default] pub required: bool, - pub onchange: Option>> + pub onchange: Option>>, } pub fn parse_date(date_str: String) -> Result { @@ -49,6 +49,6 @@ pub fn parse_date(date_str: String) -> Result { Err(error) => { log::error!("Falied to parse Date in DatePicker: {error}"); Err(()) - }, + } } -} \ No newline at end of file +} diff --git a/src/components/dropdown.rs b/src/components/dropdown.rs index 5f7a79f..f8091ac 100644 --- a/src/components/dropdown.rs +++ b/src/components/dropdown.rs @@ -1,12 +1,14 @@ use std::fmt::Display; -use jl_types::domain::{option_wrapper::OptionWrapper}; +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(props: &DropDownProps) -> Html { +pub fn dropdown( + props: &DropDownProps, +) -> Html { let selection_changed_cb = { let onchange_cb = props.onchange.clone(); let selected = props.selected.clone(); @@ -14,22 +16,29 @@ pub fn dropdown(props: &Drop selected.set(option.option.clone()); match onchange_cb.clone() { Some(additional_cb) => additional_cb.emit(option), - None => {}, + None => {} }; - }) }; - let drop_down = comp_with::>>(yew_utils::components::drop_down::DropDownProps { - initial: { - OptionWrapper::new((*props.selected).clone())}, - options: { - let mut options: Vec> = props.options.clone().into_iter().map(|option| OptionWrapper::new(Some(option))).collect(); - if props.has_none { options.insert(0, OptionWrapper::new(None)); } - options + let drop_down = comp_with::>>( + yew_utils::components::drop_down::DropDownProps { + initial: { OptionWrapper::new((*props.selected).clone()) }, + options: { + let mut options: Vec> = 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()), }, - 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} @@ -47,5 +56,5 @@ pub struct DropDownProps { #[prop_or_default] pub onchange: Option>>, #[prop_or_default] - pub has_none: bool -} \ No newline at end of file + pub has_none: bool, +} diff --git a/src/components/feature.rs b/src/components/feature.rs index fe169aa..b26e357 100644 --- a/src/components/feature.rs +++ b/src/components/feature.rs @@ -3,11 +3,11 @@ use yew::prelude::*; #[function_component(FeatureItem)] pub fn feature_item(props: &FeatureItemProps) -> Html { let props = props.clone(); - html!{ + html! {
-
+
{props.title} @@ -27,4 +27,4 @@ pub struct FeatureItemProps { pub title: String, pub subtitle: String, pub icon: String, -} \ No newline at end of file +} diff --git a/src/components/floating_widget.rs b/src/components/floating_widget.rs index 8332eaf..d6f21c0 100644 --- a/src/components/floating_widget.rs +++ b/src/components/floating_widget.rs @@ -1,7 +1,6 @@ use uuid::Uuid; use yew::prelude::*; -//TODO: Finish, add whatsapp link or email link? #[function_component(FloatingWidget)] pub fn floating_widget(props: &FloatingWidgetProps) -> Html { let message = format!("Buenas, me interesa conocer mas sobre esta propiedad: %0A https://proyectosenconstruccion.com/details/{}", props.project_id); @@ -20,4 +19,4 @@ pub fn floating_widget(props: &FloatingWidgetProps) -> Html { pub struct FloatingWidgetProps { pub project_id: Uuid, pub phone_number: String, -} \ No newline at end of file +} diff --git a/src/components/footer.rs b/src/components/footer.rs index fd47bef..ea18a25 100644 --- a/src/components/footer.rs +++ b/src/components/footer.rs @@ -27,9 +27,9 @@ pub fn page_footer() -> Html {
- - - + + + /*
@@ -39,7 +39,7 @@ pub fn page_footer() -> Html {
*/ - + } -} \ No newline at end of file +} diff --git a/src/components/media_picker.rs b/src/components/media_picker.rs new file mode 100644 index 0000000..cb9f35e --- /dev/null +++ b/src/components/media_picker.rs @@ -0,0 +1,129 @@ +use jl_types::domain::media::{Media, MediaList}; +use yew::prelude::*; + +use crate::components::textfield::get_value_from_input_event; + +#[function_component(MediaPicker)] +pub fn media_picker(props: &MediaPickerProps) -> Html { + html! { + <> +
{"Media del proyecto"}
+
+ +
+ + } +} + +#[derive(PartialEq, Properties, Clone)] +pub struct MediaPickerProps { + pub value: UseStateHandle, + pub onchange: Option>, + #[prop_or_default] + pub required: bool, +} +#[function_component(MediaListRendered)] +fn render_media_list(props: &MediaListProps) -> Html { + let mut media_elements = (*props.medialist).clone().media_list.into_iter().enumerate().map(|(index, media)| { + html! { +
+ { + match media { + Media::Photo(url) => html! { + + }, + Media::Video(url) => html! { + + } + } + } +
cb.emit(String::new()), + None => {} + }; + let mut media = (*media_handle).clone(); + media.media_list.remove(index); + media_handle.set(media); + }) + }> + +
+
+ } + }).collect::>(); + let pressed = use_state(|| false); + let onclick = { + let pressed = pressed.clone(); + Callback::from(move |event: MouseEvent| { + event.stop_propagation(); + pressed.set(true); + }) + }; + let video_str = use_state_eq(|| String::new()); + let onvideo_input_changed = { + let video_str = video_str.clone(); + Callback::from(move |e: InputEvent| { + let value = get_value_from_input_event(e); + video_str.set(value); + }) + }; + let onvideo_keypress = { + let video_str = video_str.clone(); + let media_handle = props.medialist.clone(); + let onchange_cb = props.onchange.clone(); + Callback::from(move |e: KeyboardEvent| { + if e.key() == String::from("Enter") { + match onchange_cb.clone() { + Some(cb) => cb.emit(String::new()), + None => {} + }; + let mut media = (*media_handle).clone(); + media.media_list.push(Media::Video((*video_str).clone())); + media_handle.set(media); + } + }) + }; + let onphoto_upload = { + let media_handle = props.medialist.clone(); + let onchange_cb = props.onchange.clone(); + Callback::from(move |_: InputEvent| { + match onchange_cb.clone() { + Some(cb) => cb.emit(String::new()), + None => {} + }; + //TODO: Upload picture, then push url into medialist + let mut media = (*media_handle).clone(); + media.media_list.push(Media::Photo("".into())); + media_handle.set(media); + }) + }; + + media_elements.push(html! { +
+ {if *pressed { + html! { + <> +
+ +
+
+ +
+ + } + } else { + html! {} + }} +
+ }); + media_elements.into_iter().collect() +} +#[derive(Properties, PartialEq)] +pub struct MediaListProps { + pub medialist: UseStateHandle, + pub onchange: Option>, +} diff --git a/src/components/media_slideshow.rs b/src/components/media_slideshow.rs index 08cd2c5..d94bbbb 100644 --- a/src/components/media_slideshow.rs +++ b/src/components/media_slideshow.rs @@ -1,7 +1,6 @@ use jl_types::domain::media::Media; use yew::prelude::*; - #[function_component(MediaSlideshow)] pub fn media_slideshow(props: &MediaSlideshowProps) -> Html { let current_media_index = use_state(|| 0); @@ -11,7 +10,7 @@ pub fn media_slideshow(props: &MediaSlideshowProps) -> Html { let total_media_count = total_media_count.clone(); Callback::from(move |_| { if *current_media_index > 0 { - current_media_index.set(*current_media_index -1); + current_media_index.set(*current_media_index - 1); } else { current_media_index.set(total_media_count - 1); } @@ -47,7 +46,7 @@ pub fn media_slideshow(props: &MediaSlideshowProps) -> Html { "display: none;" }} src={format!("{url}?autoplay=1&mute=1")}> - + } } }).collect::() @@ -69,4 +68,4 @@ pub fn media_slideshow(props: &MediaSlideshowProps) -> Html { #[derive(Properties, PartialEq, PartialOrd)] pub struct MediaSlideshowProps { pub media_list: Vec, -} \ No newline at end of file +} diff --git a/src/components/mod.rs b/src/components/mod.rs index d9182ee..2125c2c 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,12 +1,14 @@ -pub mod nav_bar; -pub mod project_card; -pub mod media_slideshow; -pub mod floating_widget; -pub mod feature; -pub mod footer; -pub mod agent_card; pub mod admin_nav_bar; pub mod admin_project; -pub mod textfield; +pub mod agent_card; +pub mod datepicker; pub mod dropdown; -pub mod datepicker; \ No newline at end of file +pub mod feature; +pub mod floating_widget; +pub mod footer; +pub mod media_picker; +pub mod media_slideshow; +pub mod nav_bar; +pub mod new_widget; +pub mod project_card; +pub mod textfield; diff --git a/src/components/nav_bar.rs b/src/components/nav_bar.rs index 280ea11..5f82994 100644 --- a/src/components/nav_bar.rs +++ b/src/components/nav_bar.rs @@ -1,12 +1,15 @@ -use stdweb::web::{IEventTarget, event::ResizeEvent}; +use stdweb::web::{event::ResizeEvent, IEventTarget}; use yew::prelude::*; use yew_router::prelude::{use_navigator, use_route}; -use crate::{routes::main_router::{Route}, constants::{NAVBAR_COL_LANDING, NAVBAR_COL_CONTACTO, NAVBAR_COL_PROYECTOS, NAVBAR_COL_AGENTES}}; +use crate::{ + constants::{ + NAVBAR_COL_AGENTES, NAVBAR_COL_CONTACTO, NAVBAR_COL_LANDING, NAVBAR_COL_PROYECTOS, + }, + routes::main_router::Route, +}; //use yew_router::prelude::use_navigator; - - #[function_component(NavigationBar)] pub fn navigation_bar() -> Html { let current_route: Option = use_route(); @@ -23,10 +26,12 @@ pub fn navigation_bar() -> Html { let navbar_toggle = navbar_toggle.clone(); Callback::from(move |_| navbar_toggle.set(!*navbar_toggle)) }; - let window_device_handle = use_state_eq(|| if stdweb::web::window().inner_width() > 750 { - WindowDevice::Desktop - } else { - WindowDevice::Mobile + let window_device_handle = use_state_eq(|| { + if stdweb::web::window().inner_width() > 750 { + WindowDevice::Desktop + } else { + WindowDevice::Mobile + } }); let window_device_handle_cloned = window_device_handle.clone(); stdweb::web::window().add_event_listener(move |_: ResizeEvent| { @@ -37,16 +42,15 @@ pub fn navigation_bar() -> Html { window_device_handle_cloned.set(WindowDevice::Mobile) } }); - - + html! {
- - + +
Html { } } } - +
} } @@ -117,5 +121,5 @@ pub fn navigation_bar() -> Html { #[derive(PartialEq, Eq, PartialOrd, Ord)] enum WindowDevice { Desktop, - Mobile -} \ No newline at end of file + Mobile, +} diff --git a/src/components/new_widget.rs b/src/components/new_widget.rs new file mode 100644 index 0000000..d7e4339 --- /dev/null +++ b/src/components/new_widget.rs @@ -0,0 +1,34 @@ +use yew::prelude::*; +use yew_router::prelude::use_navigator; + +use crate::{ + pages::admin::edit::{EditItem, EditType}, + routes::main_router::Route, +}; + +#[function_component(NewThingWidget)] +pub fn new_thing_widget(props: &NewThingWidgetProps) -> Html { + let navigator = use_navigator().unwrap(); + let onclick = { + let edit_item = props.item.clone(); + let navigator = navigator.clone(); + Callback::from(move |_| { + navigator.push(&Route::AdminEdit { + edit_type: EditType::New, + edit_item: edit_item.clone(), + }); + }) + }; + html! { + +
+ +
+
+ } +} + +#[derive(Properties, PartialEq)] +pub struct NewThingWidgetProps { + pub item: EditItem, +} diff --git a/src/components/project_card.rs b/src/components/project_card.rs index 64fc414..85b6a5a 100644 --- a/src/components/project_card.rs +++ b/src/components/project_card.rs @@ -1,16 +1,15 @@ -use jl_types::{domain::{media::Media}, dto::project_card::ProjectCardDto}; +use jl_types::{domain::media::Media, dto::project_card::ProjectCardDto}; use thousands::Separable; use yew::prelude::*; use yew_router::prelude::use_navigator; use crate::routes::main_router::Route; - #[function_component(ProjectCard)] pub fn project_card(props: &ProjectCardProps) -> Html { let navigator = use_navigator().unwrap(); let project_id = props.project.id.clone(); - let project_view_cb = Callback::from(move |_|{ + let project_view_cb = Callback::from(move |_| { navigator.push(&Route::Details { project_id }); }); @@ -25,30 +24,35 @@ pub fn project_card(props: &ProjectCardProps) -> Html { cover_image_url = String::new() } - let project_title = format!("{} en {}, {}", props.project.project_type, props.project.district, props.project.city); - - let project_price = format!("Desde US${}", match props.project.starts_from { - Some(price) => { - let price_separated = price.separate_with_commas(); - if price_separated.contains(".") { - price_separated - } else { - format!("{price_separated}.00") + let project_title = format!( + "{} en {}, {}", + props.project.project_type, props.project.district, props.project.city + ); + + let project_price = format!( + "Desde US${}", + match props.project.starts_from { + Some(price) => { + let price_separated = price.separate_with_commas(); + if price_separated.contains(".") { + price_separated + } else { + format!("{price_separated}.00") + } } - }, - None => "0.00".into() - }); + None => "0.00".into(), + } + ); let project_condition = props.project.project_condition.to_string(); let project_est_finish_date = props.project.finish_date.format("%m/%Y"); //let project_location_written; - - html!{ + html! {
{"project - +
{project_title}
@@ -71,5 +75,5 @@ pub fn project_card(props: &ProjectCardProps) -> Html { #[derive(Properties, PartialEq, PartialOrd)] pub struct ProjectCardProps { - pub project: ProjectCardDto -} \ No newline at end of file + pub project: ProjectCardDto, +} diff --git a/src/components/textfield.rs b/src/components/textfield.rs index 8dad1ba..2490d84 100644 --- a/src/components/textfield.rs +++ b/src/components/textfield.rs @@ -3,7 +3,6 @@ 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 { @@ -11,24 +10,26 @@ pub fn textfield(props: &TextFieldProps) -> Html { 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); - }, + 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_textarea_event(e); + match onchange.clone() { + Some(onchange) => { + onchange.emit(value.clone()); + } + None => {} + }; + handle.set(value); } }) }; @@ -42,7 +43,7 @@ pub fn textfield(props: &TextFieldProps) -> Html { html! {