From 3e86f8b1b903492e601a09a2bdc6389cbced5520 Mon Sep 17 00:00:00 2001 From: Steven Burnett Date: Thu, 16 Aug 2018 21:57:35 -0600 Subject: [PATCH] fix eslint for announcements Change-Id: Id5ba0a2d5b1c09372a7b8de61ba0532d8f4a0760 Reviewed-on: https://gerrit.instructure.com/161137 Reviewed-by: Landon Gilbert-Bland Tested-by: Jenkins Product-Review: Steven Burnett QA-Review: Steven Burnett --- .eslintrc.js | 4 +- app/jsx/announcements/actions.js | 197 +++++++------ app/jsx/announcements/apiClient.js | 75 ++--- .../components/AddExternalFeed.js | 32 ++- .../components/AnnouncementEmptyState.js | 2 +- .../components/AnnouncementsIndex.js | 59 ++-- .../components/ConfirmDeleteModal.js | 67 +++-- .../components/ExternalFeedsTray.js | 60 ++-- .../announcements/components/IndexHeader.js | 134 +++++---- .../announcements/components/RSSFeedList.js | 29 +- .../__tests__/AddExternalFeed.test.js | 10 +- .../__tests__/AnnouncementsEmptyState.test.js | 2 +- .../__tests__/ExternalFeedsTray.test.js | 12 +- .../components/__tests__/RSSFeedList.test.js | 6 +- app/jsx/announcements/index.js | 14 +- app/jsx/announcements/propTypes.js | 4 +- app/jsx/announcements/reducer.js | 261 ++++++++++-------- app/jsx/announcements/store.js | 6 +- 18 files changed, 565 insertions(+), 409 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 669913abe1c..c5b35431b3b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -93,7 +93,9 @@ module.exports = { // now to conform to prettier. files: [ 'app/jsx/permissions/**/*.js', - 'app/jsx/account_course_user_search/**/*.js' + 'app/jsx/account_course_user_search/**/*.js', + 'app/jsx/discussions/**/*.js', + 'app/jsx/announcements/**/*.js' ], rules: { 'prettier/prettier': 'error' diff --git a/app/jsx/announcements/actions.js b/app/jsx/announcements/actions.js index 891e5aab88b..d7132b8ac9c 100644 --- a/app/jsx/announcements/actions.js +++ b/app/jsx/announcements/actions.js @@ -17,24 +17,27 @@ */ import I18n from 'i18n!announcements_v2' -import { createActions } from 'redux-actions' +import {createActions} from 'redux-actions' import isEqual from 'lodash/isEqual' import range from 'lodash/range' import $ from 'jquery' -import 'compiled/jquery.rails_flash_notifications' +import 'compiled/jquery.rails_flash_notifications' // eslint-disable-line import * as apiClient from './apiClient' -import { createPaginationActions } from '../shared/reduxPagination' -import { notificationActions } from '../shared/reduxNotifications' +import {createPaginationActions} from '../shared/reduxPagination' +import {notificationActions} from '../shared/reduxNotifications' function fetchAnnouncements(dispatch, getState, payload) { return (resolve, reject) => { - apiClient.getAnnouncements(getState(), payload) + apiClient + .getAnnouncements(getState(), payload) .then(res => { - $.screenReaderFlashMessageExclusive(I18n.t('%{count} announcements found.', { count: res.data.length })) + $.screenReaderFlashMessageExclusive( + I18n.t('%{count} announcements found.', {count: res.data.length}) + ) resolve(res) }) - .catch(err => reject({ err, message: I18n.t('An error ocurred while loading announcements') })) + .catch(err => reject({err, message: I18n.t('An error ocurred while loading announcements')})) } } const announcementActions = createPaginationActions('announcements', fetchAnnouncements) @@ -62,12 +65,9 @@ const types = [ 'SET_ANNOUNCEMENTS_IS_LOCKING' ] -const actions = Object.assign( - createActions(...types), - announcementActions.actionCreators, -) +const actions = Object.assign(createActions(...types), announcementActions.actionCreators) -actions.searchAnnouncements = function searchAnnouncements (searchOpts) { +actions.searchAnnouncements = function searchAnnouncements(searchOpts) { return (dispatch, getState) => { const oldSearch = getState().announcementsSearch dispatch(actions.updateAnnouncementsSearch(searchOpts)) @@ -76,45 +76,52 @@ actions.searchAnnouncements = function searchAnnouncements (searchOpts) { if (!isEqual(oldSearch, newSearch)) { // uncache pages if we change the search query - dispatch(actions.clearAnnouncementsPage({ pages: range(1, state.announcements.lastPage + 1) })) - dispatch(actions.getAnnouncements({ page: 1, select: true })) + dispatch(actions.clearAnnouncementsPage({pages: range(1, state.announcements.lastPage + 1)})) + dispatch(actions.getAnnouncements({page: 1, select: true})) } } } -actions.getExternalFeeds = function () { +actions.getExternalFeeds = function() { return (dispatch, getState) => { dispatch(actions.loadingExternalFeedStart()) - apiClient.getExternalFeeds(getState()) + apiClient + .getExternalFeeds(getState()) .then(resp => { - dispatch(actions.loadingExternalFeedSuccess({ feeds: resp.data })) - }).catch((err) => { - dispatch(actions.loadingExternalFeedFail({ - message: I18n.t('Failed to Load External Feeds'), - err - })) + dispatch(actions.loadingExternalFeedSuccess({feeds: resp.data})) + }) + .catch(err => { + dispatch( + actions.loadingExternalFeedFail({ + message: I18n.t('Failed to Load External Feeds'), + err + }) + ) }) } } -actions.deleteExternalFeed = function ({ feedId }) { +actions.deleteExternalFeed = function({feedId}) { return (dispatch, getState) => { - if(!getState().externalRssFeed.isDeleting) { + if (!getState().externalRssFeed.isDeleting) { dispatch(actions.deleteExternalFeedStart()) - apiClient.deleteExternalFeed(getState(), feedId) + apiClient + .deleteExternalFeed(getState(), feedId) .then(() => { - dispatch(actions.deleteExternalFeedSuccess({ feedId })) + dispatch(actions.deleteExternalFeedSuccess({feedId})) const successMessage = I18n.t('External Feed deleted successfully') $.screenReaderFlashMessage(successMessage) - dispatch(notificationActions.notifyInfo({ message: successMessage })) + dispatch(notificationActions.notifyInfo({message: successMessage})) }) - .catch((err) => { + .catch(err => { const failMessage = I18n.t('Failed to delete external feed') $.screenReaderFlashMessage(failMessage) - dispatch(actions.deleteExternalFeedFail({ - message: failMessage, - err - })) + dispatch( + actions.deleteExternalFeedFail({ + message: failMessage, + err + }) + ) }) } } @@ -122,88 +129,113 @@ actions.deleteExternalFeed = function ({ feedId }) { actions.toggleAnnouncementsLock = (announcements, isLocking = true) => (dispatch, getState) => { dispatch(actions.lockAnnouncementsStart()) - apiClient.lockAnnouncements(getState(), [].concat(announcements), isLocking) + apiClient + .lockAnnouncements(getState(), [].concat(announcements), isLocking) .then(res => { if (res.successes.length) { - dispatch(actions.lockAnnouncementsSuccess({ res, locked: isLocking })) + dispatch(actions.lockAnnouncementsSuccess({res, locked: isLocking})) if (isLocking) { - dispatch(notificationActions.notifyInfo({ message: I18n.t('Announcements locked successfully') })) + dispatch( + notificationActions.notifyInfo({message: I18n.t('Announcements locked successfully')}) + ) } else { - dispatch(notificationActions.notifyInfo({ message: I18n.t('Announcements unlocked successfully') })) + dispatch( + notificationActions.notifyInfo({message: I18n.t('Announcements unlocked successfully')}) + ) } } else if (res.failures.length) { - dispatch(actions.lockAnnouncementsFail({ - err: res.failures, - message: I18n.t('An error occurred while updating announcements locked state.'), - })) + dispatch( + actions.lockAnnouncementsFail({ + err: res.failures, + message: I18n.t('An error occurred while updating announcements locked state.') + }) + ) } }) .catch(err => { - dispatch(actions.lockAnnouncementsFail({ err, message: I18n.t('An error occurred while locking announcements.') })) + dispatch( + actions.lockAnnouncementsFail({ + err, + message: I18n.t('An error occurred while locking announcements.') + }) + ) }) } -actions.announcementSelectionChangeStart = ({ selected , id }) => (dispatch, getState) => { - dispatch(actions.setAnnouncementSelection({ selected , id })) +actions.announcementSelectionChangeStart = ({selected, id}) => (dispatch, getState) => { + dispatch(actions.setAnnouncementSelection({selected, id})) const state = getState() - const { announcements } = state - const { items } = announcements.pages[announcements.currentPage] + const {announcements} = state + const {items} = announcements.pages[announcements.currentPage] - const selectedItems = items.filter(item => - state.selectedAnnouncements.includes(item.id)) + const selectedItems = items.filter(item => state.selectedAnnouncements.includes(item.id)) // if all the selected items are locked, we want to unlock // if any of the selected items are unlocked, we lock everything - const hasUnlockedItems = selectedItems - .reduce((hasAnyUnlocked, item) => hasAnyUnlocked || !item.locked, false) + const hasUnlockedItems = selectedItems.reduce( + (hasAnyUnlocked, item) => hasAnyUnlocked || !item.locked, + false + ) dispatch(actions.setAnnouncementsIsLocking(hasUnlockedItems)) } actions.toggleSelectedAnnouncementsLock = () => (dispatch, getState) => { const state = getState() - const { announcements } = state - const { items } = announcements.pages[announcements.currentPage] + const {announcements} = state + const {items} = announcements.pages[announcements.currentPage] - const selectedItems = items.filter(item => - state.selectedAnnouncements.includes(item.id)) + const selectedItems = items.filter(item => state.selectedAnnouncements.includes(item.id)) // if all the selected items are locked, we want to unlock // if any of the selected items are unlocked, we lock everything - const hasUnlockedItems = selectedItems - .reduce((hasAnyUnlocked, item) => hasAnyUnlocked || !item.locked, false) + const hasUnlockedItems = selectedItems.reduce( + (hasAnyUnlocked, item) => hasAnyUnlocked || !item.locked, + false + ) actions.toggleAnnouncementsLock(state.selectedAnnouncements, hasUnlockedItems)(dispatch, getState) dispatch(actions.setAnnouncementsIsLocking(!hasUnlockedItems)) // isLocking } -actions.deleteAnnouncements = (announcements) => (dispatch, getState) => { +actions.deleteAnnouncements = announcements => (dispatch, getState) => { dispatch(actions.deleteAnnouncementsStart()) - apiClient.deleteAnnouncements(getState(), [].concat(announcements)) + apiClient + .deleteAnnouncements(getState(), [].concat(announcements)) .then(res => { if (res.successes.length) { const pageState = getState().announcements dispatch(actions.deleteAnnouncementsSuccess(res)) // uncache all pages after this page, as they are no longer correct once you delete items - dispatch(actions.clearAnnouncementsPage({ pages: range(pageState.currentPage, pageState.lastPage + 1) })) + dispatch( + actions.clearAnnouncementsPage({ + pages: range(pageState.currentPage, pageState.lastPage + 1) + }) + ) - dispatch(notificationActions.notifyInfo({ message: I18n.t('Announcements deleted successfully') })) + dispatch( + notificationActions.notifyInfo({message: I18n.t('Announcements deleted successfully')}) + ) // reload current page after deleting items - dispatch(actions.getAnnouncements({ page: pageState.currentPage, select: true })) + dispatch(actions.getAnnouncements({page: pageState.currentPage, select: true})) } else if (res.failures.length) { - dispatch(actions.deleteAnnouncementsFail({ - err: res.failures, - message: I18n.t('An error occurred while deleting announcements.'), - })) + dispatch( + actions.deleteAnnouncementsFail({ + err: res.failures, + message: I18n.t('An error occurred while deleting announcements.') + }) + ) } }) .catch(err => { - dispatch(actions.deleteAnnouncementsFail({ - err, - message: I18n.t('An error occurred while deleting announcements.'), - })) + dispatch( + actions.deleteAnnouncementsFail({ + err, + message: I18n.t('An error occurred while deleting announcements.') + }) + ) }) } @@ -212,28 +244,33 @@ actions.deleteSelectedAnnouncements = () => (dispatch, getState) => { actions.deleteAnnouncements(state.selectedAnnouncements)(dispatch, getState) } -actions.addExternalFeed = function (payload) { +actions.addExternalFeed = function(payload) { return (dispatch, getState) => { dispatch(actions.addExternalFeedStart()) - apiClient.addExternalFeed(getState(), payload) + apiClient + .addExternalFeed(getState(), payload) .then(resp => { - dispatch(actions.addExternalFeedSuccess({ feed: resp.data})) + dispatch(actions.addExternalFeedSuccess({feed: resp.data})) const successMessage = I18n.t('External feed successfully added') $.screenReaderFlashMessage(successMessage) - dispatch(notificationActions.notifyInfo({ message: successMessage })) + dispatch(notificationActions.notifyInfo({message: successMessage})) }) - .catch((err) => { + .catch(err => { const failMessage = I18n.t('Failed to add new feed') $.screenReaderFlashMessage(failMessage) - dispatch(actions.addExternalFeedFail({ - message: failMessage, - err - })) + dispatch( + actions.addExternalFeedFail({ + message: failMessage, + err + }) + ) }) } } -const actionTypes = types.reduce((typesMap, actionType) => - Object.assign(typesMap, { [actionType]: actionType }), {}) +const actionTypes = types.reduce( + (typesMap, actionType) => Object.assign(typesMap, {[actionType]: actionType}), + {} +) -export { actionTypes, actions as default } +export {actionTypes, actions as default} diff --git a/app/jsx/announcements/apiClient.js b/app/jsx/announcements/apiClient.js index 7b536117765..a02d8b2108a 100644 --- a/app/jsx/announcements/apiClient.js +++ b/app/jsx/announcements/apiClient.js @@ -17,65 +17,70 @@ */ import axios from 'axios' -import { encodeQueryString } from '../shared/queryString' +import {encodeQueryString} from '../shared/queryString' import makePromisePool from '../shared/makePromisePool' const MAX_CONCURRENT_REQS = 5 -export function getAnnouncements ({ contextType, contextId, announcements, announcementsSearch }, { page }) { - const { term, filter } = announcementsSearch +export function getAnnouncements( + {contextType, contextId, announcements, announcementsSearch}, + {page} +) { + const {term, filter} = announcementsSearch const params = [ - { only_announcements: true }, - { per_page: 40 }, - { page: page || announcements.currentPage }, - { search_term: term || null }, - { filter_by: filter || null } + {only_announcements: true}, + {per_page: 40}, + {page: page || announcements.currentPage}, + {search_term: term || null}, + {filter_by: filter || null} ] if (contextType === 'course') { - params.push({ 'include[]': 'sections_user_count' }) - params.push({ 'include[]': 'sections' }) + params.push({'include[]': 'sections_user_count'}) + params.push({'include[]': 'sections'}) } const queryString = encodeQueryString(params) return axios.get(`/api/v1/${contextType}s/${contextId}/discussion_topics?${queryString}`) } -export function lockAnnouncements ({ contextType, contextId }, announcements, locked = true) { - return makePromisePool(announcements, (annId) => { - const url = `/api/v1/${contextType}s/${contextId}/discussion_topics/${annId}` - return axios.put(url, { locked }) - }, { - poolSize: MAX_CONCURRENT_REQS, - }) +export function lockAnnouncements({contextType, contextId}, announcements, locked = true) { + return makePromisePool( + announcements, + annId => { + const url = `/api/v1/${contextType}s/${contextId}/discussion_topics/${annId}` + return axios.put(url, {locked}) + }, + { + poolSize: MAX_CONCURRENT_REQS + } + ) } -export function deleteAnnouncements ({ contextType, contextId }, announcements) { - return makePromisePool(announcements, (annId) => { - const url = `/api/v1/${contextType}s/${contextId}/discussion_topics/${annId}` - return axios.delete(url) - }, { - poolSize: MAX_CONCURRENT_REQS, - }) +export function deleteAnnouncements({contextType, contextId}, announcements) { + return makePromisePool( + announcements, + annId => { + const url = `/api/v1/${contextType}s/${contextId}/discussion_topics/${annId}` + return axios.delete(url) + }, + { + poolSize: MAX_CONCURRENT_REQS + } + ) } -export function getExternalFeeds ({ contextType, contextId }) { - const params = encodeQueryString([ - { per_page: 100 } - ]) +export function getExternalFeeds({contextType, contextId}) { + const params = encodeQueryString([{per_page: 100}]) return axios.get(`/api/v1/${contextType}s/${contextId}/external_feeds?${params}`) } -export function deleteExternalFeed ({ contextType, contextId}, feedId) { +export function deleteExternalFeed({contextType, contextId}, feedId) { return axios.delete(`/api/v1/${contextType}s/${contextId}/external_feeds/${feedId}`) } -export function addExternalFeed ({ contextType, contextId }, { url, verbosity, header_match }) { - const params = encodeQueryString([ - { url }, - { verbosity }, - { header_match: header_match || null } - ]) +export function addExternalFeed({contextType, contextId}, {url, verbosity, header_match}) { + const params = encodeQueryString([{url}, {verbosity}, {header_match: header_match || null}]) return axios.post(`/api/v1/${contextType}s/${contextId}/external_feeds?${params}`) } diff --git a/app/jsx/announcements/components/AddExternalFeed.js b/app/jsx/announcements/components/AddExternalFeed.js index 3889f0a031b..de6e9d00562 100644 --- a/app/jsx/announcements/components/AddExternalFeed.js +++ b/app/jsx/announcements/components/AddExternalFeed.js @@ -22,7 +22,7 @@ import {bool, func} from 'prop-types' import {connect} from 'react-redux' import {bindActionCreators} from 'redux' import $ from 'jquery' -import 'compiled/jquery.rails_flash_notifications' +import 'compiled/jquery.rails_flash_notifications' // eslint-disable-line import Button from '@instructure/ui-buttons/lib/components/Button' import View from '@instructure/ui-layout/lib/components/View' @@ -33,7 +33,7 @@ import RadioInput from '@instructure/ui-forms/lib/components/RadioInput' import RadioInputGroup from '@instructure/ui-forms/lib/components/RadioInputGroup' import ScreenReaderContent from '@instructure/ui-a11y/lib/components/ScreenReaderContent' import ToggleDetails from '@instructure/ui-toggle-details/lib/components/ToggleDetails' -import { ConnectedRSSFeedList } from './RSSFeedList' +import {ConnectedRSSFeedList} from './RSSFeedList' import actions from '../actions' import select from '../../shared/select' @@ -47,7 +47,7 @@ const verbosityTypes = [ export default class AddExternalFeed extends React.Component { static propTypes = { defaultOpen: bool, - isSaving: bool.isRequired, + isSaving: bool.isRequired, // eslint-disable-line addExternalFeed: func.isRequired } @@ -65,7 +65,7 @@ export default class AddExternalFeed extends React.Component { focusOnToggleHeader = () => { setTimeout(() => { - this.toggleBtn.focus(); + this.toggleBtn.focus() }) } @@ -80,9 +80,12 @@ export default class AddExternalFeed extends React.Component { toggleOpenState = (event, expanded) => { $.screenReaderFlashMessage(I18n.t('dropdown changed state to %{expanded}.', {expanded})) - this.setState({ - isOpen: expanded - }, this.focusOnToggleHeader) + this.setState( + { + isOpen: expanded + }, + this.focusOnToggleHeader + ) } clearAddRSS = () => { @@ -126,7 +129,7 @@ export default class AddExternalFeed extends React.Component { ) } - toggleRef = (c) => { + toggleRef = c => { this.toggleBtn = c && c.querySelector('button') } @@ -152,7 +155,7 @@ export default class AddExternalFeed extends React.Component { textAlign="start" className="announcements-tray__rss-feed-root" > - + ) } @@ -235,7 +238,11 @@ export default class AddExternalFeed extends React.Component { expanded={this.state.isOpen} name="external-rss-feed__toggle" > - this.toggleBtn}> + this.toggleBtn} + > {this.renderTextInput( this.state.feedURL, I18n.t('Feed url'), @@ -260,4 +267,7 @@ const connectState = state => }) const connectActions = dispatch => bindActionCreators(select(actions, ['addExternalFeed']), dispatch) -export const ConnectedAddExternalFeed = connect(connectState, connectActions)(AddExternalFeed) +export const ConnectedAddExternalFeed = connect( + connectState, + connectActions +)(AddExternalFeed) diff --git a/app/jsx/announcements/components/AnnouncementEmptyState.js b/app/jsx/announcements/components/AnnouncementEmptyState.js index 913cbc92a26..b13509a4f19 100644 --- a/app/jsx/announcements/components/AnnouncementEmptyState.js +++ b/app/jsx/announcements/components/AnnouncementEmptyState.js @@ -31,7 +31,7 @@ const AnnouncementEmptyState = props => ( - + {I18n.t('No Announcements')} diff --git a/app/jsx/announcements/components/AnnouncementsIndex.js b/app/jsx/announcements/components/AnnouncementsIndex.js index 6965d6a1638..963b14d1f12 100644 --- a/app/jsx/announcements/components/AnnouncementsIndex.js +++ b/app/jsx/announcements/components/AnnouncementsIndex.js @@ -55,11 +55,11 @@ export default class AnnouncementsIndex extends Component { masterCourseData: masterCourseDataShape, deleteAnnouncements: func.isRequired, toggleAnnouncementsLock: func.isRequired, - announcementsLocked: bool.isRequired, + announcementsLocked: bool.isRequired } static defaultProps = { - masterCourseData: null, + masterCourseData: null } componentDidMount() { @@ -68,23 +68,25 @@ export default class AnnouncementsIndex extends Component { } } - onManageAnnouncement = (e, { action, id, lock }) => { + onManageAnnouncement = (e, {action, id, lock}) => { switch (action) { case 'delete': showConfirmDelete({ selectedCount: 1, - modalRef: (modal) => { this.deleteModal = modal }, + modalRef: modal => { + this.deleteModal = modal + }, onConfirm: () => { this.props.deleteAnnouncements(id) if (this.searchInput) this.searchInput.focus() - }, + } }) - break; + break case 'lock': this.props.toggleAnnouncementsLock(id, lock) - break; + break default: - break; + break } } @@ -94,13 +96,7 @@ export default class AnnouncementsIndex extends Component { renderEmptyAnnouncements() { if (this.props.hasLoadedAnnouncements && !this.props.announcements.length) { - return ( - - ) + return } else { return null } @@ -154,12 +150,8 @@ export default class AnnouncementsIndex extends Component { onClick={this.selectPage(page)} current={page === this.props.announcementsPage} > - - {I18n.t('Page %{pageNum}', {pageNum: page})} - - + {I18n.t('Page %{pageNum}', {pageNum: page})} + ) } @@ -188,7 +180,11 @@ export default class AnnouncementsIndex extends Component { {I18n.t('Announcements')} - { this.searchInput = c }} /> + { + this.searchInput = c + }} + /> {this.renderSpinner(this.props.isLoadingAnnouncements, I18n.t('Loading Announcements'))} {this.renderEmptyAnnouncements()} {this.renderAnnouncements()} @@ -201,14 +197,23 @@ export default class AnnouncementsIndex extends Component { const connectState = state => Object.assign( { - isCourseContext: state.contextType === 'course', + isCourseContext: state.contextType === 'course' }, selectPaginationState(state, 'announcements'), select(state, ['permissions', 'masterCourseData', 'announcementsLocked']) ) const connectActions = dispatch => - bindActionCreators(select(actions, - ['getAnnouncements', 'announcementSelectionChangeStart', 'deleteAnnouncements', 'toggleAnnouncementsLock'] - ), dispatch) + bindActionCreators( + select(actions, [ + 'getAnnouncements', + 'announcementSelectionChangeStart', + 'deleteAnnouncements', + 'toggleAnnouncementsLock' + ]), + dispatch + ) -export const ConnectedAnnouncementsIndex = connect(connectState, connectActions)(AnnouncementsIndex) +export const ConnectedAnnouncementsIndex = connect( + connectState, + connectActions +)(AnnouncementsIndex) diff --git a/app/jsx/announcements/components/ConfirmDeleteModal.js b/app/jsx/announcements/components/ConfirmDeleteModal.js index 6aa7eba48db..28b82216409 100644 --- a/app/jsx/announcements/components/ConfirmDeleteModal.js +++ b/app/jsx/announcements/components/ConfirmDeleteModal.js @@ -21,19 +21,22 @@ import React, {Component} from 'react' import ReactDOM from 'react-dom' import {func, number, node} from 'prop-types' -import Modal, { ModalBody, ModalFooter } from '../../shared/components/InstuiModal' +import Modal, {ModalBody, ModalFooter} from '../../shared/components/InstuiModal' import Button from '@instructure/ui-buttons/lib/components/Button' -export function showConfirmDelete (props) { +export function showConfirmDelete(props) { const parent = document.createElement('div') parent.setAttribute('class', 'confirm-delete-modal-container') document.body.appendChild(parent) - function showConfirmDeleteRef (modal) { + function showConfirmDeleteRef(modal) { if (modal) modal.show() } - ReactDOM.render(, parent) + ReactDOM.render( + , + parent + ) } export default class ConfirmDeleteModal extends Component { @@ -43,25 +46,25 @@ export default class ConfirmDeleteModal extends Component { onCancel: func, onHide: func, modalRef: func, - parent: node, + parent: node } static defaultProps = { onCancel: null, onHide: null, parent: null, - modalRef: null, + modalRef: null } state = { - show: false, + show: false } - componentDidMount () { + componentDidMount() { if (this.props.modalRef) this.props.modalRef(this) } - componentWillUnmount () { + componentWillUnmount() { if (this.props.modalRef) this.props.modalRef(null) } @@ -75,19 +78,18 @@ export default class ConfirmDeleteModal extends Component { this.hide() } - show () { - this.setState({ show: true }) + show() { + this.setState({show: true}) } - hide () { - this.setState({ show: false }, - () => { - if (this.props.onHide) setTimeout(this.props.onHide) - if (this.props.parent) ReactDOM.unmountComponentAtNode(this.props.parent) - }) + hide() { + this.setState({show: false}, () => { + if (this.props.onHide) setTimeout(this.props.onHide) + if (this.props.parent) ReactDOM.unmountComponentAtNode(this.props.parent) + }) } - render () { + render() { return ( - {I18n.t({ - one: 'You are about to delete 1 announcement. Are you sure?', - other: 'You are about to delete %{count} announcements. Are you sure?', - }, { count: this.props.selectedCount })} + {I18n.t( + { + one: 'You are about to delete 1 announcement. Are you sure?', + other: 'You are about to delete %{count} announcements. Are you sure?' + }, + {count: this.props.selectedCount} + )}   + > + {I18n.t('Cancel')} +   + variant="danger" + > + {I18n.t('Delete')} + ) } } - diff --git a/app/jsx/announcements/components/ExternalFeedsTray.js b/app/jsx/announcements/components/ExternalFeedsTray.js index 16174a76649..d1061429ee3 100644 --- a/app/jsx/announcements/components/ExternalFeedsTray.js +++ b/app/jsx/announcements/components/ExternalFeedsTray.js @@ -17,8 +17,8 @@ */ import I18n from 'i18n!announcements_v2' -import React, { Component } from 'react' -import { string } from 'prop-types' +import React, {Component} from 'react' +import {string} from 'prop-types' import Tray from '@instructure/ui-overlays/lib/components/Tray' import Link from '@instructure/ui-elements/lib/components/Link' @@ -28,7 +28,7 @@ import View from '@instructure/ui-layout/lib/components/View' import IconRssLine from '@instructure/ui-icons/lib/Line/IconRss' import Text from '@instructure/ui-elements/lib/components/Text' -import { ConnectedAddExternalFeed } from './AddExternalFeed' +import {ConnectedAddExternalFeed} from './AddExternalFeed' import propTypes from '../propTypes' export default class ExternalFeedsTray extends Component { @@ -38,11 +38,11 @@ export default class ExternalFeedsTray extends Component { } static defaultProps = { - atomFeedUrl: null, + atomFeedUrl: null } state = { - open: false, + open: false } renderTrayContent() { @@ -57,12 +57,10 @@ export default class ExternalFeedsTray extends Component { renderHeader() { return ( - - {I18n.t('External feeds')} + + + {I18n.t('External feeds')} + ) } @@ -70,15 +68,14 @@ export default class ExternalFeedsTray extends Component { renderRssFeedLink() { if (this.props.atomFeedUrl) { return ( - + {this.rssFeedLink = link}} - href={this.props.atomFeedUrl}> + linkRef={link => { + this.rssFeedLink = link + }} + href={this.props.atomFeedUrl} + > {I18n.t('RSS Feed')} @@ -97,28 +94,31 @@ export default class ExternalFeedsTray extends Component { textAlign="start" className="announcements-tray__add-rss-root" > - {I18n.t("Feeds")} + + {I18n.t('Feeds')} +
- - + +
) } - render () { + render() { return ( { - this.setState({ open: false }) + this.setState({open: false}) }} placement="end" > diff --git a/app/jsx/announcements/components/IndexHeader.js b/app/jsx/announcements/components/IndexHeader.js index 31b03bf4508..0afdf4f5094 100644 --- a/app/jsx/announcements/components/IndexHeader.js +++ b/app/jsx/announcements/components/IndexHeader.js @@ -17,16 +17,16 @@ */ import I18n from 'i18n!announcements_v2' -import React, { Component } from 'react' -import { string, func, bool, number } from 'prop-types' -import { connect } from 'react-redux' -import { debounce } from 'lodash' -import { bindActionCreators } from 'redux' +import React, {Component} from 'react' +import {string, func, bool, number} from 'prop-types' +import {connect} from 'react-redux' +import {debounce} from 'lodash' +import {bindActionCreators} from 'redux' import Button from '@instructure/ui-buttons/lib/components/Button' import TextInput from '@instructure/ui-forms/lib/components/TextInput' import Select from '@instructure/ui-core/lib/components/Select' -import Grid, { GridCol, GridRow } from '@instructure/ui-layout/lib/components/Grid' +import Grid, {GridCol, GridRow} from '@instructure/ui-layout/lib/components/Grid' import View from '@instructure/ui-layout/lib/components/View' import ScreenReaderContent from '@instructure/ui-a11y/lib/components/ScreenReaderContent' import PresentationContent from '@instructure/ui-a11y/lib/components/PresentationContent' @@ -62,46 +62,52 @@ export default class IndexHeader extends Component { toggleSelectedAnnouncementsLock: func.isRequired, deleteSelectedAnnouncements: func.isRequired, searchInputRef: func, - announcementsLocked: bool.isRequired, + announcementsLocked: bool.isRequired } static defaultProps = { isBusy: false, atomFeedUrl: null, selectedCount: 0, - searchInputRef: null, + searchInputRef: null } - onSearch = debounce(() => { - const term = this.searchInput.value - this.props.searchAnnouncements({ term }) - }, SEARCH_TIME_DELAY, { - leading: false, - trailing: true, - }) + onSearch = debounce( + () => { + const term = this.searchInput.value + this.props.searchAnnouncements({term}) + }, + SEARCH_TIME_DELAY, + { + leading: false, + trailing: true + } + ) onDelete = () => { showConfirmDelete({ - modalRef: (modal) => { this.deleteModal = modal }, + modalRef: modal => { + this.deleteModal = modal + }, selectedCount: this.props.selectedCount, onConfirm: () => this.props.deleteSelectedAnnouncements(), onHide: () => { - const { deleteBtn, searchInput } = this + const {deleteBtn, searchInput} = this if (deleteBtn && deleteBtn._button && !deleteBtn._button.disabled) { deleteBtn.focus() } else if (searchInput) { searchInput.focus() } - }, + } }) } - searchInputRef = (input) => { + searchInputRef = input => { this.searchInput = input if (this.props.searchInputRef) this.props.searchInputRef(input) } - render () { + render() { return ( @@ -110,17 +116,24 @@ export default class IndexHeader extends Component { {I18n.t('Search announcements by title')}} + label={ + + {I18n.t('Search announcements by title')} + + } placeholder={I18n.t('Search')} icon={() => } ref={this.searchInputRef} @@ -129,8 +142,7 @@ export default class IndexHeader extends Component { /> - { - this.props.permissions.manage_content && + {this.props.permissions.manage_content && !this.props.announcementsLocked && (this.props.isToggleLocking ? ( ) : ( - )) - } - {this.props.permissions.manage_content && + ))} + {this.props.permissions.manage_content && ( } - {this.props.permissions.create && + ref={c => { + this.deleteBtn = c + }} + > + + + {I18n.t('Delete Selected Announcements')} + + + )} + {this.props.permissions.create && ( - } + )} - + ) } } -const connectState = state => Object.assign({ - isBusy: state.isLockingAnnouncements || state.isDeletingAnnouncements, - selectedCount: state.selectedAnnouncements.length, - isToggleLocking: state.isToggleLocking, -}, select(state, ['contextType', 'contextId', 'permissions', 'atomFeedUrl', 'announcementsLocked'])) -const selectedActions = ['searchAnnouncements', 'toggleSelectedAnnouncementsLock', 'deleteSelectedAnnouncements'] +const connectState = state => + Object.assign( + { + isBusy: state.isLockingAnnouncements || state.isDeletingAnnouncements, + selectedCount: state.selectedAnnouncements.length, + isToggleLocking: state.isToggleLocking + }, + select(state, ['contextType', 'contextId', 'permissions', 'atomFeedUrl', 'announcementsLocked']) + ) +const selectedActions = [ + 'searchAnnouncements', + 'toggleSelectedAnnouncementsLock', + 'deleteSelectedAnnouncements' +] const connectActions = dispatch => bindActionCreators(select(actions, selectedActions), dispatch) -export const ConnectedIndexHeader = connect(connectState, connectActions)(IndexHeader) +export const ConnectedIndexHeader = connect( + connectState, + connectActions +)(IndexHeader) diff --git a/app/jsx/announcements/components/RSSFeedList.js b/app/jsx/announcements/components/RSSFeedList.js index 8bd2ce3ac9f..ed05550e3c7 100644 --- a/app/jsx/announcements/components/RSSFeedList.js +++ b/app/jsx/announcements/components/RSSFeedList.js @@ -56,8 +56,12 @@ export default class RSSFeedList extends React.Component { deleteExternalFeed = (id, index) => { this.props.deleteExternalFeed({feedId: id}) - const previousIndex = index - 1; - const elFocus = index ? () => { document.getElementById(`feed-row-${previousIndex}`).focus() } : this.props.focusLastElement + const previousIndex = index - 1 + const elFocus = index + ? () => { + document.getElementById(`feed-row-${previousIndex}`).focus() + } + : this.props.focusLastElement setTimeout(() => { elFocus() @@ -75,11 +79,17 @@ export default class RSSFeedList extends React.Component { ) } - renderFeedRow({ display_name, id, external_feed_entries_count = 0, url }, index) { + renderFeedRow({display_name, id, external_feed_entries_count = 0, url}, index) { return (
- + @@ -101,7 +111,7 @@ export default class RSSFeedList extends React.Component { size="small" placement="end" > - + @@ -121,9 +131,7 @@ export default class RSSFeedList extends React.Component { } else { return ( - {this.props.feeds.map((feed, index) => - this.renderFeedRow(feed, index) - )} + {this.props.feeds.map((feed, index) => this.renderFeedRow(feed, index))}
) @@ -141,4 +149,7 @@ const connectActions = dispatch => Object.assign(select(actions, ['getExternalFeeds', 'deleteExternalFeed'])), dispatch ) -export const ConnectedRSSFeedList = connect(connectState, connectActions)(RSSFeedList) +export const ConnectedRSSFeedList = connect( + connectState, + connectActions +)(RSSFeedList) diff --git a/app/jsx/announcements/components/__tests__/AddExternalFeed.test.js b/app/jsx/announcements/components/__tests__/AddExternalFeed.test.js index ced4be51d03..bf766a7fc40 100644 --- a/app/jsx/announcements/components/__tests__/AddExternalFeed.test.js +++ b/app/jsx/announcements/components/__tests__/AddExternalFeed.test.js @@ -18,13 +18,13 @@ import '@instructure/ui-themes/lib/canvas' import React from 'react' -import { shallow } from 'enzyme' +import {shallow} from 'enzyme' import AddExternalFeed from '../AddExternalFeed' const defaultProps = () => ({ defaultOpen: false, isSaving: false, - addExternalFeed: () => {}, + addExternalFeed: () => {} }) test('renders the AddExternalFeed component', () => { @@ -76,7 +76,11 @@ test('submits the AddExternalFeed with correct arguments', () => { }) tree.instance().handleRadioSelectionSetVerbosity('full') tree.instance().addRssSelection() - expect(addFeedSpy.mock.calls[0][0]).toMatchObject({"header_match": "phrase", "url": "url", "verbosity": "full"}) + expect(addFeedSpy.mock.calls[0][0]).toMatchObject({ + header_match: 'phrase', + url: 'url', + verbosity: 'full' + }) }) test('isDoneSelecting correctly returns true when all arguments are set', () => { diff --git a/app/jsx/announcements/components/__tests__/AnnouncementsEmptyState.test.js b/app/jsx/announcements/components/__tests__/AnnouncementsEmptyState.test.js index 4a86d5b2102..550740c68d5 100644 --- a/app/jsx/announcements/components/__tests__/AnnouncementsEmptyState.test.js +++ b/app/jsx/announcements/components/__tests__/AnnouncementsEmptyState.test.js @@ -18,7 +18,7 @@ import '@instructure/ui-themes/lib/canvas' import React from 'react' -import { mount } from 'enzyme' +import {mount} from 'enzyme' import AnnouncementEmptyState from '../AnnouncementEmptyState' const defaultProps = () => ({ diff --git a/app/jsx/announcements/components/__tests__/ExternalFeedsTray.test.js b/app/jsx/announcements/components/__tests__/ExternalFeedsTray.test.js index 483b9d202da..87df9f89941 100644 --- a/app/jsx/announcements/components/__tests__/ExternalFeedsTray.test.js +++ b/app/jsx/announcements/components/__tests__/ExternalFeedsTray.test.js @@ -18,12 +18,12 @@ import '@instructure/ui-themes/lib/canvas' import React from 'react' -import { mount, shallow } from 'enzyme' +import {mount, shallow} from 'enzyme' import ExternalFeedsTray from '../ExternalFeedsTray' -import { ConnectedRSSFeedList } from '../RSSFeedList' +import {ConnectedRSSFeedList} from '../RSSFeedList' const defaultProps = () => ({ - atomFeedUrl: "www.test.com", + atomFeedUrl: 'www.test.com', permissions: { create: false, manage_content: false, @@ -37,7 +37,7 @@ test('renders the ExternalFeedsTray component', () => { }) test('renders the AddExternalFeed component when user has permissions', () => { - const props = defaultProps(); + const props = defaultProps() props.permissions = { create: true, manage_content: false, @@ -49,7 +49,7 @@ test('renders the AddExternalFeed component when user has permissions', () => { }) test('does not render the AddExternalFeed component when user is student', () => { - const props = defaultProps(); + const props = defaultProps() props.permissions = { create: false, manage_content: false, @@ -61,7 +61,7 @@ test('does not render the AddExternalFeed component when user is student', () => }) test('does not render the RSSFeedList component when user is student', () => { - const props = defaultProps(); + const props = defaultProps() props.permissions = { create: false, manage_content: false, diff --git a/app/jsx/announcements/components/__tests__/RSSFeedList.test.js b/app/jsx/announcements/components/__tests__/RSSFeedList.test.js index cd66032c67f..e62844e74a7 100644 --- a/app/jsx/announcements/components/__tests__/RSSFeedList.test.js +++ b/app/jsx/announcements/components/__tests__/RSSFeedList.test.js @@ -18,7 +18,7 @@ import '@instructure/ui-themes/lib/canvas' import React from 'react' -import { mount } from 'enzyme' +import {mount} from 'enzyme' import RSSFeedList from '../RSSFeedList' const defaultProps = () => ({ @@ -58,7 +58,7 @@ const defaultFeeds = () => [ id: '55', external_feed_entries_count: 5, url: 'donotcare.com' - }, + } ] test('renders the RSSFeedList component', () => { @@ -129,5 +129,5 @@ test('calls deleteExternalFeed with correct feed ID when deleting feed', () => { const instance = tree.instance() instance.deleteExternalFeed('22') expect(props.deleteExternalFeed.mock.calls).toHaveLength(1) - expect(props.deleteExternalFeed.mock.calls[0][0]).toEqual({ feedId: '22'}) + expect(props.deleteExternalFeed.mock.calls[0][0]).toEqual({feedId: '22'}) }) diff --git a/app/jsx/announcements/index.js b/app/jsx/announcements/index.js index fc2ba426a6a..4da91996980 100644 --- a/app/jsx/announcements/index.js +++ b/app/jsx/announcements/index.js @@ -18,20 +18,20 @@ import React from 'react' import ReactDOM from 'react-dom' -import { Provider } from 'react-redux' +import {Provider} from 'react-redux' -import { subscribeFlashNotifications } from '../shared/reduxNotifications' -import { ConnectedAnnouncementsIndex } from './components/AnnouncementsIndex' +import {subscribeFlashNotifications} from '../shared/reduxNotifications' +import {ConnectedAnnouncementsIndex} from './components/AnnouncementsIndex' import createStore from './store' -export default function createAnnouncementsIndex (root, data = {}) { +export default function createAnnouncementsIndex(root, data = {}) { const store = createStore(data) - function unmount () { + function unmount() { ReactDOM.unmountComponentAtNode(root) } - function render () { + function render() { ReactDOM.render( @@ -42,5 +42,5 @@ export default function createAnnouncementsIndex (root, data = {}) { subscribeFlashNotifications(store) - return { unmount, render } + return {unmount, render} } diff --git a/app/jsx/announcements/propTypes.js b/app/jsx/announcements/propTypes.js index e1d9f6baac7..554cf282ddc 100644 --- a/app/jsx/announcements/propTypes.js +++ b/app/jsx/announcements/propTypes.js @@ -16,14 +16,14 @@ * with this program. If not, see . */ -import { shape, bool, string, number } from 'prop-types' +import {shape, bool, string, number} from 'prop-types' const propTypes = {} propTypes.permissions = shape({ create: bool.isRequired, manage_content: bool.isRequired, - moderate: bool.isRequired, + moderate: bool.isRequired }) propTypes.rssFeed = shape({ diff --git a/app/jsx/announcements/reducer.js b/app/jsx/announcements/reducer.js index c204f485364..70c60aa5a64 100644 --- a/app/jsx/announcements/reducer.js +++ b/app/jsx/announcements/reducer.js @@ -18,49 +18,47 @@ import uniq from 'lodash/uniq' import without from 'lodash/without' -import { combineReducers } from 'redux' -import { handleActions } from 'redux-actions' -import { actionTypes } from './actions' -import { reduceNotifications } from '../shared/reduxNotifications' -import { createPaginatedReducer } from '../shared/reduxPagination' +import {combineReducers} from 'redux' +import {handleActions} from 'redux-actions' +import {actionTypes} from './actions' +import {reduceNotifications} from '../shared/reduxNotifications' +import {createPaginatedReducer} from '../shared/reduxPagination' const MIN_SEATCH_LENGTH = 3 -const identity = (defaultState = null) => ( - state => (state === undefined ? defaultState : state) -) +const identity = (defaultState = null) => state => (state === undefined ? defaultState : state) const reduceAnnouncementsPagination = createPaginatedReducer('announcements') -const reduceItems = handleActions({ - [actionTypes.LOCK_ANNOUNCEMENTS_SUCCESS]: (state, action) => { - const successIds = action.payload.res.successes.map(success => success.data) - return state.map(item => { - return successIds.includes(item.id) - ? ({ ...item, locked: action.payload.locked }) - : item - }) +const reduceItems = handleActions( + { + [actionTypes.LOCK_ANNOUNCEMENTS_SUCCESS]: (state, action) => { + const successIds = action.payload.res.successes.map(success => success.data) + return state.map( + item => (successIds.includes(item.id) ? {...item, locked: action.payload.locked} : item) + ) + } }, -}, []) + [] +) -function reducePage (page = {}, action) { - return ({ ...page, items: reduceItems(page.items, action) }) +function reducePage(page = {}, action) { + return {...page, items: reduceItems(page.items, action)} } -function reduceCurrentPage (currentPage) { - return (announcements = {}, action) => - ({ - ...announcements, - pages: { - ...announcements.pages, - [currentPage]: reducePage(announcements.pages[currentPage], action), - }, - }) +function reduceCurrentPage(currentPage) { + return (announcements = {}, action) => ({ + ...announcements, + pages: { + ...announcements.pages, + [currentPage]: reducePage(announcements.pages[currentPage], action) + } + }) } -function reduceAnnouncements (announcements, action) { - const { currentPage, pages } = announcements - let newState = { ...announcements } +function reduceAnnouncements(announcements, action) { + const {currentPage, pages} = announcements + let newState = {...announcements} if (currentPage && pages && pages[currentPage]) { newState = reduceCurrentPage(currentPage)(announcements, action) @@ -76,106 +74,137 @@ export default combineReducers({ permissions: identity({}), masterCourseData: identity(null), atomFeedUrl: identity(null), - isToggleLocking: handleActions({ - [actionTypes.SET_ANNOUNCEMENTS_IS_LOCKING] : (state, action) => action.payload - }, false), + isToggleLocking: handleActions( + { + [actionTypes.SET_ANNOUNCEMENTS_IS_LOCKING]: (state, action) => action.payload + }, + false + ), announcements: (state, action) => { const paginatedState = reduceAnnouncementsPagination(state, action) const newState = reduceAnnouncements(paginatedState, action) return newState }, announcementsSearch: combineReducers({ - term: handleActions({ - [actionTypes.UPDATE_ANNOUNCEMENTS_SEARCH]: (state, action) => { - const term = action.payload && action.payload.term - if (term === undefined) { - return state - } else if (term.length < MIN_SEATCH_LENGTH) { - return '' - } else { - return term + term: handleActions( + { + [actionTypes.UPDATE_ANNOUNCEMENTS_SEARCH]: (state, action) => { + const term = action.payload && action.payload.term + if (term === undefined) { + return state + } else if (term.length < MIN_SEATCH_LENGTH) { + return '' + } else { + return term + } } - } }, ''), - filter: handleActions({ - [actionTypes.UPDATE_ANNOUNCEMENTS_SEARCH]: (state, action) => { - const filter = action.payload && action.payload.filter - if (filter === undefined) { - return state - } else { - return filter + }, + '' + ), + filter: handleActions( + { + [actionTypes.UPDATE_ANNOUNCEMENTS_SEARCH]: (state, action) => { + const filter = action.payload && action.payload.filter + if (filter === undefined) { + return state + } else { + return filter + } } - } - }, 'all'), + }, + 'all' + ) }), - selectedAnnouncements: handleActions({ - [actionTypes.SET_ANNOUNCEMENT_SELECTION]: (state, action) => { - if (action.payload.selected) { - return uniq([...state, action.payload.id]) - } else { - return without(state, action.payload.id) - } + selectedAnnouncements: handleActions( + { + [actionTypes.SET_ANNOUNCEMENT_SELECTION]: (state, action) => { + if (action.payload.selected) { + return uniq([...state, action.payload.id]) + } else { + return without(state, action.payload.id) + } + }, + [actionTypes.CLEAR_ANNOUNCEMENT_SELECTIONS]: () => [], + [actionTypes.DELETE_ANNOUNCEMENTS_SUCCESS]: () => [] }, - [actionTypes.CLEAR_ANNOUNCEMENT_SELECTIONS]: () => [], - [actionTypes.DELETE_ANNOUNCEMENTS_SUCCESS]: () => [], - }, []), - isLockingAnnouncements: handleActions({ - [actionTypes.LOCK_ANNOUNCEMENTS_START]: () => true, - [actionTypes.LOCK_ANNOUNCEMENTS_SUCCESS]: () => false, - [actionTypes.LOCK_ANNOUNCEMENTS_FAIL]: () => false, - }, false), - isDeletingAnnouncements: handleActions({ - [actionTypes.DELETE_ANNOUNCEMENTS_START]: () => true, - [actionTypes.DELETE_ANNOUNCEMENTS_SUCCESS]: () => false, - [actionTypes.DELETE_ANNOUNCEMENTS_FAIL]: () => false, - }, false), + [] + ), + isLockingAnnouncements: handleActions( + { + [actionTypes.LOCK_ANNOUNCEMENTS_START]: () => true, + [actionTypes.LOCK_ANNOUNCEMENTS_SUCCESS]: () => false, + [actionTypes.LOCK_ANNOUNCEMENTS_FAIL]: () => false + }, + false + ), + isDeletingAnnouncements: handleActions( + { + [actionTypes.DELETE_ANNOUNCEMENTS_START]: () => true, + [actionTypes.DELETE_ANNOUNCEMENTS_SUCCESS]: () => false, + [actionTypes.DELETE_ANNOUNCEMENTS_FAIL]: () => false + }, + false + ), externalRssFeed: combineReducers({ - isSaving: handleActions({ - [actionTypes.ADD_EXTERNAL_FEED_START]: () => true, - [actionTypes.ADD_EXTERNAL_FEED_FAIL]: () => false, - [actionTypes.ADD_EXTERNAL_FEED_SUCCESS]: () => false - }, false), - isDeleting: handleActions({ - [actionTypes.DELETE_EXTERNAL_FEED_START]: () => true, - [actionTypes.DELETE_EXTERNAL_FEED_FAIL]: () => false, - [actionTypes.DELETE_EXTERNAL_FEED_SUCCESS]: () => false - }, false), - feeds: handleActions({ - [actionTypes.LOADING_EXTERNAL_FEED_SUCCESS]: (state, action) => { - const feeds = action.payload && action.payload.feeds - if (feeds === undefined || !Array.isArray(feeds)) { - return state - } - return feeds + isSaving: handleActions( + { + [actionTypes.ADD_EXTERNAL_FEED_START]: () => true, + [actionTypes.ADD_EXTERNAL_FEED_FAIL]: () => false, + [actionTypes.ADD_EXTERNAL_FEED_SUCCESS]: () => false }, - [actionTypes.LOADING_EXTERNAL_FEED_FAIL]: () => [], - [actionTypes.ADD_EXTERNAL_FEED_SUCCESS]: (state, action) => { - const feed = action.payload && action.payload.feed - if (feed === undefined || !feed.id) { - return state - } - - const newState = state.slice(); - newState.push(feed) - return newState + false + ), + isDeleting: handleActions( + { + [actionTypes.DELETE_EXTERNAL_FEED_START]: () => true, + [actionTypes.DELETE_EXTERNAL_FEED_FAIL]: () => false, + [actionTypes.DELETE_EXTERNAL_FEED_SUCCESS]: () => false }, - [actionTypes.DELETE_EXTERNAL_FEED_SUCCESS]: (state, action) => { - const feedId = action.payload && action.payload.feedId - if (feedId === undefined) { - return state - } + false + ), + feeds: handleActions( + { + [actionTypes.LOADING_EXTERNAL_FEED_SUCCESS]: (state, action) => { + const feeds = action.payload && action.payload.feeds + if (feeds === undefined || !Array.isArray(feeds)) { + return state + } + return feeds + }, + [actionTypes.LOADING_EXTERNAL_FEED_FAIL]: () => [], + [actionTypes.ADD_EXTERNAL_FEED_SUCCESS]: (state, action) => { + const feed = action.payload && action.payload.feed + if (feed === undefined || !feed.id) { + return state + } - const removedState = state.filter(el => el.id !== feedId ) - if (removedState.length === state.length) { - return state + const newState = state.slice() + newState.push(feed) + return newState + }, + [actionTypes.DELETE_EXTERNAL_FEED_SUCCESS]: (state, action) => { + const feedId = action.payload && action.payload.feedId + if (feedId === undefined) { + return state + } + + const removedState = state.filter(el => el.id !== feedId) + if (removedState.length === state.length) { + return state + } + return removedState } - return removedState - } - }, []), - hasLoadedFeed: handleActions({ - [actionTypes.LOADING_EXTERNAL_FEED_START]: () => false, - [actionTypes.LOADING_EXTERNAL_FEED_SUCCESS]: () => true, - [actionTypes.LOADING_EXTERNAL_FEED_FAIL]: () => true - }, false) + }, + [] + ), + hasLoadedFeed: handleActions( + { + [actionTypes.LOADING_EXTERNAL_FEED_START]: () => false, + [actionTypes.LOADING_EXTERNAL_FEED_SUCCESS]: () => true, + [actionTypes.LOADING_EXTERNAL_FEED_FAIL]: () => true + }, + false + ) }), notifications: reduceNotifications, announcementsLocked: identity(false) diff --git a/app/jsx/announcements/store.js b/app/jsx/announcements/store.js index be554dbe13a..0c21af41abf 100644 --- a/app/jsx/announcements/store.js +++ b/app/jsx/announcements/store.js @@ -16,16 +16,16 @@ * with this program. If not, see . */ -import { createStore, applyMiddleware } from 'redux' +import {createStore, applyMiddleware} from 'redux' import ReduxThunk from 'redux-thunk' import rootReducer from './reducer' -export default function configStore (initialState) { +export default function configStore(initialState) { const middleware = [ ReduxThunk, // this is so redux-logger is not included in the production webpack bundle - (process.env.NODE_ENV !== 'production') && require('redux-logger')() // eslint-disable-line global-require + process.env.NODE_ENV !== 'production' && require('redux-logger')() // eslint-disable-line global-require ].filter(Boolean) return applyMiddleware(...middleware)(createStore)(rootReducer, initialState) }