Skip to content

Commit

Permalink
refactor: #1325 Refactor toast messages using react-redux hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
Vu Nguyen committed Jun 22, 2020
1 parent d5d00c9 commit 7bd287f
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`SetDeveloperStatusModal should match snapshot 1`] = `
<Provider
store={
Object {
"clearActions": [Function],
"dispatch": [Function],
"getActions": [Function],
"getState": [Function],
"replaceReducer": [Function],
"subscribe": [Function],
}
}
>
<ToastMessage>
<Component
message=""
onCloseToast={[Function]}
variant="primary"
visible={false}
>
<div
className="toast "
data-test="toast-wrapper"
onClick={[Function]}
>
<Component
fullWidth={true}
type="reset"
variant="primary"
>
<button
className="button is-primary is-fullwidth "
data-test=""
disabled={false}
type="reset"
/>
</Component>
</div>
</Component>
</ToastMessage>
</Provider>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`SetDeveloperStatusModal should match snapshot 1`] = `
<Provider
store={
Object {
"clearActions": [Function],
"dispatch": [Function],
"getActions": [Function],
"getState": [Function],
"replaceReducer": [Function],
"subscribe": [Function],
}
}
>
<Toast>
<Component
componentError={null}
errorClearedComponent={[Function]}
errorClearedServer={[Function]}
serverError={null}
>
<div
className="toast "
data-test="toast-wrapper"
onClick={[Function]}
>
<Component
fullWidth={true}
type="reset"
variant="danger"
>
<button
className="button is-danger is-fullwidth "
data-test=""
disabled={false}
type="reset"
/>
</Component>
</div>
</Component>
</Toast>
</Provider>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react'
import * as ReactRedux from 'react-redux'
import { mount } from 'enzyme'
import configureStore from 'redux-mock-store'
import appState from '@/reducers/__stubs__/app-state'
import { hideNotificationMessage } from '@/actions/notification-message'
import ToastMessage, { handleOnCloseToast } from '../toast-message'

describe('SetDeveloperStatusModal', () => {
let store
let spyDispatch
beforeEach(() => {
/* mocking store */
const mockStore = configureStore()
store = mockStore(appState)
spyDispatch = jest.spyOn(ReactRedux, 'useDispatch').mockImplementation(() => store.dispatch)
})

it('should match snapshot', () => {
const wrapper = mount(
<ReactRedux.Provider store={store}>
<ToastMessage />
</ReactRedux.Provider>,
)
expect(wrapper).toMatchSnapshot()
})

describe('handleOnCloseToast', () => {
it('should run correctly', () => {
const fn = handleOnCloseToast(spyDispatch)
fn()
expect(spyDispatch).toBeCalledWith(hideNotificationMessage(null))
})
})
})
43 changes: 43 additions & 0 deletions packages/marketplace/src/components/ui/__tests__/toast.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react'
import * as ReactRedux from 'react-redux'
import { mount } from 'enzyme'
import configureStore from 'redux-mock-store'
import appState from '@/reducers/__stubs__/app-state'
import { errorClearedComponent, errorClearedServer } from '@/actions/error'
import Toast, { handleErrorClearedComponentCallback, handleErrorClearedServerCallback } from '../toast'

describe('SetDeveloperStatusModal', () => {
let store
let spyDispatch
beforeEach(() => {
/* mocking store */
const mockStore = configureStore()
store = mockStore(appState)
spyDispatch = jest.spyOn(ReactRedux, 'useDispatch').mockImplementation(() => store.dispatch)
})

it('should match snapshot', () => {
const wrapper = mount(
<ReactRedux.Provider store={store}>
<Toast />
</ReactRedux.Provider>,
)
expect(wrapper).toMatchSnapshot()
})

describe('handleErrorClearedComponentCallback', () => {
it('should run correctly', () => {
const fn = handleErrorClearedComponentCallback(spyDispatch)
fn()
expect(spyDispatch).toBeCalledWith(errorClearedComponent(null))
})
})

describe('errorClearedServer', () => {
it('should run correctly', () => {
const fn = handleErrorClearedServerCallback(spyDispatch)
fn()
expect(spyDispatch).toBeCalledWith(errorClearedServer(null))
})
})
})
44 changes: 24 additions & 20 deletions packages/marketplace/src/components/ui/toast-message.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
import { connect } from 'react-redux'
import * as React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Dispatch } from 'redux'
import { ToastMessage, ToastVariant } from '@reapit/elements'
import { ReduxState } from '../../types/core'
import { hideNotificationMessage } from '../../actions/notification-message'
import { ToastMessage as ToastMessageElement } from '@reapit/elements'
import { hideNotificationMessage } from '@/actions/notification-message'
import { selectNotificationMessageState } from '@/selector/notification-message'

interface ToastMessageMappedActions {
onCloseToast: () => void
}
export type ToastMessageProps = {}

