Add and style register view
This commit is contained in:
parent
b22210d55a
commit
0e2cc62c30
@ -52,3 +52,8 @@
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
#login .twoRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
37
jirs-client/js/css/register.css
Normal file
37
jirs-client/js/css/register.css
Normal file
@ -0,0 +1,37 @@
|
||||
#register > .styledForm {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 auto 24px;
|
||||
width: 400px;
|
||||
background: rgb(255, 255, 255) none repeat scroll 0 0;
|
||||
border-radius: 3px;
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 0 10px;
|
||||
box-sizing: border-box;
|
||||
color: var(--textMedium);
|
||||
}
|
||||
|
||||
#register > .styledForm:first-of-type {
|
||||
margin-top: 124.5px;
|
||||
}
|
||||
|
||||
#register .twoRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#register > .styledForm > .formElement > .noPasswordSection {
|
||||
line-height: 32px;
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#register > .styledForm > .formElement > .noPasswordSection > .styledIcon {
|
||||
margin-right: 5px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
#register > .styledForm > .formElement > .noPasswordSection > span {
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
}
|
11
jirs-client/js/css/styledLink.css
Normal file
11
jirs-client/js/css/styledLink.css
Normal file
@ -0,0 +1,11 @@
|
||||
.styledLink {
|
||||
color: var(--textDark);
|
||||
font-family: var(--font-medium);
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
line-height: 2;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-size: 14.5px;
|
||||
}
|
@ -18,9 +18,11 @@
|
||||
@import "./css/styledEditor.css";
|
||||
@import "./css/styledComment.css";
|
||||
@import "./css/styledPage.css";
|
||||
@import "./css/styledLink.css";
|
||||
@import "./css/app.css";
|
||||
@import "./css/issue.css";
|
||||
@import "./css/project.css";
|
||||
@import "./css/projectSettings.css";
|
||||
@import "./css/timeTracking.css";
|
||||
@import "./css/login.css";
|
||||
@import "./css/register.css";
|
||||
|
@ -10,13 +10,14 @@ use crate::shared::styled_editor::Mode as TabMode;
|
||||
use crate::shared::styled_select::StyledSelectChange;
|
||||
|
||||
mod api;
|
||||
mod login;
|
||||
mod modal;
|
||||
mod model;
|
||||
mod project;
|
||||
mod project_settings;
|
||||
mod register;
|
||||
mod shared;
|
||||
mod sign_in;
|
||||
mod sign_up;
|
||||
mod validations;
|
||||
mod ws;
|
||||
|
||||
pub type AvatarFilterActive = bool;
|
||||
@ -30,7 +31,8 @@ pub enum EditIssueModalSection {
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, PartialEq, Hash)]
|
||||
pub enum FieldId {
|
||||
Login(LoginFieldId),
|
||||
SignIn(SignInFieldId),
|
||||
SignUp(SignUpFieldId),
|
||||
// issue
|
||||
AddIssueModal(IssueFieldId),
|
||||
EditIssueModal(EditIssueModalSection),
|
||||
@ -103,10 +105,14 @@ impl std::fmt::Display for FieldId {
|
||||
ProjectFieldId::Description => f.write_str("projectSettings-description"),
|
||||
ProjectFieldId::Category => f.write_str("projectSettings-category"),
|
||||
},
|
||||
FieldId::Login(sub) => match sub {
|
||||
LoginFieldId::Email => f.write_str("login-email"),
|
||||
LoginFieldId::Username => f.write_str("login-username"),
|
||||
LoginFieldId::Token => f.write_str("login-token"),
|
||||
FieldId::SignIn(sub) => match sub {
|
||||
SignInFieldId::Email => f.write_str("login-email"),
|
||||
SignInFieldId::Username => f.write_str("login-username"),
|
||||
SignInFieldId::Token => f.write_str("login-token"),
|
||||
},
|
||||
FieldId::SignUp(sub) => match sub {
|
||||
SignUpFieldId::Username => f.write_str("signUp-email"),
|
||||
SignUpFieldId::Email => f.write_str("signUp-username"),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -193,7 +199,7 @@ fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||
}
|
||||
Msg::AuthTokenErased => {
|
||||
seed::push_route(vec!["login"]);
|
||||
orders.skip().send_msg(Msg::ChangePage(Page::Login));
|
||||
orders.skip().send_msg(Msg::ChangePage(Page::SignIn));
|
||||
authorize_or_redirect();
|
||||
return;
|
||||
}
|
||||
@ -210,8 +216,8 @@ fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||
match model.page {
|
||||
Page::Project | Page::AddIssue | Page::EditIssue(..) => project::update(msg, model, orders),
|
||||
Page::ProjectSettings => project_settings::update(msg, model, orders),
|
||||
Page::Login => login::update(msg, model, orders),
|
||||
Page::Register => register::update(msg, model, orders),
|
||||
Page::SignIn => sign_in::update(msg, model, orders),
|
||||
Page::SignUp => sign_up::update(msg, model, orders),
|
||||
}
|
||||
if cfg!(debug_assertions) {
|
||||
// debug!(model);
|
||||
@ -223,8 +229,8 @@ fn view(model: &model::Model) -> Node<Msg> {
|
||||
Page::Project | Page::AddIssue => project::view(model),
|
||||
Page::EditIssue(_id) => project::view(model),
|
||||
Page::ProjectSettings => project_settings::view(model),
|
||||
Page::Login => login::view(model),
|
||||
Page::Register => register::view(model),
|
||||
Page::SignIn => sign_in::view(model),
|
||||
Page::SignUp => sign_up::view(model),
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,8 +247,8 @@ fn routes(url: Url) -> Option<Msg> {
|
||||
},
|
||||
"add-issue" => Some(Msg::ChangePage(Page::AddIssue)),
|
||||
"project-settings" => Some(Msg::ChangePage(model::Page::ProjectSettings)),
|
||||
"login" => Some(Msg::ChangePage(model::Page::Login)),
|
||||
"register" => Some(Msg::ChangePage(model::Page::Register)),
|
||||
"login" => Some(Msg::ChangePage(model::Page::SignIn)),
|
||||
"register" => Some(Msg::ChangePage(model::Page::SignUp)),
|
||||
_ => Some(Msg::ChangePage(model::Page::Project)),
|
||||
}
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ pub enum Page {
|
||||
EditIssue(IssueId),
|
||||
AddIssue,
|
||||
ProjectSettings,
|
||||
Login,
|
||||
Register,
|
||||
SignIn,
|
||||
SignUp,
|
||||
}
|
||||
|
||||
impl Page {
|
||||
@ -151,8 +151,8 @@ impl Page {
|
||||
Page::EditIssue(id) => format!("/issues/{id}", id = id),
|
||||
Page::AddIssue => "/add-issues".to_string(),
|
||||
Page::ProjectSettings => "/project-settings".to_string(),
|
||||
Page::Login => "/login".to_string(),
|
||||
Page::Register => "/register".to_string(),
|
||||
Page::SignIn => "/login".to_string(),
|
||||
Page::SignUp => "/register".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -219,7 +219,7 @@ impl ProjectSettingsPage {
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct LoginPage {
|
||||
pub struct SignInPage {
|
||||
pub username: String,
|
||||
pub email: String,
|
||||
pub token: String,
|
||||
@ -231,9 +231,20 @@ pub struct LoginPage {
|
||||
pub token_touched: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SignUpPage {
|
||||
pub username: String,
|
||||
pub email: String,
|
||||
pub sign_up_success: bool,
|
||||
// touched
|
||||
pub username_touched: bool,
|
||||
pub email_touched: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PageContent {
|
||||
Login(LoginPage),
|
||||
SignIn(SignInPage),
|
||||
SignUp(SignUpPage),
|
||||
Project(ProjectPage),
|
||||
ProjectSettings(ProjectSettingsPage),
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
use crate::{model, Msg};
|
||||
use seed::{prelude::*, *};
|
||||
|
||||
pub fn update(_msg: Msg, _model: &mut model::Model, _orders: &mut impl Orders<Msg>) {}
|
||||
|
||||
pub fn view(_model: &model::Model) -> Node<Msg> {
|
||||
div![]
|
||||
}
|
@ -16,6 +16,7 @@ pub mod styled_field;
|
||||
pub mod styled_form;
|
||||
pub mod styled_icon;
|
||||
pub mod styled_input;
|
||||
pub mod styled_link;
|
||||
pub mod styled_modal;
|
||||
pub mod styled_select;
|
||||
pub mod styled_select_child;
|
||||
|
85
jirs-client/src/shared/styled_link.rs
Normal file
85
jirs-client/src/shared/styled_link.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use seed::{prelude::*, *};
|
||||
|
||||
use crate::shared::ToNode;
|
||||
use crate::Msg;
|
||||
|
||||
pub struct StyledLink {
|
||||
children: Vec<Node<Msg>>,
|
||||
class_list: Vec<String>,
|
||||
href: String,
|
||||
}
|
||||
|
||||
impl StyledLink {
|
||||
pub fn build() -> StyledLinkBuilder {
|
||||
StyledLinkBuilder::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct StyledLinkBuilder {
|
||||
children: Vec<Node<Msg>>,
|
||||
class_list: Vec<String>,
|
||||
href: String,
|
||||
}
|
||||
|
||||
impl StyledLinkBuilder {
|
||||
pub fn add_child(mut self, child: Node<Msg>) -> Self {
|
||||
self.children.push(child);
|
||||
self
|
||||
}
|
||||
pub fn add_class<S>(mut self, name: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
self.class_list.push(name.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn href<S>(mut self, href: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
self.href = href.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn text<S>(mut self, s: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
let text: String = s.into();
|
||||
self.children.push(span![text]);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> StyledLink {
|
||||
StyledLink {
|
||||
children: self.children,
|
||||
class_list: self.class_list,
|
||||
href: self.href,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToNode for StyledLink {
|
||||
fn into_node(self) -> Node<Msg> {
|
||||
render(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(values: StyledLink) -> Node<Msg> {
|
||||
let StyledLink {
|
||||
children,
|
||||
mut class_list,
|
||||
href,
|
||||
} = values;
|
||||
class_list.push("styledLink".to_string());
|
||||
|
||||
a![
|
||||
attrs![
|
||||
At::Class => class_list.join(" "),
|
||||
At::Href => href,
|
||||
],
|
||||
children,
|
||||
]
|
||||
}
|
@ -6,40 +6,42 @@ use uuid::Uuid;
|
||||
use jirs_data::WsMsg;
|
||||
|
||||
use crate::api::send_ws_msg;
|
||||
use crate::model::{LoginPage, Page, PageContent};
|
||||
use crate::model::{Page, PageContent, SignInPage};
|
||||
use crate::shared::styled_button::StyledButton;
|
||||
use crate::shared::styled_field::StyledField;
|
||||
use crate::shared::styled_form::StyledForm;
|
||||
use crate::shared::styled_icon::{Icon, StyledIcon};
|
||||
use crate::shared::styled_input::StyledInput;
|
||||
use crate::shared::styled_link::StyledLink;
|
||||
use crate::shared::{outer_layout, write_auth_token, ToNode};
|
||||
use crate::{model, FieldId, LoginFieldId, Msg};
|
||||
use crate::validations::{is_email, is_token};
|
||||
use crate::{model, FieldId, Msg, SignInFieldId};
|
||||
|
||||
pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||
if model.page != Page::Login {
|
||||
if model.page != Page::SignIn {
|
||||
return;
|
||||
}
|
||||
|
||||
if msg == Msg::ChangePage(Page::Login) {
|
||||
model.page_content = PageContent::Login(LoginPage::default());
|
||||
if msg == Msg::ChangePage(Page::SignIn) {
|
||||
model.page_content = PageContent::SignIn(SignInPage::default());
|
||||
return;
|
||||
}
|
||||
|
||||
let page = match &mut model.page_content {
|
||||
PageContent::Login(page) => page,
|
||||
PageContent::SignIn(page) => page,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
match msg {
|
||||
Msg::InputChanged(FieldId::Login(LoginFieldId::Username), value) => {
|
||||
Msg::InputChanged(FieldId::SignIn(SignInFieldId::Username), value) => {
|
||||
page.username = value;
|
||||
page.username_touched = true;
|
||||
}
|
||||
Msg::InputChanged(FieldId::Login(LoginFieldId::Email), value) => {
|
||||
Msg::InputChanged(FieldId::SignIn(SignInFieldId::Email), value) => {
|
||||
page.email = value;
|
||||
page.email_touched = true;
|
||||
}
|
||||
Msg::InputChanged(FieldId::Login(LoginFieldId::Token), value) => {
|
||||
Msg::InputChanged(FieldId::SignIn(SignInFieldId::Token), value) => {
|
||||
page.token = value;
|
||||
page.token_touched = true;
|
||||
}
|
||||
@ -78,11 +80,11 @@ pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>)
|
||||
|
||||
pub fn view(model: &model::Model) -> Node<Msg> {
|
||||
let page = match &model.page_content {
|
||||
PageContent::Login(page) => page,
|
||||
PageContent::SignIn(page) => page,
|
||||
_ => return empty![],
|
||||
};
|
||||
|
||||
let username = StyledInput::build(FieldId::Login(LoginFieldId::Username))
|
||||
let username = StyledInput::build(FieldId::SignIn(SignInFieldId::Username))
|
||||
.value(page.username.as_str())
|
||||
.valid(!page.username_touched || page.username.len() > 1)
|
||||
.build()
|
||||
@ -93,7 +95,7 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let email = StyledInput::build(FieldId::Login(LoginFieldId::Email))
|
||||
let email = StyledInput::build(FieldId::SignIn(SignInFieldId::Email))
|
||||
.value(page.email.as_str())
|
||||
.valid(!page.email_touched || is_email(page.email.as_str()))
|
||||
.build()
|
||||
@ -116,7 +118,15 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
||||
}
|
||||
.build()
|
||||
.into_node();
|
||||
let submit_field = StyledField::build().input(submit).build().into_node();
|
||||
let register_link = StyledLink::build()
|
||||
.text("Register")
|
||||
.href("/register")
|
||||
.build()
|
||||
.into_node();
|
||||
let submit_field = StyledField::build()
|
||||
.input(div![class!["twoRow"], submit, register_link,])
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let help_icon = StyledIcon::build(Icon::Help)
|
||||
.add_class("noPasswordHelp")
|
||||
@ -145,7 +155,7 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let token = StyledInput::build(FieldId::Login(LoginFieldId::Token))
|
||||
let token = StyledInput::build(FieldId::SignIn(SignInFieldId::Token))
|
||||
.value(page.token.as_str())
|
||||
.valid(!page.token_touched || is_token(page.token.as_str()))
|
||||
.build()
|
||||
@ -177,28 +187,3 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
||||
let children = vec![sign_in_form, bind_token_form];
|
||||
outer_layout(model, "login", children)
|
||||
}
|
||||
|
||||
fn is_token(s: &str) -> bool {
|
||||
uuid::Uuid::from_str(s).is_ok()
|
||||
}
|
||||
|
||||
fn is_email(s: &str) -> bool {
|
||||
let mut has_at = false;
|
||||
let mut has_dot = false;
|
||||
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'\n' | ' ' | '\t' | '\r' => return false,
|
||||
'@' if !has_at => {
|
||||
has_at = true;
|
||||
}
|
||||
'@' if has_at => return false,
|
||||
'.' if has_at => {
|
||||
has_dot = true;
|
||||
}
|
||||
_ if has_dot => return true,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
127
jirs-client/src/sign_up.rs
Normal file
127
jirs-client/src/sign_up.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use seed::{prelude::*, *};
|
||||
|
||||
use jirs_data::{SignUpFieldId, WsMsg};
|
||||
|
||||
use crate::model::{Page, PageContent, SignUpPage};
|
||||
use crate::shared::styled_button::StyledButton;
|
||||
use crate::shared::styled_field::StyledField;
|
||||
use crate::shared::styled_form::StyledForm;
|
||||
use crate::shared::styled_icon::{Icon, StyledIcon};
|
||||
use crate::shared::styled_input::StyledInput;
|
||||
use crate::shared::styled_link::StyledLink;
|
||||
use crate::shared::{outer_layout, ToNode};
|
||||
use crate::validations::is_email;
|
||||
use crate::{model, FieldId, Msg};
|
||||
|
||||
pub fn update(msg: Msg, model: &mut model::Model, _orders: &mut impl Orders<Msg>) {
|
||||
if model.page != Page::SignUp {
|
||||
return;
|
||||
}
|
||||
|
||||
if msg == Msg::ChangePage(Page::SignUp) {
|
||||
model.page_content = PageContent::SignUp(SignUpPage::default());
|
||||
return;
|
||||
}
|
||||
|
||||
let page = match &mut model.page_content {
|
||||
PageContent::SignUp(page) => page,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
match msg {
|
||||
Msg::InputChanged(FieldId::SignUp(SignUpFieldId::Username), value) => {
|
||||
page.username = value;
|
||||
page.username_touched = true;
|
||||
}
|
||||
Msg::InputChanged(FieldId::SignUp(SignUpFieldId::Email), value) => {
|
||||
page.email = value;
|
||||
page.email_touched = true;
|
||||
}
|
||||
Msg::WsMsg(WsMsg::SignUpSuccess) => {
|
||||
page.sign_up_success = true;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view(model: &model::Model) -> Node<Msg> {
|
||||
let page = match &model.page_content {
|
||||
PageContent::SignUp(page) => page,
|
||||
_ => return empty![],
|
||||
};
|
||||
|
||||
let username = StyledInput::build(FieldId::SignUp(SignUpFieldId::Username))
|
||||
.value(page.username.as_str())
|
||||
.valid(!page.username_touched || page.username.len() > 1)
|
||||
.build()
|
||||
.into_node();
|
||||
let username_field = StyledField::build()
|
||||
.label("Username")
|
||||
.input(username)
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let email = StyledInput::build(FieldId::SignUp(SignUpFieldId::Email))
|
||||
.value(page.email.as_str())
|
||||
.valid(!page.email_touched || is_email(page.email.as_str()))
|
||||
.build()
|
||||
.into_node();
|
||||
let email_field = StyledField::build()
|
||||
.label("E-Mail")
|
||||
.input(email)
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let submit = if page.sign_up_success {
|
||||
StyledButton::build()
|
||||
.success()
|
||||
.text("✓ Please check your mail")
|
||||
} else {
|
||||
StyledButton::build()
|
||||
.primary()
|
||||
.text("Register")
|
||||
.on_click(mouse_ev(Ev::Click, |_| Msg::SignInRequest))
|
||||
}
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let sign_in_link = StyledLink::build()
|
||||
.text("Sign In")
|
||||
.href("/login")
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let submit_field = StyledField::build()
|
||||
.input(div![class!["twoRow"], submit, sign_in_link,])
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let help_icon = StyledIcon::build(Icon::Help)
|
||||
.add_class("noPasswordHelp")
|
||||
.size(22)
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let no_pass_section = div![
|
||||
class!["noPasswordSection"],
|
||||
attrs![At::Title => "We don't believe password is helping anyone. Instead after user provide correct login and e-mail he'll receive mail with 1-use token."],
|
||||
help_icon,
|
||||
span!["Why I don't see password?"]
|
||||
];
|
||||
|
||||
let sign_up_form = StyledForm::build()
|
||||
.heading("Sign In to your account")
|
||||
.on_submit(ev(Ev::Submit, |ev| {
|
||||
ev.stop_propagation();
|
||||
ev.prevent_default();
|
||||
Msg::SignInRequest
|
||||
}))
|
||||
.add_field(username_field)
|
||||
.add_field(email_field)
|
||||
.add_field(submit_field)
|
||||
.add_field(no_pass_section)
|
||||
.build()
|
||||
.into_node();
|
||||
let children = vec![sign_up_form];
|
||||
outer_layout(model, "register", children)
|
||||
}
|
26
jirs-client/src/validations.rs
Normal file
26
jirs-client/src/validations.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn is_email(s: &str) -> bool {
|
||||
let mut has_at = false;
|
||||
let mut has_dot = false;
|
||||
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'\n' | ' ' | '\t' | '\r' => return false,
|
||||
'@' if !has_at => {
|
||||
has_at = true;
|
||||
}
|
||||
'@' if has_at => return false,
|
||||
'.' if has_at => {
|
||||
has_dot = true;
|
||||
}
|
||||
_ if has_dot => return true,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn is_token(s: &str) -> bool {
|
||||
uuid::Uuid::from_str(s).is_ok()
|
||||
}
|
@ -484,12 +484,18 @@ pub enum ProjectFieldId {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialOrd, PartialEq, Hash)]
|
||||
pub enum LoginFieldId {
|
||||
pub enum SignInFieldId {
|
||||
Username,
|
||||
Email,
|
||||
Token,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialOrd, PartialEq, Hash)]
|
||||
pub enum SignUpFieldId {
|
||||
Username,
|
||||
Email,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialOrd, PartialEq, Hash)]
|
||||
pub enum CommentFieldId {
|
||||
Body,
|
||||
@ -524,6 +530,7 @@ pub enum WsMsg {
|
||||
BindTokenCheck(Uuid),
|
||||
BindTokenBad,
|
||||
BindTokenOk(Uuid),
|
||||
SignUpSuccess,
|
||||
|
||||
// project page
|
||||
ProjectRequest,
|
||||
|
Loading…
Reference in New Issue
Block a user