From 4fa82d713b5c42ae0bc18f432d25508ed889641d Mon Sep 17 00:00:00 2001 From: mgentili Date: Wed, 24 Apr 2019 09:27:42 +0200 Subject: [PATCH 01/12] [#157929923] add-badge-messages [#157929923] not completed. For the moment the badge is visible in all the tabs. Logic for badge is not implemented --- package.json | 1 + .../messages/MessageListComponent.tsx | 1 - ts/navigation/MainNavigator.tsx | 49 +++++++++++---- yarn.lock | 60 ++++++++++++++++++- 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 76cbbdc345f..bbf8031ac47 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "@types/react": "16.8.10", "@types/react-native": "0.57.42", "@types/react-native-background-timer": "^2.0.0", + "@types/react-native-elements": "^0.18.0", "@types/react-native-i18n": "^2.0.0", "@types/react-native-loading-spinner-overlay": "^0.5.1", "@types/react-native-push-notification": "^3.0.2", diff --git a/ts/components/messages/MessageListComponent.tsx b/ts/components/messages/MessageListComponent.tsx index f88f71106dc..c88590dca6b 100644 --- a/ts/components/messages/MessageListComponent.tsx +++ b/ts/components/messages/MessageListComponent.tsx @@ -71,7 +71,6 @@ class MessageListComponent extends React.Component { const refreshControl = ( ); - return ( + + + + + + ); }, tabBarOnPress: options => { diff --git a/yarn.lock b/yarn.lock index a386bf839f4..d0c268ee39c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1071,6 +1071,13 @@ version "2.0.0" resolved "https://registry.yarnpkg.com/@types/react-native-background-timer/-/react-native-background-timer-2.0.0.tgz#c44c57f8fbca9d9d5521fdd72a8f55232b79381e" +"@types/react-native-elements@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@types/react-native-elements/-/react-native-elements-0.18.0.tgz#81cf92d75a5d9ed73599761da37bd2b05b107a91" + integrity sha512-Tt0aq6HlN31Wexica9MwTwxnt46fLyx6yzMFJWPx2hqACrvBZfFTlwCoWMRa6ArR/kX3XJbAe6vKEBuZ08Zvtw== + dependencies: + react-native-elements "*" + "@types/react-native-i18n@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/react-native-i18n/-/react-native-i18n-2.0.0.tgz#2df92b3392d813b39530bd126aad429eedc9c3de" @@ -2633,6 +2640,14 @@ color@^3.0.0: color-convert "^1.9.1" color-string "^1.5.2" +color@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/color/-/color-3.1.0.tgz#d8e9fb096732875774c84bf922815df0308d0ffc" + integrity sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + color@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/color/-/color-1.0.3.tgz#e48e832d85f14ef694fb468811c2d5cfe729b55d" @@ -2996,6 +3011,11 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" +deepmerge@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.2.0.tgz#58ef463a57c08d376547f8869fdc5bcee957f44e" + integrity sha512-6+LuZGU7QCNUnAJyX8cIrlzoEgggTM6B7mm+znKOX4t5ltluT9KLjN6g61ECMS0LTsLW7yDpNoxhix5FZcrIow== + default-require-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" @@ -4199,6 +4219,13 @@ hoist-non-react-statics@^3.0.1: dependencies: react-is "^16.3.2" +hoist-non-react-statics@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" + integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== + dependencies: + react-is "^16.7.0" + hoist-non-react-statics@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.2.1.tgz#c09c0555c84b38a7ede6912b61efddafd6e75e1e" @@ -6677,6 +6704,11 @@ ono@^4.0.3, ono@^4.0.5: dependencies: format-util "^1.0.3" +opencollective-postinstall@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89" + integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw== + opn@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/opn/-/opn-3.0.3.tgz#b6d99e7399f78d65c3baaffef1fb288e9b85243a" @@ -7271,7 +7303,7 @@ react-is@^16.6.3: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa" integrity sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g== -react-is@^16.8.3, react-is@^16.8.4: +react-is@^16.7.0, react-is@^16.8.3, react-is@^16.8.4: version "16.8.6" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== @@ -7328,6 +7360,19 @@ react-native-easy-grid@0.2.1: dependencies: lodash "4.17.11" +react-native-elements@*: + version "1.1.0" + resolved "https://registry.yarnpkg.com/react-native-elements/-/react-native-elements-1.1.0.tgz#f99bcda4459a886f3ab4591c684c099d37aedf2b" + integrity sha512-n1eOL0kUdlH01zX7bn1p7qhYXn7kquqxYQ0oWlxoAck9t5Db/KeK5ViOsAk8seYSvAG6Pe7OxgzRFnMfFhng0Q== + dependencies: + color "^3.1.0" + deepmerge "^3.1.0" + hoist-non-react-statics "^3.1.0" + opencollective-postinstall "^2.0.0" + prop-types "^15.5.8" + react-native-ratings "^6.3.0" + react-native-status-bar-height "^2.2.0" + react-native-exception-handler@2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/react-native-exception-handler/-/react-native-exception-handler-2.10.0.tgz#0d828a4f2c7c4469a2929fa46d20535def726903" @@ -7408,6 +7453,14 @@ react-native-qrcode-scanner@^1.1.0: prop-types "^15.5.10" react-native-permissions "^1.1.1" +react-native-ratings@^6.3.0: + version "6.3.1" + resolved "https://registry.yarnpkg.com/react-native-ratings/-/react-native-ratings-6.3.1.tgz#4e4bd87f376423dc62c933f570fc1932c78adaa4" + integrity sha512-+WEtk4wPvnoN5YbfWcmyM4LpKOlvkrFlpQe0KrqeWBAOkN6OXOZYBtiCh97dCIb8Ovpm7goOEcTf3T1MGCi2LA== + dependencies: + lodash "^4.17.4" + prop-types "^15.5.10" + react-native-safe-area-view@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.12.0.tgz#5c312f087300ecf82e8541c3eac25d560e147f22" @@ -7430,6 +7483,11 @@ react-native-splash-screen@^3.2.0: resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.2.0.tgz#d47ec8557b1ba988ee3ea98d01463081b60fff45" integrity sha512-Ls9qiNZzW/OLFoI25wfjjAcrf2DZ975hn2vr6U9gyuxi2nooVbzQeFoQS5vQcbCt9QX5NY8ASEEAtlLdIa6KVg== +react-native-status-bar-height@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/react-native-status-bar-height/-/react-native-status-bar-height-2.3.1.tgz#b92ce9112c2367290847ac11284d9d84a6330169" + integrity sha512-m9nGKYfFn6ljF1abafzF5cFaD9JCzXwj7kNE9CuF+g0TgtItH70eY2uHaCV9moENTftqd5XIS3Cx0mf4WfistA== + react-native-svg@^6.5.3: version "6.5.3" resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-6.5.3.tgz#44004c4cdc4a289acb613d718eda6f80e0c5a026" From 2c986b9007461d6cee752da86fed2e01bf589542 Mon Sep 17 00:00:00 2001 From: mgentili Date: Wed, 24 Apr 2019 16:32:53 +0200 Subject: [PATCH 02/12] [#157929923]-add-badge-messages [#157929923] not completed. Badge graphic is ok on Android, I must check it on iOS. The logic for the badge counter has not implemented yet. --- .../messages/MessageListComponent.tsx | 8 ++- ts/navigation/MainNavigator.tsx | 52 ++++++++++--------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/ts/components/messages/MessageListComponent.tsx b/ts/components/messages/MessageListComponent.tsx index c88590dca6b..26996195763 100644 --- a/ts/components/messages/MessageListComponent.tsx +++ b/ts/components/messages/MessageListComponent.tsx @@ -12,7 +12,8 @@ import { MessageState } from "../../store/reducers/entities/messages/messagesByI import { PaymentByRptIdState } from "../../store/reducers/entities/payments"; import { ServicesByIdState } from "../../store/reducers/entities/services/servicesById"; import { MessageListItemComponent } from "./MessageListItemComponent"; - +// tslint:disable-next-line: no-var-keyword +var messagesToRead = 0; type OwnProps = { messages: ReadonlyArray; servicesById: ServicesByIdState; @@ -67,10 +68,13 @@ class MessageListComponent extends React.Component { paymentByRptId, ListEmptyComponent } = this.props; - const refreshControl = ( ); + + messagesToRead = messages.filter(obj => !obj.isRead).length + alert(messagesToRead); + return ( - - - + {routeName === ROUTES.MESSAGES_NAVIGATOR ? ( + + + 99 + + + ) : null} Date: Wed, 24 Apr 2019 16:36:57 +0200 Subject: [PATCH 03/12] [#157929923]-add-badge-messages [#157929923] not completed. Badge graphic is ok on Android, I must check it on iOS. The logic for the badge counter has not implemented yet. --- ts/components/messages/MessageListComponent.tsx | 2 +- ts/navigation/MainNavigator.tsx | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ts/components/messages/MessageListComponent.tsx b/ts/components/messages/MessageListComponent.tsx index 26996195763..eed5670673c 100644 --- a/ts/components/messages/MessageListComponent.tsx +++ b/ts/components/messages/MessageListComponent.tsx @@ -72,7 +72,7 @@ class MessageListComponent extends React.Component { ); - messagesToRead = messages.filter(obj => !obj.isRead).length + messagesToRead = messages.filter(obj => !obj.isRead).length; alert(messagesToRead); return ( diff --git a/ts/navigation/MainNavigator.tsx b/ts/navigation/MainNavigator.tsx index 14a6986a888..9f5add4051a 100644 --- a/ts/navigation/MainNavigator.tsx +++ b/ts/navigation/MainNavigator.tsx @@ -9,8 +9,6 @@ import { NavigationState, StackActions } from "react-navigation"; -import MessageListComponent from "../components/messages/MessageListComponent"; - import IconFont from "../components/ui/IconFont"; import I18n from "../i18n"; import { makeFontStyleObject } from "../theme/fonts"; From 4f7653ecc1b46cab6f1a5ca0aa5c5cc281236d8c Mon Sep 17 00:00:00 2001 From: mgentili Date: Mon, 29 Apr 2019 17:05:02 +0200 Subject: [PATCH 04/12] [#157929923] add-badge-messages [#157929923] add-badge-messages. Modified badge layout and added method for reading the number of messages. Tested on ios and android --- package.json | 1 - .../messages/MessageListComponent.tsx | 13 ++++++--- ts/navigation/MainNavigator.tsx | 29 ++++++++++++------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index bbf8031ac47..76cbbdc345f 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,6 @@ "@types/react": "16.8.10", "@types/react-native": "0.57.42", "@types/react-native-background-timer": "^2.0.0", - "@types/react-native-elements": "^0.18.0", "@types/react-native-i18n": "^2.0.0", "@types/react-native-loading-spinner-overlay": "^0.5.1", "@types/react-native-push-notification": "^3.0.2", diff --git a/ts/components/messages/MessageListComponent.tsx b/ts/components/messages/MessageListComponent.tsx index eed5670673c..b02740d4701 100644 --- a/ts/components/messages/MessageListComponent.tsx +++ b/ts/components/messages/MessageListComponent.tsx @@ -12,8 +12,8 @@ import { MessageState } from "../../store/reducers/entities/messages/messagesByI import { PaymentByRptIdState } from "../../store/reducers/entities/payments"; import { ServicesByIdState } from "../../store/reducers/entities/services/servicesById"; import { MessageListItemComponent } from "./MessageListItemComponent"; -// tslint:disable-next-line: no-var-keyword -var messagesToRead = 0; +// tslint:disable-next-line:no-let +let messagesToRead = 0; type OwnProps = { messages: ReadonlyArray; servicesById: ServicesByIdState; @@ -73,8 +73,6 @@ class MessageListComponent extends React.Component { ); messagesToRead = messages.filter(obj => !obj.isRead).length; - alert(messagesToRead); - return ( { /> ); } + + public getMessagesToRead() { + if (messagesToRead > 99) { + return 99; + } + return messagesToRead; + } } export default MessageListComponent; diff --git a/ts/navigation/MainNavigator.tsx b/ts/navigation/MainNavigator.tsx index 9f5add4051a..8f3f5157ff4 100644 --- a/ts/navigation/MainNavigator.tsx +++ b/ts/navigation/MainNavigator.tsx @@ -1,7 +1,6 @@ -import { Badge, Right } from "native-base"; +import { Badge } from "native-base"; import * as React from "react"; import { Platform, StyleSheet, Text, View } from "react-native"; - import { createBottomTabNavigator, NavigationRoute, @@ -9,6 +8,7 @@ import { NavigationState, StackActions } from "react-navigation"; +import MessageListComponent from "../components/messages/MessageListComponent"; import IconFont from "../components/ui/IconFont"; import I18n from "../i18n"; import { makeFontStyleObject } from "../theme/fonts"; @@ -100,7 +100,9 @@ const styles = StyleSheet.create({ elevation: 0.1, shadowColor: "white", height: 19, - width: 19 + width: 19, + left: 12, + bottom: 10 } }); @@ -178,20 +180,27 @@ const navigation = createBottomTabNavigator( tabBarIcon: (options: { tintColor: string | null; focused: boolean }) => { const { routeName } = nav.state; const iconName: string = getIcon(routeName); + const messagesToRead = MessageListComponent.prototype.getMessagesToRead(); return ( - {routeName === ROUTES.MESSAGES_NAVIGATOR ? ( - - - 99 - - - ) : null} + {routeName === ROUTES.MESSAGES_NAVIGATOR ? ( + Platform.OS === "ios" ? ( + + + {messagesToRead} + + + ) : ( + + {messagesToRead} + + ) + ) : null} ); }, From cc4db3ab908c6ace97309a7275191203658a860b Mon Sep 17 00:00:00 2001 From: mgentili Date: Fri, 3 May 2019 16:36:30 +0200 Subject: [PATCH 05/12] [#157929923]-add-badge-message-tab [#157929923]-add-badge-message-tab. Added store redux for badge --- .../messages/MessageListComponent.tsx | 14 ++++---- ts/navigation/MainNavigator.tsx | 16 +++++---- ts/store/actions/messages.ts | 7 +++- ts/store/reducers/entities/messages/badge.ts | 35 +++++++++++++++++++ ts/store/reducers/entities/messages/index.ts | 8 +++-- 5 files changed, 63 insertions(+), 17 deletions(-) create mode 100644 ts/store/reducers/entities/messages/badge.ts diff --git a/ts/components/messages/MessageListComponent.tsx b/ts/components/messages/MessageListComponent.tsx index b02740d4701..e1349e14742 100644 --- a/ts/components/messages/MessageListComponent.tsx +++ b/ts/components/messages/MessageListComponent.tsx @@ -7,7 +7,8 @@ import { RefreshControl, StyleSheet } from "react-native"; - +import { store } from "../../App"; +import { setNumberMessagesUnread } from "../../store/actions/messages"; import { MessageState } from "../../store/reducers/entities/messages/messagesById"; import { PaymentByRptIdState } from "../../store/reducers/entities/payments"; import { ServicesByIdState } from "../../store/reducers/entities/services/servicesById"; @@ -73,6 +74,10 @@ class MessageListComponent extends React.Component { ); messagesToRead = messages.filter(obj => !obj.isRead).length; + store.dispatch( + setNumberMessagesUnread(messagesToRead < 99 ? messagesToRead : 99) + ); + return ( { /> ); } - - public getMessagesToRead() { - if (messagesToRead > 99) { - return 99; - } - return messagesToRead; - } } export default MessageListComponent; diff --git a/ts/navigation/MainNavigator.tsx b/ts/navigation/MainNavigator.tsx index 8f3f5157ff4..179459948c6 100644 --- a/ts/navigation/MainNavigator.tsx +++ b/ts/navigation/MainNavigator.tsx @@ -8,9 +8,10 @@ import { NavigationState, StackActions } from "react-navigation"; -import MessageListComponent from "../components/messages/MessageListComponent"; +import { store } from "../App"; import IconFont from "../components/ui/IconFont"; import I18n from "../i18n"; +import { badgeNumberSelector } from "../store/reducers/entities/messages/badge"; import { makeFontStyleObject } from "../theme/fonts"; import variables from "../theme/variables"; import MessageNavigator from "./MessagesNavigator"; @@ -90,7 +91,8 @@ const styles = StyleSheet.create({ position: "absolute", height: 19, width: 19, - paddingLeft: 2 + textAlign: "center", + paddingRight: 3 }, badgeStyle: { backgroundColor: variables.brandPrimary, @@ -180,7 +182,6 @@ const navigation = createBottomTabNavigator( tabBarIcon: (options: { tintColor: string | null; focused: boolean }) => { const { routeName } = nav.state; const iconName: string = getIcon(routeName); - const messagesToRead = MessageListComponent.prototype.getMessagesToRead(); return ( - {routeName === ROUTES.MESSAGES_NAVIGATOR ? ( + {routeName === ROUTES.MESSAGES_NAVIGATOR && + badgeNumberSelector(store.getState()).badgeCount > 0 ? ( Platform.OS === "ios" ? ( - {messagesToRead} + {badgeNumberSelector(store.getState()).badgeCount} ) : ( - {messagesToRead} + + {badgeNumberSelector(store.getState()).badgeCount} + ) ) : null} diff --git a/ts/store/actions/messages.ts b/ts/store/actions/messages.ts index c27a33ed501..ba86b67d21c 100644 --- a/ts/store/actions/messages.ts +++ b/ts/store/actions/messages.ts @@ -50,10 +50,15 @@ export const setMessagesArchivedState = createAction( resolve({ ids, archived }) ); +export const setNumberMessagesUnread = createStandardAction("MESSAGES_UNREAD")< + number +>(); + export type MessagesActions = | ActionType | ActionType | ActionType | ActionType | ActionType - | ActionType; + | ActionType + | ActionType; diff --git a/ts/store/reducers/entities/messages/badge.ts b/ts/store/reducers/entities/messages/badge.ts new file mode 100644 index 00000000000..49e16c893b4 --- /dev/null +++ b/ts/store/reducers/entities/messages/badge.ts @@ -0,0 +1,35 @@ +/** + * Badge reducer + */ +import { getType } from "typesafe-actions"; +import { setNumberMessagesUnread } from "../../../actions/messages"; +import { Action } from "../../../actions/types"; +import { GlobalState } from "../../types"; + +export type BadgeNumberState = Readonly<{ + badgeCount: number; +}>; + +export function getInitialState(): BadgeNumberState { + return { + badgeCount: 0 + }; +} + +const reducer = ( + state: BadgeNumberState = getInitialState(), + action: Action +): BadgeNumberState => { + switch (action.type) { + case getType(setNumberMessagesUnread): + return { ...state, badgeCount: action.payload }; + default: + return state; + } +}; + +export default reducer; + +// Selector +export const badgeNumberSelector = (state: GlobalState) => + state.entities.messages.badge; diff --git a/ts/store/reducers/entities/messages/index.ts b/ts/store/reducers/entities/messages/index.ts index 1f05c8dc6c8..83001ba1104 100644 --- a/ts/store/reducers/entities/messages/index.ts +++ b/ts/store/reducers/entities/messages/index.ts @@ -8,10 +8,12 @@ import { createSelector } from "reselect"; import { isDefined } from "../../../../utils/guards"; import { Action } from "../../../actions/types"; +import badgeReducer, { BadgeNumberState } from "./badge"; import messagesAllIdsReducer, { messagesAllIdsSelector, MessagesAllIdsState } from "./messagesAllIds"; + import messagesByIdReducer, { messagesStateByIdSelector, MessageStateById @@ -20,16 +22,18 @@ import messagesByIdReducer, { export type MessagesState = Readonly<{ byId: MessageStateById; allIds: MessagesAllIdsState; // FIXME: is this used? + badge: BadgeNumberState; }>; const reducer = combineReducers({ byId: messagesByIdReducer, - allIds: messagesAllIdsReducer + allIds: messagesAllIdsReducer, + badge: badgeReducer }); // Selectors -/** +/**- * Returns array of messages IDs inversely lexically ordered. */ export const lexicallyOrderedMessagesIds = createSelector( From 740cf3d18df5ad5494d663a2203917477a8ddff3 Mon Sep 17 00:00:00 2001 From: mgentili Date: Mon, 13 May 2019 14:15:55 +0200 Subject: [PATCH 06/12] [#157929923]-add-badge-message-tab Completed badge implementation. It works correctly on ios and android. --- ts/components/MessagesTabIcon.tsx | 76 +++++++++++++++++++ .../messages/MessageListComponent.tsx | 11 +-- ts/navigation/MainNavigator.tsx | 36 +++------ ts/screens/messages/MessageDetailScreen.tsx | 13 +++- ts/screens/messages/MessagesHomeScreen.tsx | 44 +++++++++-- ts/store/actions/messages.ts | 6 +- ts/store/reducers/entities/messages/badge.ts | 19 +++-- 7 files changed, 148 insertions(+), 57 deletions(-) create mode 100644 ts/components/MessagesTabIcon.tsx diff --git a/ts/components/MessagesTabIcon.tsx b/ts/components/MessagesTabIcon.tsx new file mode 100644 index 00000000000..4af4ed5e9d1 --- /dev/null +++ b/ts/components/MessagesTabIcon.tsx @@ -0,0 +1,76 @@ +import { Badge, View } from "native-base"; +import React from "react"; +import { Platform, StyleSheet, Text } from "react-native"; +import { connect } from "react-redux"; +import { badgeSelector } from "../store/reducers/entities/messages/badge"; +import { GlobalState } from "../store/reducers/types"; +import variables from "../theme/variables"; +import IconFont from "./ui/IconFont"; + +type OwnProps = { + color?: string; +}; + +const styles = StyleSheet.create({ + textBadgeStyle: { + fontSize: 10, + fontFamily: "Titillium Web", + fontWeight: "bold", + color: "white", + flex: 1, + position: "absolute", + height: 19, + width: 19, + textAlign: "center", + paddingRight: 3 + }, + badgeStyle: { + backgroundColor: variables.brandPrimary, + borderColor: "white", + borderWidth: 2, + position: "absolute", + elevation: 0.1, + shadowColor: "white", + height: 19, + width: 19, + left: 12, + bottom: 10 + } +}); + +type Props = OwnProps & ReturnType; + +/** + * Message icon add badge. + */ +class MessagesTabIcon extends React.PureComponent { + public render() { + const { color, badge } = this.props; + return ( + + + {badge > 0 ? ( + Platform.OS === "ios" ? ( + + {badge} + + ) : ( + + {badge} + + ) + ) : null} + + ); + } +} + +const mapStateToProps = (state: GlobalState) => ({ + badge: badgeSelector(state) +}); + +export default connect(mapStateToProps)(MessagesTabIcon); diff --git a/ts/components/messages/MessageListComponent.tsx b/ts/components/messages/MessageListComponent.tsx index e1349e14742..1877db1885d 100644 --- a/ts/components/messages/MessageListComponent.tsx +++ b/ts/components/messages/MessageListComponent.tsx @@ -7,14 +7,11 @@ import { RefreshControl, StyleSheet } from "react-native"; -import { store } from "../../App"; -import { setNumberMessagesUnread } from "../../store/actions/messages"; import { MessageState } from "../../store/reducers/entities/messages/messagesById"; import { PaymentByRptIdState } from "../../store/reducers/entities/payments"; import { ServicesByIdState } from "../../store/reducers/entities/services/servicesById"; import { MessageListItemComponent } from "./MessageListItemComponent"; -// tslint:disable-next-line:no-let -let messagesToRead = 0; + type OwnProps = { messages: ReadonlyArray; servicesById: ServicesByIdState; @@ -42,7 +39,6 @@ const keyExtractor = (_: MessageState) => _.meta.id; class MessageListComponent extends React.Component { private renderItem = (info: ListRenderItemInfo) => { const { meta } = info.item; - const service = this.props.servicesById[meta.sender_service_id]; return ( @@ -73,11 +69,6 @@ class MessageListComponent extends React.Component { ); - messagesToRead = messages.filter(obj => !obj.isRead).length; - store.dispatch( - setNumberMessagesUnread(messagesToRead < 99 ? messagesToRead : 99) - ); - return ( { const { routeName } = nav.state; const iconName: string = getIcon(routeName); - return ( - + if (routeName === ROUTES.MESSAGES_NAVIGATOR) { + return ( + + ); + } else { + return ( - {routeName === ROUTES.MESSAGES_NAVIGATOR && - badgeNumberSelector(store.getState()).badgeCount > 0 ? ( - Platform.OS === "ios" ? ( - - - {badgeNumberSelector(store.getState()).badgeCount} - - - ) : ( - - - {badgeNumberSelector(store.getState()).badgeCount} - - - ) - ) : null} - - ); + ); + } }, tabBarOnPress: options => { if (options.navigation.state.index > 0) { diff --git a/ts/screens/messages/MessageDetailScreen.tsx b/ts/screens/messages/MessageDetailScreen.tsx index 8a1ee3fdc13..44a4109b0ec 100644 --- a/ts/screens/messages/MessageDetailScreen.tsx +++ b/ts/screens/messages/MessageDetailScreen.tsx @@ -5,7 +5,6 @@ import * as React from "react"; import { ActivityIndicator, StyleSheet } from "react-native"; import { NavigationScreenProps } from "react-navigation"; import { connect } from "react-redux"; - import { CreatedMessageWithoutContent } from "../../../definitions/backend/CreatedMessageWithoutContent"; import { ServiceId } from "../../../definitions/backend/ServiceId"; import { ServicePublic } from "../../../definitions/backend/ServicePublic"; @@ -15,7 +14,8 @@ import I18n from "../../i18n"; import { contentServiceLoad } from "../../store/actions/content"; import { loadMessageWithRelations, - setMessageReadState + setMessageReadState, + setNumberMessagesUnread } from "../../store/actions/messages"; import { navigateToServiceDetailsScreen } from "../../store/actions/navigation"; import { Dispatch, ReduxProps } from "../../store/actions/types"; @@ -28,6 +28,7 @@ import ServiceDetailsScreen from "../preferences/ServiceDetailsScreen"; type MessageDetailScreenNavigationParams = { messageId: string; + badgeNumber: number; }; type OwnProps = NavigationScreenProps; @@ -156,6 +157,7 @@ export class MessageDetailScreen extends React.PureComponent { if (pot.isSome(potMessage) && !maybeRead.getOrElse(true)) { // Set the message read state to TRUE this.props.setMessageReadState(true); + this.props.updateBadgeNumber(); } }; @@ -181,7 +183,6 @@ export class MessageDetailScreen extends React.PureComponent { const mapStateToProps = (state: GlobalState, ownProps: OwnProps) => { const messageId = ownProps.navigation.getParam("messageId"); - const maybeMessageState = fromNullable( messageStateByIdSelector(messageId)(state) ); @@ -211,6 +212,7 @@ const mapStateToProps = (state: GlobalState, ownProps: OwnProps) => { const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps) => { const messageId = ownProps.navigation.getParam("messageId"); + const badgeNumber = ownProps.navigation.getParam("badgeNumber"); return { contentServiceLoad: (serviceId: ServiceId) => dispatch(contentServiceLoad.request(serviceId)), @@ -220,7 +222,10 @@ const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps) => { dispatch(setMessageReadState(messageId, isRead)), navigateToServiceDetailsScreen: ( params: InferNavigationParams - ) => dispatch(navigateToServiceDetailsScreen(params)) + ) => dispatch(navigateToServiceDetailsScreen(params)), + updateBadgeNumber: () => { + dispatch(setNumberMessagesUnread(badgeNumber - 1)); + } }; }; diff --git a/ts/screens/messages/MessagesHomeScreen.tsx b/ts/screens/messages/MessagesHomeScreen.tsx index 9e499c8fcdd..8fdb895d73c 100644 --- a/ts/screens/messages/MessagesHomeScreen.tsx +++ b/ts/screens/messages/MessagesHomeScreen.tsx @@ -1,4 +1,5 @@ import { none, Option, some } from "fp-ts/lib/Option"; +import * as pot from "italia-ts-commons/lib/pot"; import debounce from "lodash/debounce"; import { Button, @@ -15,7 +16,6 @@ import * as React from "react"; import { StyleSheet } from "react-native"; import { NavigationScreenProps } from "react-navigation"; import { connect } from "react-redux"; - import MessagesArchive from "../../components/messages/MessagesArchive"; import MessagesDeadlines from "../../components/messages/MessagesDeadlines"; import MessagesInbox from "../../components/messages/MessagesInbox"; @@ -25,11 +25,13 @@ import IconFont from "../../components/ui/IconFont"; import I18n from "../../i18n"; import { loadMessages, - setMessagesArchivedState + setMessagesArchivedState, + setNumberMessagesUnread } from "../../store/actions/messages"; import { navigateToMessageDetailScreenAction } from "../../store/actions/navigation"; import { Dispatch } from "../../store/actions/types"; import { lexicallyOrderedMessagesStateSelector } from "../../store/reducers/entities/messages"; +import { MessageState } from "../../store/reducers/entities/messages/messagesById"; import { paymentsByRptIdSelector } from "../../store/reducers/entities/payments"; import { servicesByIdSelector } from "../../store/reducers/entities/services/servicesById"; import { GlobalState } from "../../store/reducers/types"; @@ -37,7 +39,8 @@ import customVariables from "../../theme/variables"; // Used to disable the Deadlines tab const DEADLINES_TAB_ENABLED = false; - +// tslint:disable-next-line:no-let +let badgeNumber = 0; type Props = NavigationScreenProps & ReturnType & ReturnType; @@ -93,6 +96,18 @@ const renderTabBar = (props: any) => { ); }; +/** + * Filter only the messages that are unreaded. + */ +const generateMessagesStateUnreadedArray = ( + potMessagesState: pot.Pot, string> +): ReadonlyArray => + pot.getOrElse( + pot.map(potMessagesState, _ => + _.filter(messageState => !messageState.isRead) + ), + [] + ); /** * A screen that contains all the Tabs related to messages. */ @@ -109,6 +124,19 @@ class MessagesHomeScreen extends React.Component { this.props.refreshMessages(); } + public componentDidUpdate(prevProps: Props) { + const badgeNumberPrev = generateMessagesStateUnreadedArray( + prevProps.lexicallyOrderedMessagesState + ).filter(obj => !obj.isRead).length; + badgeNumber = generateMessagesStateUnreadedArray( + this.props.lexicallyOrderedMessagesState + ).filter(obj => !obj.isRead).length; + + if (badgeNumberPrev !== badgeNumber) { + this.props.updateBadgeNumber(badgeNumber); + } + } + public render() { const { searchText } = this.state; @@ -273,13 +301,17 @@ const mapStateToProps = (state: GlobalState) => ({ }); const mapDispatchToProps = (dispatch: Dispatch) => ({ - refreshMessages: () => dispatch(loadMessages.request()), + refreshMessages: () => { + dispatch(loadMessages.request()); + }, navigateToMessageDetail: (messageId: string) => - dispatch(navigateToMessageDetailScreenAction({ messageId })), + dispatch(navigateToMessageDetailScreenAction({ messageId, badgeNumber })), updateMessagesArchivedState: ( ids: ReadonlyArray, archived: boolean - ) => dispatch(setMessagesArchivedState(ids, archived)) + ) => dispatch(setMessagesArchivedState(ids, archived)), + updateBadgeNumber: (messagesUnread: number) => + dispatch(setNumberMessagesUnread(messagesUnread)) }); export default connect( diff --git a/ts/store/actions/messages.ts b/ts/store/actions/messages.ts index ba86b67d21c..5efc31d12d4 100644 --- a/ts/store/actions/messages.ts +++ b/ts/store/actions/messages.ts @@ -50,9 +50,9 @@ export const setMessagesArchivedState = createAction( resolve({ ids, archived }) ); -export const setNumberMessagesUnread = createStandardAction("MESSAGES_UNREAD")< - number ->(); +export const setNumberMessagesUnread = createStandardAction( + "SET_NUMBER_MESSAGES_UNREAD" +)(); export type MessagesActions = | ActionType diff --git a/ts/store/reducers/entities/messages/badge.ts b/ts/store/reducers/entities/messages/badge.ts index 49e16c893b4..b10d7514821 100644 --- a/ts/store/reducers/entities/messages/badge.ts +++ b/ts/store/reducers/entities/messages/badge.ts @@ -6,30 +6,29 @@ import { setNumberMessagesUnread } from "../../../actions/messages"; import { Action } from "../../../actions/types"; import { GlobalState } from "../../types"; -export type BadgeNumberState = Readonly<{ - badgeCount: number; -}>; +export type BadgeNumberState = { + count: number; +}; export function getInitialState(): BadgeNumberState { return { - badgeCount: 0 + count: 0 }; } -const reducer = ( +const badgeReducer = ( state: BadgeNumberState = getInitialState(), action: Action ): BadgeNumberState => { switch (action.type) { case getType(setNumberMessagesUnread): - return { ...state, badgeCount: action.payload }; + return { ...state, count: action.payload }; default: return state; } }; -export default reducer; +export const badgeSelector = (state: GlobalState) => + state.entities.messages.badge.count; -// Selector -export const badgeNumberSelector = (state: GlobalState) => - state.entities.messages.badge; +export default badgeReducer; From c6076fa171d65cbc64889183a26c955fd7c7ace4 Mon Sep 17 00:00:00 2001 From: mgentili Date: Mon, 13 May 2019 15:03:05 +0200 Subject: [PATCH 07/12] [#157929923]-add-badge-message-tab fix - Now the badge number is retrieved using BadgeSelector instead of passing it during navigation --- ts/navigation/MainNavigator.tsx | 1 - ts/screens/messages/MessageDetailScreen.tsx | 7 ++++--- ts/screens/messages/MessagesHomeScreen.tsx | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ts/navigation/MainNavigator.tsx b/ts/navigation/MainNavigator.tsx index 01d5bed5fbf..c3963ce09eb 100644 --- a/ts/navigation/MainNavigator.tsx +++ b/ts/navigation/MainNavigator.tsx @@ -17,7 +17,6 @@ import PreferencesNavigator from "./PreferencesNavigator"; import ProfileNavigator from "./ProfileNavigator"; import ROUTES from "./routes"; import WalletNavigator from "./WalletNavigator"; - type Routes = keyof typeof ROUTES; type RouteLabelMap = { [key in Routes]?: string }; diff --git a/ts/screens/messages/MessageDetailScreen.tsx b/ts/screens/messages/MessageDetailScreen.tsx index 44a4109b0ec..603ed0d675d 100644 --- a/ts/screens/messages/MessageDetailScreen.tsx +++ b/ts/screens/messages/MessageDetailScreen.tsx @@ -19,6 +19,7 @@ import { } from "../../store/actions/messages"; import { navigateToServiceDetailsScreen } from "../../store/actions/navigation"; import { Dispatch, ReduxProps } from "../../store/actions/types"; +import { badgeSelector } from "../../store/reducers/entities/messages/badge"; import { messageStateByIdSelector } from "../../store/reducers/entities/messages/messagesById"; import { serviceByIdSelector } from "../../store/reducers/entities/services/servicesById"; import { GlobalState } from "../../store/reducers/types"; @@ -28,9 +29,9 @@ import ServiceDetailsScreen from "../preferences/ServiceDetailsScreen"; type MessageDetailScreenNavigationParams = { messageId: string; - badgeNumber: number; }; - +// tslint:disable-next-line: no-let +let badgeNumber = 0; type OwnProps = NavigationScreenProps; type Props = OwnProps & @@ -182,6 +183,7 @@ export class MessageDetailScreen extends React.PureComponent { } const mapStateToProps = (state: GlobalState, ownProps: OwnProps) => { + badgeNumber = badgeSelector(state); const messageId = ownProps.navigation.getParam("messageId"); const maybeMessageState = fromNullable( messageStateByIdSelector(messageId)(state) @@ -212,7 +214,6 @@ const mapStateToProps = (state: GlobalState, ownProps: OwnProps) => { const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps) => { const messageId = ownProps.navigation.getParam("messageId"); - const badgeNumber = ownProps.navigation.getParam("badgeNumber"); return { contentServiceLoad: (serviceId: ServiceId) => dispatch(contentServiceLoad.request(serviceId)), diff --git a/ts/screens/messages/MessagesHomeScreen.tsx b/ts/screens/messages/MessagesHomeScreen.tsx index 8fdb895d73c..5ed1412aa6a 100644 --- a/ts/screens/messages/MessagesHomeScreen.tsx +++ b/ts/screens/messages/MessagesHomeScreen.tsx @@ -39,8 +39,6 @@ import customVariables from "../../theme/variables"; // Used to disable the Deadlines tab const DEADLINES_TAB_ENABLED = false; -// tslint:disable-next-line:no-let -let badgeNumber = 0; type Props = NavigationScreenProps & ReturnType & ReturnType; @@ -128,7 +126,7 @@ class MessagesHomeScreen extends React.Component { const badgeNumberPrev = generateMessagesStateUnreadedArray( prevProps.lexicallyOrderedMessagesState ).filter(obj => !obj.isRead).length; - badgeNumber = generateMessagesStateUnreadedArray( + const badgeNumber = generateMessagesStateUnreadedArray( this.props.lexicallyOrderedMessagesState ).filter(obj => !obj.isRead).length; @@ -305,7 +303,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ dispatch(loadMessages.request()); }, navigateToMessageDetail: (messageId: string) => - dispatch(navigateToMessageDetailScreenAction({ messageId, badgeNumber })), + dispatch(navigateToMessageDetailScreenAction({ messageId })), updateMessagesArchivedState: ( ids: ReadonlyArray, archived: boolean From c1c8ff78c694b1af3bce12a8ca45659a8fc7b244 Mon Sep 17 00:00:00 2001 From: mgentili Date: Wed, 15 May 2019 14:38:43 +0200 Subject: [PATCH 08/12] [#157929923] add badge message tab Fix implementation badge messages. Now I don't use reducer but i get the number for badge by list of messages --- ts/components/MessagesTabIcon.tsx | 31 +++++++++++++---- ts/screens/messages/MessageDetailScreen.tsx | 14 ++------ ts/screens/messages/MessagesHomeScreen.tsx | 35 ++------------------ ts/store/reducers/entities/messages/badge.ts | 34 ------------------- ts/store/reducers/entities/messages/index.ts | 3 -- 5 files changed, 30 insertions(+), 87 deletions(-) delete mode 100644 ts/store/reducers/entities/messages/badge.ts diff --git a/ts/components/MessagesTabIcon.tsx b/ts/components/MessagesTabIcon.tsx index 4af4ed5e9d1..bc6e44c2823 100644 --- a/ts/components/MessagesTabIcon.tsx +++ b/ts/components/MessagesTabIcon.tsx @@ -1,8 +1,10 @@ +import * as pot from "italia-ts-commons/lib/pot"; import { Badge, View } from "native-base"; import React from "react"; import { Platform, StyleSheet, Text } from "react-native"; import { connect } from "react-redux"; -import { badgeSelector } from "../store/reducers/entities/messages/badge"; +import { lexicallyOrderedMessagesStateSelector } from "../store/reducers/entities/messages"; +import { MessageState } from "../store/reducers/entities/messages/messagesById"; import { GlobalState } from "../store/reducers/types"; import variables from "../theme/variables"; import IconFont from "./ui/IconFont"; @@ -40,12 +42,25 @@ const styles = StyleSheet.create({ type Props = OwnProps & ReturnType; +/** + * Filters the list of messages and returns the number of unread messages. + */ +const getNumberMessagesUnread = ( + potMessagesState: pot.Pot, string> +): number => + pot.getOrElse( + pot.map(potMessagesState, _ => + _.filter(messageState => !messageState.isRead) + ), + [] + ).length; + /** * Message icon add badge. */ class MessagesTabIcon extends React.PureComponent { public render() { - const { color, badge } = this.props; + const { color, messagesUnread } = this.props; return ( { size={variables.iconSize3} color={color} /> - {badge > 0 ? ( + {messagesUnread > 0 ? ( Platform.OS === "ios" ? ( - {badge} + + {messagesUnread} + ) : ( - {badge} + {messagesUnread} ) ) : null} @@ -70,7 +87,9 @@ class MessagesTabIcon extends React.PureComponent { } const mapStateToProps = (state: GlobalState) => ({ - badge: badgeSelector(state) + messagesUnread: getNumberMessagesUnread( + lexicallyOrderedMessagesStateSelector(state) + ) }); export default connect(mapStateToProps)(MessagesTabIcon); diff --git a/ts/screens/messages/MessageDetailScreen.tsx b/ts/screens/messages/MessageDetailScreen.tsx index 1b8390b1f1a..8aa03ac7cde 100644 --- a/ts/screens/messages/MessageDetailScreen.tsx +++ b/ts/screens/messages/MessageDetailScreen.tsx @@ -14,12 +14,10 @@ import I18n from "../../i18n"; import { contentServiceLoad } from "../../store/actions/content"; import { loadMessageWithRelations, - setMessageReadState, - setNumberMessagesUnread + setMessageReadState } from "../../store/actions/messages"; import { navigateToServiceDetailsScreen } from "../../store/actions/navigation"; import { Dispatch, ReduxProps } from "../../store/actions/types"; -import { badgeSelector } from "../../store/reducers/entities/messages/badge"; import { messageStateByIdSelector } from "../../store/reducers/entities/messages/messagesById"; import { serviceByIdSelector } from "../../store/reducers/entities/services/servicesById"; import { GlobalState } from "../../store/reducers/types"; @@ -32,8 +30,7 @@ import ServiceDetailsScreen from "../preferences/ServiceDetailsScreen"; type MessageDetailScreenNavigationParams = { messageId: string; }; -// tslint:disable-next-line: no-let -let badgeNumber = 0; + type OwnProps = NavigationScreenProps; type Props = OwnProps & @@ -258,7 +255,6 @@ export class MessageDetailScreen extends React.PureComponent { if (pot.isSome(potMessage) && !maybeRead.getOrElse(true)) { // Set the message read state to TRUE this.props.setMessageReadState(true); - this.props.updateBadgeNumber(); } }; @@ -283,7 +279,6 @@ export class MessageDetailScreen extends React.PureComponent { } const mapStateToProps = (state: GlobalState, ownProps: OwnProps) => { - badgeNumber = badgeSelector(state); const messageId = ownProps.navigation.getParam("messageId"); const maybeMessageState = fromNullable( messageStateByIdSelector(messageId)(state) @@ -323,10 +318,7 @@ const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps) => { dispatch(setMessageReadState(messageId, isRead)), navigateToServiceDetailsScreen: ( params: InferNavigationParams - ) => dispatch(navigateToServiceDetailsScreen(params)), - updateBadgeNumber: () => { - dispatch(setNumberMessagesUnread(badgeNumber - 1)); - } + ) => dispatch(navigateToServiceDetailsScreen(params)) }; }; diff --git a/ts/screens/messages/MessagesHomeScreen.tsx b/ts/screens/messages/MessagesHomeScreen.tsx index f267a113ca3..2c760f803b0 100644 --- a/ts/screens/messages/MessagesHomeScreen.tsx +++ b/ts/screens/messages/MessagesHomeScreen.tsx @@ -1,5 +1,4 @@ import { none, Option, some } from "fp-ts/lib/Option"; -import * as pot from "italia-ts-commons/lib/pot"; import debounce from "lodash/debounce"; import { Button, @@ -25,13 +24,11 @@ import IconFont from "../../components/ui/IconFont"; import I18n from "../../i18n"; import { loadMessages, - setMessagesArchivedState, - setNumberMessagesUnread + setMessagesArchivedState } from "../../store/actions/messages"; import { navigateToMessageDetailScreenAction } from "../../store/actions/navigation"; import { Dispatch } from "../../store/actions/types"; import { lexicallyOrderedMessagesStateSelector } from "../../store/reducers/entities/messages"; -import { MessageState } from "../../store/reducers/entities/messages/messagesById"; import { paymentsByRptIdSelector } from "../../store/reducers/entities/payments"; import { servicesByIdSelector } from "../../store/reducers/entities/services/servicesById"; import { GlobalState } from "../../store/reducers/types"; @@ -94,18 +91,6 @@ const renderTabBar = (props: any) => { ); }; -/** - * Filter only the messages that are unreaded. - */ -const generateMessagesStateUnreadedArray = ( - potMessagesState: pot.Pot, string> -): ReadonlyArray => - pot.getOrElse( - pot.map(potMessagesState, _ => - _.filter(messageState => !messageState.isRead) - ), - [] - ); /** * A screen that contains all the Tabs related to messages. */ @@ -121,20 +106,6 @@ class MessagesHomeScreen extends React.Component { public componentDidMount() { this.props.refreshMessages(); } - - public componentDidUpdate(prevProps: Props) { - const badgeNumberPrev = generateMessagesStateUnreadedArray( - prevProps.lexicallyOrderedMessagesState - ).filter(obj => !obj.isRead).length; - const badgeNumber = generateMessagesStateUnreadedArray( - this.props.lexicallyOrderedMessagesState - ).filter(obj => !obj.isRead).length; - - if (badgeNumberPrev !== badgeNumber) { - this.props.updateBadgeNumber(badgeNumber); - } - } - public render() { const { searchText } = this.state; @@ -307,9 +278,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ updateMessagesArchivedState: ( ids: ReadonlyArray, archived: boolean - ) => dispatch(setMessagesArchivedState(ids, archived)), - updateBadgeNumber: (messagesUnread: number) => - dispatch(setNumberMessagesUnread(messagesUnread)) + ) => dispatch(setMessagesArchivedState(ids, archived)) }); export default connect( diff --git a/ts/store/reducers/entities/messages/badge.ts b/ts/store/reducers/entities/messages/badge.ts deleted file mode 100644 index b10d7514821..00000000000 --- a/ts/store/reducers/entities/messages/badge.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Badge reducer - */ -import { getType } from "typesafe-actions"; -import { setNumberMessagesUnread } from "../../../actions/messages"; -import { Action } from "../../../actions/types"; -import { GlobalState } from "../../types"; - -export type BadgeNumberState = { - count: number; -}; - -export function getInitialState(): BadgeNumberState { - return { - count: 0 - }; -} - -const badgeReducer = ( - state: BadgeNumberState = getInitialState(), - action: Action -): BadgeNumberState => { - switch (action.type) { - case getType(setNumberMessagesUnread): - return { ...state, count: action.payload }; - default: - return state; - } -}; - -export const badgeSelector = (state: GlobalState) => - state.entities.messages.badge.count; - -export default badgeReducer; diff --git a/ts/store/reducers/entities/messages/index.ts b/ts/store/reducers/entities/messages/index.ts index a4aecde6ef6..1c89b480dc1 100644 --- a/ts/store/reducers/entities/messages/index.ts +++ b/ts/store/reducers/entities/messages/index.ts @@ -8,7 +8,6 @@ import { createSelector } from "reselect"; import { isDefined } from "../../../../utils/guards"; import { Action } from "../../../actions/types"; -import badgeReducer, { BadgeNumberState } from "./badge"; import messagesAllIdsReducer, { messagesAllIdsSelector, MessagesAllIdsState @@ -25,14 +24,12 @@ import messagesIdsByServiceIdReducer, { export type MessagesState = Readonly<{ byId: MessageStateById; allIds: MessagesAllIdsState; // FIXME: is this used? - badge: BadgeNumberState; idsByServiceId: MessagesIdsByServiceId; }>; const reducer = combineReducers({ byId: messagesByIdReducer, allIds: messagesAllIdsReducer, - badge: badgeReducer, idsByServiceId: messagesIdsByServiceIdReducer }); From 1e29f4f85c635e2f7e7af87e956fd36cdf88e186 Mon Sep 17 00:00:00 2001 From: mgentili Date: Wed, 15 May 2019 14:57:37 +0200 Subject: [PATCH 09/12] [#157929923] add badge message tab Added control if badge number is greater than 99 --- ts/components/MessagesTabIcon.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ts/components/MessagesTabIcon.tsx b/ts/components/MessagesTabIcon.tsx index bc6e44c2823..29bf82f1a28 100644 --- a/ts/components/MessagesTabIcon.tsx +++ b/ts/components/MessagesTabIcon.tsx @@ -87,9 +87,10 @@ class MessagesTabIcon extends React.PureComponent { } const mapStateToProps = (state: GlobalState) => ({ - messagesUnread: getNumberMessagesUnread( - lexicallyOrderedMessagesStateSelector(state) - ) + messagesUnread: + getNumberMessagesUnread(lexicallyOrderedMessagesStateSelector(state)) < 99 + ? getNumberMessagesUnread(lexicallyOrderedMessagesStateSelector(state)) + : 99 }); export default connect(mapStateToProps)(MessagesTabIcon); From 1715e8d8e08ccd83964c7bbf20ec16a42baedb21 Mon Sep 17 00:00:00 2001 From: mgentili Date: Mon, 20 May 2019 11:15:13 +0200 Subject: [PATCH 10/12] [#157929923] Add badge messages Created selector for unread messages and improved the code --- ts/components/MessagesTabIcon.tsx | 53 ++++++-------------- ts/navigation/MainNavigator.tsx | 31 +++--------- ts/store/actions/messages.ts | 7 +-- ts/store/reducers/entities/messages/index.ts | 11 ++++ 4 files changed, 35 insertions(+), 67 deletions(-) diff --git a/ts/components/MessagesTabIcon.tsx b/ts/components/MessagesTabIcon.tsx index 29bf82f1a28..71089fff0a8 100644 --- a/ts/components/MessagesTabIcon.tsx +++ b/ts/components/MessagesTabIcon.tsx @@ -1,10 +1,8 @@ -import * as pot from "italia-ts-commons/lib/pot"; import { Badge, View } from "native-base"; import React from "react"; import { Platform, StyleSheet, Text } from "react-native"; import { connect } from "react-redux"; -import { lexicallyOrderedMessagesStateSelector } from "../store/reducers/entities/messages"; -import { MessageState } from "../store/reducers/entities/messages/messagesById"; +import { messagesUnreadSelector } from "../store/reducers/entities/messages"; import { GlobalState } from "../store/reducers/types"; import variables from "../theme/variables"; import IconFont from "./ui/IconFont"; @@ -12,7 +10,7 @@ import IconFont from "./ui/IconFont"; type OwnProps = { color?: string; }; - +const MAX_BADGE_VALUE = 99; const styles = StyleSheet.create({ textBadgeStyle: { fontSize: 10, @@ -24,7 +22,8 @@ const styles = StyleSheet.create({ height: 19, width: 19, textAlign: "center", - paddingRight: 3 + paddingRight: 3, + top: Platform.OS === "ios" ? 0 : undefined }, badgeStyle: { backgroundColor: variables.brandPrimary, @@ -42,25 +41,12 @@ const styles = StyleSheet.create({ type Props = OwnProps & ReturnType; -/** - * Filters the list of messages and returns the number of unread messages. - */ -const getNumberMessagesUnread = ( - potMessagesState: pot.Pot, string> -): number => - pot.getOrElse( - pot.map(potMessagesState, _ => - _.filter(messageState => !messageState.isRead) - ), - [] - ).length; - /** * Message icon add badge. */ class MessagesTabIcon extends React.PureComponent { public render() { - const { color, messagesUnread } = this.props; + const { color, badgeValue } = this.props; return ( { size={variables.iconSize3} color={color} /> - {messagesUnread > 0 ? ( - Platform.OS === "ios" ? ( - - - {messagesUnread} - - - ) : ( - - {messagesUnread} - - ) + {badgeValue > 0 ? ( + + {badgeValue} + ) : null} ); } } -const mapStateToProps = (state: GlobalState) => ({ - messagesUnread: - getNumberMessagesUnread(lexicallyOrderedMessagesStateSelector(state)) < 99 - ? getNumberMessagesUnread(lexicallyOrderedMessagesStateSelector(state)) - : 99 -}); +function mapStateToProps(state: GlobalState) { + const messagesUnread = messagesUnreadSelector(state); + return { + badgeValue: + messagesUnread < MAX_BADGE_VALUE ? messagesUnread : MAX_BADGE_VALUE + }; +} export default connect(mapStateToProps)(MessagesTabIcon); diff --git a/ts/navigation/MainNavigator.tsx b/ts/navigation/MainNavigator.tsx index 2179d3a3523..31cff42df88 100644 --- a/ts/navigation/MainNavigator.tsx +++ b/ts/navigation/MainNavigator.tsx @@ -1,3 +1,10 @@ +/** + * Main navigator, handling the navigation within + * the app *after* the login has occurred. This takes + * care of displaying a tab navigator with the + * appropriate icons + */ + import * as React from "react"; import { Platform, StyleSheet, Text } from "react-native"; import { @@ -79,30 +86,6 @@ const styles = StyleSheet.create({ shadowRadius: variables.footerShadowRadius, // Android shadow elevation: variables.footerElevation - }, - textBadgeStyle: { - fontSize: 10, - fontFamily: "Titillium Web", - fontWeight: "bold", - color: "white", - flex: 1, - position: "absolute", - height: 19, - width: 19, - textAlign: "center", - paddingRight: 3 - }, - badgeStyle: { - backgroundColor: variables.brandPrimary, - borderColor: "white", - borderWidth: 2, - position: "absolute", - elevation: 0.1, - shadowColor: "white", - height: 19, - width: 19, - left: 12, - bottom: 10 } }); diff --git a/ts/store/actions/messages.ts b/ts/store/actions/messages.ts index c893b0096c9..173ec6c0330 100644 --- a/ts/store/actions/messages.ts +++ b/ts/store/actions/messages.ts @@ -54,15 +54,10 @@ export const setMessagesArchivedState = createAction( resolve({ ids, archived }) ); -export const setNumberMessagesUnread = createStandardAction( - "SET_NUMBER_MESSAGES_UNREAD" -)(); - export type MessagesActions = | ActionType | ActionType | ActionType | ActionType | ActionType - | ActionType - | ActionType; + | ActionType; diff --git a/ts/store/reducers/entities/messages/index.ts b/ts/store/reducers/entities/messages/index.ts index 1c89b480dc1..c985848d44d 100644 --- a/ts/store/reducers/entities/messages/index.ts +++ b/ts/store/reducers/entities/messages/index.ts @@ -60,4 +60,15 @@ export const lexicallyOrderedMessagesStateSelector = createSelector( ) ); +export const messagesUnreadSelector = createSelector( + lexicallyOrderedMessagesStateSelector, + potMessagesState => + pot.getOrElse( + pot.map(potMessagesState, _ => + _.filter(messageState => !messageState.isRead) + ), + [] + ).length +); + export default reducer; From 571cefbab035593aab19ce6df56bb780f955d808 Mon Sep 17 00:00:00 2001 From: mgentili Date: Mon, 20 May 2019 14:19:02 +0200 Subject: [PATCH 11/12] [#157929923] Add badge messages tab Revert yarn.lock --- yarn.lock | 60 +------------------------------------------------------ 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/yarn.lock b/yarn.lock index 04f6907a9f8..39ea9c93c76 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1071,13 +1071,6 @@ version "2.0.0" resolved "https://registry.yarnpkg.com/@types/react-native-background-timer/-/react-native-background-timer-2.0.0.tgz#c44c57f8fbca9d9d5521fdd72a8f55232b79381e" -"@types/react-native-elements@^0.18.0": - version "0.18.0" - resolved "https://registry.yarnpkg.com/@types/react-native-elements/-/react-native-elements-0.18.0.tgz#81cf92d75a5d9ed73599761da37bd2b05b107a91" - integrity sha512-Tt0aq6HlN31Wexica9MwTwxnt46fLyx6yzMFJWPx2hqACrvBZfFTlwCoWMRa6ArR/kX3XJbAe6vKEBuZ08Zvtw== - dependencies: - react-native-elements "*" - "@types/react-native-i18n@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/react-native-i18n/-/react-native-i18n-2.0.0.tgz#2df92b3392d813b39530bd126aad429eedc9c3de" @@ -2641,14 +2634,6 @@ color@^3.0.0: color-convert "^1.9.1" color-string "^1.5.2" -color@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/color/-/color-3.1.0.tgz#d8e9fb096732875774c84bf922815df0308d0ffc" - integrity sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg== - dependencies: - color-convert "^1.9.1" - color-string "^1.5.2" - color@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/color/-/color-1.0.3.tgz#e48e832d85f14ef694fb468811c2d5cfe729b55d" @@ -3012,11 +2997,6 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" -deepmerge@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.2.0.tgz#58ef463a57c08d376547f8869fdc5bcee957f44e" - integrity sha512-6+LuZGU7QCNUnAJyX8cIrlzoEgggTM6B7mm+znKOX4t5ltluT9KLjN6g61ECMS0LTsLW7yDpNoxhix5FZcrIow== - default-require-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" @@ -4220,13 +4200,6 @@ hoist-non-react-statics@^3.0.1: dependencies: react-is "^16.3.2" -hoist-non-react-statics@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" - integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== - dependencies: - react-is "^16.7.0" - hoist-non-react-statics@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.2.1.tgz#c09c0555c84b38a7ede6912b61efddafd6e75e1e" @@ -6719,11 +6692,6 @@ ono@^4.0.3, ono@^4.0.5: dependencies: format-util "^1.0.3" -opencollective-postinstall@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89" - integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw== - opn@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/opn/-/opn-3.0.3.tgz#b6d99e7399f78d65c3baaffef1fb288e9b85243a" @@ -7318,7 +7286,7 @@ react-is@^16.6.3: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa" integrity sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g== -react-is@^16.7.0, react-is@^16.8.3, react-is@^16.8.4: +react-is@^16.8.3, react-is@^16.8.4: version "16.8.6" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== @@ -7375,19 +7343,6 @@ react-native-easy-grid@0.2.1: dependencies: lodash "4.17.11" -react-native-elements@*: - version "1.1.0" - resolved "https://registry.yarnpkg.com/react-native-elements/-/react-native-elements-1.1.0.tgz#f99bcda4459a886f3ab4591c684c099d37aedf2b" - integrity sha512-n1eOL0kUdlH01zX7bn1p7qhYXn7kquqxYQ0oWlxoAck9t5Db/KeK5ViOsAk8seYSvAG6Pe7OxgzRFnMfFhng0Q== - dependencies: - color "^3.1.0" - deepmerge "^3.1.0" - hoist-non-react-statics "^3.1.0" - opencollective-postinstall "^2.0.0" - prop-types "^15.5.8" - react-native-ratings "^6.3.0" - react-native-status-bar-height "^2.2.0" - react-native-exception-handler@2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/react-native-exception-handler/-/react-native-exception-handler-2.10.0.tgz#0d828a4f2c7c4469a2929fa46d20535def726903" @@ -7478,14 +7433,6 @@ react-native-qrcode-scanner@^1.1.0: prop-types "^15.5.10" react-native-permissions "^1.1.1" -react-native-ratings@^6.3.0: - version "6.3.1" - resolved "https://registry.yarnpkg.com/react-native-ratings/-/react-native-ratings-6.3.1.tgz#4e4bd87f376423dc62c933f570fc1932c78adaa4" - integrity sha512-+WEtk4wPvnoN5YbfWcmyM4LpKOlvkrFlpQe0KrqeWBAOkN6OXOZYBtiCh97dCIb8Ovpm7goOEcTf3T1MGCi2LA== - dependencies: - lodash "^4.17.4" - prop-types "^15.5.10" - react-native-safe-area-view@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.12.0.tgz#5c312f087300ecf82e8541c3eac25d560e147f22" @@ -7508,11 +7455,6 @@ react-native-splash-screen@^3.2.0: resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.2.0.tgz#d47ec8557b1ba988ee3ea98d01463081b60fff45" integrity sha512-Ls9qiNZzW/OLFoI25wfjjAcrf2DZ975hn2vr6U9gyuxi2nooVbzQeFoQS5vQcbCt9QX5NY8ASEEAtlLdIa6KVg== -react-native-status-bar-height@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/react-native-status-bar-height/-/react-native-status-bar-height-2.3.1.tgz#b92ce9112c2367290847ac11284d9d84a6330169" - integrity sha512-m9nGKYfFn6ljF1abafzF5cFaD9JCzXwj7kNE9CuF+g0TgtItH70eY2uHaCV9moENTftqd5XIS3Cx0mf4WfistA== - react-native-svg@^6.5.3: version "6.5.3" resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-6.5.3.tgz#44004c4cdc4a289acb613d718eda6f80e0c5a026" From 31e64beeea89c1919854375ecd42da9468562d92 Mon Sep 17 00:00:00 2001 From: mgentili Date: Mon, 20 May 2019 14:25:47 +0200 Subject: [PATCH 12/12] [#157929923] Add badge messages tab Fix for prettier after merge --- ts/screens/messages/MessagesHomeScreen.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/ts/screens/messages/MessagesHomeScreen.tsx b/ts/screens/messages/MessagesHomeScreen.tsx index 13d87d8946b..006f028a21e 100644 --- a/ts/screens/messages/MessagesHomeScreen.tsx +++ b/ts/screens/messages/MessagesHomeScreen.tsx @@ -106,6 +106,7 @@ class MessagesHomeScreen extends React.Component { public componentDidMount() { this.props.refreshMessages(); } + public render() { const { searchText } = this.state;