interface ToastMessageMappedProps {
visible: boolean
variant: ToastVariant
message: string
export const handleOnCloseToast = (dispatch: Dispatch) => {
return () => {
dispatch(hideNotificationMessage(null))
}
}

const mapStateToProps = (state: ReduxState): ToastMessageMappedProps => ({
visible: state.noticationMessage.visible,
variant: state.noticationMessage.variant || 'primary',
message: state.noticationMessage.message,
})
const ToastMessage: React.FC<ToastMessageProps> = () => {
const dispatch = useDispatch()
const { message, variant, visible } = useSelector(selectNotificationMessageState)
const onCloseToast = React.useCallback(handleOnCloseToast(dispatch), [dispatch])

const mapDispatchToProps = (dispatch: Dispatch): ToastMessageMappedActions => ({
onCloseToast: () => dispatch(hideNotificationMessage(null)),
})
return (
<ToastMessageElement
visible={visible}
message={message}
variant={variant || 'primary'}
onCloseToast={onCloseToast}
/>
)
}

export default connect(mapStateToProps, mapDispatchToProps)(ToastMessage)
export default ToastMessage
50 changes: 30 additions & 20 deletions packages/marketplace/src/components/ui/toast.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,37 @@
import { connect } from 'react-redux'
import * as React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Dispatch } from 'redux'
import { Toast, ErrorData } from '@reapit/elements'
import { ReduxState } from '../../types/core'
import { errorClearedServer, errorClearedComponent } from '../../actions/error'
import { Toast as ToastElement } from '@reapit/elements'
import { errorClearedServer, errorClearedComponent } from '@/actions/error'
import { selectErrorState } from '@/selector/error'

interface ToastMappedActions {
errorClearedServer: () => void
errorClearedComponent: () => void
}
export type ToastProps = {}

interface ToastMappedProps {
serverError: ErrorData | null
componentError: ErrorData | null
export const handleErrorClearedServerCallback = (dispatch: Dispatch) => {
return () => {
dispatch(errorClearedServer(null))
}
}
export const handleErrorClearedComponentCallback = (dispatch: Dispatch) => {
return () => {
dispatch(errorClearedComponent(null))
}
}

const mapStateToProps = (state: ReduxState): ToastMappedProps => ({
serverError: state.error.serverError,
componentError: state.error.componentError,
})
const Toast: React.FC<ToastProps> = () => {
const dispatch = useDispatch()
const { componentError, serverError } = useSelector(selectErrorState)
const errorClearedServerCallback = React.useCallback(handleErrorClearedServerCallback(dispatch), [dispatch])
const errorClearedComponentCallback = React.useCallback(handleErrorClearedComponentCallback(dispatch), [dispatch])

const mapDispatchToProps = (dispatch: Dispatch): ToastMappedActions => ({
errorClearedServer: () => dispatch(errorClearedServer(null)),
errorClearedComponent: () => dispatch(errorClearedComponent(null)),
})
return (
<ToastElement
componentError={componentError}
serverError={serverError}
errorClearedComponent={errorClearedComponentCallback}
errorClearedServer={errorClearedServerCallback}
/>
)
}

export default connect(mapStateToProps, mapDispatchToProps)(Toast)
export default Toast
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ exports[`App should match a snapshot 1`] = `
<Component>
<Component />
</Component>
<Connect(Component) />
<Connect(Component) />
<Toast />
<ToastMessage />
</Provider>
`;
23 changes: 23 additions & 0 deletions packages/marketplace/src/selector/__tests__/error.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ReduxState } from '@/types/core'
import { selectErrorState } from '../error'

describe('selectNotificationMessageState', () => {
it('should run correctly', () => {
const input = {
error: {
componentError: {
type: 'COMPONENT',
message: 'test',
},
},
} as ReduxState
const result = selectErrorState(input)
expect(result).toEqual(input.error)
})

it('should run correctly and return []', () => {
const input = {} as ReduxState
const result = selectErrorState(input)
expect(result).toEqual(undefined)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ReduxState } from '@/types/core'
import { selectNotificationMessageState } from '../notification-message'

describe('selectNotificationMessageState', () => {
it('should run correctly', () => {
const input = {
noticationMessage: {
visible: true,
message: 'test',
},
} as ReduxState
const result = selectNotificationMessageState(input)
expect(result).toEqual(input.noticationMessage)
})

it('should run correctly and return []', () => {
const input = {} as ReduxState
const result = selectNotificationMessageState(input)
expect(result).toEqual(undefined)
})
})
6 changes: 6 additions & 0 deletions packages/marketplace/src/selector/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ReduxState } from '@/types/core'
import { ErrorState } from '@/reducers/error'

export const selectErrorState = (state: ReduxState): ErrorState => {
return state.error
}
6 changes: 6 additions & 0 deletions packages/marketplace/src/selector/notification-message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ReduxState } from '@/types/core'
import { NotificationMessageState } from '@/reducers/notification-message'

export const selectNotificationMessageState = (state: ReduxState): NotificationMessageState => {
return state.noticationMessage
}

0 comments on commit 7bd287f

Please sign in to comment.