use seed::{prelude::*, *}; use jirs_data::{ProjectCategory, TimeTracking, ToVec, UpdateProjectPayload, WsMsg}; use crate::api::send_ws_msg; use crate::model::{Model, Page, PageContent, ProjectSettingsPage}; use crate::shared::styled_button::StyledButton; use crate::shared::styled_checkbox::StyledCheckbox; use crate::shared::styled_editor::StyledEditor; use crate::shared::styled_field::StyledField; use crate::shared::styled_form::StyledForm; use crate::shared::styled_select::{StyledSelect, StyledSelectChange}; use crate::shared::styled_textarea::StyledTextarea; use crate::shared::{inner_layout, ToChild, ToNode}; use crate::FieldChange::TabChanged; use crate::{model, FieldId, Msg, PageChanged, ProjectFieldId, ProjectPageChange}; static TIME_TRACKING_FIBONACCI: &'static str = "Tracking employees’ time carries the risk of having them feel like they are being spied on. This is one of the most common fears that employees have when a time tracking system is implemented. No one likes to feel like they’re always being watched."; static TIME_TRACKING_HOURLY: &'static str = "Employees may feel intimidated by demands to track their time. Or they could feel that they’re constantly being watched and evaluated. And for overly ambitious managers, employee time tracking may open the doors to excessive micromanaging."; pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders) { if model.user.is_none() { return; } if model.page != Page::ProjectSettings { return; } match msg { Msg::WsMsg(WsMsg::AuthorizeLoaded(..)) => { send_ws_msg(WsMsg::ProjectRequest); } Msg::ChangePage(Page::ProjectSettings) => { send_ws_msg(WsMsg::ProjectRequest); build_page_content(model); } Msg::WsMsg(WsMsg::ProjectLoaded(..)) => { build_page_content(model); } _ => (), } let page = match &mut model.page_content { PageContent::ProjectSettings(page) => page, _ => return, }; page.project_category_state.update(&msg, orders); page.time_tracking.update(&msg); match msg { Msg::StrInputChanged(FieldId::ProjectSettings(ProjectFieldId::Name), text) => { page.payload.name = Some(text); } Msg::StrInputChanged(FieldId::ProjectSettings(ProjectFieldId::Url), text) => { page.payload.url = Some(text); } Msg::StrInputChanged(FieldId::ProjectSettings(ProjectFieldId::Description), text) => { page.payload.description = Some(text); } Msg::StyledSelectChanged( FieldId::ProjectSettings(ProjectFieldId::Category), StyledSelectChange::Changed(value), ) => { let category = value.into(); page.payload.category = Some(category); } Msg::ModalChanged(TabChanged( FieldId::ProjectSettings(ProjectFieldId::Description), mode, )) => { page.description_mode = mode; } Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::SubmitForm)) => { send_ws_msg(WsMsg::ProjectUpdateRequest(UpdateProjectPayload { id: page.payload.id, name: page.payload.name.clone(), url: page.payload.url.clone(), description: page.payload.description.clone(), category: page.payload.category.clone(), time_tracking: Some(page.time_tracking.value.into()), })); } _ => (), } } fn build_page_content(model: &mut Model) { let project = match &model.project { Some(project) => project, _ => return, }; model.page_content = PageContent::ProjectSettings(Box::new(ProjectSettingsPage::new(project))); } pub fn view(model: &model::Model) -> Node { let page = match &model.page_content { PageContent::ProjectSettings(page) => page, _ => return empty![], }; let name = StyledTextarea::build(FieldId::ProjectSettings(ProjectFieldId::Name)) .value(page.payload.name.as_ref().cloned().unwrap_or_default()) .height(39) .max_height(39) .disable_auto_resize() .build() .into_node(); let name_field = StyledField::build() .label("Name") .input(name) .tip("") .build() .into_node(); let url = StyledTextarea::build(FieldId::ProjectSettings(ProjectFieldId::Url)) .height(39) .max_height(39) .disable_auto_resize() .value(page.payload.url.as_ref().cloned().unwrap_or_default()) .build() .into_node(); let url_field = StyledField::build() .label("Url") .input(url) .tip("") .build() .into_node(); let description = StyledEditor::build(FieldId::ProjectSettings(ProjectFieldId::Description)) .text( page.payload .description .as_ref() .cloned() .unwrap_or_default(), ) .update_on(Ev::Change) .mode(page.description_mode.clone()) .build() .into_node(); let description_field = StyledField::build() .input(description) .label("Description") .tip("Describe the project in as much detail as you'd like.") .build() .into_node(); let category = StyledSelect::build(FieldId::ProjectSettings(ProjectFieldId::Category)) .opened(page.project_category_state.opened) .text_filter(page.project_category_state.text_filter.as_str()) .valid(true) .normal() .options( ProjectCategory::ordered() .into_iter() .map(|c| c.to_child()) .collect(), ) .selected(vec![page .payload .category .as_ref() .cloned() .unwrap_or_default() .to_child()]) .build() .into_node(); let category_field = StyledField::build() .label("Project Category") .input(category) .build() .into_node(); let time_tracking = StyledCheckbox::build(FieldId::ProjectSettings(ProjectFieldId::TimeTracking)) .options(vec![ TimeTracking::Untracked.to_child(), TimeTracking::Fibonacci.to_child(), TimeTracking::Hourly.to_child(), ]) .state(&page.time_tracking) .add_class("timeTracking") .build() .into_node(); let time_tracking_type: TimeTracking = page.time_tracking.value.into(); let time_tracking_field = StyledField::build() .input(time_tracking) .tip(match time_tracking_type { TimeTracking::Fibonacci => TIME_TRACKING_FIBONACCI, TimeTracking::Hourly => TIME_TRACKING_HOURLY, _ => "", }) .build() .into_node(); let save_button = StyledButton::build() .add_class("actionButton") .on_click(mouse_ev(Ev::Click, |ev| { ev.prevent_default(); Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::SubmitForm)) })) .text("Save changes") .build() .into_node(); let form = StyledForm::build() .heading("Project Details") .on_submit(ev(Ev::Submit, |ev| { ev.prevent_default(); Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::SubmitForm)) })) .add_field(name_field) .add_field(url_field) .add_field(description_field) .add_field(category_field) .add_field(time_tracking_field) .add_field(save_button) .build() .into_node(); let project_section = vec![div![class!["formContainer"], form]]; inner_layout(model, "projectSettings", project_section, empty![]) }