diff --git a/app/containers/RoomTypeIcon/OmnichannelRoomIcon.tsx b/app/containers/RoomTypeIcon/OmnichannelRoomIcon.tsx index 864a55155..8ea4517cc 100644 --- a/app/containers/RoomTypeIcon/OmnichannelRoomIcon.tsx +++ b/app/containers/RoomTypeIcon/OmnichannelRoomIcon.tsx @@ -1,10 +1,10 @@ import React from 'react'; import { StyleProp, ViewStyle } from 'react-native'; import { SvgUri } from 'react-native-svg'; -import { useSelector } from 'react-redux'; -import { OmnichannelSourceType, IApplicationState, IOmnichannelSource } from '../../definitions'; +import { OmnichannelSourceType, IOmnichannelSource } from '../../definitions'; import { STATUS_COLORS } from '../../lib/constants'; +import { useAppSelector } from '../../lib/hooks'; import { CustomIcon, TIconsName } from '../CustomIcon'; interface IIconMap { @@ -29,8 +29,8 @@ interface IOmnichannelRoomIconProps { } export const OmnichannelRoomIcon = ({ size, style, sourceType, status }: IOmnichannelRoomIconProps) => { - const baseUrl = useSelector((state: IApplicationState) => state.server?.server); - const connected = useSelector((state: IApplicationState) => state.meteor?.connected); + const baseUrl = useAppSelector(state => state.server?.server); + const connected = useAppSelector(state => state.meteor?.connected); if (sourceType?.type === OmnichannelSourceType.APP && sourceType.id && sourceType.sidebarIcon && connected) { return ( diff --git a/app/containers/Status/index.tsx b/app/containers/Status/index.tsx index 0e5d55497..b925c6949 100644 --- a/app/containers/Status/index.tsx +++ b/app/containers/Status/index.tsx @@ -1,12 +1,12 @@ import React from 'react'; -import { useSelector } from 'react-redux'; -import { IApplicationState, TUserStatus } from '../../definitions'; +import { TUserStatus } from '../../definitions'; import Status from './Status'; import { IStatus } from './definition'; +import { useAppSelector } from '../../lib/hooks'; const StatusContainer = ({ id, style, size = 32, ...props }: Omit): React.ReactElement => { - const status = useSelector((state: IApplicationState) => + const status = useAppSelector(state => state.meteor.connected ? state.activeUsers[id] && state.activeUsers[id].status : 'loading' ) as TUserStatus; return ; diff --git a/app/lib/hooks/index.ts b/app/lib/hooks/index.ts new file mode 100644 index 000000000..e32a49c6b --- /dev/null +++ b/app/lib/hooks/index.ts @@ -0,0 +1 @@ +export * from './useAppSelector'; diff --git a/app/lib/hooks/useAppSelector.ts b/app/lib/hooks/useAppSelector.ts new file mode 100644 index 000000000..58c524b6b --- /dev/null +++ b/app/lib/hooks/useAppSelector.ts @@ -0,0 +1,5 @@ +import { TypedUseSelectorHook, useSelector } from 'react-redux'; + +import { IApplicationState } from '../../definitions'; + +export const useAppSelector: TypedUseSelectorHook = useSelector; diff --git a/app/lib/methods/useServer.ts b/app/lib/methods/useServer.ts index c282a5cf6..60e367a01 100644 --- a/app/lib/methods/useServer.ts +++ b/app/lib/methods/useServer.ts @@ -1,13 +1,13 @@ import { useEffect, useState } from 'react'; -import { useSelector } from 'react-redux'; import { IApplicationState, TServerModel } from '../../definitions'; import database from '../database'; +import { useAppSelector } from '../hooks'; export default function useServer() { const [server, setServer] = useState(null); - const shareServer = useSelector((state: IApplicationState) => state.share.server.server); - const appServer = useSelector((state: IApplicationState) => state.server.server); + const shareServer = useAppSelector((state: IApplicationState) => state.share.server.server); + const appServer = useAppSelector((state: IApplicationState) => state.server.server); useEffect(() => { async function init() { diff --git a/app/views/AuthLoadingView.tsx b/app/views/AuthLoadingView.tsx index b3402afec..075ff7cd1 100644 --- a/app/views/AuthLoadingView.tsx +++ b/app/views/AuthLoadingView.tsx @@ -1,12 +1,11 @@ import React from 'react'; import { ActivityIndicator, StyleSheet, Text, View } from 'react-native'; -import { useSelector } from 'react-redux'; -import { IApplicationState } from '../definitions'; import I18n from '../i18n'; import StatusBar from '../containers/StatusBar'; import { useTheme } from '../theme'; import sharedStyles from './Styles'; +import { useAppSelector } from '../lib/hooks'; const styles = StyleSheet.create({ container: { @@ -23,7 +22,7 @@ const styles = StyleSheet.create({ }); const AuthLoadingView = React.memo((): React.ReactElement => { - const text = useSelector((state: IApplicationState) => state.app.text); + const text = useAppSelector(state => state.app.text); const { colors } = useTheme(); return ( diff --git a/app/views/CannedResponseDetail.tsx b/app/views/CannedResponseDetail.tsx index d27d00c13..afd137bd9 100644 --- a/app/views/CannedResponseDetail.tsx +++ b/app/views/CannedResponseDetail.tsx @@ -2,7 +2,6 @@ import React, { useEffect } from 'react'; import { StackNavigationProp } from '@react-navigation/stack'; import { RouteProp } from '@react-navigation/native'; import { StyleSheet, Text, View, ScrollView } from 'react-native'; -import { useSelector } from 'react-redux'; import I18n from '../i18n'; import SafeAreaView from '../containers/SafeAreaView'; @@ -17,6 +16,7 @@ import { ICannedResponse } from '../definitions/ICannedResponse'; import { ChatsStackParamList } from '../stacks/types'; import sharedStyles from './Styles'; import { getRoomTitle, getUidDirectMessage } from '../lib/methods'; +import { useAppSelector } from '../lib/hooks'; const styles = StyleSheet.create({ scroll: { @@ -96,8 +96,8 @@ interface ICannedResponseDetailProps { const CannedResponseDetail = ({ navigation, route }: ICannedResponseDetailProps): JSX.Element => { const { cannedResponse } = route?.params; const { theme } = useTheme(); - const { isMasterDetail } = useSelector((state: any) => state.app); - const { rooms } = useSelector((state: any) => state.room); + const { isMasterDetail } = useAppSelector(state => state.app); + const { rooms } = useAppSelector(state => state.room); useEffect(() => { navigation.setOptions({ diff --git a/app/views/CannedResponsesListView/index.tsx b/app/views/CannedResponsesListView/index.tsx index 33ae96d09..16817ac09 100644 --- a/app/views/CannedResponsesListView/index.tsx +++ b/app/views/CannedResponsesListView/index.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useState, useCallback } from 'react'; import { FlatList } from 'react-native'; -import { useSelector } from 'react-redux'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { RouteProp } from '@react-navigation/native'; import { HeaderBackButton, StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; @@ -30,8 +29,8 @@ import { ChatsStackParamList } from '../../stacks/types'; import { ISubscription } from '../../definitions/ISubscription'; import { getRoomTitle, getUidDirectMessage } from '../../lib/methods'; import { Services } from '../../lib/services'; -import { IApplicationState } from '../../definitions'; import { ILivechatDepartment } from '../../definitions/ILivechatDepartment'; +import { useAppSelector } from '../../lib/hooks'; const COUNT = 25; @@ -76,8 +75,8 @@ const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListView const insets = useSafeAreaInsets(); const { theme } = useTheme(); - const isMasterDetail = useSelector((state: IApplicationState) => state.app.isMasterDetail); - const rooms = useSelector((state: IApplicationState) => state.room.rooms); + const isMasterDetail = useAppSelector(state => state.app.isMasterDetail); + const rooms = useAppSelector(state => state.room.rooms); const getRoomFromDb = async () => { const { rid } = route.params; diff --git a/app/views/DiscussionsView/index.tsx b/app/views/DiscussionsView/index.tsx index 13d701619..930e5ceeb 100644 --- a/app/views/DiscussionsView/index.tsx +++ b/app/views/DiscussionsView/index.tsx @@ -1,11 +1,10 @@ import React, { useEffect, useLayoutEffect, useState } from 'react'; import { FlatList, StyleSheet } from 'react-native'; -import { useSelector } from 'react-redux'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { HeaderBackButton, StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; import { RouteProp } from '@react-navigation/core'; -import { IApplicationState, IMessageFromServer } from '../../definitions'; +import { IMessageFromServer } from '../../definitions'; import { ChatsStackParamList } from '../../stacks/types'; import ActivityIndicator from '../../containers/ActivityIndicator'; import I18n from '../../i18n'; @@ -23,6 +22,7 @@ import SearchHeader from '../../containers/SearchHeader'; import { TThreadModel } from '../../definitions/IThread'; import Item from './Item'; import { Services } from '../../lib/services'; +import { useAppSelector } from '../../lib/hooks'; const API_FETCH_COUNT = 50; @@ -42,8 +42,8 @@ const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): React.Re const rid = route.params?.rid; const t = route.params?.t; - const baseUrl = useSelector((state: IApplicationState) => state.server?.server); - const isMasterDetail = useSelector((state: IApplicationState) => state.app?.isMasterDetail); + const baseUrl = useAppSelector(state => state.server?.server); + const isMasterDetail = useAppSelector(state => state.app?.isMasterDetail); const [loading, setLoading] = useState(false); const [discussions, setDiscussions] = useState([]); diff --git a/app/views/DisplayPrefsView.tsx b/app/views/DisplayPrefsView.tsx index 61dd958f8..085a368c7 100644 --- a/app/views/DisplayPrefsView.tsx +++ b/app/views/DisplayPrefsView.tsx @@ -3,7 +3,7 @@ import { StackNavigationProp } from '@react-navigation/stack'; import { useNavigation } from '@react-navigation/native'; import { Switch } from 'react-native'; import { RadioButton } from 'react-native-ui-lib'; -import { useDispatch, useSelector } from 'react-redux'; +import { useDispatch } from 'react-redux'; import { setPreference } from '../actions/sortPreferences'; import { DisplayMode, SortBy } from '../lib/constants'; @@ -12,21 +12,22 @@ 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 { IPreferences } from '../definitions'; import I18n from '../i18n'; import { SettingsStackParamList } from '../stacks/types'; import { useTheme } from '../theme'; import { events, logEvent } from '../utils/log'; import { saveSortPreference } from '../lib/methods'; +import { useAppSelector } from '../lib/hooks'; const DisplayPrefsView = (): React.ReactElement => { const navigation = useNavigation>(); const { colors } = useTheme(); - const { sortBy, groupByType, showFavorites, showUnread, showAvatar, displayMode } = useSelector( - (state: IApplicationState) => state.sortPreferences + const { sortBy, groupByType, showFavorites, showUnread, showAvatar, displayMode } = useAppSelector( + state => state.sortPreferences ); - const { isMasterDetail } = useSelector((state: IApplicationState) => state.app); + const { isMasterDetail } = useAppSelector(state => state.app); const dispatch = useDispatch(); useEffect(() => { diff --git a/app/views/SecurityPrivacyView.tsx b/app/views/SecurityPrivacyView.tsx index 5487819d1..b57b7ae7a 100644 --- a/app/views/SecurityPrivacyView.tsx +++ b/app/views/SecurityPrivacyView.tsx @@ -2,14 +2,13 @@ import AsyncStorage from '@react-native-community/async-storage'; import { StackNavigationProp } from '@react-navigation/stack'; import React, { useEffect, useState } from 'react'; import { Switch } from 'react-native'; -import { useSelector } from 'react-redux'; import * as List from '../containers/List'; import SafeAreaView from '../containers/SafeAreaView'; import StatusBar from '../containers/StatusBar'; -import { IApplicationState } from '../definitions'; import I18n from '../i18n'; import { ANALYTICS_EVENTS_KEY, CRASH_REPORT_KEY, isFDroidBuild, SWITCH_TRACK_COLOR } from '../lib/constants'; +import { useAppSelector } from '../lib/hooks'; import useServer from '../lib/methods/useServer'; import { SettingsStackParamList } from '../stacks/types'; import { handleLocalAuthentication } from '../utils/localAuthentication'; @@ -31,7 +30,7 @@ const SecurityPrivacyView = ({ navigation }: ISecurityPrivacyViewProps): JSX.Ele const [analyticsEventsState, setAnalyticsEventsState] = useState(getReportAnalyticsEventsValue()); const [server] = useServer(); - const e2eEnabled = useSelector((state: IApplicationState) => state.settings.E2E_Enable); + const e2eEnabled = useAppSelector(state => state.settings.E2E_Enable); useEffect(() => { navigation.setOptions({ diff --git a/app/views/UserPreferencesView/index.tsx b/app/views/UserPreferencesView/index.tsx index b178406f4..bb6b45dcd 100644 --- a/app/views/UserPreferencesView/index.tsx +++ b/app/views/UserPreferencesView/index.tsx @@ -1,7 +1,7 @@ import { StackNavigationProp } from '@react-navigation/stack'; import React, { useEffect } from 'react'; import { Switch } from 'react-native'; -import { useDispatch, useSelector } from 'react-redux'; +import { useDispatch } from 'react-redux'; import { setUser } from '../../actions/login'; import I18n from '../../i18n'; @@ -12,15 +12,15 @@ import * as List from '../../containers/List'; import { SWITCH_TRACK_COLOR } from '../../lib/constants'; import { getUserSelector } from '../../selectors/login'; import { ProfileStackParamList } from '../../stacks/types'; -import { IApplicationState } from '../../definitions'; import { Services } from '../../lib/services'; +import { useAppSelector } from '../../lib/hooks'; interface IUserPreferencesViewProps { navigation: StackNavigationProp; } const UserPreferencesView = ({ navigation }: IUserPreferencesViewProps): JSX.Element => { - const { enableMessageParserEarlyAdoption, id } = useSelector((state: IApplicationState) => getUserSelector(state)); + const { enableMessageParserEarlyAdoption, id } = useAppSelector(state => getUserSelector(state)); const dispatch = useDispatch(); useEffect(() => {