Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User can login and log out #9

Merged
merged 16 commits into from Feb 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -5,6 +5,8 @@ Tribal is a social fitness application.
# Features included:
* Visitors can view sessions
* Visitors can register on the site
* User can log in and log out
* Responsive design

# Contributors
(In Alphabetical order)
Expand Down
73 changes: 73 additions & 0 deletions app/controllers/devise/sessions_controller.rb
@@ -0,0 +1,73 @@
class Devise::SessionsController < DeviseController
prepend_before_action :require_no_authentication, only: [:new, :create]
prepend_before_action :allow_params_authentication!, only: :create
prepend_before_action :verify_signed_out_user, only: :destroy
prepend_before_action(only: [:create, :destroy]) { request.env["devise.skip_timeout"] = true }

def new
self.resource = resource_class.new(sign_in_params)
clean_up_passwords(resource)
yield resource if block_given?
respond_with(resource, serialize_options(resource))
end

def create
if warden.authenticate
self.resource = warden.authenticate!(auth_options)
set_flash_message!(:notice, :signed_in)
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
else
render json: {errors: "Invalid Email or password."}
end
end

def destroy
signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
set_flash_message! :notice, :signed_out if signed_out
yield if block_given?
end

protected

def sign_in_params
params.permit(:email,:password)
end

def serialize_options(resource)
methods = resource_class.authentication_keys.dup
methods = methods.keys if methods.is_a?(Hash)
methods << :password if resource.respond_to?(:password)
{ methods: methods, only: [:password] }
end

def auth_options
{ scope: resource_name }
end

def translation_scope
'devise.sessions'
end

private

def verify_signed_out_user
if all_signed_out?
set_flash_message! :notice, :already_signed_out
respond_to_on_destroy
end
end

def all_signed_out?
users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) }
users.all?(&:blank?)
end

def respond_to_on_destroy
respond_to do |format|
format.all { head :no_content }
format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) }
end
end
end
8 changes: 4 additions & 4 deletions client/bundles/Main/components/App.jsx
@@ -1,8 +1,8 @@
import React from "react";
import { Route, Switch, BrowserRouter, NavLink } from "react-router-dom";
import { Route, Switch, BrowserRouter } from "react-router-dom";
import Main from "./Main";
import Registration from "./Registration";

import Registration from "./authentication/Registration";
import Login from "./authentication/Login";

