diff --git a/app/actions/customEmojis.js b/app/actions/customEmojis.js deleted file mode 100644 index 740a936ac..000000000 --- a/app/actions/customEmojis.js +++ /dev/null @@ -1,8 +0,0 @@ -import * as types from './actionsTypes'; - -export function setCustomEmojis(emojis) { - return { - type: types.SET_CUSTOM_EMOJIS, - emojis - }; -} diff --git a/app/actions/customEmojis.ts b/app/actions/customEmojis.ts new file mode 100644 index 000000000..261fbd241 --- /dev/null +++ b/app/actions/customEmojis.ts @@ -0,0 +1,17 @@ +import { Action } from 'redux'; + +import { ICustomEmojis } from '../reducers/customEmojis'; +import { SET_CUSTOM_EMOJIS } from './actionsTypes'; + +export interface ISetCustomEmojis extends Action { + emojis: ICustomEmojis; +} + +export type TActionCustomEmojis = ISetCustomEmojis; + +export function setCustomEmojis(emojis: ICustomEmojis): ISetCustomEmojis { + return { + type: SET_CUSTOM_EMOJIS, + emojis + }; +} diff --git a/app/actions/deepLinking.js b/app/actions/deepLinking.js deleted file mode 100644 index dfd540b6f..000000000 --- a/app/actions/deepLinking.js +++ /dev/null @@ -1,8 +0,0 @@ -import * as types from './actionsTypes'; - -export function deepLinkingOpen(params) { - return { - type: types.DEEP_LINKING.OPEN, - params - }; -} diff --git a/app/actions/deepLinking.ts b/app/actions/deepLinking.ts new file mode 100644 index 000000000..78ea929bb --- /dev/null +++ b/app/actions/deepLinking.ts @@ -0,0 +1,25 @@ +import { Action } from 'redux'; + +import { DEEP_LINKING } from './actionsTypes'; + +interface IParams { + path: string; + rid: string; + messageId: string; + host: string; + isCall: boolean; + fullURL: string; + type: string; + token: string; +} + +interface IDeepLinkingOpen extends Action { + params: Partial; +} + +export function deepLinkingOpen(params: Partial): IDeepLinkingOpen { + return { + type: DEEP_LINKING.OPEN, + params + }; +} diff --git a/app/actions/encryption.js b/app/actions/encryption.js deleted file mode 100644 index 390dfe903..000000000 --- a/app/actions/encryption.js +++ /dev/null @@ -1,35 +0,0 @@ -import * as types from './actionsTypes'; - -export function encryptionInit() { - return { - type: types.ENCRYPTION.INIT - }; -} - -export function encryptionStop() { - return { - type: types.ENCRYPTION.STOP - }; -} - -export function encryptionSet(enabled = false, banner = null) { - return { - type: types.ENCRYPTION.SET, - enabled, - banner - }; -} - -export function encryptionSetBanner(banner) { - return { - type: types.ENCRYPTION.SET_BANNER, - banner - }; -} - -export function encryptionDecodeKey(password) { - return { - type: types.ENCRYPTION.DECODE_KEY, - password - }; -} diff --git a/app/actions/encryption.ts b/app/actions/encryption.ts new file mode 100644 index 000000000..be3fb43fa --- /dev/null +++ b/app/actions/encryption.ts @@ -0,0 +1,52 @@ +import { Action } from 'redux'; + +import { IBanner } from '../reducers/encryption'; +import { ENCRYPTION } from './actionsTypes'; + +export interface IEncryptionSet extends Action { + enabled: boolean; + banner: IBanner; +} + +export interface IEncryptionSetBanner extends Action { + banner: IBanner; +} +export interface IEncryptionDecodeKey extends Action { + password: string; +} + +export type TActionEncryption = IEncryptionSet & IEncryptionSetBanner & IEncryptionDecodeKey; + +export function encryptionInit(): Action { + return { + type: ENCRYPTION.INIT + }; +} + +export function encryptionStop(): Action { + return { + type: ENCRYPTION.STOP + }; +} + +export function encryptionSet(enabled = false, banner: IBanner = ''): IEncryptionSet { + return { + type: ENCRYPTION.SET, + enabled, + banner + }; +} + +export function encryptionSetBanner(banner: IBanner = ''): IEncryptionSetBanner { + return { + type: ENCRYPTION.SET_BANNER, + banner + }; +} + +export function encryptionDecodeKey(password: string): IEncryptionDecodeKey { + return { + type: ENCRYPTION.DECODE_KEY, + password + }; +} diff --git a/app/actions/inviteLinks.js b/app/actions/inviteLinks.js deleted file mode 100644 index cd2fd1639..000000000 --- a/app/actions/inviteLinks.js +++ /dev/null @@ -1,54 +0,0 @@ -import * as types from './actionsTypes'; - -export function inviteLinksSetToken(token) { - return { - type: types.INVITE_LINKS.SET_TOKEN, - token - }; -} - -export function inviteLinksRequest(token) { - return { - type: types.INVITE_LINKS.REQUEST, - token - }; -} - -export function inviteLinksSuccess() { - return { - type: types.INVITE_LINKS.SUCCESS - }; -} - -export function inviteLinksFailure() { - return { - type: types.INVITE_LINKS.FAILURE - }; -} - -export function inviteLinksClear() { - return { - type: types.INVITE_LINKS.CLEAR - }; -} - -export function inviteLinksCreate(rid) { - return { - type: types.INVITE_LINKS.CREATE, - rid - }; -} - -export function inviteLinksSetParams(params) { - return { - type: types.INVITE_LINKS.SET_PARAMS, - params - }; -} - -export function inviteLinksSetInvite(invite) { - return { - type: types.INVITE_LINKS.SET_INVITE, - invite - }; -} diff --git a/app/actions/inviteLinks.ts b/app/actions/inviteLinks.ts new file mode 100644 index 000000000..3f32865d9 --- /dev/null +++ b/app/actions/inviteLinks.ts @@ -0,0 +1,61 @@ +import { Action } from 'redux'; + +import { TInvite } from '../reducers/inviteLinks'; +import { INVITE_LINKS } from './actionsTypes'; + +interface IInviteLinksGeneric extends Action { + token: string; +} + +interface IInviteLinksCreate extends Action { + rid: string; +} + +interface IInviteLinksSetInvite extends Action { + invite: TInvite; +} + +type TParams = Record; + +interface IInviteLinksSetParams extends Action { + params: TParams; +} + +export type TActionInviteLinks = IInviteLinksGeneric & IInviteLinksCreate & IInviteLinksSetInvite & IInviteLinksSetParams; + +export const inviteLinksSetToken = (token: string): IInviteLinksGeneric => ({ + type: INVITE_LINKS.SET_TOKEN, + token +}); + +export const inviteLinksRequest = (token: string): IInviteLinksGeneric => ({ + type: INVITE_LINKS.REQUEST, + token +}); + +export const inviteLinksSuccess = (): Action => ({ + type: INVITE_LINKS.SUCCESS +}); + +export const inviteLinksFailure = (): Action => ({ + type: INVITE_LINKS.FAILURE +}); + +export const inviteLinksClear = (): Action => ({ + type: INVITE_LINKS.CLEAR +}); + +export const inviteLinksCreate = (rid: string): IInviteLinksCreate => ({ + type: INVITE_LINKS.CREATE, + rid +}); + +export const inviteLinksSetParams = (params: TParams): IInviteLinksSetParams => ({ + type: INVITE_LINKS.SET_PARAMS, + params +}); + +export const inviteLinksSetInvite = (invite: TInvite): IInviteLinksSetInvite => ({ + type: INVITE_LINKS.SET_INVITE, + invite +}); diff --git a/app/actions/messages.js b/app/actions/messages.js deleted file mode 100644 index 9f40809c7..000000000 --- a/app/actions/messages.js +++ /dev/null @@ -1,8 +0,0 @@ -import * as types from './actionsTypes'; - -export function replyBroadcast(message) { - return { - type: types.MESSAGES.REPLY_BROADCAST, - message - }; -} diff --git a/app/actions/messages.ts b/app/actions/messages.ts new file mode 100644 index 000000000..eb0383abf --- /dev/null +++ b/app/actions/messages.ts @@ -0,0 +1,16 @@ +import { Action } from 'redux'; + +import { MESSAGES } from './actionsTypes'; + +type IMessage = Record; + +interface IReplyBroadcast extends Action { + message: IMessage; +} + +export function replyBroadcast(message: IMessage): IReplyBroadcast { + return { + type: MESSAGES.REPLY_BROADCAST, + message + }; +} diff --git a/app/actions/roles.js b/app/actions/roles.js deleted file mode 100644 index 8ee30425b..000000000 --- a/app/actions/roles.js +++ /dev/null @@ -1,20 +0,0 @@ -import * as types from './actionsTypes'; - -export function setRoles(roles) { - return { - type: types.ROLES.SET, - roles - }; -} -export function updateRoles(id, desc) { - return { - type: types.ROLES.UPDATE, - payload: { id, desc } - }; -} -export function removeRoles(id) { - return { - type: types.ROLES.REMOVE, - payload: { id } - }; -} diff --git a/app/actions/roles.ts b/app/actions/roles.ts new file mode 100644 index 000000000..3dbfa370d --- /dev/null +++ b/app/actions/roles.ts @@ -0,0 +1,39 @@ +import { Action } from 'redux'; + +import { IRoles } from '../reducers/roles'; +import { ROLES } from './actionsTypes'; + +export interface ISetRoles extends Action { + roles: IRoles; +} + +export interface IUpdateRoles extends Action { + payload: { id: string; desc: string }; +} + +export interface IRemoveRoles extends Action { + payload: { id: string }; +} + +export type IActionRoles = ISetRoles & IUpdateRoles & IRemoveRoles; + +export function setRoles(roles: IRoles): ISetRoles { + return { + type: ROLES.SET, + roles + }; +} + +export function updateRoles(id: string, desc: string): IUpdateRoles { + return { + type: ROLES.UPDATE, + payload: { id, desc } + }; +} + +export function removeRoles(id: string): IRemoveRoles { + return { + type: ROLES.REMOVE, + payload: { id } + }; +} diff --git a/app/actions/rooms.js b/app/actions/rooms.js deleted file mode 100644 index 0f708f8cf..000000000 --- a/app/actions/rooms.js +++ /dev/null @@ -1,58 +0,0 @@ -import * as types from './actionsTypes'; - -export function roomsRequest(params = { allData: false }) { - return { - type: types.ROOMS.REQUEST, - params - }; -} - -export function roomsSuccess() { - return { - type: types.ROOMS.SUCCESS - }; -} - -export function roomsFailure(err) { - return { - type: types.ROOMS.FAILURE, - err - }; -} - -export function roomsRefresh() { - return { - type: types.ROOMS.REFRESH - }; -} - -export function setSearch(searchText) { - return { - type: types.ROOMS.SET_SEARCH, - searchText - }; -} - -export function closeServerDropdown() { - return { - type: types.ROOMS.CLOSE_SERVER_DROPDOWN - }; -} - -export function toggleServerDropdown() { - return { - type: types.ROOMS.TOGGLE_SERVER_DROPDOWN - }; -} - -export function openSearchHeader() { - return { - type: types.ROOMS.OPEN_SEARCH_HEADER - }; -} - -export function closeSearchHeader() { - return { - type: types.ROOMS.CLOSE_SEARCH_HEADER - }; -} diff --git a/app/actions/rooms.ts b/app/actions/rooms.ts new file mode 100644 index 000000000..514582ff6 --- /dev/null +++ b/app/actions/rooms.ts @@ -0,0 +1,78 @@ +import { Action } from 'redux'; + +import { ROOMS } from './actionsTypes'; + +export interface IRoomsRequest extends Action { + params: any; +} + +export interface ISetSearch extends Action { + searchText: string; +} + +export interface IRoomsFailure extends Action { + err: Record | string; +} + +export type IRoomsAction = IRoomsRequest & ISetSearch & IRoomsFailure; + +export function roomsRequest( + params: { + allData: boolean; + } = { allData: false } +): IRoomsRequest { + return { + type: ROOMS.REQUEST, + params + }; +} + +export function roomsSuccess(): Action { + return { + type: ROOMS.SUCCESS + }; +} + +export function roomsFailure(err: string): IRoomsFailure { + return { + type: ROOMS.FAILURE, + err + }; +} + +export function roomsRefresh(): Action { + return { + type: ROOMS.REFRESH + }; +} + +export function setSearch(searchText: string): ISetSearch { + return { + type: ROOMS.SET_SEARCH, + searchText + }; +} + +export function closeServerDropdown(): Action { + return { + type: ROOMS.CLOSE_SERVER_DROPDOWN + }; +} + +export function toggleServerDropdown(): Action { + return { + type: ROOMS.TOGGLE_SERVER_DROPDOWN + }; +} + +export function openSearchHeader(): Action { + return { + type: ROOMS.OPEN_SEARCH_HEADER + }; +} + +export function closeSearchHeader(): Action { + return { + type: ROOMS.CLOSE_SEARCH_HEADER + }; +} diff --git a/app/actions/server.js b/app/actions/server.js index fea239450..acc7c7cb3 100644 --- a/app/actions/server.js +++ b/app/actions/server.js @@ -24,11 +24,12 @@ export function selectServerFailure() { }; } -export function serverRequest(server, username = null, fromServerHistory = false) { +// TODO +export function serverRequest(server, username, fromServerHistory = false) { return { type: SERVER.REQUEST, server, - username, + username: username || null, fromServerHistory }; } diff --git a/app/actions/settings.js b/app/actions/settings.js deleted file mode 100644 index 6fae375bc..000000000 --- a/app/actions/settings.js +++ /dev/null @@ -1,21 +0,0 @@ -import { SETTINGS } from './actionsTypes'; - -export function addSettings(settings) { - return { - type: SETTINGS.ADD, - payload: settings - }; -} - -export function updateSettings(id, value) { - return { - type: SETTINGS.UPDATE, - payload: { id, value } - }; -} - -export function clearSettings() { - return { - type: SETTINGS.CLEAR - }; -} diff --git a/app/actions/settings.ts b/app/actions/settings.ts new file mode 100644 index 000000000..77b8dcc77 --- /dev/null +++ b/app/actions/settings.ts @@ -0,0 +1,34 @@ +import { Action } from 'redux'; + +import { ISettings, TSettings } from '../reducers/settings'; +import { SETTINGS } from './actionsTypes'; + +interface IAddSettings extends Action { + payload: ISettings; +} + +interface IUpdateSettings extends Action { + payload: { id: string; value: TSettings }; +} + +export type IActionSettings = IAddSettings & IUpdateSettings; + +export function addSettings(settings: ISettings): IAddSettings { + return { + type: SETTINGS.ADD, + payload: settings + }; +} + +export function updateSettings(id: string, value: TSettings): IUpdateSettings { + return { + type: SETTINGS.UPDATE, + payload: { id, value } + }; +} + +export function clearSettings(): Action { + return { + type: SETTINGS.CLEAR + }; +} diff --git a/app/actions/sortPreferences.js b/app/actions/sortPreferences.js deleted file mode 100644 index e452e74c0..000000000 --- a/app/actions/sortPreferences.js +++ /dev/null @@ -1,15 +0,0 @@ -import * as types from './actionsTypes'; - -export function setAllPreferences(preferences) { - return { - type: types.SORT_PREFERENCES.SET_ALL, - preferences - }; -} - -export function setPreference(preference) { - return { - type: types.SORT_PREFERENCES.SET, - preference - }; -} diff --git a/app/actions/sortPreferences.ts b/app/actions/sortPreferences.ts new file mode 100644 index 000000000..6a3328616 --- /dev/null +++ b/app/actions/sortPreferences.ts @@ -0,0 +1,28 @@ +import { Action } from 'redux'; + +import { IPreferences } from '../definitions'; +import { SORT_PREFERENCES } from './actionsTypes'; + +interface ISetAllPreferences extends Action { + preferences: IPreferences; +} + +interface ISetPreference extends Action { + preference: Partial; +} + +export type TActionSortPreferences = ISetAllPreferences & ISetPreference; + +export function setAllPreferences(preferences: IPreferences): ISetAllPreferences { + return { + type: SORT_PREFERENCES.SET_ALL, + preferences + }; +} + +export function setPreference(preference: Partial): ISetPreference { + return { + type: SORT_PREFERENCES.SET, + preference + }; +} diff --git a/app/actions/usersTyping.js b/app/actions/usersTyping.js deleted file mode 100644 index fb8f5980b..000000000 --- a/app/actions/usersTyping.js +++ /dev/null @@ -1,21 +0,0 @@ -import { USERS_TYPING } from './actionsTypes'; - -export function addUserTyping(username) { - return { - type: USERS_TYPING.ADD, - username - }; -} - -export function removeUserTyping(username) { - return { - type: USERS_TYPING.REMOVE, - username - }; -} - -export function clearUserTyping() { - return { - type: USERS_TYPING.CLEAR - }; -} diff --git a/app/actions/usersTyping.ts b/app/actions/usersTyping.ts new file mode 100644 index 000000000..19077ce65 --- /dev/null +++ b/app/actions/usersTyping.ts @@ -0,0 +1,29 @@ +import { Action } from 'redux'; + +import { USERS_TYPING } from './actionsTypes'; + +export interface IUsersTypingGenericAction extends Action { + username: string; +} + +export type TActionUserTyping = IUsersTypingGenericAction & Action; + +export function addUserTyping(username: string): IUsersTypingGenericAction { + return { + type: USERS_TYPING.ADD, + username + }; +} + +export function removeUserTyping(username: string): IUsersTypingGenericAction { + return { + type: USERS_TYPING.REMOVE, + username + }; +} + +export function clearUserTyping(): Action { + return { + type: USERS_TYPING.CLEAR + }; +} diff --git a/app/containers/RoomHeader/index.tsx b/app/containers/RoomHeader/index.tsx index fb00bc10c..4c21ecba2 100644 --- a/app/containers/RoomHeader/index.tsx +++ b/app/containers/RoomHeader/index.tsx @@ -1,10 +1,11 @@ +import { dequal } from 'dequal'; import React, { Component } from 'react'; import { connect } from 'react-redux'; -import { dequal } from 'dequal'; -import RoomHeader from './RoomHeader'; +import { IApplicationState } from '../../definitions'; import { withDimensions } from '../../dimensions'; import I18n from '../../i18n'; +import RoomHeader from './RoomHeader'; interface IRoomHeaderContainerProps { title: string; @@ -122,8 +123,8 @@ class RoomHeaderContainer extends Component { } } -const mapStateToProps = (state: any, ownProps: any) => { - let statusText; +const mapStateToProps = (state: IApplicationState, ownProps: any) => { + let statusText = ''; let status = 'offline'; const { roomUserId, type, visitor = {}, tmid } = ownProps; diff --git a/app/definitions/IPreferences.ts b/app/definitions/IPreferences.ts new file mode 100644 index 000000000..d444dd7e4 --- /dev/null +++ b/app/definitions/IPreferences.ts @@ -0,0 +1,10 @@ +import { SortBy, DisplayMode } from '../constants/constantDisplayMode'; + +export interface IPreferences { + sortBy: SortBy; + groupByType: boolean; + showFavorites: boolean; + showUnread: boolean; + showAvatar: boolean; + displayMode: DisplayMode; +} diff --git a/app/definitions/index.ts b/app/definitions/index.ts index 80eeb88ca..5abdd95c3 100644 --- a/app/definitions/index.ts +++ b/app/definitions/index.ts @@ -8,6 +8,8 @@ export * from './INotification'; export * from './IRoom'; export * from './IServer'; export * from './ISubscription'; +export * from './IPreferences'; +export * from './IServerHistory'; export interface IBaseScreen, S extends string> { navigation: StackNavigationProp; diff --git a/app/definitions/redux/index.ts b/app/definitions/redux/index.ts index 1b9941979..e43b1e878 100644 --- a/app/definitions/redux/index.ts +++ b/app/definitions/redux/index.ts @@ -1,12 +1,24 @@ -import { TActionSelectedUsers } from '../../actions/selectedUsers'; import { TActionActiveUsers } from '../../actions/activeUsers'; +import { TActionCustomEmojis } from '../../actions/customEmojis'; +import { TActionEncryption } from '../../actions/encryption'; +import { TActionInviteLinks } from '../../actions/inviteLinks'; +import { IActionRoles } from '../../actions/roles'; +import { TActionSelectedUsers } from '../../actions/selectedUsers'; +import { IActionSettings } from '../../actions/settings'; +import { TActionSortPreferences } from '../../actions/sortPreferences'; +import { TActionUserTyping } from '../../actions/usersTyping'; // REDUCERS import { IActiveUsers } from '../../reducers/activeUsers'; +import { IEncryption } from '../../reducers/encryption'; +import { IInviteLinks } from '../../reducers/inviteLinks'; +import { IRoles } from '../../reducers/roles'; import { ISelectedUsers } from '../../reducers/selectedUsers'; import { IConnect } from '../../reducers/connect'; +import { ISettings } from '../../reducers/settings'; + export interface IApplicationState { - settings: any; + settings: ISettings; login: any; meteor: IConnect; server: any; @@ -20,13 +32,21 @@ export interface IApplicationState { customEmojis: any; activeUsers: IActiveUsers; usersTyping: any; - inviteLinks: any; + inviteLinks: IInviteLinks; createDiscussion: any; inquiry: any; enterpriseModules: any; - encryption: any; + encryption: IEncryption; permissions: any; - roles: any; + roles: IRoles; } -export type TApplicationActions = TActionActiveUsers & TActionSelectedUsers; +export type TApplicationActions = TActionActiveUsers & + TActionSelectedUsers & + TActionCustomEmojis & + TActionInviteLinks & + IActionRoles & + IActionSettings & + TActionEncryption & + TActionSortPreferences & + TActionUserTyping; diff --git a/app/reducers/activeUsers.ts b/app/reducers/activeUsers.ts index 9877a5ceb..1c32a13fb 100644 --- a/app/reducers/activeUsers.ts +++ b/app/reducers/activeUsers.ts @@ -4,7 +4,7 @@ import { SET_ACTIVE_USERS } from '../actions/actionsTypes'; type TUserStatus = 'online' | 'offline'; export interface IActiveUser { status: TUserStatus; - statusText?: string; + statusText: string; } export interface IActiveUsers { diff --git a/app/reducers/customEmojis.js b/app/reducers/customEmojis.js deleted file mode 100644 index fbdaeab80..000000000 --- a/app/reducers/customEmojis.js +++ /dev/null @@ -1,14 +0,0 @@ -import { SET_CUSTOM_EMOJIS } from '../actions/actionsTypes'; - -const initialState = { - customEmojis: {} -}; - -export default function customEmojis(state = initialState, action) { - switch (action.type) { - case SET_CUSTOM_EMOJIS: - return action.emojis; - default: - return state; - } -} diff --git a/app/reducers/customEmojis.test.ts b/app/reducers/customEmojis.test.ts new file mode 100644 index 000000000..3f507f04c --- /dev/null +++ b/app/reducers/customEmojis.test.ts @@ -0,0 +1,16 @@ +import { setCustomEmojis } from '../actions/customEmojis'; +import { ICustomEmojis, initialState } from './customEmojis'; +import { mockedStore } from './mockedStore'; + +describe('test reducer', () => { + it('should return initial state', () => { + const state = mockedStore.getState().customEmojis; + expect(state).toEqual(initialState); + }); + it('should return modified store after action', () => { + const emojis: ICustomEmojis = { dog: { name: 'dog', extension: 'jpg' }, cat: { name: 'cat', extension: 'jpg' } }; + mockedStore.dispatch(setCustomEmojis(emojis)); + const state = mockedStore.getState().customEmojis; + expect(state).toEqual(emojis); + }); +}); diff --git a/app/reducers/customEmojis.ts b/app/reducers/customEmojis.ts new file mode 100644 index 000000000..859d634d4 --- /dev/null +++ b/app/reducers/customEmojis.ts @@ -0,0 +1,23 @@ +import { SET_CUSTOM_EMOJIS } from '../actions/actionsTypes'; +import { TApplicationActions } from '../definitions'; + +// There are at least three interfaces for emoji, but none of them includes only this data. +interface IEmoji { + name: string; + extension: string; +} + +export interface ICustomEmojis { + [key: string]: IEmoji; +} + +export const initialState: ICustomEmojis = {}; + +export default function customEmojis(state = initialState, action: TApplicationActions): ICustomEmojis { + switch (action.type) { + case SET_CUSTOM_EMOJIS: + return action.emojis; + default: + return state; + } +} diff --git a/app/reducers/encryption.test.ts b/app/reducers/encryption.test.ts new file mode 100644 index 000000000..96abe2a7a --- /dev/null +++ b/app/reducers/encryption.test.ts @@ -0,0 +1,28 @@ +import { encryptionSet, encryptionInit, encryptionSetBanner } from '../actions/encryption'; +import { mockedStore } from './mockedStore'; +import { initialState } from './encryption'; + +describe('test encryption reducer', () => { + it('should return initial state', () => { + const state = mockedStore.getState().encryption; + expect(state).toEqual(initialState); + }); + + it('should return modified store after encryptionSet', () => { + mockedStore.dispatch(encryptionSet(true, 'BANNER')); + const state = mockedStore.getState().encryption; + expect(state).toEqual({ banner: 'BANNER', enabled: true }); + }); + + it('should return empty store after encryptionInit', () => { + mockedStore.dispatch(encryptionInit()); + const state = mockedStore.getState().encryption; + expect(state).toEqual({ banner: '', enabled: false }); + }); + + it('should return initial state after encryptionSetBanner', () => { + mockedStore.dispatch(encryptionSetBanner('BANNER_NEW')); + const state = mockedStore.getState().encryption; + expect(state).toEqual({ banner: 'BANNER_NEW', enabled: false }); + }); +}); diff --git a/app/reducers/encryption.js b/app/reducers/encryption.ts similarity index 54% rename from app/reducers/encryption.js rename to app/reducers/encryption.ts index 0145ae2d1..061dc7c94 100644 --- a/app/reducers/encryption.js +++ b/app/reducers/encryption.ts @@ -1,11 +1,18 @@ import { ENCRYPTION } from '../actions/actionsTypes'; +import { TApplicationActions } from '../definitions'; -const initialState = { +export type IBanner = string; +export interface IEncryption { + enabled: boolean; + banner: IBanner; +} + +export const initialState: IEncryption = { enabled: false, - banner: null + banner: '' }; -export default function encryption(state = initialState, action) { +export default function encryption(state = initialState, action: TApplicationActions): IEncryption { switch (action.type) { case ENCRYPTION.SET: return { diff --git a/app/reducers/inviteLinks.test.ts b/app/reducers/inviteLinks.test.ts new file mode 100644 index 000000000..ed1a34a46 --- /dev/null +++ b/app/reducers/inviteLinks.test.ts @@ -0,0 +1,72 @@ +import { + inviteLinksClear, + inviteLinksFailure, + inviteLinksRequest, + inviteLinksSetInvite, + inviteLinksSetParams, + inviteLinksSetToken, + inviteLinksSuccess +} from '../actions/inviteLinks'; +import { initialState } from './inviteLinks'; +import { mockedStore } from './mockedStore'; + +describe('test roles reducer', () => { + const invite = { + _id: 'nZestg', + days: 1, + maxUses: 0, + createdAt: '2022-01-17T20:32:44.695Z', + expires: '2022-01-18T20:32:44.695Z', + uses: 0, + _updatedAt: '2022-01-17T20:32:44.695Z', + url: 'https://go.rocket.chat/invite?host=open.rocket.chat&path=invite%2FnZestg', + success: true, + token: '' + }; + it('should return initial state', () => { + const state = mockedStore.getState().inviteLinks; + expect(state).toEqual(initialState); + }); + + it('should return initialState after call inviteLinksFailure', () => { + mockedStore.dispatch(inviteLinksFailure()); + const state = mockedStore.getState().inviteLinks; + expect(state).toEqual(initialState); + }); + + it('should return initialState after call inviteLinksSuccess', () => { + mockedStore.dispatch(inviteLinksSuccess()); + const state = mockedStore.getState().inviteLinks; + expect(state).toEqual(initialState); + }); + + it('should return correctly token after call inviteLinksSetToken', () => { + mockedStore.dispatch(inviteLinksSetToken('xxx')); + const { token } = mockedStore.getState().inviteLinks; + expect(token).toEqual('xxx'); + }); + + it('should return correctly invite value after call inviteLinksSetInvite', () => { + mockedStore.dispatch(inviteLinksSetInvite(invite)); + const state = mockedStore.getState().inviteLinks; + expect(state.invite).toEqual(invite); + }); + + it('should return modified store after call inviteLinksSetParams', () => { + mockedStore.dispatch(inviteLinksSetParams({ token: 'nZestg' })); + const { token } = mockedStore.getState().inviteLinks; + expect(token).toEqual('nZestg'); + }); + + it('should return initialState after call inviteLinksClear', () => { + mockedStore.dispatch(inviteLinksClear()); + const state = mockedStore.getState().inviteLinks; + expect(state).toEqual(initialState); + }); + + it('should return actual state after call inviteLinksRequest', () => { + mockedStore.dispatch(inviteLinksRequest('xxx')); + const state = mockedStore.getState().inviteLinks; + expect(state).toEqual(initialState); + }); +}); diff --git a/app/reducers/inviteLinks.js b/app/reducers/inviteLinks.ts similarity index 53% rename from app/reducers/inviteLinks.js rename to app/reducers/inviteLinks.ts index 2126c4896..9ccd36e76 100644 --- a/app/reducers/inviteLinks.js +++ b/app/reducers/inviteLinks.ts @@ -1,18 +1,26 @@ +import { TActionInviteLinks } from '../actions/inviteLinks'; import { INVITE_LINKS } from '../actions/actionsTypes'; -const initialState = { +export type TInvite = { url: string; expires: string; maxUses: number; uses: number; [x: string]: any }; + +export interface IInviteLinks { + token: string; + days: number; + maxUses: number; + invite: TInvite; +} + +export const initialState: IInviteLinks = { token: '', days: 1, maxUses: 0, - invite: {} + invite: { url: '', expires: '', maxUses: 0, uses: 0 } }; -export default (state = initialState, action) => { +export default (state = initialState, action: TActionInviteLinks): IInviteLinks => { switch (action.type) { case INVITE_LINKS.SET_TOKEN: - return { - token: action.token - }; + return { ...state, token: action.token }; case INVITE_LINKS.SET_PARAMS: return { ...state, diff --git a/app/reducers/roles.test.ts b/app/reducers/roles.test.ts new file mode 100644 index 000000000..8348a8712 --- /dev/null +++ b/app/reducers/roles.test.ts @@ -0,0 +1,35 @@ +import { setRoles, updateRoles, removeRoles } from '../actions/roles'; +import { mockedStore } from './mockedStore'; +import { initialState } from './roles'; + +describe('test roles reducer', () => { + it('should return initial state', () => { + const state = mockedStore.getState().roles; + expect(state).toEqual(initialState); + }); + + it('should return modified store after call setRoles action', () => { + const roles = { admin: 'enabled', user: 'enabled', dog: 'carlitos' }; + mockedStore.dispatch(setRoles(roles)); + const state = mockedStore.getState().roles; + expect(state.admin).toEqual('enabled'); + expect(state.user).toEqual('enabled'); + expect(state.dog).toEqual('carlitos'); + }); + + it('should return modified store after call updateRoles action', () => { + mockedStore.dispatch(updateRoles('admin', 'disabled')); + const state = mockedStore.getState().roles; + expect(state.admin).toEqual('disabled'); + expect(state.user).toEqual('enabled'); + expect(state.dog).toEqual('carlitos'); + }); + + it('should return modified store after call removeRoles action', () => { + mockedStore.dispatch(removeRoles('dog')); + const state = mockedStore.getState().roles; + expect(state.admin).toEqual('disabled'); + expect(state.user).toEqual('enabled'); + expect(state.dog).toEqual(undefined); + }); +}); diff --git a/app/reducers/roles.js b/app/reducers/roles.ts similarity index 63% rename from app/reducers/roles.js rename to app/reducers/roles.ts index 93cbffcb0..fc4f11248 100644 --- a/app/reducers/roles.js +++ b/app/reducers/roles.ts @@ -1,8 +1,11 @@ import { ROLES } from '../actions/actionsTypes'; +import { IActionRoles } from '../actions/roles'; -const initialState = {}; +export type IRoles = Record; -export default function permissions(state = initialState, action) { +export const initialState: IRoles = {}; + +export default function roles(state = initialState, action: IActionRoles): IRoles { switch (action.type) { case ROLES.SET: return action.roles; diff --git a/app/reducers/rooms.test.ts b/app/reducers/rooms.test.ts new file mode 100644 index 000000000..4bf1312ec --- /dev/null +++ b/app/reducers/rooms.test.ts @@ -0,0 +1,77 @@ +import { + closeSearchHeader, + closeServerDropdown, + openSearchHeader, + roomsFailure, + roomsRefresh, + roomsRequest, + roomsSuccess, + setSearch, + toggleServerDropdown +} from '../actions/rooms'; +import { mockedStore } from './mockedStore'; +import { initialState } from './rooms'; + +describe('test selectedUsers reducer', () => { + it('should return initial state', () => { + const state = mockedStore.getState().rooms; + expect(state).toEqual(initialState); + }); + + it('should return modified store after call roomsRequest', () => { + mockedStore.dispatch(roomsRequest()); + const state = mockedStore.getState().rooms; + const manipulated = { ...initialState, isFetching: true, failure: false, errorMessage: {} }; + expect(state).toEqual(manipulated); + }); + + it('should return modified store after call roomsSuccess', () => { + mockedStore.dispatch(roomsSuccess()); + const state = mockedStore.getState().rooms; + const manipulated = { ...initialState, isFetching: false, refreshing: false }; + expect(state).toEqual(manipulated); + }); + + it('should return modified store after call roomsRefresh', () => { + mockedStore.dispatch(roomsRefresh()); + const state = mockedStore.getState().rooms; + const manipulated = { ...initialState, isFetching: true, refreshing: true }; + expect(state).toEqual(manipulated); + }); + + it('should return modified store after call setSearch', () => { + mockedStore.dispatch(setSearch('dog')); + const state = mockedStore.getState().rooms; + expect(state.searchText).toEqual('dog'); + }); + + it('should return modified store after call closeServerDropdown', () => { + mockedStore.dispatch(closeServerDropdown()); + const state = mockedStore.getState().rooms; + expect(state.closeServerDropdown).toEqual(!initialState.closeServerDropdown); + }); + + it('should return modified store after call toggleServerDropdown', () => { + mockedStore.dispatch(toggleServerDropdown()); + const state = mockedStore.getState().rooms; + expect(state.showServerDropdown).toEqual(!initialState.showServerDropdown); + }); + + it('should return modified store after call openSearchHeader', () => { + mockedStore.dispatch(openSearchHeader()); + const state = mockedStore.getState().rooms; + expect(state.showSearchHeader).toEqual(true); + }); + + it('should return modified store after call closeSearchHeader', () => { + mockedStore.dispatch(closeSearchHeader()); + const state = mockedStore.getState().rooms; + expect(state.showSearchHeader).toEqual(false); + }); + + it('should return modified store after call roomsFailure', () => { + mockedStore.dispatch(roomsFailure('error')); + const state = mockedStore.getState().rooms; + expect(state.errorMessage).toEqual('error'); + }); +}); diff --git a/app/reducers/rooms.js b/app/reducers/rooms.ts similarity index 57% rename from app/reducers/rooms.js rename to app/reducers/rooms.ts index 660f5f1e7..1a6705086 100644 --- a/app/reducers/rooms.js +++ b/app/reducers/rooms.ts @@ -1,6 +1,18 @@ -import * as types from '../actions/actionsTypes'; +import { IRoomsAction } from '../actions/rooms'; +import { ROOMS } from '../actions/actionsTypes'; -const initialState = { +export interface IRooms { + isFetching: boolean; + refreshing: boolean; + failure: boolean; + errorMessage: Record | string; + searchText: string; + showServerDropdown: boolean; + closeServerDropdown: boolean; + showSearchHeader: boolean; +} + +export const initialState: IRooms = { isFetching: false, refreshing: false, failure: false, @@ -11,22 +23,22 @@ const initialState = { showSearchHeader: false }; -export default function login(state = initialState, action) { +export default function rooms(state = initialState, action: IRoomsAction): IRooms { switch (action.type) { - case types.ROOMS.REQUEST: + case ROOMS.REQUEST: return { ...state, isFetching: true, failure: false, errorMessage: {} }; - case types.ROOMS.SUCCESS: + case ROOMS.SUCCESS: return { ...state, isFetching: false, refreshing: false }; - case types.ROOMS.FAILURE: + case ROOMS.FAILURE: return { ...state, isFetching: false, @@ -34,33 +46,33 @@ export default function login(state = initialState, action) { failure: true, errorMessage: action.err }; - case types.ROOMS.REFRESH: + case ROOMS.REFRESH: return { ...state, isFetching: true, refreshing: true }; - case types.ROOMS.SET_SEARCH: + case ROOMS.SET_SEARCH: return { ...state, searchText: action.searchText }; - case types.ROOMS.CLOSE_SERVER_DROPDOWN: + case ROOMS.CLOSE_SERVER_DROPDOWN: return { ...state, closeServerDropdown: !state.closeServerDropdown }; - case types.ROOMS.TOGGLE_SERVER_DROPDOWN: + case ROOMS.TOGGLE_SERVER_DROPDOWN: return { ...state, showServerDropdown: !state.showServerDropdown }; - case types.ROOMS.OPEN_SEARCH_HEADER: + case ROOMS.OPEN_SEARCH_HEADER: return { ...state, showSearchHeader: true }; - case types.ROOMS.CLOSE_SEARCH_HEADER: + case ROOMS.CLOSE_SEARCH_HEADER: return { ...state, showSearchHeader: false diff --git a/app/reducers/settings.test.ts b/app/reducers/settings.test.ts new file mode 100644 index 000000000..da93ce3cc --- /dev/null +++ b/app/reducers/settings.test.ts @@ -0,0 +1,31 @@ +import { addSettings, clearSettings, updateSettings } from '../actions/settings'; +import { mockedStore } from './mockedStore'; +import { initialState } from './settings'; + +describe('test settings reducer', () => { + it('should return initial state', () => { + const state = mockedStore.getState().settings; + expect(state).toEqual(initialState); + }); + + const settings = { API_Use_REST_For_DDP_Calls: true, FileUpload_MaxFileSize: 600857600, Jitsi_URL_Room_Prefix: 'RocketChat' }; + + it('should return modified store after call addSettings action', () => { + mockedStore.dispatch(addSettings(settings)); + const state = mockedStore.getState().settings; + expect(state).toEqual(settings); + }); + + it('should return correctly settings after call updateSettings action', () => { + const id = 'Jitsi_URL_Room_Prefix'; + mockedStore.dispatch(updateSettings(id, 'ChatRocket')); + const state = mockedStore.getState().settings; + expect(state[id]).toEqual('ChatRocket'); + }); + + it('should return initial state after clearSettings', () => { + mockedStore.dispatch(clearSettings()); + const state = mockedStore.getState().settings; + expect(state).toEqual({}); + }); +}); diff --git a/app/reducers/settings.js b/app/reducers/settings.ts similarity index 54% rename from app/reducers/settings.js rename to app/reducers/settings.ts index 6e9ab5005..028431ed0 100644 --- a/app/reducers/settings.js +++ b/app/reducers/settings.ts @@ -1,8 +1,13 @@ +import { IActionSettings } from '../actions/settings'; import { SETTINGS } from '../actions/actionsTypes'; -const initialState = {}; +export type TSettings = string | number | boolean; -export default (state = initialState, action) => { +export type ISettings = Record; + +export const initialState: ISettings = {}; + +export default (state = initialState, action: IActionSettings): ISettings => { switch (action.type) { case SETTINGS.ADD: return { diff --git a/app/reducers/sortPreferences.test.ts b/app/reducers/sortPreferences.test.ts new file mode 100644 index 000000000..5de29933d --- /dev/null +++ b/app/reducers/sortPreferences.test.ts @@ -0,0 +1,35 @@ +import { IPreferences } from '../definitions'; +import { setAllPreferences, setPreference } from '../actions/sortPreferences'; +import { mockedStore } from './mockedStore'; +import { initialState } from './sortPreferences'; +import { DisplayMode, SortBy } from '../constants/constantDisplayMode'; + +describe('test sortPreferences reducer', () => { + it('should return initial state', () => { + const state = mockedStore.getState().sortPreferences; + expect(state).toEqual(initialState); + }); + + it('should return correctly value after call setPreference action', () => { + const preferences: IPreferences = { + displayMode: DisplayMode.Condensed, + groupByType: true, + showAvatar: true, + showFavorites: true, + showUnread: true, + sortBy: SortBy.Activity + }; + mockedStore.dispatch(setAllPreferences(preferences)); + const state = mockedStore.getState().sortPreferences; + expect(state).toEqual(preferences); + }); + + it('should return correctly value after call setPreference action', () => { + const preference: Partial = { + displayMode: DisplayMode.Expanded + }; + mockedStore.dispatch(setPreference(preference)); + const { displayMode } = mockedStore.getState().sortPreferences; + expect(displayMode).toEqual(DisplayMode.Expanded); + }); +}); diff --git a/app/reducers/sortPreferences.js b/app/reducers/sortPreferences.ts similarity index 72% rename from app/reducers/sortPreferences.js rename to app/reducers/sortPreferences.ts index 4ad9e797d..2083e8f7a 100644 --- a/app/reducers/sortPreferences.js +++ b/app/reducers/sortPreferences.ts @@ -1,7 +1,8 @@ import { SORT_PREFERENCES } from '../actions/actionsTypes'; import { DisplayMode, SortBy } from '../constants/constantDisplayMode'; +import { IPreferences, TApplicationActions } from '../definitions'; -const initialState = { +export const initialState: IPreferences = { sortBy: SortBy.Activity, groupByType: false, showFavorites: false, @@ -10,7 +11,7 @@ const initialState = { displayMode: DisplayMode.Expanded }; -export default (state = initialState, action) => { +export default (state = initialState, action: TApplicationActions): IPreferences => { switch (action.type) { case SORT_PREFERENCES.SET_ALL: return { diff --git a/app/reducers/usersTyping.test.ts b/app/reducers/usersTyping.test.ts new file mode 100644 index 000000000..26e527882 --- /dev/null +++ b/app/reducers/usersTyping.test.ts @@ -0,0 +1,30 @@ +import { addUserTyping, removeUserTyping, clearUserTyping } from '../actions/usersTyping'; +import { mockedStore } from './mockedStore'; +import { initialState } from './usersTyping'; + +describe('test usersTyping reducer', () => { + it('should return initial state', () => { + const state = mockedStore.getState().usersTyping; + expect(state).toEqual(initialState); + }); + + it('should return modified store after addUserTyping', () => { + mockedStore.dispatch(addUserTyping('diego')); + mockedStore.dispatch(addUserTyping('carlos')); + mockedStore.dispatch(addUserTyping('maria')); + const state = mockedStore.getState().usersTyping; + expect(state).toEqual(['diego', 'carlos', 'maria']); + }); + + it('should return modified store after removeUserTyping', () => { + mockedStore.dispatch(removeUserTyping('diego')); + const state = mockedStore.getState().usersTyping; + expect(state).toEqual(['carlos', 'maria']); + }); + + it('should return initial state after reset', () => { + mockedStore.dispatch(clearUserTyping()); + const state = mockedStore.getState().usersTyping; + expect(state).toEqual(initialState); + }); +}); diff --git a/app/reducers/usersTyping.js b/app/reducers/usersTyping.ts similarity index 72% rename from app/reducers/usersTyping.js rename to app/reducers/usersTyping.ts index acecab632..ecfbbb77d 100644 --- a/app/reducers/usersTyping.js +++ b/app/reducers/usersTyping.ts @@ -1,8 +1,11 @@ import { USERS_TYPING } from '../actions/actionsTypes'; +import { TApplicationActions } from '../definitions'; -const initialState = []; +export type IUsersTyping = string[]; -export default function usersTyping(state = initialState, action) { +export const initialState: IUsersTyping = []; + +export default function usersTyping(state = initialState, action: TApplicationActions): IUsersTyping { switch (action.type) { case USERS_TYPING.ADD: if (state.findIndex(item => item === action.username) === -1) { diff --git a/app/views/DisplayPrefsView.tsx b/app/views/DisplayPrefsView.tsx index 959682c4c..f793eb920 100644 --- a/app/views/DisplayPrefsView.tsx +++ b/app/views/DisplayPrefsView.tsx @@ -1,31 +1,23 @@ +import { StackNavigationProp } from '@react-navigation/stack'; import React, { useEffect } from 'react'; import { Switch } from 'react-native'; import { RadioButton } from 'react-native-ui-lib'; -import { StackNavigationProp } from '@react-navigation/stack'; import { useDispatch, useSelector } from 'react-redux'; import { setPreference } from '../actions/sortPreferences'; -import RocketChat from '../lib/rocketchat'; -import StatusBar from '../containers/StatusBar'; -import I18n from '../i18n'; -import * as List from '../containers/List'; -import { useTheme } from '../theme'; import { themes } from '../constants/colors'; -import * as HeaderButton from '../containers/HeaderButton'; -import SafeAreaView from '../containers/SafeAreaView'; -import { ICON_SIZE } from '../containers/List/constants'; -import log, { events, logEvent } from '../utils/log'; import { DisplayMode, SortBy } from '../constants/constantDisplayMode'; +import * as HeaderButton from '../containers/HeaderButton'; +import * as List from '../containers/List'; +import { ICON_SIZE } from '../containers/List/constants'; +import SafeAreaView from '../containers/SafeAreaView'; +import StatusBar from '../containers/StatusBar'; +import { IApplicationState, IPreferences } from '../definitions'; +import I18n from '../i18n'; +import RocketChat from '../lib/rocketchat'; import { SettingsStackParamList } from '../stacks/types'; - -interface IParam { - sortBy: SortBy; - groupByType: boolean; - showFavorites: boolean; - showUnread: boolean; - showAvatar: boolean; - displayMode: DisplayMode; -} +import { useTheme } from '../theme'; +import log, { events, logEvent } from '../utils/log'; interface IDisplayPrefsView { navigation: StackNavigationProp; @@ -36,7 +28,7 @@ const DisplayPrefsView = (props: IDisplayPrefsView): JSX.Element => { const { theme } = useTheme(); const { sortBy, groupByType, showFavorites, showUnread, showAvatar, displayMode } = useSelector( - (state: any) => state.sortPreferences + (state: IApplicationState) => state.sortPreferences ); const { isMasterDetail } = useSelector((state: any) => state.app); const dispatch = useDispatch(); @@ -53,7 +45,7 @@ const DisplayPrefsView = (props: IDisplayPrefsView): JSX.Element => { } }, []); - const setSortPreference = async (param: Partial) => { + const setSortPreference = async (param: Partial) => { try { dispatch(setPreference(param)); await RocketChat.saveSortPreference(param); diff --git a/app/views/E2EEnterYourPasswordView.tsx b/app/views/E2EEnterYourPasswordView.tsx index 6d63f90dd..6e08b07b9 100644 --- a/app/views/E2EEnterYourPasswordView.tsx +++ b/app/views/E2EEnterYourPasswordView.tsx @@ -1,23 +1,23 @@ +import { StackNavigationOptions } from '@react-navigation/stack'; import React from 'react'; import { ScrollView, StyleSheet, Text } from 'react-native'; import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; -import I18n from '../i18n'; -import { withTheme } from '../theme'; -import Button from '../containers/Button'; +import { encryptionDecodeKey } from '../actions/encryption'; import { themes } from '../constants/colors'; -import TextInput from '../containers/TextInput'; -import SafeAreaView from '../containers/SafeAreaView'; +import Button from '../containers/Button'; import * as HeaderButton from '../containers/HeaderButton'; -import { encryptionDecodeKey as encryptionDecodeKeyAction } from '../actions/encryption'; -import scrollPersistTaps from '../utils/scrollPersistTaps'; -import KeyboardView from '../presentation/KeyboardView'; +import SafeAreaView from '../containers/SafeAreaView'; import StatusBar from '../containers/StatusBar'; -import { events, logEvent } from '../utils/log'; -import sharedStyles from './Styles'; +import TextInput from '../containers/TextInput'; +import { IBaseScreen } from '../definitions'; +import I18n from '../i18n'; +import KeyboardView from '../presentation/KeyboardView'; import { E2EEnterYourPasswordStackParamList } from '../stacks/types'; +import { withTheme } from '../theme'; +import { events, logEvent } from '../utils/log'; +import scrollPersistTaps from '../utils/scrollPersistTaps'; +import sharedStyles from './Styles'; const styles = StyleSheet.create({ container: { @@ -34,21 +34,17 @@ interface IE2EEnterYourPasswordViewState { password: string; } -interface IE2EEnterYourPasswordViewProps { - encryptionDecodeKey: (password: string) => void; - theme: string; - navigation: StackNavigationProp; -} +type TE2EEnterYourPasswordViewProps = IBaseScreen; -class E2EEnterYourPasswordView extends React.Component { +class E2EEnterYourPasswordView extends React.Component { private passwordInput?: TextInput; - static navigationOptions = ({ navigation }: Pick): StackNavigationOptions => ({ + static navigationOptions = ({ navigation }: Pick): StackNavigationOptions => ({ headerLeft: () => , title: I18n.t('Enter_Your_E2E_Password') }); - constructor(props: IE2EEnterYourPasswordViewProps) { + constructor(props: TE2EEnterYourPasswordViewProps) { super(props); this.state = { password: '' @@ -58,8 +54,8 @@ class E2EEnterYourPasswordView extends React.Component { logEvent(events.E2E_ENTER_PW_SUBMIT); const { password } = this.state; - const { encryptionDecodeKey } = this.props; - encryptionDecodeKey(password); + const { dispatch } = this.props; + dispatch(encryptionDecodeKey(password)); }; render() { @@ -109,7 +105,4 @@ class E2EEnterYourPasswordView extends React.Component ({ - encryptionDecodeKey: (password: string) => dispatch(encryptionDecodeKeyAction(password)) -}); -export default connect(null, mapDispatchToProps)(withTheme(E2EEnterYourPasswordView)); +export default connect(null)(withTheme(E2EEnterYourPasswordView)); diff --git a/app/views/E2ESaveYourPasswordView.tsx b/app/views/E2ESaveYourPasswordView.tsx index 3d9a32ee1..cc7bac83f 100644 --- a/app/views/E2ESaveYourPasswordView.tsx +++ b/app/views/E2ESaveYourPasswordView.tsx @@ -1,25 +1,24 @@ import React from 'react'; -import { StackNavigationProp } from '@react-navigation/stack'; -import { Dispatch } from 'redux'; -import { connect } from 'react-redux'; import { Clipboard, ScrollView, StyleSheet, Text, View } from 'react-native'; +import { connect } from 'react-redux'; -import { encryptionSetBanner as encryptionSetBannerAction } from '../actions/encryption'; -import { E2E_RANDOM_PASSWORD_KEY } from '../lib/encryption/constants'; +import { encryptionSetBanner } from '../actions/encryption'; +import { themes } from '../constants/colors'; +import Button from '../containers/Button'; import * as HeaderButton from '../containers/HeaderButton'; -import scrollPersistTaps from '../utils/scrollPersistTaps'; import SafeAreaView from '../containers/SafeAreaView'; -import UserPreferences from '../lib/userPreferences'; -import { events, logEvent } from '../utils/log'; import StatusBar from '../containers/StatusBar'; import { LISTENER } from '../containers/Toast'; -import { themes } from '../constants/colors'; -import EventEmitter from '../utils/events'; -import Button from '../containers/Button'; -import { withTheme } from '../theme'; +import { IApplicationState, IBaseScreen } from '../definitions'; import I18n from '../i18n'; -import sharedStyles from './Styles'; +import { E2E_RANDOM_PASSWORD_KEY } from '../lib/encryption/constants'; +import UserPreferences from '../lib/userPreferences'; import { E2ESaveYourPasswordStackParamList } from '../stacks/types'; +import { withTheme } from '../theme'; +import EventEmitter from '../utils/events'; +import { events, logEvent } from '../utils/log'; +import scrollPersistTaps from '../utils/scrollPersistTaps'; +import sharedStyles from './Styles'; const styles = StyleSheet.create({ container: { @@ -59,11 +58,8 @@ interface IE2ESaveYourPasswordViewState { password: string; } -interface IE2ESaveYourPasswordViewProps { +interface IE2ESaveYourPasswordViewProps extends IBaseScreen { server: string; - navigation: StackNavigationProp; - encryptionSetBanner(): void; - theme: string; } class E2ESaveYourPasswordView extends React.Component { @@ -103,11 +99,11 @@ class E2ESaveYourPasswordView extends React.Component { logEvent(events.E2E_SAVE_PW_SAVED); - const { navigation, server, encryptionSetBanner } = this.props; + const { navigation, server, dispatch } = this.props; // Remove stored password await UserPreferences.removeItem(`${server}-${E2E_RANDOM_PASSWORD_KEY}`); // Hide encryption banner - encryptionSetBanner(); + dispatch(encryptionSetBanner()); navigation.pop(); }; @@ -173,10 +169,8 @@ class E2ESaveYourPasswordView extends React.Component ({ +const mapStateToProps = (state: IApplicationState) => ({ server: state.server.server }); -const mapDispatchToProps = (dispatch: Dispatch) => ({ - encryptionSetBanner: () => dispatch(encryptionSetBannerAction()) -}); -export default connect(mapStateToProps, mapDispatchToProps)(withTheme(E2ESaveYourPasswordView)); + +export default connect(mapStateToProps)(withTheme(E2ESaveYourPasswordView)); diff --git a/app/views/InviteUsersEditView/index.tsx b/app/views/InviteUsersEditView/index.tsx index 4ae1a67df..10f356ae3 100644 --- a/app/views/InviteUsersEditView/index.tsx +++ b/app/views/InviteUsersEditView/index.tsx @@ -1,25 +1,21 @@ +import { StackNavigationOptions } from '@react-navigation/stack'; import React from 'react'; import { TextInputProps, View } from 'react-native'; -import { connect } from 'react-redux'; import RNPickerSelect from 'react-native-picker-select'; -import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; -import { RouteProp } from '@react-navigation/core'; -import { Dispatch } from 'redux'; +import { connect } from 'react-redux'; -import { - inviteLinksCreate as inviteLinksCreateAction, - inviteLinksSetParams as inviteLinksSetParamsAction -} from '../../actions/inviteLinks'; -import * as List from '../../containers/List'; -import Button from '../../containers/Button'; -import I18n from '../../i18n'; -import StatusBar from '../../containers/StatusBar'; +import { inviteLinksCreate, inviteLinksSetParams } from '../../actions/inviteLinks'; import { themes } from '../../constants/colors'; -import { withTheme } from '../../theme'; +import Button from '../../containers/Button'; +import * as List from '../../containers/List'; import SafeAreaView from '../../containers/SafeAreaView'; +import StatusBar from '../../containers/StatusBar'; +import { IApplicationState, IBaseScreen } from '../../definitions'; +import I18n from '../../i18n'; +import { ChatsStackParamList } from '../../stacks/types'; +import { withTheme } from '../../theme'; import { events, logEvent } from '../../utils/log'; import styles from './styles'; -import { ChatsStackParamList } from '../../stacks/types'; const OPTIONS = { days: [ @@ -68,12 +64,7 @@ const OPTIONS = { ] }; -interface IInviteUsersEditViewProps { - navigation: StackNavigationProp; - route: RouteProp; - theme: string; - createInviteLink(rid: string): void; - inviteLinksSetParams(params: { [key: string]: number }): void; +interface IInviteUsersEditViewProps extends IBaseScreen { days: number; maxUses: number; } @@ -91,18 +82,18 @@ class InviteUsersEditView extends React.Component { + const { dispatch } = this.props; logEvent(events.IU_EDIT_SET_LINK_PARAM); - const { inviteLinksSetParams } = this.props; const params = { [key]: value }; - inviteLinksSetParams(params); + dispatch(inviteLinksSetParams(params)); }; createInviteLink = () => { + const { dispatch, navigation } = this.props; logEvent(events.IU_EDIT_CREATE_LINK); - const { createInviteLink, navigation } = this.props; - createInviteLink(this.rid); + dispatch(inviteLinksCreate(this.rid)); navigation.pop(); }; @@ -151,14 +142,9 @@ class InviteUsersEditView extends React.Component ({ +const mapStateToProps = (state: IApplicationState) => ({ days: state.inviteLinks.days, maxUses: state.inviteLinks.maxUses }); -const mapDispatchToProps = (dispatch: Dispatch) => ({ - inviteLinksSetParams: (params: object) => dispatch(inviteLinksSetParamsAction(params)), - createInviteLink: (rid: string) => dispatch(inviteLinksCreateAction(rid)) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(withTheme(InviteUsersEditView)); +export default connect(mapStateToProps)(withTheme(InviteUsersEditView)); diff --git a/app/views/InviteUsersView/index.tsx b/app/views/InviteUsersView/index.tsx index 60ae339ad..51838f27a 100644 --- a/app/views/InviteUsersView/index.tsx +++ b/app/views/InviteUsersView/index.tsx @@ -1,62 +1,49 @@ +import { StackNavigationOptions } from '@react-navigation/stack'; +import moment from 'moment'; import React from 'react'; import { ScrollView, Share, View } from 'react-native'; -import moment from 'moment'; import { connect } from 'react-redux'; -import { StackNavigationProp, StackNavigationOptions } from '@react-navigation/stack'; -import { RouteProp } from '@react-navigation/core'; -import { Dispatch } from 'redux'; -import { ChatsStackParamList } from '../../stacks/types'; -import { - inviteLinksClear as inviteLinksClearAction, - inviteLinksCreate as inviteLinksCreateAction -} from '../../actions/inviteLinks'; -import RCTextInput from '../../containers/TextInput'; -import Markdown from '../../containers/markdown'; -import Button from '../../containers/Button'; -import scrollPersistTaps from '../../utils/scrollPersistTaps'; -import I18n from '../../i18n'; -import StatusBar from '../../containers/StatusBar'; +import { inviteLinksClear, inviteLinksCreate } from '../../actions/inviteLinks'; import { themes } from '../../constants/colors'; -import { withTheme } from '../../theme'; +import Button from '../../containers/Button'; +import Markdown from '../../containers/markdown'; import SafeAreaView from '../../containers/SafeAreaView'; +import StatusBar from '../../containers/StatusBar'; +import RCTextInput from '../../containers/TextInput'; +import { IApplicationState, IBaseScreen } from '../../definitions'; +import I18n from '../../i18n'; +import { TInvite } from '../../reducers/inviteLinks'; +import { ChatsStackParamList } from '../../stacks/types'; +import { withTheme } from '../../theme'; import { events, logEvent } from '../../utils/log'; +import scrollPersistTaps from '../../utils/scrollPersistTaps'; import styles from './styles'; -interface IInviteUsersViewProps { - navigation: StackNavigationProp; - route: RouteProp; - theme: string; +interface IInviteUsersViewProps extends IBaseScreen { timeDateFormat: string; - invite: { - url: string; - expires: number; - maxUses: number; - uses: number; - }; - createInviteLink(rid: string): void; - clearInviteLink(): void; + invite: TInvite; } class InviteUsersView extends React.Component { - private rid: string; - static navigationOptions = (): StackNavigationOptions => ({ title: I18n.t('Invite_users') }); + private rid: string; + constructor(props: IInviteUsersViewProps) { super(props); this.rid = props.route.params?.rid; } componentDidMount() { - const { createInviteLink } = this.props; - createInviteLink(this.rid); + const { dispatch } = this.props; + dispatch(inviteLinksCreate(this.rid)); } componentWillUnmount() { - const { clearInviteLink } = this.props; - clearInviteLink(); + const { dispatch } = this.props; + dispatch(inviteLinksClear()); } share = () => { @@ -133,16 +120,9 @@ class InviteUsersView extends React.Component { } } -const mapStateToProps = (state: any) => ({ - timeDateFormat: state.settings.Message_TimeAndDateFormat, - days: state.inviteLinks.days, - maxUses: state.inviteLinks.maxUses, +const mapStateToProps = (state: IApplicationState) => ({ + timeDateFormat: state.settings.Message_TimeAndDateFormat as string, invite: state.inviteLinks.invite }); -const mapDispatchToProps = (dispatch: Dispatch) => ({ - createInviteLink: (rid: string) => dispatch(inviteLinksCreateAction(rid)), - clearInviteLink: () => dispatch(inviteLinksClearAction()) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(withTheme(InviteUsersView)); +export default connect(mapStateToProps)(withTheme(InviteUsersView)); diff --git a/app/views/NewServerView/index.tsx b/app/views/NewServerView/index.tsx index 93e493bea..191895ceb 100644 --- a/app/views/NewServerView/index.tsx +++ b/app/views/NewServerView/index.tsx @@ -1,39 +1,37 @@ -import React from 'react'; -import { Text, Keyboard, StyleSheet, View, BackHandler, Image } from 'react-native'; -import { connect } from 'react-redux'; -import { Base64 } from 'js-base64'; -import parse from 'url-parse'; import { Q } from '@nozbe/watermelondb'; +import { Base64 } from 'js-base64'; +import React from 'react'; +import { BackHandler, Image, Keyboard, StyleSheet, Text, View } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; import Orientation from 'react-native-orientation-locker'; -import { StackNavigationProp } from '@react-navigation/stack'; -import { Dispatch } from 'redux'; +import { connect } from 'react-redux'; +import parse from 'url-parse'; -import UserPreferences from '../../lib/userPreferences'; -import EventEmitter from '../../utils/events'; -import { selectServerRequest, serverRequest, serverFinishAdd as serverFinishAddAction } from '../../actions/server'; -import { inviteLinksClear as inviteLinksClearAction } from '../../actions/inviteLinks'; -import sharedStyles from '../Styles'; -import Button from '../../containers/Button'; -import OrSeparator from '../../containers/OrSeparator'; -import FormContainer, { FormContainerInner } from '../../containers/FormContainer'; -import I18n from '../../i18n'; +import { inviteLinksClear } from '../../actions/inviteLinks'; +import { selectServerRequest, serverFinishAdd, serverRequest } from '../../actions/server'; import { themes } from '../../constants/colors'; -import { events, logEvent } from '../../utils/log'; -import { withTheme } from '../../theme'; -import { BASIC_AUTH_KEY, setBasicAuth } from '../../utils/fetch'; +import Button from '../../containers/Button'; +import FormContainer, { FormContainerInner } from '../../containers/FormContainer'; import * as HeaderButton from '../../containers/HeaderButton'; -import { showConfirmationAlert } from '../../utils/info'; +import OrSeparator from '../../containers/OrSeparator'; +import { IBaseScreen, TServerHistory } from '../../definitions'; +import { withDimensions } from '../../dimensions'; +import I18n from '../../i18n'; import database from '../../lib/database'; import { sanitizeLikeString } from '../../lib/database/utils'; -import SSLPinning from '../../utils/sslPinning'; import RocketChat from '../../lib/rocketchat'; -import { isTablet } from '../../utils/deviceInfo'; -import { verticalScale, moderateScale } from '../../utils/scaling'; -import { withDimensions } from '../../dimensions'; -import ServerInput from './ServerInput'; +import UserPreferences from '../../lib/userPreferences'; import { OutsideParamList } from '../../stacks/types'; -import { TServerHistory } from '../../definitions/IServerHistory'; +import { withTheme } from '../../theme'; +import { isTablet } from '../../utils/deviceInfo'; +import EventEmitter from '../../utils/events'; +import { BASIC_AUTH_KEY, setBasicAuth } from '../../utils/fetch'; +import { showConfirmationAlert } from '../../utils/info'; +import { events, logEvent } from '../../utils/log'; +import { moderateScale, verticalScale } from '../../utils/scaling'; +import SSLPinning from '../../utils/sslPinning'; +import sharedStyles from '../Styles'; +import ServerInput from './ServerInput'; const styles = StyleSheet.create({ onboardingImage: { @@ -68,20 +66,14 @@ const styles = StyleSheet.create({ } }); -interface INewServerView { - navigation: StackNavigationProp; - theme: string; +interface INewServerViewProps extends IBaseScreen { connecting: boolean; - connectServer(server: string, username?: string, fromServerHistory?: boolean): void; - selectServer(server: string): void; previousServer: string; - inviteLinksClear(): void; - serverFinishAdd(): void; width: number; height: number; } -interface IState { +interface INewServerViewState { text: string; connectingOpen: boolean; certificate: any; @@ -93,8 +85,8 @@ interface ISubmitParams { username?: string; } -class NewServerView extends React.Component { - constructor(props: INewServerView) { +class NewServerView extends React.Component { + constructor(props: INewServerViewProps) { super(props); if (!isTablet) { Orientation.lockToPortrait(); @@ -118,9 +110,9 @@ class NewServerView extends React.Component { componentWillUnmount() { EventEmitter.removeListener('NewServer', this.handleNewServerEvent); BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress); - const { previousServer, serverFinishAdd } = this.props; + const { previousServer, dispatch } = this.props; if (previousServer) { - serverFinishAdd(); + dispatch(serverFinishAdd()); } } @@ -169,9 +161,9 @@ class NewServerView extends React.Component { }; close = () => { - const { selectServer, previousServer, inviteLinksClear } = this.props; - inviteLinksClear(); - selectServer(previousServer); + const { dispatch, previousServer } = this.props; + dispatch(inviteLinksClear()); + dispatch(selectServerRequest(previousServer)); }; handleNewServerEvent = (event: { server: string }) => { @@ -179,10 +171,10 @@ class NewServerView extends React.Component { if (!server) { return; } - const { connectServer } = this.props; + const { dispatch } = this.props; this.setState({ text: server }); server = this.completeUrl(server); - connectServer(server); + dispatch(serverRequest(server)); }; onPressServerHistory = (serverHistory: TServerHistory) => { @@ -192,7 +184,7 @@ class NewServerView extends React.Component { submit = async ({ fromServerHistory = false, username }: ISubmitParams = {}) => { logEvent(events.NS_CONNECT_TO_WORKSPACE); const { text, certificate } = this.state; - const { connectServer } = this.props; + const { dispatch } = this.props; this.setState({ connectingOpen: false }); @@ -207,9 +199,9 @@ class NewServerView extends React.Component { await this.basicAuth(server, text); if (fromServerHistory) { - connectServer(server, username, true); + dispatch(serverRequest(server, username, true)); } else { - connectServer(server); + dispatch(serverRequest(server)); } } }; @@ -217,8 +209,8 @@ class NewServerView extends React.Component { connectOpen = () => { logEvent(events.NS_JOIN_OPEN_WORKSPACE); this.setState({ connectingOpen: true }); - const { connectServer } = this.props; - connectServer('https://open.rocket.chat'); + const { dispatch } = this.props; + dispatch(serverRequest('https://open.rocket.chat')); }; basicAuth = async (server: string, text: string) => { @@ -283,7 +275,7 @@ class NewServerView extends React.Component { await db.write(async () => { await item.destroyPermanently(); }); - this.setState((prevstate: IState) => ({ + this.setState((prevstate: INewServerViewState) => ({ serversHistory: prevstate.serversHistory.filter((server: TServerHistory) => server.id !== item.id) })); } catch { @@ -417,12 +409,4 @@ const mapStateToProps = (state: any) => ({ previousServer: state.server.previousServer }); -const mapDispatchToProps = (dispatch: Dispatch) => ({ - connectServer: (server: string, username: string & null, fromServerHistory?: boolean) => - dispatch(serverRequest(server, username, fromServerHistory)), - selectServer: (server: string) => dispatch(selectServerRequest(server)), - inviteLinksClear: () => dispatch(inviteLinksClearAction()), - serverFinishAdd: () => dispatch(serverFinishAddAction()) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withTheme(NewServerView))); +export default connect(mapStateToProps)(withDimensions(withTheme(NewServerView))); diff --git a/app/views/RoomsListView/Header/index.js b/app/views/RoomsListView/Header/index.js index b97f65e15..e77358784 100644 --- a/app/views/RoomsListView/Header/index.js +++ b/app/views/RoomsListView/Header/index.js @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { toggleServerDropdown, closeServerDropdown, setSearch as setSearchAction } from '../../../actions/rooms'; +import { toggleServerDropdown, closeServerDropdown, setSearch } from '../../../actions/rooms'; import { withTheme } from '../../../theme'; import EventEmitter from '../../../utils/events'; import { KEY_COMMAND, handleCommandOpenServerDropdown } from '../../../commands'; @@ -19,10 +19,7 @@ class RoomsListHeaderView extends PureComponent { connected: PropTypes.bool, isFetching: PropTypes.bool, theme: PropTypes.string, - server: PropTypes.string, - open: PropTypes.func, - close: PropTypes.func, - setSearch: PropTypes.func + server: PropTypes.string }; componentDidMount() { @@ -45,17 +42,17 @@ class RoomsListHeaderView extends PureComponent { }; onSearchChangeText = text => { - const { setSearch } = this.props; - setSearch(text.trim()); + const { dispatch } = this.props; + dispatch(setSearch(text.trim())); }; onPress = () => { logEvent(events.RL_TOGGLE_SERVER_DROPDOWN); - const { showServerDropdown, close, open } = this.props; + const { showServerDropdown, dispatch } = this.props; if (showServerDropdown) { - close(); + dispatch(closeServerDropdown()); } else { - open(); + dispatch(toggleServerDropdown()); } }; @@ -89,10 +86,4 @@ const mapStateToProps = state => ({ server: state.server.server }); -const mapDispatchtoProps = dispatch => ({ - close: () => dispatch(closeServerDropdown()), - open: () => dispatch(toggleServerDropdown()), - setSearch: searchText => dispatch(setSearchAction(searchText)) -}); - -export default connect(mapStateToProps, mapDispatchtoProps)(withTheme(RoomsListHeaderView)); +export default connect(mapStateToProps)(withTheme(RoomsListHeaderView)); diff --git a/app/views/RoomsListView/ServerDropdown.js b/app/views/RoomsListView/ServerDropdown.js index 97b52d666..8dd42ee92 100644 --- a/app/views/RoomsListView/ServerDropdown.js +++ b/app/views/RoomsListView/ServerDropdown.js @@ -6,9 +6,9 @@ import { withSafeAreaInsets } from 'react-native-safe-area-context'; import * as List from '../../containers/List'; import Button from '../../containers/Button'; -import { toggleServerDropdown as toggleServerDropdownAction } from '../../actions/rooms'; -import { selectServerRequest as selectServerRequestAction, serverInitAdd as serverInitAddAction } from '../../actions/server'; -import { appStart as appStartAction, ROOT_OUTSIDE } from '../../actions/app'; +import { toggleServerDropdown } from '../../actions/rooms'; +import { selectServerRequest, serverInitAdd } from '../../actions/server'; +import { appStart, ROOT_OUTSIDE } from '../../actions/app'; import RocketChat from '../../lib/rocketchat'; import I18n from '../../i18n'; import EventEmitter from '../../utils/events'; @@ -36,11 +36,7 @@ class ServerDropdown extends Component { closeServerDropdown: PropTypes.bool, server: PropTypes.string, theme: PropTypes.string, - isMasterDetail: PropTypes.bool, - appStart: PropTypes.func, - toggleServerDropdown: PropTypes.func, - selectServerRequest: PropTypes.func, - initAdd: PropTypes.func + isMasterDetail: PropTypes.bool }; constructor(props) { @@ -89,13 +85,13 @@ class ServerDropdown extends Component { } close = () => { - const { toggleServerDropdown } = this.props; + const { dispatch } = this.props; Animated.timing(this.animatedValue, { toValue: 0, duration: ANIMATION_DURATION, easing: Easing.inOut(Easing.quad), useNativeDriver: true - }).start(() => toggleServerDropdown()); + }).start(() => dispatch(toggleServerDropdown())); }; createWorkspace = async () => { @@ -108,10 +104,10 @@ class ServerDropdown extends Component { }; navToNewServer = previousServer => { - const { appStart, initAdd } = this.props; + const { dispatch } = this.props; batch(() => { - appStart({ root: ROOT_OUTSIDE }); - initAdd(previousServer); + dispatch(appStart({ root: ROOT_OUTSIDE })); + dispatch(serverInitAdd(previousServer)); }); }; @@ -125,7 +121,7 @@ class ServerDropdown extends Component { }; select = async (server, version) => { - const { server: currentServer, selectServerRequest, isMasterDetail } = this.props; + const { server: currentServer, dispatch, isMasterDetail } = this.props; this.close(); if (currentServer !== server) { logEvent(events.RL_CHANGE_SERVER); @@ -142,7 +138,7 @@ class ServerDropdown extends Component { }, ANIMATION_DURATION); } else { await localAuthenticate(server); - selectServerRequest(server, version); + dispatch(selectServerRequest(server, version, true, true)); } } }; @@ -263,11 +259,4 @@ const mapStateToProps = state => ({ isMasterDetail: state.app.isMasterDetail }); -const mapDispatchToProps = dispatch => ({ - toggleServerDropdown: () => dispatch(toggleServerDropdownAction()), - selectServerRequest: (server, version) => dispatch(selectServerRequestAction(server, version, true, true)), - appStart: params => dispatch(appStartAction(params)), - initAdd: previousServer => dispatch(serverInitAddAction(previousServer)) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(withSafeAreaInsets(withTheme(ServerDropdown))); +export default connect(mapStateToProps)(withSafeAreaInsets(withTheme(ServerDropdown))); diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 9dc3bca73..1ee94cee6 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -12,19 +12,13 @@ import RocketChat from '../../lib/rocketchat'; import RoomItem, { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from '../../presentation/RoomItem'; import log, { logEvent, events } from '../../utils/log'; import I18n from '../../i18n'; -import { - closeSearchHeader as closeSearchHeaderAction, - closeServerDropdown as closeServerDropdownAction, - openSearchHeader as openSearchHeaderAction, - roomsRequest as roomsRequestAction -} from '../../actions/rooms'; -import { appStart as appStartAction, ROOT_OUTSIDE } from '../../actions/app'; +import { closeSearchHeader, closeServerDropdown, openSearchHeader, roomsRequest } from '../../actions/rooms'; +import { appStart, ROOT_OUTSIDE } from '../../actions/app'; import debounce from '../../utils/debounce'; import { isIOS, isTablet } from '../../utils/deviceInfo'; import * as HeaderButton from '../../containers/HeaderButton'; import StatusBar from '../../containers/StatusBar'; import ActivityIndicator from '../../containers/ActivityIndicator'; -import { selectServerRequest as selectServerRequestAction, serverInitAdd as serverInitAddAction } from '../../actions/server'; import { animateNextTransition } from '../../utils/layoutAnimation'; import { withTheme } from '../../theme'; import { themes } from '../../constants/colors'; @@ -124,11 +118,6 @@ class RoomsListView extends React.Component { refreshing: PropTypes.bool, StoreLastMessage: PropTypes.bool, theme: PropTypes.string, - openSearchHeader: PropTypes.func, - closeSearchHeader: PropTypes.func, - appStart: PropTypes.func, - roomsRequest: PropTypes.func, - closeServerDropdown: PropTypes.func, useRealName: PropTypes.bool, isMasterDetail: PropTypes.bool, rooms: PropTypes.array, @@ -169,7 +158,7 @@ class RoomsListView extends React.Component { } componentDidMount() { - const { navigation, closeServerDropdown } = this.props; + const { navigation, dispatch } = this.props; this.handleHasPermission(); this.mounted = true; @@ -193,7 +182,7 @@ class RoomsListView extends React.Component { }); this.unsubscribeBlur = navigation.addListener('blur', () => { this.animated = false; - closeServerDropdown(); + dispatch(closeServerDropdown()); this.cancelSearch(); if (this.backHandler && this.backHandler.remove) { this.backHandler.remove(); @@ -553,9 +542,9 @@ class RoomsListView extends React.Component { initSearching = () => { logEvent(events.RL_SEARCH); - const { openSearchHeader } = this.props; + const { dispatch } = this.props; this.internalSetState({ searching: true }, () => { - openSearchHeader(); + dispatch(openSearchHeader()); this.search(''); this.setHeader(); }); @@ -563,7 +552,7 @@ class RoomsListView extends React.Component { cancelSearch = () => { const { searching } = this.state; - const { closeSearchHeader } = this.props; + const { dispatch } = this.props; if (!searching) { return; @@ -573,7 +562,7 @@ class RoomsListView extends React.Component { this.setState({ searching: false, search: [] }, () => { this.setHeader(); - closeSearchHeader(); + dispatch(closeSearchHeader()); setTimeout(() => { this.scrollToTop(); }, 200); @@ -842,7 +831,7 @@ class RoomsListView extends React.Component { }; handleCommands = ({ event }) => { - const { navigation, server, isMasterDetail, appStart, initAdd } = this.props; + const { navigation, server, isMasterDetail, dispatch, initAdd } = this.props; const { input } = event; if (handleCommandShowPreferences(event)) { navigation.navigate('SettingsView'); @@ -862,7 +851,7 @@ class RoomsListView extends React.Component { } } else if (handleCommandAddNewServer(event)) { batch(() => { - appStart({ root: ROOT_OUTSIDE }); + dispatch(appStart({ root: ROOT_OUTSIDE })); initAdd(server); }); } @@ -870,11 +859,11 @@ class RoomsListView extends React.Component { onRefresh = () => { const { searching } = this.state; - const { roomsRequest } = this.props; + const { dispatch } = this.props; if (searching) { return; } - roomsRequest({ allData: true }); + dispatch(roomsRequest({ allData: true })); }; onEndReached = () => { @@ -1045,14 +1034,4 @@ const mapStateToProps = state => ({ createDiscussionPermission: state.permissions['start-discussion'] }); -const mapDispatchToProps = dispatch => ({ - openSearchHeader: () => dispatch(openSearchHeaderAction()), - closeSearchHeader: () => dispatch(closeSearchHeaderAction()), - roomsRequest: params => dispatch(roomsRequestAction(params)), - selectServerRequest: server => dispatch(selectServerRequestAction(server)), - closeServerDropdown: () => dispatch(closeServerDropdownAction()), - appStart: params => dispatch(appStartAction(params)), - initAdd: previousServer => dispatch(serverInitAddAction(previousServer)) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withTheme(withSafeAreaInsets(RoomsListView)))); +export default connect(mapStateToProps)(withDimensions(withTheme(withSafeAreaInsets(RoomsListView)))); diff --git a/app/views/TeamChannelsView.tsx b/app/views/TeamChannelsView.tsx index bf2df4ff1..160c28ff5 100644 --- a/app/views/TeamChannelsView.tsx +++ b/app/views/TeamChannelsView.tsx @@ -1,36 +1,36 @@ +import { Q } from '@nozbe/watermelondb'; +import { HeaderBackButton, StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; import React from 'react'; import { Alert, FlatList, Keyboard } from 'react-native'; -import { RouteProp } from '@react-navigation/native'; -import { Dispatch } from 'redux'; -import { Q } from '@nozbe/watermelondb'; import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context'; import { connect } from 'react-redux'; -import { HeaderBackButton, StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; -import StatusBar from '../containers/StatusBar'; -import RoomHeader from '../containers/RoomHeader'; -import { withTheme } from '../theme'; -import log, { events, logEvent } from '../utils/log'; -import database from '../lib/database'; -import { getUserSelector } from '../selectors/login'; +import { deleteRoom } from '../actions/room'; +import { themes } from '../constants/colors'; +import { withActionSheet } from '../containers/ActionSheet'; +import ActivityIndicator from '../containers/ActivityIndicator'; +import BackgroundContainer from '../containers/BackgroundContainer'; import { getHeaderTitlePosition } from '../containers/Header'; import * as HeaderButton from '../containers/HeaderButton'; -import BackgroundContainer from '../containers/BackgroundContainer'; +import RoomHeader from '../containers/RoomHeader'; import SafeAreaView from '../containers/SafeAreaView'; -import ActivityIndicator from '../containers/ActivityIndicator'; import SearchHeader from '../containers/SearchHeader'; -import RoomItem, { ROW_HEIGHT } from '../presentation/RoomItem'; -import RocketChat from '../lib/rocketchat'; +import StatusBar from '../containers/StatusBar'; +import { IApplicationState, IBaseScreen } from '../definitions'; import { withDimensions } from '../dimensions'; -import { isIOS } from '../utils/deviceInfo'; -import debounce from '../utils/debounce'; -import { showErrorAlert } from '../utils/info'; -import { goRoom } from '../utils/goRoom'; import I18n from '../i18n'; -import { withActionSheet } from '../containers/ActionSheet'; -import { deleteRoom as deleteRoomAction } from '../actions/room'; +import database from '../lib/database'; import { CustomIcon } from '../lib/Icons'; -import { themes } from '../constants/colors'; +import RocketChat from '../lib/rocketchat'; +import RoomItem, { ROW_HEIGHT } from '../presentation/RoomItem'; +import { getUserSelector } from '../selectors/login'; +import { ChatsStackParamList } from '../stacks/types'; +import { withTheme } from '../theme'; +import debounce from '../utils/debounce'; +import { isIOS } from '../utils/deviceInfo'; +import { goRoom } from '../utils/goRoom'; +import { showErrorAlert } from '../utils/info'; +import log, { events, logEvent } from '../utils/log'; const API_FETCH_COUNT = 25; const PERMISSION_DELETE_C = 'delete-c'; @@ -78,9 +78,11 @@ interface ITeamChannelsViewState { showCreate: boolean; } -interface ITeamChannelsViewProps { - route: RouteProp<{ TeamChannelsView: { teamId: string } }, 'TeamChannelsView'>; +type IProps = Omit, 'navigation'> & { navigation: StackNavigationProp; +}; + +interface ITeamChannelsViewProps extends IProps { isMasterDetail: boolean; insets: EdgeInsets; theme: string; @@ -93,7 +95,6 @@ interface ITeamChannelsViewProps { deleteCPermission: string[]; deletePPermission: string[]; showActionSheet: (options: any) => void; - deleteRoom: (rid: string, t: string) => void; showAvatar: boolean; displayMode: string; } @@ -422,7 +423,7 @@ class TeamChannelsView extends React.Component { logEvent(events.TC_DELETE_ROOM); - const { deleteRoom } = this.props; + const { dispatch } = this.props; Alert.alert( I18n.t('Are_you_sure_question_mark'), @@ -435,7 +436,7 @@ class TeamChannelsView extends React.Component deleteRoom(item._id, item.t) + onPress: () => dispatch(deleteRoom(item._id, item.t)) } ], { cancelable: false } @@ -574,7 +575,7 @@ class TeamChannelsView extends React.Component ({ +const mapStateToProps = (state: IApplicationState) => ({ baseUrl: state.server.server, user: getUserSelector(state), useRealName: state.settings.UI_Use_Real_Name, @@ -589,11 +590,4 @@ const mapStateToProps = (state: any) => ({ displayMode: state.sortPreferences.displayMode }); -const mapDispatchToProps = (dispatch: Dispatch) => ({ - deleteRoom: (rid: string, t: string) => dispatch(deleteRoomAction(rid, t)) -}); - -export default connect( - mapStateToProps, - mapDispatchToProps -)(withDimensions(withSafeAreaInsets(withTheme(withActionSheet(TeamChannelsView))))); +export default connect(mapStateToProps)(withDimensions(withSafeAreaInsets(withTheme(withActionSheet(TeamChannelsView)))));