Finished search logic
This commit is contained in:
parent
3b801c59fe
commit
12095f4141
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -212,6 +212,14 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "err"
|
||||
version = "0.1.1"
|
||||
source = "git+https://git.franklinblanco.dev/franklinblanco/err.git#d814091e7367d101197c35e2f7e56a744ce4296b"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.9.0"
|
||||
@ -698,6 +706,7 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
name = "jl-frontend"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"err",
|
||||
"jl-types",
|
||||
"js-sys",
|
||||
"log",
|
||||
@ -726,7 +735,6 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"uuid",
|
||||
"yew",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -27,6 +27,8 @@ uuid = { version = "1.3.0", features = ["v4", "fast-rng", "macro-diagnostics", "
|
||||
log = "0.4"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.88"
|
||||
err = { git = "https://git.franklinblanco.dev/franklinblanco/err.git" }
|
||||
|
||||
|
||||
# Core
|
||||
jl-types = { path = "../jl-types", features = ["yew", "wasm"] }
|
||||
jl-types = { path = "../jl-types", features = ["wasm"] }
|
||||
|
@ -7,17 +7,26 @@ Divide the Details page into 3 main sections:
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
align-items: center;
|
||||
padding: 0px 30px;
|
||||
background-color: black;
|
||||
margin-top: 30px;
|
||||
width: 100%;
|
||||
align-items: start;
|
||||
padding: 0px 15px;
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
.details-head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.details-head-image-frame {
|
||||
display: flex;
|
||||
height: 300px;
|
||||
width: 100%;
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
.details-head-title {
|
||||
font-size: 25px;
|
||||
}
|
@ -57,6 +57,18 @@
|
||||
background-color:rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.project-search-button {
|
||||
margin-top: 20px;
|
||||
height: 50px;
|
||||
background-color: #252631;
|
||||
color: white;
|
||||
border: 0px;
|
||||
border-radius: 5px;
|
||||
font-size: large;
|
||||
font-family: Source Sans Pro;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
/* Results */
|
||||
|
||||
.project-search-results-container {
|
||||
|
@ -0,0 +1,25 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use jl_types::{dto::{filters::Filter, listing::Listing}, domain::project::Project};
|
||||
use reqwest::Method;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::base::perform_request_without_client;
|
||||
|
||||
const BASE_URL: &str = "http://localhost:8095/";
|
||||
|
||||
pub async fn get_all_cities() -> Result<HashSet<String>, err::Error> {
|
||||
perform_request_without_client::<String, HashSet<String>>(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<HashSet<String>, err::Error> {
|
||||
perform_request_without_client::<String, HashSet<String>>(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<Filter>) -> Result<Vec<Project>, err::Error> {
|
||||
perform_request_without_client::<String, Vec<Project>>(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<Listing, err::Error> {
|
||||
perform_request_without_client::<String, Listing>(BASE_URL.into(), Method::GET, format!("read/project/{project_id}"), None, 200, Vec::new(), None).await
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
use err::{Error, MessageResource};
|
||||
use reqwest::Client;
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
|
||||
|
||||
/// 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.
|
||||
pub async fn perform_request_without_client<B: Serialize, R: DeserializeOwned>(
|
||||
base_url: String,
|
||||
method: reqwest::Method,
|
||||
path: String,
|
||||
body: Option<B>,
|
||||
expected_status_code: u16,
|
||||
headers: Vec<(String, String)>,
|
||||
params: Option<Vec<(String, String)>>
|
||||
) -> Result<R, Error> {
|
||||
let client = Client::new();
|
||||
let mut req_incomplete =
|
||||
client.request(method, format!("{url}{path}", url = base_url, path = path));
|
||||
|
||||
for header in headers {
|
||||
req_incomplete = req_incomplete.header(&header.0, &header.1);
|
||||
}
|
||||
|
||||
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),
|
||||
};
|
||||
println!("{:?}", req_complete);
|
||||
match req_complete.send().await {
|
||||
// Error handling here
|
||||
Ok(res) => {
|
||||
// Request sent correctly
|
||||
match res.status().as_u16() == expected_status_code {
|
||||
true => {
|
||||
match res.json::<R>().await {
|
||||
Ok(resp_dto) => Ok(resp_dto), // Return correctly deserialized obj
|
||||
Err(err) => Err(Error::Serde(MessageResource::from(err))),
|
||||
}
|
||||
}
|
||||
false => {
|
||||
//If status code is any other than expected
|
||||
Err(Error::UnexpectedStatusCode(
|
||||
expected_status_code,
|
||||
res.status().as_u16(),
|
||||
match res.json::<Vec<MessageResource>>().await {
|
||||
Ok(messages) => messages,
|
||||
Err(e) => vec![MessageResource::from(e)],
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
// Request couldn't be sent
|
||||
Err(Error::Network(MessageResource::from(e)))
|
||||
}
|
||||
}
|
||||
}
|
@ -37,12 +37,12 @@ pub fn navigation_bar() -> Html {
|
||||
{NAVBAR_COL_LANDING}
|
||||
</div>
|
||||
|
||||
<div onclick={move |_| cloned_navigator_2.push(&Route::Search { property_state: ProjectState::Finished })} class={"navbar-item"}>
|
||||
{NAVBAR_COL_PROYECTOS_ACABADOS}
|
||||
<div onclick={move |_| cloned_navigator_2.push(&Route::Search { project_state: ProjectState::InConstruction })} class={"navbar-item"}>
|
||||
{NAVBAR_COL_PROYECTOS_EN_CONSTRUCCION}
|
||||
</div>
|
||||
|
||||
<div onclick={move |_| cloned_navigator_3.push(&Route::Search { property_state: ProjectState::InConstruction })} class={"navbar-item"}>
|
||||
{NAVBAR_COL_PROYECTOS_EN_CONSTRUCCION}
|
||||
<div onclick={move |_| cloned_navigator_3.push(&Route::Search { project_state: ProjectState::Finished })} class={"navbar-item"}>
|
||||
{NAVBAR_COL_PROYECTOS_ACABADOS}
|
||||
</div>
|
||||
|
||||
<div onclick={move |_| cloned_navigator_4.push(&Route::Contact)} class={"navbar-item"}>
|
||||
|
@ -1,4 +1,4 @@
|
||||
use uuid::Uuid;
|
||||
use jl_types::domain::{project::Project, media::Media};
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::use_navigator;
|
||||
|
||||
@ -6,15 +6,24 @@ use crate::routes::main_router::Route;
|
||||
|
||||
|
||||
#[function_component(ProjectCard)]
|
||||
pub fn project_card() -> Html {
|
||||
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 |_|{
|
||||
navigator.push(&Route::Details { property_id: Uuid::default() });
|
||||
navigator.push(&Route::Details { project_id });
|
||||
});
|
||||
let cover_image_url;
|
||||
if let Some(first_media) = props.project.media.media_list.get(0) {
|
||||
cover_image_url = match first_media {
|
||||
Media::Photo(url) => url.clone(),
|
||||
Media::Video(_) => String::new(),
|
||||
}
|
||||
} else {
|
||||
cover_image_url = String::new()
|
||||
}
|
||||
html!{
|
||||
<div class={"project-search-result-card"} onclick={project_view_cb}>
|
||||
<img src={"https://refa.com.do/uploads/posiv.jpg"} alt={"project image"} class={"project-search-result-card-picture"}/>
|
||||
<img src={cover_image_url} alt={"project image"} class={"project-search-result-card-picture"}/>
|
||||
|
||||
<div class={"project-search-result-card-title"}>
|
||||
{"Suites by refa Piantini"}
|
||||
@ -42,3 +51,8 @@ pub fn project_card() -> Html {
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ProjectCardProps {
|
||||
pub project: Project
|
||||
}
|
@ -1,21 +1,31 @@
|
||||
use uuid::Uuid;
|
||||
use yew::prelude::*;
|
||||
|
||||
use crate::components::nav_bar::NavigationBar;
|
||||
|
||||
#[function_component(DetailsPage)]
|
||||
pub fn details_page() -> Html {
|
||||
pub fn details_page(_props: &DetailsPageProps) -> Html {
|
||||
html!{
|
||||
<>
|
||||
<NavigationBar/>
|
||||
<div class={"page-container"}>
|
||||
<div class={"details-container"}>
|
||||
<div class={"details-head"}>
|
||||
<div class={""}>
|
||||
<div class={"details-head-image-frame"}>
|
||||
|
||||
</div>
|
||||
<div class={"details-head-title"}>{"Suites by refa piantini"}</div>
|
||||
<div class={"details-head-price"}>{"RD$123,130.00"}</div>
|
||||
<div>{"Andres Julio Aybar #39"}</div>
|
||||
<div>{"Descripción"}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct DetailsPageProps {
|
||||
pub project_id: Uuid
|
||||
}
|
@ -1,29 +1,63 @@
|
||||
use jl_types::domain::{project_state::ProjectState, project_type::ProjectType, project_condition::ProjectCondition};
|
||||
use jl_types::{domain::{project_state::ProjectState, project_type::ProjectType, project_condition::ProjectCondition, project::Project}, dto::filters::Filter};
|
||||
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, project_card::ProjectCard};
|
||||
use crate::{components::{nav_bar::NavigationBar, project_card::ProjectCard}, api::backend::{get_all_cities, get_all_districts_in_city, get_all_projects_with_filters_paged}};
|
||||
|
||||
|
||||
#[function_component(SearchPage)]
|
||||
pub fn search_page(_props: &SearchPageProperties) -> Html {
|
||||
pub fn search_page(props: &SearchPageProperties) -> Html {
|
||||
// let force_update_trigger = use_force_update();
|
||||
let cities_handle = use_state(|| Vec::from([OptionWrapper::new(None)]));
|
||||
let districts_handle = use_state(|| Vec::from([OptionWrapper::new(None)]));
|
||||
let search_results_handle: UseStateHandle<Vec<Project>> = use_state(|| Vec::new());
|
||||
let page_counter: UseStateHandle<i64> = use_state(|| 1);
|
||||
|
||||
let mut filters = Vec::new();
|
||||
if props.project_state.eq(&ProjectState::Finished) {
|
||||
filters.push(Filter::Finished);
|
||||
}
|
||||
|
||||
// All code to execute on first render and never again
|
||||
use_state(|| {
|
||||
let cities_handle = cities_handle.clone();
|
||||
let search_results_handle = search_results_handle.clone();
|
||||
let page_counter = page_counter.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
match get_all_cities().await {
|
||||
Ok(cities) => {
|
||||
let mut cities: Vec<OptionWrapper<String>> = cities.into_iter().map(|location| OptionWrapper::new(Some(location))).collect();
|
||||
cities.insert(0, OptionWrapper::new(None));
|
||||
cities_handle.set(cities);
|
||||
},
|
||||
Err(error) => info!("Error in loading cities: {error}")
|
||||
};
|
||||
match get_all_projects_with_filters_paged(&(*page_counter), filters).await {
|
||||
Ok(projects) => {
|
||||
search_results_handle.set(projects)
|
||||
},
|
||||
Err(error) => info!("Error in loading projects: {error}"),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// Dropdown
|
||||
let project_type_filter: UseStateHandle<OptionWrapper<ProjectType>> = use_state(|| OptionWrapper::new(None));
|
||||
// Dropdown
|
||||
let project_condition_filter: UseStateHandle<OptionWrapper<ProjectCondition>> = use_state(|| OptionWrapper::new(None));
|
||||
// Dropdown
|
||||
let project_state_filter: UseStateHandle<OptionWrapper<ProjectState>> = use_state(|| OptionWrapper::new(None));
|
||||
// let project_state_filter: UseStateHandle<OptionWrapper<ProjectState>> = use_state(|| OptionWrapper::new(Some(props.project_state.clone())));
|
||||
// Dropdown
|
||||
let project_city_filter: UseStateHandle<OptionWrapper<String>> = use_state(|| OptionWrapper::new(None));
|
||||
// Dropdown
|
||||
let project_district_filter: UseStateHandle<OptionWrapper<String>> = use_state(|| OptionWrapper::new(None));
|
||||
//TODO: Think about price filtering
|
||||
// TextField
|
||||
/*// TextField
|
||||
let _project_min_price_filter: UseStateHandle<OptionWrapper<f64>> = use_state(|| OptionWrapper::new(None));
|
||||
// TextField
|
||||
let _project_max_price_filter: UseStateHandle<OptionWrapper<f64>> = use_state(|| OptionWrapper::new(None));
|
||||
let _project_max_price_filter: UseStateHandle<OptionWrapper<f64>> = use_state(|| OptionWrapper::new(None));*/
|
||||
|
||||
|
||||
let project_type_drop_down = comp_with::<DropDown<OptionWrapper<ProjectType>>>(DropDownProps {
|
||||
@ -39,9 +73,11 @@ pub fn search_page(_props: &SearchPageProperties) -> Html {
|
||||
class_css: Some("project-search-filter-item".into())
|
||||
});
|
||||
|
||||
/*
|
||||
// TODO: Fix ProjectState tostring printing the db insertable
|
||||
let project_state_drop_down = comp_with::<DropDown<OptionWrapper<ProjectState>>>(DropDownProps {
|
||||
initial: OptionWrapper::new(None),
|
||||
options: vec![OptionWrapper::new(None), OptionWrapper::new(Some(ProjectState::InConstruction)), OptionWrapper::new(Some(ProjectState::Finished)) ],
|
||||
initial: (*project_state_filter).clone(),
|
||||
options: vec![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<ProjectState>| {
|
||||
@ -50,7 +86,7 @@ pub fn search_page(_props: &SearchPageProperties) -> Html {
|
||||
}
|
||||
)},
|
||||
class_css: Some("project-search-filter-item".into())
|
||||
});
|
||||
});*/
|
||||
|
||||
let project_condition_drop_down = comp_with::<DropDown<OptionWrapper<ProjectCondition>>>(DropDownProps {
|
||||
initial: OptionWrapper::new(None),
|
||||
@ -67,12 +103,25 @@ pub fn search_page(_props: &SearchPageProperties) -> Html {
|
||||
|
||||
let project_city_drop_down = comp_with::<DropDown<OptionWrapper<String>>>(DropDownProps {
|
||||
initial: OptionWrapper::new(None),
|
||||
options: vec![OptionWrapper::new(None), OptionWrapper::new(Some("Santo Domingo".into())), OptionWrapper::new(Some("Punta Cana".into())) ],
|
||||
options: (*cities_handle).clone(),
|
||||
selection_changed: {
|
||||
let cloned_project_city_filter = project_city_filter.clone();
|
||||
let districts_handle = districts_handle.clone();
|
||||
|
||||
Callback::from(move |project_city: OptionWrapper<String>| {
|
||||
let districts_handle = districts_handle.clone();
|
||||
info!("{}", project_city.to_string());
|
||||
cloned_project_city_filter.set(project_city)
|
||||
cloned_project_city_filter.set(project_city.clone());
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
match get_all_districts_in_city(&project_city.to_string()).await {
|
||||
Ok(districts) => {
|
||||
let mut districts_vec: Vec<OptionWrapper<String>> = districts.into_iter().map(|district| OptionWrapper::new(Some(district))).collect();
|
||||
districts_vec.insert(0, OptionWrapper::new(None));
|
||||
districts_handle.set(districts_vec);
|
||||
},
|
||||
Err(error) => info!("Error in dropdown callback: {}", error),
|
||||
};
|
||||
});
|
||||
}
|
||||
)},
|
||||
class_css: Some("project-search-filter-item".into())
|
||||
@ -81,7 +130,7 @@ pub fn search_page(_props: &SearchPageProperties) -> Html {
|
||||
//TODO: District dropdown should only show districts in city, otherwise show nothing or disabled
|
||||
let project_district_drop_down = comp_with::<DropDown<OptionWrapper<String>>>(DropDownProps {
|
||||
initial: OptionWrapper::new(None),
|
||||
options: vec![OptionWrapper::new(None), OptionWrapper::new(Some("Evaristo Morales".into())), OptionWrapper::new(Some("Cap Cana".into())) ],
|
||||
options: (*districts_handle).clone(),
|
||||
selection_changed: {
|
||||
let cloned_project_district_filter = project_district_filter.clone();
|
||||
Callback::from(move |project_district: OptionWrapper<String>| {
|
||||
@ -92,6 +141,50 @@ pub fn search_page(_props: &SearchPageProperties) -> Html {
|
||||
class_css: Some("project-search-filter-item".into())
|
||||
});
|
||||
|
||||
let search_onclick = {
|
||||
let search_results_handle = search_results_handle.clone();
|
||||
let page_counter = page_counter.clone();
|
||||
let project_type_filter = project_type_filter.clone();
|
||||
let project_condition_filter = project_condition_filter.clone();
|
||||
let project_city_filter = project_city_filter.clone();
|
||||
let project_district_filter = project_district_filter.clone();
|
||||
|
||||
let props = props.clone();
|
||||
|
||||
Callback::from(move |_| {
|
||||
let mut filters = Vec::new();
|
||||
if props.project_state.eq(&ProjectState::Finished) {
|
||||
filters.push(Filter::Finished);
|
||||
}
|
||||
match &(*project_type_filter).option {
|
||||
Some(project_type) => filters.push(Filter::ByProjectType(project_type.clone())),
|
||||
None => {},
|
||||
};
|
||||
match &(*project_condition_filter).option {
|
||||
Some(project_condition) => filters.push(Filter::ByProjectCondition(project_condition.clone())),
|
||||
None => {},
|
||||
};
|
||||
match &(*project_city_filter).option {
|
||||
Some(project_city) => filters.push(Filter::InCity(project_city.clone())),
|
||||
None => {},
|
||||
};
|
||||
match &(*project_district_filter).option {
|
||||
Some(project_district) => filters.push(Filter::InDistrict(project_district.clone())),
|
||||
None => {},
|
||||
};
|
||||
|
||||
let search_results_handle = search_results_handle.clone();
|
||||
let page_counter = page_counter.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
match get_all_projects_with_filters_paged(&(*page_counter), filters).await {
|
||||
Ok(projects) => {
|
||||
search_results_handle.set(projects)
|
||||
},
|
||||
Err(error) => info!("Error in loading projects: {error}"),
|
||||
};
|
||||
info!("done");
|
||||
});
|
||||
})};
|
||||
html!{
|
||||
<>
|
||||
<NavigationBar/>
|
||||
@ -105,12 +198,12 @@ pub fn search_page(_props: &SearchPageProperties) -> Html {
|
||||
{project_type_drop_down}
|
||||
</div>
|
||||
|
||||
<div class={"project-search-filter-container"}>
|
||||
/*<div class={"project-search-filter-container"}>
|
||||
<div class={"project-search-filter-label"}>
|
||||
{"Estatus de Proyecto"}
|
||||
</div>
|
||||
{project_state_drop_down}
|
||||
</div>
|
||||
</div>*/
|
||||
|
||||
<div class={"project-search-filter-container"}>
|
||||
<div class={"project-search-filter-label"}>
|
||||
@ -132,15 +225,16 @@ pub fn search_page(_props: &SearchPageProperties) -> Html {
|
||||
</div>
|
||||
{project_district_drop_down}
|
||||
</div>
|
||||
|
||||
<button class={"project-search-button"} onclick={search_onclick}>
|
||||
{"Buscar"}
|
||||
</button>
|
||||
</div>
|
||||
<div class={"project-search-divider"}/>
|
||||
</div>
|
||||
|
||||
<div class={"project-search-results-container"}> // Search Results Content
|
||||
<ProjectCard/>
|
||||
<ProjectCard/>
|
||||
<ProjectCard/>
|
||||
<ProjectCard/>
|
||||
{(*search_results_handle).clone().into_iter().map(|project| html!{<ProjectCard {project}/>}).collect::<Html>()}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
@ -149,5 +243,5 @@ pub fn search_page(_props: &SearchPageProperties) -> Html {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Properties)]
|
||||
pub struct SearchPageProperties {
|
||||
pub property_state: ProjectState
|
||||
pub project_state: ProjectState,
|
||||
}
|
@ -10,10 +10,10 @@ use crate::{pages::{landing::LandingPage, search::{SearchPage}, details::Details
|
||||
pub enum Route {
|
||||
#[at("/")]
|
||||
LandingPage,
|
||||
#[at("/search/:property_state")]
|
||||
Search { property_state: ProjectState },
|
||||
#[at("/details/:property_id")]
|
||||
Details { property_id: Uuid },
|
||||
#[at("/search/:project_state")]
|
||||
Search { project_state: ProjectState },
|
||||
#[at("/details/:project_id")]
|
||||
Details { project_id: Uuid },
|
||||
#[at("/contact")]
|
||||
Contact,
|
||||
|
||||
@ -25,8 +25,8 @@ pub enum Route {
|
||||
pub fn switch(routes: Route) -> Html {
|
||||
match routes {
|
||||
Route::LandingPage => html! { <LandingPage/> },
|
||||
Route::Search { property_state } => html! { <SearchPage property_state={property_state}/> },
|
||||
Route::Details { property_id: _ } => html! { <DetailsPage/> },
|
||||
Route::Search { project_state } => html! { <SearchPage project_state={project_state}/> },
|
||||
Route::Details { project_id } => html! { <DetailsPage project_id={project_id}/> },
|
||||
Route::NotFound => html! { <NotFoundPage/> },
|
||||
Route::Contact => html! { <ContactPage/> }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user