Handle reset invitation form. Sort invitation, skip accepted invitations.

This commit is contained in:
Adrian Wozniak 2020-04-24 16:20:50 +02:00
parent 5ccf93faab
commit 9fda6def09
7 changed files with 82 additions and 14 deletions

View File

@ -16,6 +16,10 @@
margin-top: 20px; margin-top: 20px;
} }
#users > .invitationsSection > .invitationsList > .invitation.revoked {
color: var(--textLight);
}
#users > .invitationsSection > .invitationsList > .invitation > * { #users > .invitationsSection > .invitationsList > .invitation > * {
width: 25%; width: 25%;
} }

View File

@ -138,6 +138,16 @@ pub enum FieldChange {
EditComment(FieldId, i32), EditComment(FieldId, i32),
} }
#[derive(Clone, Debug, PartialEq)]
pub enum UsersPageChange {
ResetForm,
}
#[derive(Clone, Debug, PartialEq)]
pub enum PageChanged {
Users(UsersPageChange),
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Msg { pub enum Msg {
NoOp, NoOp,
@ -147,6 +157,7 @@ pub enum Msg {
ctrl: bool, ctrl: bool,
alt: bool, alt: bool,
}, },
PageChanged(PageChanged),
// Auth Token // Auth Token
AuthTokenStored, AuthTokenStored,

View File

@ -64,10 +64,10 @@ impl StyledButtonBuilder {
self.variant(Variant::Empty) self.variant(Variant::Empty)
} }
// pub fn disabled(mut self, value: bool) -> Self { pub fn disabled(mut self, value: bool) -> Self {
// self.disabled = Some(value); self.disabled = Some(value);
// self self
// } }
pub fn active(mut self, value: bool) -> Self { pub fn active(mut self, value: bool) -> Self {
self.active = Some(value); self.active = Some(value);

View File

@ -39,6 +39,15 @@ pub struct StyledSelectState {
pub field_id: FieldId, pub field_id: FieldId,
pub opened: bool, pub opened: bool,
pub text_filter: String, pub text_filter: String,
pub values: Vec<u32>,
}
impl StyledSelectState {
pub fn reset(&mut self) {
self.text_filter.clear();
self.opened = false;
self.values = vec![];
}
} }
impl StyledSelectState { impl StyledSelectState {
@ -47,6 +56,7 @@ impl StyledSelectState {
field_id, field_id,
opened: false, opened: false,
text_filter: String::new(), text_filter: String::new(),
values: vec![],
} }
} }
@ -65,6 +75,23 @@ impl StyledSelectState {
{ {
self.text_filter = text.clone(); self.text_filter = text.clone();
} }
Msg::StyledSelectChanged(field_id, StyledSelectChange::Changed(v))
if field_id == &self.field_id =>
{
self.values = vec![*v];
}
Msg::StyledSelectChanged(field_id, StyledSelectChange::RemoveMulti(v))
if field_id == &self.field_id =>
{
let mut old = vec![];
std::mem::swap(&mut old, &mut self.values);
for u in old {
if u != *v {
self.values.push(u);
}
}
}
_ => (), _ => (),
} }
} }

View File

