From 7c2d6018b6f5178983a2da9dd4b9f2846b8e9491 Mon Sep 17 00:00:00 2001 From: Franklin Date: Wed, 15 Mar 2023 19:40:56 -0400 Subject: [PATCH] Finished search filters design and functionality (UI) --- Cargo.lock | 114 +++++++++++++++++++ Cargo.toml | 5 +- css/body.css | 1 - css/navbar.css | 1 + css/project_card.css | 4 + css/search.css | 121 ++++++++------------ index.html | 11 +- src/components/mod.rs | 3 +- src/components/nav_bar.rs | 7 +- src/components/project_card.rs | 10 ++ src/main.rs | 3 + src/pages/search.rs | 201 +++++++++++++++++++++------------ src/routes/main_router.rs | 5 +- src/utils/get_value.rs | 0 src/utils/mod.rs | 1 + 15 files changed, 327 insertions(+), 160 deletions(-) create mode 100644 css/project_card.css create mode 100644 src/components/project_card.rs create mode 100644 src/utils/get_value.rs create mode 100644 src/utils/mod.rs diff --git a/Cargo.lock b/Cargo.lock index b7e9605..9a31fe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base64" version = "0.21.0" @@ -185,6 +191,12 @@ dependencies = [ "syn", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + [[package]] name = "either" version = "1.8.1" @@ -690,7 +702,9 @@ dependencies = [ "js-sys", "log", "reqwest", + "serde", "serde_json", + "stdweb", "stylist", "uuid", "wasm-bindgen", @@ -698,6 +712,7 @@ dependencies = [ "wasm-logger", "yew", "yew-router", + "yew-utils", ] [[package]] @@ -711,6 +726,7 @@ dependencies = [ "serde", "serde_json", "uuid", + "yew", ] [[package]] @@ -1108,6 +1124,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + [[package]] name = "rustls" version = "0.20.8" @@ -1157,6 +1182,21 @@ dependencies = [ "untrusted", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.156" @@ -1211,6 +1251,21 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "siphasher" version = "0.3.10" @@ -1242,6 +1297,57 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "serde", + "serde_json", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "stylist" version = "0.12.0" @@ -1827,3 +1933,11 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "yew-utils" +version = "0.3.0" +dependencies = [ + "web-sys", + "yew", +] diff --git a/Cargo.toml b/Cargo.toml index 03b2d6f..fb5d502 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,18 +12,21 @@ license = "MIT OR Apache-2.0" yew = { version = "0.20.0", features = ["csr"] } yew-router = "0.17" stylist = "0.12.0" +yew-utils = { path = "../../libs/yew-utils" } # Wasm/js stuff wasm-logger = "0.2" wasm-bindgen = "0.2.84" wasm-bindgen-futures = "0.4.34" +stdweb = "0.4.20" js-sys = "0.3" # other libs reqwest = { version = "0.11.11", features = ["rustls-tls", "json", "blocking"], default-features = false } uuid = { version = "1.3.0", features = ["v4", "fast-rng", "macro-diagnostics", "serde", "js"] } log = "0.4" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.88" # Core -jl-types = { path = "../jl-types" } \ No newline at end of file +jl-types = { path = "../jl-types", features = ["yew", "wasm"] } \ No newline at end of file diff --git a/css/body.css b/css/body.css index a304eb2..56209db 100644 --- a/css/body.css +++ b/css/body.css @@ -8,5 +8,4 @@ body { flex-direction: column; justify-content: center; align-items: stretch; - } \ No newline at end of file diff --git a/css/navbar.css b/css/navbar.css index 7fb3d1e..f1f1527 100644 --- a/css/navbar.css +++ b/css/navbar.css @@ -54,6 +54,7 @@ flex-direction: column; justify-content: flex-start; margin-top: 10px; + } .navbar-item { diff --git a/css/project_card.css b/css/project_card.css new file mode 100644 index 0000000..3c9ca7c --- /dev/null +++ b/css/project_card.css @@ -0,0 +1,4 @@ + +.project-listing-card { + border-radius: 10px; +} \ No newline at end of file diff --git a/css/search.css b/css/search.css index c38e645..d60947a 100644 --- a/css/search.css +++ b/css/search.css @@ -1,96 +1,71 @@ -.property-search-container { +.project-search-container { display: flex; flex-direction: column; justify-content: stretch; align-items: center; - padding: 10px 50px; - flex-grow: 1; + padding: 30px 30px; } -.property-search-bar-container { +.project-search-filters-container { display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - min-width: 300px; - max-width: 600px; - width: 100%; - padding: 0px 20px; - min-height: 50px; - border: 0.5px solid rgba(0, 0, 0, 0.08); - border-radius: 30px; - box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 10px; - background-color: white; - flex-grow: 1; - margin-bottom: 15px; - - color: #252631; -} - -.property-search-bar { - border: 0px; - padding: 10px; - outline: none; - font-family: Source Sans Pro; - font-size: 15px; - flex-grow: 1; -} - -.search-bar-erase-button { - display: none; -} -.search-bar-erase-button:hover { - cursor: pointer; -} - -.search-bar-filter-button { - display: flex; - justify-content: center; - align-items: center; - border-radius: 25px; - border: 1px solid rgba(0, 0, 0, 0.14); - padding: 4px; - width: 20px; - height: 20px; - font-size: 14px; -} - -.search-bar-filter-button:hover { - cursor: pointer; -} - -.property-search-filters-container { - display: flex; - flex-direction: row; - justify-content: space-evenly; + flex-direction: column; + gap: 25px; + justify-content: stretch; flex-wrap: wrap; - align-items: center; + align-items: stretch; width: 100%; } -.property-search-filter-item { +.project-search-filter-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: start; + gap: 10px; +} + +.project-search-filter-label { + font-size: 16px; + font-weight: bold; + font-family: Source Sans Pro; +} + +.project-search-filter-item { display: flex; flex-direction: row; - justify-content: space-between; + justify-content: center; align-items: center; - min-width: 75px; + min-width: 150px; + width: 100%; + min-height: 50px; - color: black; padding: 5px 10px; - border: 1px solid rgba(0, 0, 0, 0.5); + border: 1px solid rgba(0, 0, 0, 0.0); + background-color: rgba(0, 0, 0, 0.04); border-radius: 5px; - font-family: Open Sans; - font-weight: bold; - font-size: 15px; + font-family: Source Sans Pro; + font-size: 16px; +} + + +.project-search-divider { + width: 100%; + margin: 35px 30px; + height: 1px; + background-color:rgba(0, 0, 0, 0.1); +} + + +.project-search-results-container { + display: flex; + flex-direction: column; + justify-content: start; + align-items: center; } -.property-search-results-container { - color: purple; -} - -.property-search-result-card { - color: orange +.project-search-result-card { + background-color: white; } diff --git a/index.html b/index.html index 1156bc6..d38834f 100644 --- a/index.html +++ b/index.html @@ -4,10 +4,13 @@ JL - - - - + + + + + + + diff --git a/src/components/mod.rs b/src/components/mod.rs index 937dfe6..d5e08a5 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,2 +1,3 @@ pub mod nav_bar; -pub mod search_filter; \ No newline at end of file +pub mod search_filter; +pub mod project_card; \ No newline at end of file diff --git a/src/components/nav_bar.rs b/src/components/nav_bar.rs index 7f3bd9f..c2c56dc 100644 --- a/src/components/nav_bar.rs +++ b/src/components/nav_bar.rs @@ -1,7 +1,8 @@ +use jl_types::domain::project_state::ProjectState; use yew::prelude::*; use yew_router::prelude::use_navigator; -use crate::{routes::main_router::{Route}, constants::{NAVBAR_TITLE, NAVBAR_COL_LANDING, NAVBAR_COL_PROYECTOS_ACABADOS, NAVBAR_COL_CONTACTO, NAVBAR_COL_PROYECTOS_EN_CONSTRUCCION}, pages::search::PropertyState}; +use crate::{routes::main_router::{Route}, constants::{NAVBAR_TITLE, NAVBAR_COL_LANDING, NAVBAR_COL_PROYECTOS_ACABADOS, NAVBAR_COL_CONTACTO, NAVBAR_COL_PROYECTOS_EN_CONSTRUCCION}}; //use yew_router::prelude::use_navigator; @@ -36,11 +37,11 @@ pub fn navigation_bar() -> Html { {NAVBAR_COL_LANDING} -
+
{NAVBAR_COL_PROYECTOS_ACABADOS}
-
+
{NAVBAR_COL_PROYECTOS_EN_CONSTRUCCION}
diff --git a/src/components/project_card.rs b/src/components/project_card.rs new file mode 100644 index 0000000..4151f62 --- /dev/null +++ b/src/components/project_card.rs @@ -0,0 +1,10 @@ +use jl_types::domain::project::Project; +use yew::prelude::*; + +#[function_component(ProjectCard)] +pub fn project_card(_props: &Project) -> Html { + + html!{ +
+ } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 093fdfa..d47114e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ pub mod components; pub mod routes; pub mod pages; pub mod constants; +pub mod utils; use yew::prelude::*; use yew_router::{BrowserRouter, Switch}; @@ -18,5 +19,7 @@ fn App() -> Html { } } fn main() { + wasm_logger::init(wasm_logger::Config::default()); + stdweb::initialize(); yew::Renderer::::new().render(); } \ No newline at end of file diff --git a/src/pages/search.rs b/src/pages/search.rs index 1e15810..ab707b5 100644 --- a/src/pages/search.rs +++ b/src/pages/search.rs @@ -1,60 +1,140 @@ -use std::{fmt::Display, str::FromStr}; - +use jl_types::domain::{project_state::ProjectState, project_type::ProjectType, project_condition::ProjectCondition}; +use log::info; use yew::prelude::*; +use yew_utils::{components::drop_down::{DropDownProps, DropDown}, vdom::comp_with}; +use jl_types::domain::option_wrapper::OptionWrapper; use crate::components::nav_bar::NavigationBar; + #[function_component(SearchPage)] pub fn search_page(_props: &SearchPageProperties) -> Html { - let search_text = use_state(|| String::new()); - let clear_search_input = { - let search_text = search_text.clone(); - Callback::from(move |_| { - search_text.set(String::new()) - }) - }; + // Dropdown + let project_type_filter: UseStateHandle> = use_state(|| OptionWrapper::new(None)); + // Dropdown + let project_condition_filter: UseStateHandle> = use_state(|| OptionWrapper::new(None)); + // Dropdown + let project_state_filter: UseStateHandle> = use_state(|| OptionWrapper::new(None)); + // Dropdown + let project_city_filter: UseStateHandle> = use_state(|| OptionWrapper::new(None)); + // Dropdown + let project_district_filter: UseStateHandle> = use_state(|| OptionWrapper::new(None)); + //TODO: Think about price filtering + // TextField + let _project_min_price_filter: UseStateHandle> = use_state(|| OptionWrapper::new(None)); + // TextField + let _project_max_price_filter: UseStateHandle> = use_state(|| OptionWrapper::new(None)); + + + let project_type_drop_down = comp_with::>>(DropDownProps { + initial: OptionWrapper::new(None), + options: vec![OptionWrapper::new(None), OptionWrapper::new(Some(ProjectType::Apartamento)), OptionWrapper::new(Some(ProjectType::Casa)), OptionWrapper::new(Some(ProjectType::Oficina)), OptionWrapper::new(Some(ProjectType::Local)), OptionWrapper::new(Some(ProjectType::Solar)) ], + selection_changed: { + let cloned_project_type_filter = project_type_filter.clone(); + Callback::from(move |project_type: OptionWrapper| { + info!("{}", project_type.to_string()); + cloned_project_type_filter.set(project_type) + } + )}, + class_css: Some("project-search-filter-item".into()) + }); + + let project_state_drop_down = comp_with::>>(DropDownProps { + initial: OptionWrapper::new(None), + options: vec![OptionWrapper::new(None), OptionWrapper::new(Some(ProjectState::InConstruction)), OptionWrapper::new(Some(ProjectState::Finished)) ], + selection_changed: { + let cloned_project_state_filter = project_state_filter.clone(); + Callback::from(move |project_state: OptionWrapper| { + info!("{}", project_state.to_string()); + cloned_project_state_filter.set(project_state) + } + )}, + class_css: Some("project-search-filter-item".into()) + }); + + let project_condition_drop_down = comp_with::>>(DropDownProps { + initial: OptionWrapper::new(None), + options: vec![OptionWrapper::new(None), OptionWrapper::new(Some(ProjectCondition::New)), OptionWrapper::new(Some(ProjectCondition::Resale)) ], + selection_changed: { + let cloned_project_condition_filter = project_condition_filter.clone(); + Callback::from(move |project_condition: OptionWrapper| { + info!("{}", project_condition.to_string()); + cloned_project_condition_filter.set(project_condition) + } + )}, + class_css: Some("project-search-filter-item".into()) + }); + + let project_city_drop_down = comp_with::>>(DropDownProps { + initial: OptionWrapper::new(None), + options: vec![OptionWrapper::new(None), OptionWrapper::new(Some("Santo Domingo".into())), OptionWrapper::new(Some("Punta Cana".into())) ], + selection_changed: { + let cloned_project_city_filter = project_city_filter.clone(); + Callback::from(move |project_city: OptionWrapper| { + info!("{}", project_city.to_string()); + cloned_project_city_filter.set(project_city) + } + )}, + class_css: Some("project-search-filter-item".into()) + }); + + //TODO: District dropdown should only show districts in city, otherwise show nothing or disabled + let project_district_drop_down = comp_with::>>(DropDownProps { + initial: OptionWrapper::new(None), + options: vec![OptionWrapper::new(None), OptionWrapper::new(Some("Evaristo Morales".into())), OptionWrapper::new(Some("Cap Cana".into())) ], + selection_changed: { + let cloned_project_district_filter = project_district_filter.clone(); + Callback::from(move |project_district: OptionWrapper| { + info!("{}", project_district.to_string()); + cloned_project_district_filter.set(project_district) + } + )}, + class_css: Some("project-search-filter-item".into()) + }); + html!{ <>
-
-
// Search bar - - -
- +
+
// Filters +
+
+ {"Tipo de Proyecto"} +
+ {project_type_drop_down}
-
- -
-
- -
// Filters -
-
{"0"}
- -
{"+"}
-
-
-
{"0"}
- -
{"+"}
-
-
-
{"0"}
- -
{"+"}
-
-
-
{"0"}
- -
{"+"}
-
-
-
- //TODO: Add a spacing - +
+
+ {"Estatus de Proyecto"} +
+ {project_state_drop_down} +
+ +
+
+ {"CondiciĆ³n de Proyecto"} +
+ {project_condition_drop_down} +
+ +
+
+ {"Ciudad"} +
+ {project_city_drop_down} +
+ +
+
+ {"Sector"} +
+ {project_district_drop_down} +
+
+
+
// Search Results Content
@@ -66,34 +146,5 @@ pub fn search_page(_props: &SearchPageProperties) -> Html { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Properties)] pub struct SearchPageProperties { - pub property_state: PropertyState -} - - -#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] -pub enum PropertyState { - Finished, - #[default] - InConstruction, -} - -impl Display for PropertyState { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PropertyState::Finished => write!(f, "Finished"), - PropertyState::InConstruction => write!(f, "InConstruction"), - } - } -} - -impl FromStr for PropertyState { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "Finished" => Ok(Self::Finished), - "InConstruction" => Ok(Self::InConstruction), - _ => Err(()) - } - } + pub property_state: ProjectState } \ No newline at end of file diff --git a/src/routes/main_router.rs b/src/routes/main_router.rs index a011bba..556f93a 100644 --- a/src/routes/main_router.rs +++ b/src/routes/main_router.rs @@ -1,16 +1,17 @@ +use jl_types::domain::project_state::ProjectState; use yew_router::prelude::*; use yew::prelude::*; use uuid::Uuid; -use crate::{pages::{landing::LandingPage, search::{SearchPage, PropertyState}, details::DetailsPage, not_found::NotFoundPage, contact::ContactPage}}; +use crate::{pages::{landing::LandingPage, search::{SearchPage}, details::DetailsPage, not_found::NotFoundPage, contact::ContactPage}}; #[derive(Clone, Routable, PartialEq)] pub enum Route { #[at("/")] LandingPage, #[at("/search/:property_state")] - Search { property_state: PropertyState }, + Search { property_state: ProjectState }, #[at("/details/:property_id")] Details { property_id: Uuid }, #[at("/contact")] diff --git a/src/utils/get_value.rs b/src/utils/get_value.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..f329ff6 --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod get_value; \ No newline at end of file