Chore: Migrate redux module login to typescript (#3647)
* chore: migrate redux module login to typescript chore: update redux module login tests * update workers * wip * fix type * remove partial * add more status * migrate the rest of the stuff to typescript * fix tests and types * fix types and tests
This commit is contained in:
parent
d73886bd60
commit
219462ba3d
|
@ -1,59 +0,0 @@
|
||||||
import * as types from './actionsTypes';
|
|
||||||
|
|
||||||
export function loginRequest(credentials, logoutOnError, isFromWebView) {
|
|
||||||
return {
|
|
||||||
type: types.LOGIN.REQUEST,
|
|
||||||
credentials,
|
|
||||||
logoutOnError,
|
|
||||||
isFromWebView
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loginSuccess(user) {
|
|
||||||
return {
|
|
||||||
type: types.LOGIN.SUCCESS,
|
|
||||||
user
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loginFailure(err) {
|
|
||||||
return {
|
|
||||||
type: types.LOGIN.FAILURE,
|
|
||||||
err
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function logout(forcedByServer = false) {
|
|
||||||
return {
|
|
||||||
type: types.LOGOUT,
|
|
||||||
forcedByServer
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setUser(user) {
|
|
||||||
return {
|
|
||||||
type: types.USER.SET,
|
|
||||||
user
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setLoginServices(data) {
|
|
||||||
return {
|
|
||||||
type: types.LOGIN.SET_SERVICES,
|
|
||||||
data
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setPreference(preference) {
|
|
||||||
return {
|
|
||||||
type: types.LOGIN.SET_PREFERENCE,
|
|
||||||
preference
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setLocalAuthenticated(isLocalAuthenticated) {
|
|
||||||
return {
|
|
||||||
type: types.LOGIN.SET_LOCAL_AUTHENTICATED,
|
|
||||||
isLocalAuthenticated
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
import { Action } from 'redux';
|
||||||
|
|
||||||
|
import { IUser } from '../definitions';
|
||||||
|
import * as types from './actionsTypes';
|
||||||
|
|
||||||
|
interface ICredentials {
|
||||||
|
resume: string;
|
||||||
|
user: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILoginRequest extends Action {
|
||||||
|
credentials: any;
|
||||||
|
logoutOnError?: boolean;
|
||||||
|
isFromWebView?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILoginSuccess extends Action {
|
||||||
|
user: Partial<IUser>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILoginFailure extends Action {
|
||||||
|
err: Partial<IUser>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILogout extends Action {
|
||||||
|
forcedByServer: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISetUser extends Action {
|
||||||
|
user: Partial<IUser>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISetServices extends Action {
|
||||||
|
data: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISetPreference extends Action {
|
||||||
|
preference: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISetLocalAuthenticated extends Action {
|
||||||
|
isLocalAuthenticated: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TActionsLogin = ILoginRequest &
|
||||||
|
ILoginSuccess &
|
||||||
|
ILoginFailure &
|
||||||
|
ILogout &
|
||||||
|
ISetUser &
|
||||||
|
ISetServices &
|
||||||
|
ISetPreference &
|
||||||
|
ISetLocalAuthenticated;
|
||||||
|
|
||||||
|
export function loginRequest(
|
||||||
|
credentials: Partial<ICredentials>,
|
||||||
|
logoutOnError?: boolean,
|
||||||
|
isFromWebView?: boolean
|
||||||
|
): ILoginRequest {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.REQUEST,
|
||||||
|
credentials,
|
||||||
|
logoutOnError,
|
||||||
|
isFromWebView
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loginSuccess(user: Partial<IUser>): ILoginSuccess {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.SUCCESS,
|
||||||
|
user
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loginFailure(err: Record<string, any>): ILoginFailure {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.FAILURE,
|
||||||
|
err
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logout(forcedByServer = false): ILogout {
|
||||||
|
return {
|
||||||
|
type: types.LOGOUT,
|
||||||
|
forcedByServer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setUser(user: Partial<IUser>): ISetUser {
|
||||||
|
return {
|
||||||
|
type: types.USER.SET,
|
||||||
|
user
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setLoginServices(data: Record<string, any>): ISetServices {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.SET_SERVICES,
|
||||||
|
data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setPreference(preference: Record<string, any>): ISetPreference {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.SET_PREFERENCE,
|
||||||
|
preference
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setLocalAuthenticated(isLocalAuthenticated: boolean): ISetLocalAuthenticated {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.SET_LOCAL_AUTHENTICATED,
|
||||||
|
isLocalAuthenticated
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import Model from '@nozbe/watermelondb/Model';
|
||||||
|
|
||||||
import { UserStatus } from './UserStatus';
|
import { UserStatus } from './UserStatus';
|
||||||
import { IRocketChatRecord } from './IRocketChatRecord';
|
import { IRocketChatRecord } from './IRocketChatRecord';
|
||||||
|
import { ILoggedUser } from './ILoggedUser';
|
||||||
|
|
||||||
export interface ILoginToken {
|
export interface ILoginToken {
|
||||||
hashedToken: string;
|
hashedToken: string;
|
||||||
|
@ -93,8 +94,10 @@ export interface IUserSettings {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUser extends IRocketChatRecord {
|
export interface IUser extends IRocketChatRecord, Omit<ILoggedUser, 'username' | 'name' | 'status'> {
|
||||||
_id: string;
|
_id: string;
|
||||||
|
id: string;
|
||||||
|
token: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
type: string;
|
type: string;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { ICreateChannel } from '../../reducers/createChannel';
|
||||||
import { ICreateDiscussion } from '../../reducers/createDiscussion';
|
import { ICreateDiscussion } from '../../reducers/createDiscussion';
|
||||||
import { IEncryption } from '../../reducers/encryption';
|
import { IEncryption } from '../../reducers/encryption';
|
||||||
import { IInviteLinks } from '../../reducers/inviteLinks';
|
import { IInviteLinks } from '../../reducers/inviteLinks';
|
||||||
|
import { ILogin } from '../../reducers/login';
|
||||||
import { IRoles } from '../../reducers/roles';
|
import { IRoles } from '../../reducers/roles';
|
||||||
import { IRoom } from '../../reducers/room';
|
import { IRoom } from '../../reducers/room';
|
||||||
import { ISelectedUsers } from '../../reducers/selectedUsers';
|
import { ISelectedUsers } from '../../reducers/selectedUsers';
|
||||||
|
@ -34,8 +35,8 @@ import { IEnterpriseModules } from '../../reducers/enterpriseModules';
|
||||||
|
|
||||||
export interface IApplicationState {
|
export interface IApplicationState {
|
||||||
settings: ISettings;
|
settings: ISettings;
|
||||||
login: any;
|
|
||||||
meteor: IConnect;
|
meteor: IConnect;
|
||||||
|
login: ILogin;
|
||||||
server: IServer;
|
server: IServer;
|
||||||
selectedUsers: ISelectedUsers;
|
selectedUsers: ISelectedUsers;
|
||||||
app: IApp;
|
app: IApp;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { clearActiveUsers, setActiveUsers } from '../actions/activeUsers';
|
import { clearActiveUsers, setActiveUsers } from '../actions/activeUsers';
|
||||||
|
import { UserStatus } from '../definitions/UserStatus';
|
||||||
import { IActiveUsers, initialState } from './activeUsers';
|
import { IActiveUsers, initialState } from './activeUsers';
|
||||||
import { mockedStore } from './mockedStore';
|
import { mockedStore } from './mockedStore';
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ describe('test reducer', () => {
|
||||||
expect(state).toEqual(initialState);
|
expect(state).toEqual(initialState);
|
||||||
});
|
});
|
||||||
it('should return modified store after action', () => {
|
it('should return modified store after action', () => {
|
||||||
const activeUsers: IActiveUsers = { any: { status: 'online', statusText: 'any' } };
|
const activeUsers: IActiveUsers = { any: { status: UserStatus.ONLINE, statusText: 'any' } };
|
||||||
mockedStore.dispatch(setActiveUsers(activeUsers));
|
mockedStore.dispatch(setActiveUsers(activeUsers));
|
||||||
const state = mockedStore.getState().activeUsers;
|
const state = mockedStore.getState().activeUsers;
|
||||||
expect(state).toEqual({ ...activeUsers });
|
expect(state).toEqual({ ...activeUsers });
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { TApplicationActions } from '../definitions';
|
|
||||||
import { ACTIVE_USERS } from '../actions/actionsTypes';
|
import { ACTIVE_USERS } from '../actions/actionsTypes';
|
||||||
|
import { TApplicationActions } from '../definitions';
|
||||||
|
import { UserStatus } from '../definitions/UserStatus';
|
||||||
|
|
||||||
type TUserStatus = 'online' | 'offline' | 'away' | 'busy';
|
|
||||||
export interface IActiveUser {
|
export interface IActiveUser {
|
||||||
status: TUserStatus;
|
status: UserStatus;
|
||||||
statusText: string;
|
statusText: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
import {
|
||||||
|
loginFailure,
|
||||||
|
loginRequest,
|
||||||
|
loginSuccess,
|
||||||
|
logout,
|
||||||
|
setLocalAuthenticated,
|
||||||
|
setLoginServices,
|
||||||
|
setUser
|
||||||
|
} from '../actions/login';
|
||||||
|
import { UserStatus } from '../definitions/UserStatus';
|
||||||
|
import { initialState } from './login';
|
||||||
|
import { mockedStore } from './mockedStore';
|
||||||
|
|
||||||
|
describe('test selectedUsers reducer', () => {
|
||||||
|
it('should return initial state', () => {
|
||||||
|
const state = mockedStore.getState().login;
|
||||||
|
expect(state).toEqual(initialState);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return modified store after loginRequest', () => {
|
||||||
|
mockedStore.dispatch(loginRequest({ user: 'carlitos@email.com', password: '123456' }));
|
||||||
|
const state = mockedStore.getState().login;
|
||||||
|
expect(state).toEqual({ ...initialState, isFetching: true, isAuthenticated: false, failure: false, error: {} });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return modified store after loginFailure', () => {
|
||||||
|
mockedStore.dispatch(loginFailure({ error: 'error' }));
|
||||||
|
const state = mockedStore.getState().login.error.error;
|
||||||
|
expect(state).toEqual('error');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return modified store after loginSuccess', () => {
|
||||||
|
const user = {
|
||||||
|
id: 'ajhsiahsa',
|
||||||
|
token: 'asdasdasdas',
|
||||||
|
username: 'carlitos',
|
||||||
|
name: 'Carlitos',
|
||||||
|
customFields: {
|
||||||
|
phonenumber: ''
|
||||||
|
},
|
||||||
|
emails: [
|
||||||
|
{
|
||||||
|
address: 'carlitos@email.com',
|
||||||
|
verified: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
roles: ['user'],
|
||||||
|
isFromWebView: false,
|
||||||
|
showMessageInMainThread: false,
|
||||||
|
enableMessageParserEarlyAdoption: false,
|
||||||
|
status: UserStatus.ONLINE,
|
||||||
|
statusText: 'online'
|
||||||
|
};
|
||||||
|
mockedStore.dispatch(loginSuccess(user));
|
||||||
|
const state = mockedStore.getState().login.user;
|
||||||
|
expect(state).toEqual(user);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return modified store after setUser', () => {
|
||||||
|
const user = {
|
||||||
|
id: 'ajhsiahsa',
|
||||||
|
token: 'asdasdasdas',
|
||||||
|
username: 'carlito',
|
||||||
|
name: 'Carlitos',
|
||||||
|
customFields: {
|
||||||
|
phonenumber: ''
|
||||||
|
},
|
||||||
|
emails: [
|
||||||
|
{
|
||||||
|
address: 'carlitos@email.com',
|
||||||
|
verified: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
roles: ['user'],
|
||||||
|
isFromWebView: false,
|
||||||
|
showMessageInMainThread: false,
|
||||||
|
enableMessageParserEarlyAdoption: false
|
||||||
|
};
|
||||||
|
mockedStore.dispatch(setUser(user));
|
||||||
|
const state = mockedStore.getState().login.user.username;
|
||||||
|
expect(state).toEqual(user.username);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO PREFERENCE REDUCER WITH EMPTY PREFERENCE - NON USED?
|
||||||
|
// it('should return modified store after setPreference', () => {
|
||||||
|
// mockedStore.dispatch(setPreference({ showAvatar: true }));
|
||||||
|
// const state = mockedStore.getState().login;
|
||||||
|
// console.log(state);
|
||||||
|
// expect(state).toEqual('error');
|
||||||
|
// });
|
||||||
|
|
||||||
|
it('should return modified store after setLocalAuthenticated', () => {
|
||||||
|
mockedStore.dispatch(setLocalAuthenticated(true));
|
||||||
|
const state = mockedStore.getState().login.isLocalAuthenticated;
|
||||||
|
expect(state).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return modified store after setLoginServices', () => {
|
||||||
|
mockedStore.dispatch(setLoginServices({ facebook: { clientId: 'xxx' } }));
|
||||||
|
const state = mockedStore.getState().login.services.facebook.clientId;
|
||||||
|
expect(state).toEqual('xxx');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return modified store after logout', () => {
|
||||||
|
mockedStore.dispatch(logout());
|
||||||
|
const state = mockedStore.getState().login;
|
||||||
|
expect(state).toEqual(initialState);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,15 +1,47 @@
|
||||||
|
import { UserStatus } from '../definitions/UserStatus';
|
||||||
import * as types from '../actions/actionsTypes';
|
import * as types from '../actions/actionsTypes';
|
||||||
|
import { TActionsLogin } from '../actions/login';
|
||||||
|
import { IUser } from '../definitions';
|
||||||
|
|
||||||
const initialState = {
|
export interface IUserLogin {
|
||||||
|
id: string;
|
||||||
|
token: string;
|
||||||
|
username: string;
|
||||||
|
name: string;
|
||||||
|
language?: string;
|
||||||
|
status: UserStatus;
|
||||||
|
statusText: string;
|
||||||
|
roles: string[];
|
||||||
|
avatarETag?: string;
|
||||||
|
isFromWebView: boolean;
|
||||||
|
showMessageInMainThread: boolean;
|
||||||
|
enableMessageParserEarlyAdoption: boolean;
|
||||||
|
emails: Record<string, any>[];
|
||||||
|
customFields: Record<string, string>;
|
||||||
|
settings?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILogin {
|
||||||
|
user: Partial<IUser>;
|
||||||
|
isLocalAuthenticated: boolean;
|
||||||
|
isAuthenticated: boolean;
|
||||||
|
isFetching: boolean;
|
||||||
|
error: Record<string, any>;
|
||||||
|
services: Record<string, any>;
|
||||||
|
failure: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialState: ILogin = {
|
||||||
isLocalAuthenticated: true,
|
isLocalAuthenticated: true,
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
user: {},
|
user: {},
|
||||||
error: {},
|
error: {},
|
||||||
services: {}
|
services: {},
|
||||||
|
failure: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function login(state = initialState, action) {
|
export default function login(state = initialState, action: TActionsLogin): ILogin {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case types.APP.INIT:
|
case types.APP.INIT:
|
||||||
return initialState;
|
return initialState;
|
||||||
|
@ -60,13 +92,14 @@ export default function login(state = initialState, action) {
|
||||||
...state,
|
...state,
|
||||||
user: {
|
user: {
|
||||||
...state.user,
|
...state.user,
|
||||||
settings: {
|
settings: state.user?.settings
|
||||||
...state.user.settings,
|
? {
|
||||||
preferences: {
|
...state.user?.settings,
|
||||||
...state.user.settings.preferences,
|
preferences: state.user?.settings?.preferences
|
||||||
...action.preference
|
? { ...state.user.settings.preferences, ...action.preference }
|
||||||
}
|
: { ...action.preference }
|
||||||
}
|
}
|
||||||
|
: { profile: {}, preferences: {} }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
case types.LOGIN.SET_LOCAL_AUTHENTICATED:
|
case types.LOGIN.SET_LOCAL_AUTHENTICATED:
|
|
@ -1,7 +1,7 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
|
|
||||||
import { IApplicationState } from '../definitions';
|
import { IApplicationState, IUser } from '../definitions';
|
||||||
|
|
||||||
interface IServices {
|
interface IServices {
|
||||||
facebook: { clientId: string };
|
facebook: { clientId: string };
|
||||||
|
@ -13,7 +13,7 @@ interface IServices {
|
||||||
wordpress: { clientId: string; serverURL: string };
|
wordpress: { clientId: string; serverURL: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
const getUser = (state: IApplicationState) => {
|
const getUser = (state: IApplicationState): Partial<IUser> => {
|
||||||
if (!isEmpty(state.share?.user)) {
|
if (!isEmpty(state.share?.user)) {
|
||||||
return state.share.user;
|
return state.share.user;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,8 @@ const getLoginServices = (state: IApplicationState) => (state.login.services as
|
||||||
const getShowFormLoginSetting = (state: IApplicationState) => (state.settings.Accounts_ShowFormLogin as boolean) || false;
|
const getShowFormLoginSetting = (state: IApplicationState) => (state.settings.Accounts_ShowFormLogin as boolean) || false;
|
||||||
const getIframeEnabledSetting = (state: IApplicationState) => (state.settings.Accounts_iframe_enabled as boolean) || false;
|
const getIframeEnabledSetting = (state: IApplicationState) => (state.settings.Accounts_iframe_enabled as boolean) || false;
|
||||||
|
|
||||||
export const getUserSelector = createSelector([getUser], user => user);
|
// TODO: we need to change 42 files to fix a correct type, i believe is better to do this later
|
||||||
|
export const getUserSelector = createSelector([getUser], user => user) as any;
|
||||||
|
|
||||||
export const getShowLoginButton = createSelector(
|
export const getShowLoginButton = createSelector(
|
||||||
[getLoginServices, getShowFormLoginSetting, getIframeEnabledSetting],
|
[getLoginServices, getShowFormLoginSetting, getIframeEnabledSetting],
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
|
import { dequal } from 'dequal';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Alert, Keyboard, StyleSheet, Text, View } from 'react-native';
|
import { Alert, Keyboard, StyleSheet, Text, View } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { dequal } from 'dequal';
|
|
||||||
import { StackNavigationProp } from '@react-navigation/stack';
|
|
||||||
import { RouteProp } from '@react-navigation/core';
|
|
||||||
|
|
||||||
import Button from '../containers/Button';
|
import { loginRequest } from '../actions/login';
|
||||||
import I18n from '../i18n';
|
|
||||||
import * as HeaderButton from '../containers/HeaderButton';
|
|
||||||
import { themes } from '../constants/colors';
|
import { themes } from '../constants/colors';
|
||||||
import { withTheme } from '../theme';
|
import Button from '../containers/Button';
|
||||||
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||||
import TextInput from '../containers/TextInput';
|
import * as HeaderButton from '../containers/HeaderButton';
|
||||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
|
||||||
import LoginServices from '../containers/LoginServices';
|
import LoginServices from '../containers/LoginServices';
|
||||||
import sharedStyles from './Styles';
|
import TextInput from '../containers/TextInput';
|
||||||
|
import { IApplicationState, IBaseScreen } from '../definitions';
|
||||||
|
import I18n from '../i18n';
|
||||||
import { OutsideParamList } from '../stacks/types';
|
import { OutsideParamList } from '../stacks/types';
|
||||||
|
import { withTheme } from '../theme';
|
||||||
|
import sharedStyles from './Styles';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
registerDisabled: {
|
registerDisabled: {
|
||||||
|
@ -48,9 +47,7 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface ILoginViewProps {
|
interface ILoginViewProps extends IBaseScreen<OutsideParamList, 'LoginView'> {
|
||||||
navigation: StackNavigationProp<OutsideParamList, 'LoginView'>;
|
|
||||||
route: RouteProp<OutsideParamList, 'LoginView'>;
|
|
||||||
Site_Name: string;
|
Site_Name: string;
|
||||||
Accounts_RegistrationForm: string;
|
Accounts_RegistrationForm: string;
|
||||||
Accounts_RegistrationForm_LinkReplacementText: string;
|
Accounts_RegistrationForm_LinkReplacementText: string;
|
||||||
|
@ -63,7 +60,6 @@ interface ILoginViewProps {
|
||||||
error: string;
|
error: string;
|
||||||
};
|
};
|
||||||
failure: boolean;
|
failure: boolean;
|
||||||
theme: string;
|
|
||||||
loginRequest: Function;
|
loginRequest: Function;
|
||||||
inviteLinkToken: string;
|
inviteLinkToken: string;
|
||||||
}
|
}
|
||||||
|
@ -132,9 +128,9 @@ class LoginView extends React.Component<ILoginViewProps, any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user, password } = this.state;
|
const { user, password } = this.state;
|
||||||
const { loginRequest } = this.props;
|
const { dispatch } = this.props;
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
loginRequest({ user, password });
|
dispatch(loginRequest({ user, password }));
|
||||||
};
|
};
|
||||||
|
|
||||||
renderUserForm = () => {
|
renderUserForm = () => {
|
||||||
|
@ -243,23 +239,19 @@ class LoginView extends React.Component<ILoginViewProps, any> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: any) => ({
|
const mapStateToProps = (state: IApplicationState) => ({
|
||||||
server: state.server.server,
|
server: state.server.server,
|
||||||
Site_Name: state.settings.Site_Name,
|
Site_Name: state.settings.Site_Name as string,
|
||||||
Accounts_ShowFormLogin: state.settings.Accounts_ShowFormLogin,
|
Accounts_ShowFormLogin: state.settings.Accounts_ShowFormLogin as boolean,
|
||||||
Accounts_RegistrationForm: state.settings.Accounts_RegistrationForm,
|
Accounts_RegistrationForm: state.settings.Accounts_RegistrationForm as string,
|
||||||
Accounts_RegistrationForm_LinkReplacementText: state.settings.Accounts_RegistrationForm_LinkReplacementText,
|
Accounts_RegistrationForm_LinkReplacementText: state.settings.Accounts_RegistrationForm_LinkReplacementText as string,
|
||||||
isFetching: state.login.isFetching,
|
isFetching: state.login.isFetching,
|
||||||
failure: state.login.failure,
|
failure: state.login.failure,
|
||||||
error: state.login.error && state.login.error.data,
|
error: state.login.error && state.login.error.data,
|
||||||
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
|
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder as string,
|
||||||
Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder,
|
Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder as string,
|
||||||
Accounts_PasswordReset: state.settings.Accounts_PasswordReset,
|
Accounts_PasswordReset: state.settings.Accounts_PasswordReset as boolean,
|
||||||
inviteLinkToken: state.inviteLinks.token
|
inviteLinkToken: state.inviteLinks.token
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: any) => ({
|
export default connect(mapStateToProps)(withTheme(LoginView));
|
||||||
loginRequest: (params: any) => dispatch(loginRequestAction(params))
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(LoginView));
|
|
||||||
|
|
|
@ -1,26 +1,25 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Keyboard, StyleSheet, Text, View } from 'react-native';
|
import { Keyboard, StyleSheet, Text, View } from 'react-native';
|
||||||
import { StackNavigationProp } from '@react-navigation/stack';
|
|
||||||
import { RouteProp } from '@react-navigation/core';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import RNPickerSelect from 'react-native-picker-select';
|
import RNPickerSelect from 'react-native-picker-select';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { OutsideParamList } from '../stacks/types';
|
import { loginRequest } from '../actions/login';
|
||||||
import log, { events, logEvent } from '../utils/log';
|
|
||||||
import Button from '../containers/Button';
|
|
||||||
import I18n from '../i18n';
|
|
||||||
import * as HeaderButton from '../containers/HeaderButton';
|
|
||||||
import { themes } from '../constants/colors';
|
import { themes } from '../constants/colors';
|
||||||
import { withTheme } from '../theme';
|
import Button from '../containers/Button';
|
||||||
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||||
import TextInput from '../containers/TextInput';
|
import * as HeaderButton from '../containers/HeaderButton';
|
||||||
import isValidEmail from '../utils/isValidEmail';
|
|
||||||
import { showErrorAlert } from '../utils/info';
|
|
||||||
import RocketChat from '../lib/rocketchat';
|
|
||||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
|
||||||
import openLink from '../utils/openLink';
|
|
||||||
import LoginServices from '../containers/LoginServices';
|
import LoginServices from '../containers/LoginServices';
|
||||||
|
import TextInput from '../containers/TextInput';
|
||||||
|
import { IApplicationState, IBaseScreen } from '../definitions';
|
||||||
|
import I18n from '../i18n';
|
||||||
|
import RocketChat from '../lib/rocketchat';
|
||||||
import { getShowLoginButton } from '../selectors/login';
|
import { getShowLoginButton } from '../selectors/login';
|
||||||
|
import { OutsideParamList } from '../stacks/types';
|
||||||
|
import { withTheme } from '../theme';
|
||||||
|
import { showErrorAlert } from '../utils/info';
|
||||||
|
import isValidEmail from '../utils/isValidEmail';
|
||||||
|
import log, { events, logEvent } from '../utils/log';
|
||||||
|
import openLink from '../utils/openLink';
|
||||||
import sharedStyles from './Styles';
|
import sharedStyles from './Styles';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
@ -51,9 +50,7 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IProps {
|
interface IProps extends IBaseScreen<OutsideParamList, 'RegisterView'> {
|
||||||
navigation: StackNavigationProp<OutsideParamList, 'RegisterView'>;
|
|
||||||
route: RouteProp<OutsideParamList, 'RegisterView'>;
|
|
||||||
server: string;
|
server: string;
|
||||||
Site_Name: string;
|
Site_Name: string;
|
||||||
Gitlab_URL: string;
|
Gitlab_URL: string;
|
||||||
|
@ -63,8 +60,6 @@ interface IProps {
|
||||||
Accounts_EmailVerification: boolean;
|
Accounts_EmailVerification: boolean;
|
||||||
Accounts_ManuallyApproveNewUsers: boolean;
|
Accounts_ManuallyApproveNewUsers: boolean;
|
||||||
showLoginButton: boolean;
|
showLoginButton: boolean;
|
||||||
loginRequest: Function;
|
|
||||||
theme: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class RegisterView extends React.Component<IProps, any> {
|
class RegisterView extends React.Component<IProps, any> {
|
||||||
|
@ -130,7 +125,7 @@ class RegisterView extends React.Component<IProps, any> {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
|
|
||||||
const { name, email, password, username, customFields } = this.state;
|
const { name, email, password, username, customFields } = this.state;
|
||||||
const { loginRequest, Accounts_EmailVerification, navigation, Accounts_ManuallyApproveNewUsers } = this.props;
|
const { dispatch, Accounts_EmailVerification, navigation, Accounts_ManuallyApproveNewUsers } = this.props;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await RocketChat.register({
|
await RocketChat.register({
|
||||||
|
@ -148,11 +143,11 @@ class RegisterView extends React.Component<IProps, any> {
|
||||||
await navigation.goBack();
|
await navigation.goBack();
|
||||||
showErrorAlert(I18n.t('Wait_activation_warning'), I18n.t('Registration_Succeeded'));
|
showErrorAlert(I18n.t('Wait_activation_warning'), I18n.t('Registration_Succeeded'));
|
||||||
} else {
|
} else {
|
||||||
await loginRequest({ user: email, password });
|
dispatch(loginRequest({ user: email, password }));
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.data?.errorType === 'username-invalid') {
|
if (e.data?.errorType === 'username-invalid') {
|
||||||
return loginRequest({ user: email, password });
|
return dispatch(loginRequest({ user: email, password }));
|
||||||
}
|
}
|
||||||
if (e.data?.error) {
|
if (e.data?.error) {
|
||||||
logEvent(events.REGISTER_DEFAULT_SIGN_UP_F);
|
logEvent(events.REGISTER_DEFAULT_SIGN_UP_F);
|
||||||
|
@ -349,20 +344,16 @@ class RegisterView extends React.Component<IProps, any> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: any) => ({
|
const mapStateToProps = (state: IApplicationState) => ({
|
||||||
server: state.server.server,
|
server: state.server.server,
|
||||||
Site_Name: state.settings.Site_Name,
|
Site_Name: state.settings.Site_Name as string,
|
||||||
Gitlab_URL: state.settings.API_Gitlab_URL,
|
Gitlab_URL: state.settings.API_Gitlab_URL as string,
|
||||||
CAS_enabled: state.settings.CAS_enabled,
|
CAS_enabled: state.settings.CAS_enabled as boolean,
|
||||||
CAS_login_url: state.settings.CAS_login_url,
|
CAS_login_url: state.settings.CAS_login_url as string,
|
||||||
Accounts_CustomFields: state.settings.Accounts_CustomFields,
|
Accounts_CustomFields: state.settings.Accounts_CustomFields as string,
|
||||||
Accounts_EmailVerification: state.settings.Accounts_EmailVerification,
|
Accounts_EmailVerification: state.settings.Accounts_EmailVerification as boolean,
|
||||||
Accounts_ManuallyApproveNewUsers: state.settings.Accounts_ManuallyApproveNewUsers,
|
Accounts_ManuallyApproveNewUsers: state.settings.Accounts_ManuallyApproveNewUsers as boolean,
|
||||||
showLoginButton: getShowLoginButton(state)
|
showLoginButton: getShowLoginButton(state)
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: any) => ({
|
export default connect(mapStateToProps)(withTheme(RegisterView));
|
||||||
loginRequest: (params: any) => dispatch(loginRequestAction(params))
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(RegisterView));
|
|
||||||
|
|
|
@ -1,25 +1,26 @@
|
||||||
import React from 'react';
|
|
||||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
|
||||||
import { Dispatch } from 'redux';
|
|
||||||
import { ScrollView, StyleSheet, Text } from 'react-native';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import Orientation from 'react-native-orientation-locker';
|
|
||||||
import { RouteProp } from '@react-navigation/native';
|
import { RouteProp } from '@react-navigation/native';
|
||||||
|
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||||
|
import React from 'react';
|
||||||
|
import { ScrollView, StyleSheet, Text } from 'react-native';
|
||||||
|
import Orientation from 'react-native-orientation-locker';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
|
|
||||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
import { loginRequest } from '../actions/login';
|
||||||
import TextInput from '../containers/TextInput';
|
import { themes } from '../constants/colors';
|
||||||
import Button from '../containers/Button';
|
import Button from '../containers/Button';
|
||||||
import KeyboardView from '../presentation/KeyboardView';
|
import SafeAreaView from '../containers/SafeAreaView';
|
||||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
import StatusBar from '../containers/StatusBar';
|
||||||
|
import TextInput from '../containers/TextInput';
|
||||||
|
import { IApplicationState } from '../definitions';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
import StatusBar from '../containers/StatusBar';
|
import KeyboardView from '../presentation/KeyboardView';
|
||||||
import { withTheme } from '../theme';
|
|
||||||
import { themes } from '../constants/colors';
|
|
||||||
import { isTablet } from '../utils/deviceInfo';
|
|
||||||
import { getUserSelector } from '../selectors/login';
|
import { getUserSelector } from '../selectors/login';
|
||||||
|
import { withTheme } from '../theme';
|
||||||
|
import { isTablet } from '../utils/deviceInfo';
|
||||||
import { showErrorAlert } from '../utils/info';
|
import { showErrorAlert } from '../utils/info';
|
||||||
import SafeAreaView from '../containers/SafeAreaView';
|
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||||
import sharedStyles from './Styles';
|
import sharedStyles from './Styles';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
@ -39,9 +40,9 @@ interface ISetUsernameViewProps {
|
||||||
route: RouteProp<{ SetUsernameView: { title: string } }, 'SetUsernameView'>;
|
route: RouteProp<{ SetUsernameView: { title: string } }, 'SetUsernameView'>;
|
||||||
server: string;
|
server: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
loginRequest: ({ resume }: { resume: string }) => void;
|
|
||||||
token: string;
|
token: string;
|
||||||
theme: string;
|
theme: string;
|
||||||
|
dispatch: Dispatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernameViewState> {
|
class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernameViewState> {
|
||||||
|
@ -86,7 +87,7 @@ class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernam
|
||||||
|
|
||||||
submit = async () => {
|
submit = async () => {
|
||||||
const { username } = this.state;
|
const { username } = this.state;
|
||||||
const { loginRequest, token } = this.props;
|
const { dispatch, token } = this.props;
|
||||||
|
|
||||||
if (!username.trim()) {
|
if (!username.trim()) {
|
||||||
return;
|
return;
|
||||||
|
@ -95,7 +96,7 @@ class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernam
|
||||||
this.setState({ saving: true });
|
this.setState({ saving: true });
|
||||||
try {
|
try {
|
||||||
await RocketChat.saveUserProfile({ username });
|
await RocketChat.saveUserProfile({ username });
|
||||||
await loginRequest({ resume: token });
|
dispatch(loginRequest({ resume: token }));
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
showErrorAlert(e.message, I18n.t('Oops'));
|
showErrorAlert(e.message, I18n.t('Oops'));
|
||||||
}
|
}
|
||||||
|
@ -144,13 +145,9 @@ class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernam
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: any) => ({
|
const mapStateToProps = (state: IApplicationState) => ({
|
||||||
server: state.server.server,
|
server: state.server.server,
|
||||||
token: getUserSelector(state).token
|
token: getUserSelector(state).token
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
export default connect(mapStateToProps)(withTheme(SetUsernameView));
|
||||||
loginRequest: (params: { resume: string }) => dispatch(loginRequestAction(params))
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(SetUsernameView));
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StackNavigationProp } from '@react-navigation/stack';
|
|
||||||
import { FlatList, StyleSheet } from 'react-native';
|
import { FlatList, StyleSheet } from 'react-native';
|
||||||
import { Dispatch } from 'redux';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import I18n from '../i18n';
|
import { UserStatus } from '../definitions/UserStatus';
|
||||||
|
import { setUser } from '../actions/login';
|
||||||
|
import * as HeaderButton from '../containers/HeaderButton';
|
||||||
import * as List from '../containers/List';
|
import * as List from '../containers/List';
|
||||||
|
import Loading from '../containers/Loading';
|
||||||
|
import SafeAreaView from '../containers/SafeAreaView';
|
||||||
import Status from '../containers/Status/Status';
|
import Status from '../containers/Status/Status';
|
||||||
import TextInput from '../containers/TextInput';
|
import TextInput from '../containers/TextInput';
|
||||||
|
import { LISTENER } from '../containers/Toast';
|
||||||
|
import { IApplicationState, IBaseScreen } from '../definitions';
|
||||||
|
import I18n from '../i18n';
|
||||||
|
import RocketChat from '../lib/rocketchat';
|
||||||
|
import { getUserSelector } from '../selectors/login';
|
||||||
|
import { withTheme } from '../theme';
|
||||||
import EventEmitter from '../utils/events';
|
import EventEmitter from '../utils/events';
|
||||||
import { showErrorAlert } from '../utils/info';
|
import { showErrorAlert } from '../utils/info';
|
||||||
import Loading from '../containers/Loading';
|
|
||||||
import RocketChat from '../lib/rocketchat';
|
|
||||||
import log, { events, logEvent } from '../utils/log';
|
import log, { events, logEvent } from '../utils/log';
|
||||||
import { LISTENER } from '../containers/Toast';
|
|
||||||
import { withTheme } from '../theme';
|
|
||||||
import { getUserSelector } from '../selectors/login';
|
|
||||||
import * as HeaderButton from '../containers/HeaderButton';
|
|
||||||
import { setUser as setUserAction } from '../actions/login';
|
|
||||||
import SafeAreaView from '../containers/SafeAreaView';
|
|
||||||
|
|
||||||
const STATUS = [
|
const STATUS = [
|
||||||
{
|
{
|
||||||
|
@ -65,12 +65,9 @@ interface IStatusViewState {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IStatusViewProps {
|
interface IStatusViewProps extends IBaseScreen<any, 'StatusView'> {
|
||||||
navigation: StackNavigationProp<any, 'StatusView'>;
|
|
||||||
user: IUser;
|
user: IUser;
|
||||||
theme: string;
|
|
||||||
isMasterDetail: boolean;
|
isMasterDetail: boolean;
|
||||||
setUser: (user: IUser) => void;
|
|
||||||
Accounts_AllowInvisibleStatusOption: boolean;
|
Accounts_AllowInvisibleStatusOption: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +108,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
setCustomStatus = async (statusText: string) => {
|
setCustomStatus = async (statusText: string) => {
|
||||||
const { user, setUser } = this.props;
|
const { user, dispatch } = this.props;
|
||||||
|
|
||||||
this.setState({ loading: true });
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
@ -119,7 +116,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
||||||
const result = await RocketChat.setUserStatus(user.status, statusText);
|
const result = await RocketChat.setUserStatus(user.status, statusText);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
logEvent(events.STATUS_CUSTOM);
|
logEvent(events.STATUS_CUSTOM);
|
||||||
setUser({ statusText });
|
dispatch(setUser({ statusText }));
|
||||||
EventEmitter.emit(LISTENER, { message: I18n.t('Status_saved_successfully') });
|
EventEmitter.emit(LISTENER, { message: I18n.t('Status_saved_successfully') });
|
||||||
} else {
|
} else {
|
||||||
logEvent(events.STATUS_CUSTOM_F);
|
logEvent(events.STATUS_CUSTOM_F);
|
||||||
|
@ -156,7 +153,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
||||||
|
|
||||||
renderItem = ({ item }: { item: { id: string; name: string } }) => {
|
renderItem = ({ item }: { item: { id: string; name: string } }) => {
|
||||||
const { statusText } = this.state;
|
const { statusText } = this.state;
|
||||||
const { user, setUser } = this.props;
|
const { user, dispatch } = this.props;
|
||||||
const { id, name } = item;
|
const { id, name } = item;
|
||||||
return (
|
return (
|
||||||
<List.Item
|
<List.Item
|
||||||
|
@ -168,7 +165,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
||||||
try {
|
try {
|
||||||
const result = await RocketChat.setUserStatus(item.id, statusText);
|
const result = await RocketChat.setUserStatus(item.id, statusText);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
setUser({ status: item.id });
|
dispatch(setUser({ status: item.id as UserStatus }));
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
showErrorAlert(I18n.t(e.data.errorType));
|
showErrorAlert(I18n.t(e.data.errorType));
|
||||||
|
@ -205,14 +202,10 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: any) => ({
|
const mapStateToProps = (state: IApplicationState) => ({
|
||||||
user: getUserSelector(state),
|
user: getUserSelector(state),
|
||||||
isMasterDetail: state.app.isMasterDetail,
|
isMasterDetail: state.app.isMasterDetail,
|
||||||
Accounts_AllowInvisibleStatusOption: state.settings.Accounts_AllowInvisibleStatusOption ?? true
|
Accounts_AllowInvisibleStatusOption: (state.settings.Accounts_AllowInvisibleStatusOption as boolean) ?? true
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
export default connect(mapStateToProps)(withTheme(StatusView));
|
||||||
setUser: (user: IUser) => dispatch(setUserAction(user))
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(StatusView));
|
|
||||||
|
|
Loading…
Reference in New Issue