@ -1,9 +1,9 @@
use seed::{prelude::*, *}; use seed::{prelude::*, *};
use jirs_data::{ToVec, UserRole, UsersFieldId, WsMsg}; use jirs_data::{InvitationState, ToVec, UserRole, UsersFieldId, WsMsg};
use crate::api::send_ws_msg; use crate::api::send_ws_msg;
use crate::model::{InvitationFormState, Model, Page, PageContent, UsersPage}; use crate::model::*;
use crate::shared::styled_button::StyledButton; use crate::shared::styled_button::StyledButton;
use crate::shared::styled_field::StyledField; use crate::shared::styled_field::StyledField;
use crate::shared::styled_form::StyledForm; use crate::shared::styled_form::StyledForm;
@ -12,7 +12,7 @@ use crate::shared::styled_select::*;
use crate::shared::styled_select_child::ToStyledSelectChild; use crate::shared::styled_select_child::ToStyledSelectChild;
use crate::shared::{inner_layout, ToNode}; use crate::shared::{inner_layout, ToNode};
use crate::validations::is_email; use crate::validations::is_email;
use crate::{FieldId, Msg}; use crate::{FieldId, Msg, PageChanged, UsersPageChange};
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) { pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
if let Msg::ChangePage(Page::Users) = msg { if let Msg::ChangePage(Page::Users) = msg {
@ -40,6 +40,15 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Msg::WsMsg(WsMsg::InvitationListLoaded(invitations)) => { Msg::WsMsg(WsMsg::InvitationListLoaded(invitations)) => {
page.invitations = invitations; page.invitations = invitations;
} }
Msg::PageChanged(PageChanged::Users(UsersPageChange::ResetForm)) => {
page.name.clear();
page.name_touched = false;
page.email.clear();
page.email_touched = false;
page.user_role = UserRole::User;
page.user_role_state.reset();
page.form_state = InvitationFormState::Initial;
}
Msg::StyledSelectChanged( Msg::StyledSelectChanged(
FieldId::Users(UsersFieldId::UserRole), FieldId::Users(UsersFieldId::UserRole),
StyledSelectChange::Changed(role), StyledSelectChange::Changed(role),
@ -64,11 +73,13 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Msg::WsMsg(WsMsg::InvitationRevokeSuccess(id)) => { Msg::WsMsg(WsMsg::InvitationRevokeSuccess(id)) => {
let mut old = vec![]; let mut old = vec![];
std::mem::swap(&mut page.invitations, &mut old); std::mem::swap(&mut page.invitations, &mut old);
for invitation in old { for mut invitation in old {
if invitation.id != id { if id == invitation.id {
page.invitations.push(invitation); invitation.state = InvitationState::Revoked;
} }
page.invitations.push(invitation);
} }
send_ws_msg(WsMsg::InvitationListRequest);
} }
Msg::InviteRevokeRequest(invitation_id) => { Msg::InviteRevokeRequest(invitation_id) => {
send_ws_msg(WsMsg::InvitationRevokeRequest(invitation_id)); send_ws_msg(WsMsg::InvitationRevokeRequest(invitation_id));
@ -161,6 +172,9 @@ pub fn view(model: &Model) -> Node<Msg> {
.active(true) .active(true)
.empty() .empty()
.set_type_reset() .set_type_reset()
.on_click(mouse_ev(Ev::Click, |_| {
Msg::PageChanged(PageChanged::Users(UsersPageChange::ResetForm))
}))
.text("Reset") .text("Reset")
.build() .build()
.into_node(), .into_node(),
@ -218,11 +232,13 @@ pub fn view(model: &Model) -> Node<Msg> {
let id = invitation.id; let id = invitation.id;
let revoke = StyledButton::build() let revoke = StyledButton::build()
.text("Revoke") .text("Revoke")
.disabled(invitation.state == InvitationState::Revoked)
.on_click(mouse_ev(Ev::Click, move |_| Msg::InviteRevokeRequest(id))) .on_click(mouse_ev(Ev::Click, move |_| Msg::InviteRevokeRequest(id)))
.build() .build()
.into_node(); .into_node();
li![ li![
class!["invitation"], class!["invitation"],
attrs![At::Class => format!("{}", invitation.state)],
span![invitation.name], span![invitation.name],
span![invitation.email], span![invitation.email],
span![format!("{}", invitation.state)], span![format!("{}", invitation.state)],

View File

@ -206,7 +206,7 @@ impl ToSql<UserRoleType, Pg> for UserRole {
#[postgres(type_name = "InvitationStateType")] #[postgres(type_name = "InvitationStateType")]
pub struct InvitationStateType; pub struct InvitationStateType;
impl diesel::query_builder::QueryId for InvitationState { impl diesel::query_builder::QueryId for InvitationStateType {
type QueryId = InvitationState; type QueryId = InvitationState;
} }

View File

@ -29,7 +29,11 @@ impl Handler<ListInvitation> for DbExecutor {
.get() .get()
.map_err(|_| ServiceErrors::DatabaseConnectionLost)?; .map_err(|_| ServiceErrors::DatabaseConnectionLost)?;
let query = invitations.filter(invited_by_id.eq(msg.user_id)); let query = invitations
.filter(invited_by_id.eq(msg.user_id))
.filter(state.ne(InvitationState::Accepted))
.order_by(state.asc())
.then_order_by(updated_at.desc());
debug!("{}", diesel::debug_query::<Pg, _>(&query).to_string()); debug!("{}", diesel::debug_query::<Pg, _>(&query).to_string());
query query
.load(conn) .load(conn)
@ -120,7 +124,10 @@ impl Handler<RevokeInvitation> for DbExecutor {
.get() .get()
.map_err(|_| ServiceErrors::DatabaseConnectionLost)?; .map_err(|_| ServiceErrors::DatabaseConnectionLost)?;
let query = diesel::update(invitations) let query = diesel::update(invitations)
.set(state.eq(InvitationState::Revoked)) .set((
state.eq(InvitationState::Revoked),
updated_at.eq(chrono::Utc::now().naive_utc()),
))
.filter(id.eq(msg.id)); .filter(id.eq(msg.id));
debug!("{}", diesel::debug_query::<Pg, _>(&query).to_string()); debug!("{}", diesel::debug_query::<Pg, _>(&query).to_string());
query query
@ -163,7 +170,10 @@ impl Handler<AcceptInvitation> for DbExecutor {
} }
let query = diesel::update(invitations) let query = diesel::update(invitations)
.set(state.eq(InvitationState::Accepted)) .set((
state.eq(InvitationState::Accepted),
updated_at.eq(chrono::Utc::now().naive_utc()),
))
.filter(id.eq(invitation.id)) .filter(id.eq(invitation.id))
.filter(state.eq(InvitationState::Sent)); .filter(state.eq(InvitationState::Sent));
debug!("{}", diesel::debug_query::<Pg, _>(&query).to_string()); debug!("{}", diesel::debug_query::<Pg, _>(&query).to_string());