Finished edit project. No uploads, just fetching and playing around in the editor
This commit is contained in:
parent
39abe4caca
commit
6b20ac66f1
@ -6,7 +6,7 @@
|
|||||||
gap: 50px;
|
gap: 50px;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 50vh;
|
min-height: 50vh;
|
||||||
}
|
}
|
||||||
.admin-start-welcome-message {
|
.admin-start-welcome-message {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
@ -14,6 +14,7 @@ body {
|
|||||||
.admin-page-container {
|
.admin-page-container {
|
||||||
padding-top: 40px;
|
padding-top: 40px;
|
||||||
padding-left: 200px;
|
padding-left: 200px;
|
||||||
|
padding-bottom: 20vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
8
css/components/datepicker.css
Normal file
8
css/components/datepicker.css
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.datepicker {
|
||||||
|
height: 50px;
|
||||||
|
background-color: white;
|
||||||
|
border: solid 0.5px #d8d8d8;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
text-indent: 10px;
|
||||||
|
}
|
20
css/edit.css
20
css/edit.css
@ -31,3 +31,23 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
text-indent: 10px;
|
text-indent: 10px;
|
||||||
}
|
}
|
||||||
|
.admin-edit-submit-button {
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
margin-top: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
background-color: #02114A;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
font-family: Source Sans Pro;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
.admin-edit-submit-button:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
@ -29,6 +29,7 @@
|
|||||||
<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" />
|
||||||
|
<link data-trunk type="text/css" href="css/components/datepicker.css" rel="css" />
|
||||||
|
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro" rel="stylesheet">
|
||||||
|
54
src/components/datepicker.rs
Normal file
54
src/components/datepicker.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
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.
|
||||||
|
#[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) => {
|
||||||
|
match optional_cb.clone() {
|
||||||
|
Some(callback) => callback.emit(Some(date.clone())),
|
||||||
|
None => {},
|
||||||
|
};
|
||||||
|
date_handle.set(Some(date));
|
||||||
|
},
|
||||||
|
Err(_) => {},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
let date_handle = props.value.clone();
|
||||||
|
html! {
|
||||||
|
<div class={"textfield-container"}>
|
||||||
|
<div class={if props.required {"textfield-label-required"} else {"textfield-label"}}>{props.label.clone()}</div>
|
||||||
|
<input class={"datepicker"} type="date" oninput={cb} value={match (*date_handle).clone() {
|
||||||
|
Some(date) => date.to_string(),
|
||||||
|
None => NaiveDate::default().to_string()
|
||||||
|
}}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Properties)]
|
||||||
|
pub struct DatePickerProps {
|
||||||
|
pub label: String,
|
||||||
|
pub value: UseStateHandle<Option<NaiveDate>>,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub required: bool,
|
||||||
|
pub onchange: Option<Callback<Option<NaiveDate>>>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_date(date_str: String) -> Result<NaiveDate, ()> {
|
||||||
|
match NaiveDate::from_str(&date_str) {
|
||||||
|
Ok(date) => Ok(date),
|
||||||
|
Err(error) => {
|
||||||
|
log::error!("Falied to parse Date in DatePicker: {error}");
|
||||||
|
Err(())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -9,3 +9,4 @@ pub mod admin_nav_bar;
|
|||||||
pub mod admin_project;
|
pub mod admin_project;
|
||||||
pub mod textfield;
|
pub mod textfield;
|
||||||
pub mod dropdown;
|
pub mod dropdown;
|
||||||
|
pub mod datepicker;
|
@ -5,7 +5,7 @@ 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, textfield::{TextField, TextFieldType}, dropdown::DropDown}, api::backend::{get_project_listing, get_all_agents}};
|
use crate::{components::{admin_nav_bar::AdminNavigationBar, textfield::{TextField, TextFieldType}, dropdown::DropDown, datepicker::DatePicker}, 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)]
|
||||||
@ -99,12 +99,12 @@ pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html {
|
|||||||
let project_state = use_state_eq(|| None);
|
let project_state = use_state_eq(|| None);
|
||||||
let project_condition = use_state_eq(|| None);
|
let project_condition = use_state_eq(|| None);
|
||||||
let project_type = use_state_eq(|| None);
|
let project_type = use_state_eq(|| None);
|
||||||
let project_description = use_state_eq(|| "".to_string());
|
let project_description = use_state_eq(|| String::new());
|
||||||
let project_admin_tag: UseStateHandle<String> = use_state_eq(|| listing_opt.clone().unwrap_or_default().project.admin_tag.unwrap_or(String::new()));
|
let project_admin_tag: UseStateHandle<String> = use_state_eq(|| String::new());
|
||||||
let project_finish_date = use_state_eq(|| listing_opt.clone().unwrap_or_default().project.finish_date);
|
let project_finish_date = use_state_eq(|| None);
|
||||||
let project_floors = use_state_eq(|| listing_opt.clone().unwrap_or_default().project.floors.to_string());
|
let project_floors = use_state_eq(|| String::new());
|
||||||
let media: UseStateHandle<MediaList> = use_state_eq(|| listing_opt.clone().unwrap_or_default().project.media);
|
let media: UseStateHandle<MediaList> = use_state_eq(|| MediaList { media_list: Vec::new() });
|
||||||
let units: UseStateHandle<Vec<Unit>> = use_state_eq(|| listing_opt.clone().unwrap_or_default().units);
|
let units: UseStateHandle<Vec<Unit>> = use_state_eq(|| Vec::new());
|
||||||
|
|
||||||
let ontype_cb = {
|
let ontype_cb = {
|
||||||
let user_typed = user_typed.clone();
|
let user_typed = user_typed.clone();
|
||||||
@ -137,7 +137,6 @@ pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let all_agents = use_state(|| Vec::new());
|
let all_agents = use_state(|| Vec::new());
|
||||||
|
|
||||||
use_state(|| {
|
use_state(|| {
|
||||||
@ -184,6 +183,10 @@ pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html {
|
|||||||
},
|
},
|
||||||
None => String::new(),
|
None => String::new(),
|
||||||
});
|
});
|
||||||
|
project_finish_date.set(match listing_opt.clone() {
|
||||||
|
Some(listing) => Some(listing.project.finish_date.date()),
|
||||||
|
None => None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
@ -228,9 +231,13 @@ pub fn generate_fields_for_project(props: &ProjectFieldsProps) -> Html {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
<TextField label={"Pisos"} value={project_floors} required={true} />
|
<TextField label={"Pisos"} value={project_floors} required={true} />
|
||||||
|
<DatePicker label={"Fecha de entrega Est."} value={project_finish_date} required={true} />
|
||||||
<TextField label={"Descripción"} value={project_description} fieldtype={TextFieldType::TextArea} />
|
<TextField label={"Descripción"} value={project_description} fieldtype={TextFieldType::TextArea} />
|
||||||
<TextField label={"Comentario interno"} value={project_admin_tag} />
|
<TextField label={"Comentario interno"} value={project_admin_tag} />
|
||||||
|
|
||||||
|
<div class={"admin-edit-submit-button"}>
|
||||||
|
{"Actualizar"}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,6 @@ 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<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(|| {
|
||||||
let cities_handle = cities_handle.clone();
|
let cities_handle = cities_handle.clone();
|
||||||
|
Loading…
Reference in New Issue
Block a user