LogOut working

This commit is contained in:
Alex Gleason 2020-04-11 14:41:13 -05:00
parent 1b8544b758
commit 6c6d6297f9
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
8 changed files with 44 additions and 12 deletions

View file

@ -1,8 +1,10 @@
import api from '../api'; import api from '../api';
import { showAlert } from 'gabsocial/actions/alerts';
export const AUTH_APP_CREATED = 'AUTH_APP_CREATED'; export const AUTH_APP_CREATED = 'AUTH_APP_CREATED';
export const AUTH_APP_AUTHORIZED = 'AUTH_APP_AUTHORIZED'; export const AUTH_APP_AUTHORIZED = 'AUTH_APP_AUTHORIZED';
export const AUTH_LOGGED_IN = 'AUTH_LOGGED_IN'; export const AUTH_LOGGED_IN = 'AUTH_LOGGED_IN';
export const AUTH_LOGGED_OUT = 'AUTH_LOGGED_OUT';
export function createAuthApp() { export function createAuthApp() {
return (dispatch, getState) => { return (dispatch, getState) => {
@ -39,10 +41,20 @@ export function logIn(username, password) {
password: password password: password
}).then(response => { }).then(response => {
dispatch(authLoggedIn(response.data)); dispatch(authLoggedIn(response.data));
}).catch((error) => {
dispatch(showAlert('Login failed.', 'Invalid username or password.'));
throw error;
}); });
} }
} }
export function logOut() {
return (dispatch, getState) => {
dispatch({ type: AUTH_LOGGED_OUT });
dispatch(showAlert('Successfully logged out.', ''));
};
}
export function authAppCreated(app) { export function authAppCreated(app) {
return { return {
type: AUTH_APP_CREATED, type: AUTH_APP_CREATED,

View file

@ -13,6 +13,7 @@ import DisplayName from './display_name';
import { closeSidebar } from '../actions/sidebar'; import { closeSidebar } from '../actions/sidebar';
import { shortNumberFormat } from '../utils/numbers'; import { shortNumberFormat } from '../utils/numbers';
import { makeGetAccount } from '../selectors'; import { makeGetAccount } from '../selectors';
import { logOut } from 'gabsocial/actions/auth';
const messages = defineMessages({ const messages = defineMessages({
followers: { id: 'account.followers', defaultMessage: 'Followers' }, followers: { id: 'account.followers', defaultMessage: 'Followers' },
@ -46,6 +47,10 @@ const mapDispatchToProps = (dispatch) => ({
onClose () { onClose () {
dispatch(closeSidebar()); dispatch(closeSidebar());
}, },
onClickLogOut(e) {
dispatch(logOut());
e.preventDefault();
},
}); });
export default @connect(mapStateToProps, mapDispatchToProps) export default @connect(mapStateToProps, mapDispatchToProps)
@ -60,7 +65,7 @@ class SidebarMenu extends ImmutablePureComponent {
}; };
render () { render () {
const { sidebarOpen, onClose, intl, account } = this.props; const { sidebarOpen, onClose, intl, account, onClickLogOut } = this.props;
if (!account) return null; if (!account) return null;
const acct = account.get('acct'); const acct = account.get('acct');
@ -150,9 +155,9 @@ class SidebarMenu extends ImmutablePureComponent {
</div> </div>
<div className='sidebar-menu__section'> <div className='sidebar-menu__section'>
<a className='sidebar-menu-item' href='/auth/sign_out' data-method='delete'> <Link className='sidebar-menu-item' to='/auth/sign_out' onClick={onClickLogOut}>
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.logout)}</span> <span className='sidebar-menu-item__title'>{intl.formatMessage(messages.logout)}</span>
</a> </Link>
</div> </div>
</div> </div>

View file

@ -4,7 +4,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { createAuthApp, logIn } from 'gabsocial/actions/auth'; import { createAuthApp, logIn } from 'gabsocial/actions/auth';
import { fetchMe } from 'gabsocial/actions/me'; import { fetchMe } from 'gabsocial/actions/me';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { showAlert } from 'gabsocial/actions/alerts';
export default @connect() export default @connect()
class LoginForm extends ImmutablePureComponent { class LoginForm extends ImmutablePureComponent {
@ -29,7 +28,6 @@ class LoginForm extends ImmutablePureComponent {
dispatch(logIn(username, password)).then(() => { dispatch(logIn(username, password)).then(() => {
return dispatch(fetchMe()); return dispatch(fetchMe());
}).catch((error) => { }).catch((error) => {
dispatch(showAlert('Login failed', 'Invalid username or password.'));
this.setState({isLoading: false}); this.setState({isLoading: false});
}); });
this.setState({isLoading: true}); this.setState({isLoading: true});

View file

@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
import DropdownMenuContainer from '../../../containers/dropdown_menu_container'; import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
import { defineMessages, injectIntl } from 'react-intl'; import { defineMessages, injectIntl } from 'react-intl';
import { meUsername } from 'gabsocial/initial_state'; import { meUsername } from 'gabsocial/initial_state';
import { logOut } from 'gabsocial/actions/auth';
const messages = defineMessages({ const messages = defineMessages({
profile: { id: 'account.profile', defaultMessage: 'Profile' }, profile: { id: 'account.profile', defaultMessage: 'Profile' },
@ -24,6 +25,10 @@ const mapDispatchToProps = (dispatch) => ({
onOpenHotkeys() { onOpenHotkeys() {
dispatch(openModal('HOTKEYS')); dispatch(openModal('HOTKEYS'));
}, },
onClickLogOut(e) {
dispatch(logOut());
e.preventDefault();
},
}); });
class ActionBar extends React.PureComponent { class ActionBar extends React.PureComponent {
@ -38,7 +43,7 @@ class ActionBar extends React.PureComponent {
} }
render () { render () {
const { intl, onOpenHotkeys } = this.props; const { intl, onOpenHotkeys, onClickLogOut } = this.props;
const size = this.props.size || 16; const size = this.props.size || 16;
let menu = []; let menu = [];
@ -50,11 +55,11 @@ class ActionBar extends React.PureComponent {
menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' }); menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });
menu.push({ text: intl.formatMessage(messages.blocks), to: '/blocks' }); menu.push({ text: intl.formatMessage(messages.blocks), to: '/blocks' });
menu.push({ text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' }); menu.push({ text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' });
menu.push({ text: intl.formatMessage(messages.filters), href: '/filters' }); menu.push({ text: intl.formatMessage(messages.filters), to: '/filters' });
menu.push(null); menu.push(null);
menu.push({ text: intl.formatMessage(messages.keyboard_shortcuts), action: this.handleHotkeyClick }); menu.push({ text: intl.formatMessage(messages.keyboard_shortcuts), action: this.handleHotkeyClick });
menu.push({ text: intl.formatMessage(messages.preferences), href: '/settings/preferences' }); menu.push({ text: intl.formatMessage(messages.preferences), to: '/settings/preferences' });
menu.push({ text: intl.formatMessage(messages.logout), href: '/auth/sign_out', isLogout: true }); menu.push({ text: intl.formatMessage(messages.logout), to: '/auth/sign_out', action: onClickLogOut });
return ( return (
<div className='compose__action-bar' style={{'marginTop':'-6px'}}> <div className='compose__action-bar' style={{'marginTop':'-6px'}}>

View file

@ -5,6 +5,7 @@ import { Link } from 'react-router-dom';
import { invitesEnabled, version, repository, source_url } from 'gabsocial/initial_state'; import { invitesEnabled, version, repository, source_url } from 'gabsocial/initial_state';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { openModal } from '../../../actions/modal'; import { openModal } from '../../../actions/modal';
import { logOut } from 'gabsocial/actions/auth';
const mapStateToProps = state => { const mapStateToProps = state => {
const me = state.get('me'); const me = state.get('me');
@ -18,9 +19,13 @@ const mapDispatchToProps = (dispatch) => ({
onOpenHotkeys() { onOpenHotkeys() {
dispatch(openModal('HOTKEYS')); dispatch(openModal('HOTKEYS'));
}, },
onClickLogOut(e) {
dispatch(logOut());
e.preventDefault();
},
}); });
const LinkFooter = ({ onOpenHotkeys, account, siteTitle }) => ( const LinkFooter = ({ onOpenHotkeys, account, siteTitle, onClickLogOut }) => (
<div className='getting-started__footer'> <div className='getting-started__footer'>
<ul> <ul>
{(invitesEnabled && account) && <li><a href='/invites'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>} {(invitesEnabled && account) && <li><a href='/invites'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
@ -31,7 +36,7 @@ const LinkFooter = ({ onOpenHotkeys, account, siteTitle }) => (
<li><a href='/about/tos'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of Service' /></a> · </li> <li><a href='/about/tos'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of Service' /></a> · </li>
<li><a href='/about/dmca'><FormattedMessage id='getting_started.dmca' defaultMessage='DMCA' /></a> · </li> <li><a href='/about/dmca'><FormattedMessage id='getting_started.dmca' defaultMessage='DMCA' /></a> · </li>
<li><a href='/about/privacy'><FormattedMessage id='getting_started.privacy' defaultMessage='Privacy Policy' /></a></li> <li><a href='/about/privacy'><FormattedMessage id='getting_started.privacy' defaultMessage='Privacy Policy' /></a></li>
{account && <li> · <a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>} {account && <li> · <Link to='/auth/sign_out' onClick={onClickLogOut}><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></Link></li>}
</ul> </ul>
<p> <p>

View file

@ -479,7 +479,7 @@ class UI extends React.PureComponent {
const { me } = this.props; const { me } = this.props;
this.hotkeys = c; this.hotkeys = c;
if (!me) return; if (!me || !this.hotkeys) return;
this.hotkeys.__mousetrap__.stopCallback = (e, element) => { this.hotkeys.__mousetrap__.stopCallback = (e, element) => {
return ['TEXTAREA', 'SELECT', 'INPUT'].includes(element.tagName); return ['TEXTAREA', 'SELECT', 'INPUT'].includes(element.tagName);
}; };

View file

@ -2,6 +2,7 @@ import {
AUTH_APP_CREATED, AUTH_APP_CREATED,
AUTH_LOGGED_IN, AUTH_LOGGED_IN,
AUTH_APP_AUTHORIZED, AUTH_APP_AUTHORIZED,
AUTH_LOGGED_OUT,
} from '../actions/auth'; } from '../actions/auth';
import { Map as ImmutableMap, fromJS } from 'immutable'; import { Map as ImmutableMap, fromJS } from 'immutable';
@ -22,6 +23,9 @@ export default function auth(state = initialState, action) {
case AUTH_LOGGED_IN: case AUTH_LOGGED_IN:
localStorage.setItem('soapbox:auth:user', JSON.stringify(action.user)); // TODO: Better persistence localStorage.setItem('soapbox:auth:user', JSON.stringify(action.user)); // TODO: Better persistence
return state.set('user', ImmutableMap(action.user)); return state.set('user', ImmutableMap(action.user));
case AUTH_LOGGED_OUT:
localStorage.removeItem('soapbox:auth:user');
return state.setIn(['user'], ImmutableMap());
default: default:
return state; return state;
} }

View file

@ -1,4 +1,5 @@
import { ME_FETCH_SUCCESS, ME_FETCH_FAIL } from '../actions/me'; import { ME_FETCH_SUCCESS, ME_FETCH_FAIL } from '../actions/me';
import { AUTH_LOGGED_OUT } from '../actions/auth';
import { Map as ImmutableMap, fromJS } from 'immutable'; import { Map as ImmutableMap, fromJS } from 'immutable';
const initialState = null; const initialState = null;
@ -9,6 +10,8 @@ export default function me(state = initialState, action) {
return fromJS(action.me.id); return fromJS(action.me.id);
case ME_FETCH_FAIL: case ME_FETCH_FAIL:
return false; return false;
case AUTH_LOGGED_OUT:
return false;
default: default:
return state; return state;
} }