diff --git a/.bootstraprc b/.bootstraprc
index 4623f419..df9bc9bb 100644
--- a/.bootstraprc
+++ b/.bootstraprc
@@ -5,7 +5,8 @@
"styles": {
"mixins": true,
"grid": true,
- "forms": true
+ "forms": true,
+ "responsive-utilities":true
},
"scripts": false
diff --git a/app/assets/stylesheets/users/page.scss b/app/assets/stylesheets/users/page.scss
new file mode 100644
index 00000000..461a885b
--- /dev/null
+++ b/app/assets/stylesheets/users/page.scss
@@ -0,0 +1,3 @@
+.login-bottom-link {
+ margin-top: 12px;
+}
\ No newline at end of file
diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb
index 2b2df43c..d9a4ad10 100644
--- a/app/controllers/users/sessions_controller.rb
+++ b/app/controllers/users/sessions_controller.rb
@@ -1,9 +1,17 @@
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
class Users::SessionsController < Devise::SessionsController
+ layout 'layouts/apified', only: :new
+
+
+ def new
+ @theme = 'minimal'
+ super
+ end
def create
- respond_to do |format|
- format.html { super }
+ @theme = 'minimal'
+
+ respond_to do |format|
format.json {
warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
render :status => 200, :json => { :status => "Success" }
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb
index 77a055ae..b38248a4 100755
--- a/app/views/devise/sessions/new.html.erb
+++ b/app/views/devise/sessions/new.html.erb
@@ -1,14 +1,12 @@
<%- # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -%>
-<% content_for(:footer_hidden) {'hidden'} %>
+<% content_for :title, t("login.header") %>
+<% content_for :javascripts do %>
+ <%= IncludeAsset.js '/app/session_login_pagex.js' %>
+<% end %>
+<% content_for :stylesheets do %>
+ <%= stylesheet_link_tag 'users/page' %>
+<% end %>
-
-
-
Login
- <%= render 'users/email_login_form' %>
-
- <%= link_to "Forgot your password?", new_password_path(resource_name)%>
-
-
Don't have an account? Sign up.
-
-
+
+
diff --git a/app/views/onboard/index.html.erb b/app/views/onboard/index.html.erb
index 12b40c93..d874b5c7 100644
--- a/app/views/onboard/index.html.erb
+++ b/app/views/onboard/index.html.erb
@@ -1,6 +1,6 @@
<% content_for :title, t("registration.get_started.header") %>
<% content_for :javascripts do %>
- <%= IncludeAsset.js 'app/registration_pagex.js' %>
+ <%= IncludeAsset.js '/app/registration_pagex.js' %>
<% end %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 51c2adcc..554a819f 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -189,3 +189,11 @@ en:
footer:
terms_and_privacy: "Terms & Privacy"
about: "About"
+ login:
+ header: "Login"
+ email: "Email"
+ password: "Password"
+ login: "Login"
+ logging_in: "Logging you in..."
+ forgot_password: "Forgot Password?"
+ get_started: "Get Started"
diff --git a/config/routes.rb b/config/routes.rb
index 4082b912..a9520158 100755
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -195,7 +195,7 @@ Commitchange::Application.routes.draw do
:confirmations => 'users/confirmations'
}
devise_scope :user do
- match '/signin' => 'devise/sessions#new'
+ match '/sign_in' => 'users/sessions#new'
match '/signup' => 'devise/registrations#new'
post '/confirm' => 'users/confirmations#confirm'
match '/users/is_confirmed' => 'users/confirmations#is_confirmed'
diff --git a/javascripts/app/session_login_page.tsx b/javascripts/app/session_login_page.tsx
new file mode 100644
index 00000000..0a0b8f63
--- /dev/null
+++ b/javascripts/app/session_login_page.tsx
@@ -0,0 +1,14 @@
+// License: LGPL-3.0-or-later
+// require a root component here. This will be treated as the root of a webpack package
+import Root from "../src/components/common/Root"
+import SessionLoginPage from "../src/components/session_login_page/SessionLoginPage"
+
+import * as ReactDOM from 'react-dom'
+import * as React from 'react'
+
+function LoadReactPage(element:HTMLElement) {
+ ReactDOM.render(, element)
+}
+
+
+(window as any).LoadReactPage = LoadReactPage
\ No newline at end of file
diff --git a/javascripts/src/components/registration_page/RegistrationWizard.tsx b/javascripts/src/components/registration_page/RegistrationWizard.tsx
index 79cfc388..e7a7b8c6 100644
--- a/javascripts/src/components/registration_page/RegistrationWizard.tsx
+++ b/javascripts/src/components/registration_page/RegistrationWizard.tsx
@@ -198,7 +198,7 @@ export class InnerRegistrationWizard extends React.Component
+ buttonText="registration.wizard.save_and_finish" buttonTextOnProgress="registration.wizard.saving"/>
}
}
diff --git a/javascripts/src/components/registration_page/UserInfoForm.tsx b/javascripts/src/components/registration_page/UserInfoForm.tsx
index 05142d73..89140939 100644
--- a/javascripts/src/components/registration_page/UserInfoForm.tsx
+++ b/javascripts/src/components/registration_page/UserInfoForm.tsx
@@ -41,7 +41,7 @@ export interface UserInfoFormProps
{
form: Field
buttonText:string
- buttonTextInProgress?:string
+ buttonTextOnProgress?:string
}
@@ -63,7 +63,7 @@ class UserInfoForm extends React.Component
;
}
diff --git a/javascripts/src/components/registration_page/UserInfoPanel.tsx b/javascripts/src/components/registration_page/UserInfoPanel.tsx
index ea81fc5d..4c793fcb 100644
--- a/javascripts/src/components/registration_page/UserInfoPanel.tsx
+++ b/javascripts/src/components/registration_page/UserInfoPanel.tsx
@@ -10,7 +10,7 @@ import UserInfoForm from "./UserInfoForm";
export interface UserInfoPanelProps extends WizardTabPanelProps {
buttonText: string
- buttonTextInProgress?:string
+ buttonTextOnProgress?:string
}
class UserInfoPanel extends React.Component {
@@ -39,7 +39,7 @@ class UserInfoPanel extends React.Component
-
+
;
}
diff --git a/javascripts/src/components/session_login_page/SessionLoginForm.tsx b/javascripts/src/components/session_login_page/SessionLoginForm.tsx
new file mode 100644
index 00000000..54af5557
--- /dev/null
+++ b/javascripts/src/components/session_login_page/SessionLoginForm.tsx
@@ -0,0 +1,138 @@
+// License: LGPL-3.0-or-later
+import * as React from 'react';
+import { observer, inject} from 'mobx-react';
+import {InjectedIntlProps, injectIntl, FormattedMessage} from 'react-intl';
+import {Field, FieldDefinition, Form, initializationDefinition} from "../../../../types/mobx-react-form";
+import {Validations} from "../../lib/vjf_rules";
+import {WebLoginModel, WebUserSignInOut} from "../../lib/api/sign_in";
+
+import {HoudiniForm, StaticFormToErrorAndBackConverter} from "../../lib/houdini_form";
+import {observable, action} from 'mobx'
+import {ApiManager} from "../../lib/api_manager";
+import {BasicField} from "../common/fields";
+import ProgressableButton from "../common/ProgressableButton";
+
+export interface SessionLoginFormProps
+{
+
+ buttonText:string
+ buttonTextOnProgress:string
+ ApiManager?: ApiManager
+}
+
+export const FieldDefinitions : Array = [
+ {
+ name: 'email',
+ label: 'email',
+ type: 'text',
+ validators: [Validations.isFilled]
+ },
+ {
+ name: 'password',
+ label: 'password',
+ type: 'password',
+ validators: [Validations.isFilled]
+ }
+]
+
+export class SessionPageForm extends HoudiniForm {
+ converter: StaticFormToErrorAndBackConverter
+
+ constructor(definition: initializationDefinition, options?: any) {
+ super(definition, options)
+ this.converter = new StaticFormToErrorAndBackConverter(this.inputToForm)
+ }
+
+ signinApi: WebUserSignInOut
+
+ options() {
+ return {
+ validateOnInit: true,
+ validateOnChange: true,
+ retrieveOnlyDirtyValues: true,
+ retrieveOnlyEnabledFields: true
+ }
+ }
+
+ inputToForm = {
+ 'email': 'email',
+ 'password': 'password'
+ }
+
+ hooks() {
+ return {
+ onSuccess: async (f:SessionPageForm) => {
+ let input = this.converter.convertFormToObject(f)
+
+ try{
+ let r = await this.signinApi.postLogin(input)
+ window.location.reload()
+ }
+ catch(e){
+ if (e.error) {
+ f.invalidate(e.error)
+ }
+ else {
+ f.invalidate(e)
+ }
+ }
+ }
+ }
+ }
+}
+
+
+class InnerSessionLoginForm extends React.Component {
+ constructor(props: SessionLoginFormProps & InjectedIntlProps) {
+ super(props)
+ this.createForm();
+ }
+
+ @action.bound
+ createForm() {
+ this.form = new SessionPageForm({fields: FieldDefinitions})
+ }
+
+ @observable form: SessionPageForm
+
+ render() {
+
+ if(!this.form.signinApi){
+ this.form.signinApi = this.props.ApiManager.get(WebUserSignInOut)
+ }
+ let label: {[props:string]: string} = {
+ 'email': "login.email",
+ "password": 'login.password',
+ }
+
+ for (let key in label){
+ this.form.$(key).set('label', this.props.intl.formatMessage({id: label[key]}))
+ }
+
+ let errorDiv = !this.form.isValid ? {(this.form as any).error}
: ''
+
+ return ;
+ }
+}
+
+export default injectIntl(
+ inject('ApiManager')
+ (observer( InnerSessionLoginForm)
+ )
+)
+
+
+
diff --git a/javascripts/src/components/session_login_page/SessionLoginPage.tsx b/javascripts/src/components/session_login_page/SessionLoginPage.tsx
new file mode 100644
index 00000000..492d159d
--- /dev/null
+++ b/javascripts/src/components/session_login_page/SessionLoginPage.tsx
@@ -0,0 +1,25 @@
+// License: LGPL-3.0-or-later
+import * as React from 'react';
+import { observer } from 'mobx-react';
+import {InjectedIntlProps, injectIntl, InjectedIntl, FormattedMessage} from 'react-intl';
+import SessionLoginForm from "./SessionLoginForm";
+
+export interface SessionLoginPageProps
+{
+
+}
+
+class SessionLoginPage extends React.Component {
+ render() {
+ return ;
+ }
+}
+
+export default injectIntl(observer(SessionLoginPage))
+
+
+
diff --git a/javascripts/src/lib/api/sign_in.ts b/javascripts/src/lib/api/sign_in.ts
index b524170c..55dce752 100644
--- a/javascripts/src/lib/api/sign_in.ts
+++ b/javascripts/src/lib/api/sign_in.ts
@@ -72,7 +72,7 @@ export class WebUserSignInOut {
(xhr: JQueryXHR, textStatus: string, errorThrown: string) => {
- dfd.reject(errorThrown)
+ dfd.reject(xhr.responseJSON)
}
);
@@ -80,7 +80,7 @@ export class WebUserSignInOut {
}
}
-interface WebLoginModel {
+export interface WebLoginModel {
email:string
password:string
}
\ No newline at end of file
diff --git a/types/mobx-react-form/index.d.ts b/types/mobx-react-form/index.d.ts
index 8696dacb..afb92ddf 100644
--- a/types/mobx-react-form/index.d.ts
+++ b/types/mobx-react-form/index.d.ts
@@ -306,6 +306,9 @@ export class Form implements Base {
readonly submitting: boolean;
protected validator :any
+
+ readonly isValid :boolean;
+
}