diff --git a/src/app/actions/serviceMessage.actions.ts b/src/app/actions/serviceMessage.actions.ts index fa77544da..803ac668e 100644 --- a/src/app/actions/serviceMessage.actions.ts +++ b/src/app/actions/serviceMessage.actions.ts @@ -7,17 +7,21 @@ export interface ShowServiceMessageAction extends TabAction { type: typeof SHOW_SERVICE_MESSAGE; payload: { date: Date; - message: string; + messages: string[]; action: ServiceMessageAction | null; }; } export const showServiceMessage = ( - message: string, + messages: string[], tab: Tab, action: ServiceMessageAction | null = null ): ShowServiceMessageAction => ({ type: SHOW_SERVICE_MESSAGE, - payload: { date: new Date(), message, action }, + payload: { + date: new Date(), + messages, + action + }, meta: { tab, sendToTab: true diff --git a/src/app/background/reducers/serviceMessage.reducer.spec.ts b/src/app/background/reducers/serviceMessage.reducer.spec.ts index d83436d45..d69f3ff7a 100644 --- a/src/app/background/reducers/serviceMessage.reducer.spec.ts +++ b/src/app/background/reducers/serviceMessage.reducer.spec.ts @@ -14,7 +14,7 @@ describe('background > reducers > serviceMessage', () => { it('saves the lastShownDate from SHOW_SERVICE_MESSAGE action', () => { const now = new Date(); const clock = useFakeTimers(now.getTime()); - const action = showServiceMessage("Hey there I'm a service message", { + const action = showServiceMessage(["Hey there I'm a service message"], { id: 1, url: '' }); diff --git a/src/app/background/sagas/handleBrowserAction.saga.ts b/src/app/background/sagas/handleBrowserAction.saga.ts index f02dbf737..66a66acbe 100644 --- a/src/app/background/sagas/handleBrowserAction.saga.ts +++ b/src/app/background/sagas/handleBrowserAction.saga.ts @@ -8,15 +8,19 @@ import { import { areTosAccepted } from '../selectors/prefs'; import { getNbSubscriptions } from '../selectors/subscriptions.selectors'; import serviceMessageSaga from './serviceMessage.saga'; +import { getNumberOfUnreadNoticesOnTab } from '../selectors'; -export function* browserActionClickedSaga(action: BrowserActionClickedAction) { +export function* browserActionClickedSaga({ + meta: { tab } +}: BrowserActionClickedAction) { const tosAccepted = yield select(areTosAccepted); const nbSubscriptions = yield select(getNbSubscriptions); + const nbNotices = yield select(getNumberOfUnreadNoticesOnTab(tab.id)); if (tosAccepted && nbSubscriptions > 0) { - yield put(toggleUI(action.payload.tab, CloseCause.BrowserAction)); + yield put(toggleUI(tab, CloseCause.BrowserAction)); } else { - yield call(serviceMessageSaga, action); + yield call(serviceMessageSaga, tab, nbNotices); } } diff --git a/src/app/background/sagas/serviceMessage.saga.ts b/src/app/background/sagas/serviceMessage.saga.ts index 818fed744..91035f44b 100644 --- a/src/app/background/sagas/serviceMessage.saga.ts +++ b/src/app/background/sagas/serviceMessage.saga.ts @@ -1,27 +1,36 @@ import { put, select } from 'redux-saga/effects'; -import { showServiceMessage, TabAction } from 'app/actions'; +import * as R from 'ramda'; +import { showServiceMessage } from 'app/actions'; import { areTosAccepted } from '../selectors/prefs'; import { getNbSubscriptions } from '../selectors/subscriptions.selectors'; +import Tab from 'app/lmem/tab'; -export default function* serviceMessageSaga(tabAction: TabAction) { +export const buildMessages = (messages: string[], nbNotices = 0): string[] => { + const firstMessage = + nbNotices > 0 + ? 'Il existe une bulle sur cette page. Pour la visualiser, veuillez finaliser votre configuration.' + : 'Pour poster et recevoir des messages, veuillez finaliser votre configuration.'; + + return R.prepend(firstMessage, messages); +}; + +export default function* serviceMessageSaga(tab: Tab, nbNotices = 0) { const tosAccepted = yield select(areTosAccepted); const nbSubscriptions = yield select(getNbSubscriptions); if (!tosAccepted) { yield put( - showServiceMessage( - "Pour voir des bulles ou en créer, merci d'accepter les Conditions Générales d'Utilisation.", - tabAction.meta.tab, - { label: 'Lire et accepter les CGU', url: '/onboarding' } - ) + showServiceMessage(buildMessages([], nbNotices), tab, { + label: 'Lire et accepter les CGU', + url: '/onboarding' + }) ); } else if (tosAccepted && nbSubscriptions === 0) { yield put( - showServiceMessage( - 'Abonnez vous à des contributeurs pour recevoir leurs messages.', - tabAction.meta.tab, - { label: "M'abonner", url: '/onboarding/subscribe' } - ) + showServiceMessage(buildMessages([], nbNotices), tab, { + label: 'Choisir mes contributeurs', + url: '/settings/suggestions' + }) ); } } diff --git a/src/app/background/sagas/tab.ts b/src/app/background/sagas/tab.ts index 23468b944..b0d21b6c1 100644 --- a/src/app/background/sagas/tab.ts +++ b/src/app/background/sagas/tab.ts @@ -68,8 +68,7 @@ export function* matchContextSaga({ meta: { tab } }: MatchContextAction) { export const contextTriggeredSaga = function*({ payload: triggeredContexts, - meta: { tab }, - type + meta: { tab } }: ContextTriggeredAction) { try { const installationDetails = yield select(getInstallationDetails); @@ -99,11 +98,7 @@ export const contextTriggeredSaga = function*({ getServiceMessageLastShowDate ); if (!isToday(lastServiceMessageDate)) { - yield call(serviceMessageSaga, { - payload: triggeredContexts, - meta: { tab }, - type - }); + yield call(serviceMessageSaga, tab, noticesToShow.length); } return; } diff --git a/src/app/content/App/ServiceMessage/ServiceMessage.stories.tsx b/src/app/content/App/ServiceMessage/ServiceMessage.stories.tsx index e0a1bd2a0..e3951cae7 100644 --- a/src/app/content/App/ServiceMessage/ServiceMessage.stories.tsx +++ b/src/app/content/App/ServiceMessage/ServiceMessage.stories.tsx @@ -13,14 +13,20 @@ storiesOf('screens/ServiceMessage', module) )) .add('With an action', () => ( action('openOnboarding')} /> )) .add('Without an action', () => ( action('openOnboarding')} + /> + )) + .add('With many paragraphs', () => ( + action('openOnboarding')} /> )); diff --git a/src/app/content/App/ServiceMessage/ServiceMessage.tsx b/src/app/content/App/ServiceMessage/ServiceMessage.tsx index 21fc343b5..a1009bd18 100644 --- a/src/app/content/App/ServiceMessage/ServiceMessage.tsx +++ b/src/app/content/App/ServiceMessage/ServiceMessage.tsx @@ -24,18 +24,20 @@ const Button = styled(BackgroundButton)` `; interface ServiceMessageScreenProps { - serviceMessage: string; + messages: string[]; action?: ServiceMessageAction | null; openOnboarding: (pathname: string) => () => void; } export default ({ - serviceMessage, + messages, action, openOnboarding }: ServiceMessageScreenProps) => ( - {serviceMessage} + {messages.map((message, i) => ( + {message} + ))} {action && ( )} diff --git a/src/app/content/App/ServiceMessage/withConnect.ts b/src/app/content/App/ServiceMessage/withConnect.ts index 22dbf8a80..ca320c928 100644 --- a/src/app/content/App/ServiceMessage/withConnect.ts +++ b/src/app/content/App/ServiceMessage/withConnect.ts @@ -2,13 +2,13 @@ import { connect } from 'react-redux'; import { Dispatch } from 'redux'; import { optionsRequested } from 'app/actions'; import { - getServiceMessage, + getServiceMessages, getServiceMessageAction } from 'app/content/selectors'; import { ContentState } from '../../store'; const mapStateToProps = (state: ContentState) => ({ - serviceMessage: getServiceMessage(state) as string, + messages: getServiceMessages(state), action: getServiceMessageAction(state) }); diff --git a/src/app/content/reducers/serviceMessage.reducer.spec.ts b/src/app/content/reducers/serviceMessage.reducer.spec.ts index 57554a6d0..8ba418f4a 100644 --- a/src/app/content/reducers/serviceMessage.reducer.spec.ts +++ b/src/app/content/reducers/serviceMessage.reducer.spec.ts @@ -5,28 +5,28 @@ import { CloseCause } from 'app/lmem/ui'; import { closed, showServiceMessage } from 'app/actions'; describe('content > reducers > serviceMessage', () => { - it('initialize to null', () => { + it('initialize to []', () => { expect( // @ts-ignore serviceMessage(undefined, { type: 'UNKNOWN' }) - ).to.have.property('serviceMessage', null); + ).to.have.deep.property('messages', []); }); it('shows update message when receive SHOW_SERVICE_MESSAGE', () => { const state: ServiceMessageState = { - serviceMessage: null, + messages: [], action: null }; expect( - serviceMessage(state, showServiceMessage('message', { id: 1, url: '' })) - ).to.have.property('serviceMessage', 'message'); + serviceMessage(state, showServiceMessage(['message'], { id: 1, url: '' })) + ).to.have.deep.property('messages', ['message']); }); it('removes the update message when UI is CLOSED', () => { const state: ServiceMessageState = { - serviceMessage: null, + messages: [], action: null }; expect( serviceMessage(state, closed(CloseCause.CloseButton)) - ).to.have.property('serviceMessage', null); + ).to.have.deep.property('messages', []); }); }); diff --git a/src/app/content/reducers/serviceMessage.reducer.ts b/src/app/content/reducers/serviceMessage.reducer.ts index 41f2a4deb..ac937d639 100644 --- a/src/app/content/reducers/serviceMessage.reducer.ts +++ b/src/app/content/reducers/serviceMessage.reducer.ts @@ -6,12 +6,12 @@ export interface ServiceMessageAction { } export interface ServiceMessageState { - serviceMessage: string | null; + messages: string[]; action: ServiceMessageAction | null; } const initialState: ServiceMessageState = { - serviceMessage: null, + messages: [], action: null }; @@ -22,13 +22,13 @@ export default ( switch (action.type) { case SHOW_SERVICE_MESSAGE: { return { - serviceMessage: action.payload.message, + messages: action.payload.messages, action: action.payload.action }; } case CLOSED: { return { - serviceMessage: null, + messages: [], action: null }; } diff --git a/src/app/content/selectors/serviceMessage.selectors.spec.ts b/src/app/content/selectors/serviceMessage.selectors.spec.ts index 3c2d48ae6..ac144ca55 100644 --- a/src/app/content/selectors/serviceMessage.selectors.spec.ts +++ b/src/app/content/selectors/serviceMessage.selectors.spec.ts @@ -10,7 +10,7 @@ describe('content > selectors > serviceMessage', () => { it('returns false if there is no serviceMessage', () => { const state: StateWithServiceMessage = { serviceMessage: { - serviceMessage: null, + messages: [], action: null } }; @@ -19,7 +19,7 @@ describe('content > selectors > serviceMessage', () => { it('returns true if serviceMessage is true', () => { const state: StateWithServiceMessage = { serviceMessage: { - serviceMessage: "Hey I'm a service message.", + messages: ["Hey I'm a service message."], action: null } }; diff --git a/src/app/content/selectors/serviceMessage.selectors.ts b/src/app/content/selectors/serviceMessage.selectors.ts index cfae2ce56..ec1c1a00b 100644 --- a/src/app/content/selectors/serviceMessage.selectors.ts +++ b/src/app/content/selectors/serviceMessage.selectors.ts @@ -10,14 +10,14 @@ export const getServiceMessageState = ( state: StateWithServiceMessage ): ServiceMessageState => state.serviceMessage; -export const getServiceMessage = createSelector( +export const getServiceMessages = createSelector( [getServiceMessageState], - R.prop('serviceMessage') + R.prop('messages') ); export const hasServiceMessage = createSelector( - [getServiceMessage], - serviceMessage => !!serviceMessage + [getServiceMessages], + serviceMessages => serviceMessages.length > 0 ); export const getServiceMessageAction = createSelector(