export class App extends React.Component {
constructor(props) {
Expand All @@ -11,7 +11,6 @@ export class App extends React.Component {
sessions: props
}
}

componentDidMount(){
this.setState({
sessions: this.props
Expand All @@ -24,6 +23,7 @@ export class App extends React.Component {
<Switch>
<Route exact path ='/' render={() => <Main sessions={this.state.sessions} />} />;
<Route exact path ='/register' render={() => <Registration />} />;
<Route exact path ='/login' render={() => <Login />} />;
</Switch>
</BrowserRouter>
</div>
Expand Down
72 changes: 29 additions & 43 deletions client/bundles/Main/components/Main.jsx
@@ -1,66 +1,52 @@
import React from "react";
import AllSessions from "./AllSessions";
import { NavLink, Link } from 'react-router-dom'
import MainSessionsDisplay from "./sessions/MainSessionsDisplay";
import MainNavLinks from "./MainNavLinks";

const axios = require("axios");

export default class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
availableSessions: props.sessions.availableSessions,
bookedSessions: props.sessions.bookedSessions,
fullSessions: props.sessions.fullSessions,
user: props.sessions.user
sessions: props.sessions,
user: ""
};
this.logout = this.logout.bind(this);
}

componentWillMount() {
this.setState({
availableSessions: this.props.sessions.availableSessions,
bookedSessions: this.props.sessions.bookedSessions,
fullSessions: this.props.sessions.fullSessions,
sessions: this.props.sessions,
user: this.props.sessions.user
})
}

logout() {
event.preventDefault();
const config = {
headers: {
"Content-Type": "application/json",
}
};
axios.delete(
"/users/sign_out", config
).then((response) => {
document.location.href = "/";
}).catch(function (error) {
console.log(error);
})
}
render() {
return (
<div className='main_container'>
<div className='header'>
<img src="./assets/logo.png" id="logo" alt="logo" />
<p id="title">Tribal</p>
</div>
<div className='wrapper-col content'>
</div>
<div className='content'>
<div id='available'>
<div className="wrapper-col">
<NavLink className="button m-4" to='/register'>
Sign up
</NavLink>
<h4 className="m-4">Hello, {this.state.user ? this.state.user.first_name : 'Stranger'}!</h4>
</div>
<h1>Available sessions</h1>
<div className='session_wrapper'>
<AllSessions sessionlist={this.state.availableSessions} />
</div>
<br />
</div>
<div id='booked'>
<h1>Booked sessions</h1>
<div className='session_wrapper'>
<AllSessions sessionlist={this.state.bookedSessions} />
</div>
<br />
<div className='content wrapper-col'>
<MainNavLinks user={this.state.user} logout={this.logout}/>
<h4 className="m-4">Hello, {this.state.user ? this.state.user.first_name : 'Stranger'}!</h4>
<div style = {this.state.user? {}:{display: "none"} }>
<MainSessionsDisplay sessions={this.state.sessions} />
</div>
<div id='full'>
<h1>Full sessions</h1>
<div className='session_wrapper'>
<AllSessions sessionlist={this.state.fullSessions} />
</div>
</div>
</div>

<div className='footer'>
<p>FOOTER</p>
</div>
</div>
);
Expand Down
38 changes: 38 additions & 0 deletions client/bundles/Main/components/MainNavLinks.jsx
@@ -0,0 +1,38 @@
import React from "react";
import { NavLink } from "react-router-dom";

function MainNavLinks(props) {
return (

<div>
<div>
<NavLink
style={props.user ? { display: "none" } : {}}
className="button m-4"
to="/register"
>
Sign up
</NavLink>
<NavLink
style={props.user ? { display: "none" } : {}}
className="button m-4"
to="/login"
>
Login
</NavLink>
<button
style={props.user ? {} : { display: "none" }}
className="button m-4"
onClick={props.logout}
>
Logout
</button>
</div>
</div>

)
}

export default MainNavLinks


8 changes: 0 additions & 8 deletions client/bundles/Main/components/WithRouter.jsx

This file was deleted.

67 changes: 67 additions & 0 deletions client/bundles/Main/components/authentication/Login.jsx
@@ -0,0 +1,67 @@
import React, { Component } from "react";
import ReactOnRails from "react-on-rails";
import LoginForm from "./LoginForm";

const axios = require("axios");

export class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
formErrors: ""
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}

onSubmit() {
event.preventDefault();
const csrfToken = ReactOnRails.authenticityToken();
let loginForm = document.getElementById("Login-form");
const data = new FormData(loginForm);

const config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"X-CSRF-Token": csrfToken
}
};
axios
.post("/users/sign_in", data, config)
.then(response => {
if (response.data.errors) {
let errors = response.data.errors;
this.setState({
formErrors: errors
});
} else {
document.location.href = "/";
}
})
.catch(function (error) {
console.log(error);
});
}

onChange() {
this.setState({
[event.target.id]: event.target.value
});
}
render() {
return (
<div className='main_container'>
<div className="mt-4 text-center whitespace-pre-wrap" >{this.state.formErrors}</div>
<LoginForm
onSubmit={this.onSubmit}
onChange={this.onChange}
email={this.state.email}
password={this.state.password} />
</div>
);
}
}

export default Login;
37 changes: 37 additions & 0 deletions client/bundles/Main/components/authentication/LoginForm.jsx
@@ -0,0 +1,37 @@
import React from 'react';

export default function LoginForm(props) {
return (
<div className="main_container">
<h1 className="m-4">Login</h1>
<form
id="Login-form"
name="Login-form"
onSubmit={props.onSubmit}
className="wrapper-col"
>
<label htmlFor="Email">Email</label>
<input
onChange={props.onChange}
value={props.email}
id="email"
name="user[email]"
type="email"
className="m-4"
/>
<label htmlFor="password">Password</label>
<input
onChange={props.onChange}
value={props.password}
id="password"
name="user[password]"
type="password"
className="m-4"
/>
<button className="button" name="Submit" type="submit">
Log in
</button>
</form>
</div>
);
}