at the end of the day, it was inevitable
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
import {ReduxModule} from '../../../abstract/reduxModule'
|
||||
|
||||
class ThemeForm extends ReduxModule {
|
||||
|
||||
getNamespace () {
|
||||
return '[Theme form]'
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
export default ThemeForm
|
||||
|
||||
/*export class ThemeForm extends abstractModule {
|
||||
constructor () {
|
||||
super();
|
||||
this.initNamespace('THEMES_');
|
||||
}
|
||||
|
||||
initInitialState () {
|
||||
const rgbaString = 'rgba(0, 0, 0, 1)';
|
||||
const string = '';
|
||||
const int = 0;
|
||||
const boolean = false;
|
||||
const languageCode = 'en';
|
||||
const File = new File;
|
||||
|
||||
const FontOptions = {
|
||||
family: string,
|
||||
size: int,
|
||||
style: {
|
||||
bold: boolean,
|
||||
italic: boolean,
|
||||
underline: boolean
|
||||
}
|
||||
};
|
||||
|
||||
// sample of structure for backend
|
||||
const BackendThemeOptions = {
|
||||
type: 'enhanced' || 'plain',
|
||||
summary: string,
|
||||
conclusion: string,
|
||||
header: {
|
||||
imageUrl: string,
|
||||
logoLink: string || '',
|
||||
title: 'Newsletter' // only for enhanced
|
||||
},
|
||||
fonts: {
|
||||
header: FontOptions,
|
||||
tableOfContents: FontOptions,
|
||||
feeTitle: FontOptions,
|
||||
articleHeadline: FontOptions,
|
||||
source: FontOptions,
|
||||
author: FontOptions,
|
||||
date: FontOptions,
|
||||
articleContent: FontOptions
|
||||
},
|
||||
content: {
|
||||
highlightKeywords: {
|
||||
bold: boolean,
|
||||
color: rgbaString
|
||||
},
|
||||
showInfo: {
|
||||
sourceCountry: boolean,
|
||||
articleSentiment: boolean,
|
||||
articleCount: boolean,
|
||||
images: boolean,
|
||||
sharingOptions: boolean,
|
||||
sectionDivider: boolean,
|
||||
userComments: 'no' || 'with_author_date' || 'without_author_date',
|
||||
tableOfContents: {
|
||||
visible: boolean,
|
||||
headline: 'no' || 'headline' || 'headline_source_date' || 'source_headline_date'
|
||||
}
|
||||
},
|
||||
language: languageCode,
|
||||
extract: 'start' || 'context' || 'no'
|
||||
},
|
||||
colors: {
|
||||
background: {
|
||||
header: rgbaString,
|
||||
emailBody: rgbaString,
|
||||
accent: rgbaString
|
||||
},
|
||||
text: {
|
||||
header: rgbaString,
|
||||
articleHeadline: rgbaString,
|
||||
articleContent: rgbaString,
|
||||
author: rgbaString,
|
||||
publishDate: rgbaString,
|
||||
source: rgbaString
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.initialState = fromJS({
|
||||
name: string,
|
||||
template: string,
|
||||
options: {
|
||||
type: 'enhanced' || 'plain',
|
||||
summary: {
|
||||
value: string,
|
||||
isEdit: boolean
|
||||
},
|
||||
conclusion: {
|
||||
value: string,
|
||||
isEdit: boolean
|
||||
},
|
||||
header: {
|
||||
imageUrl: {
|
||||
file: File,
|
||||
url: string
|
||||
},
|
||||
logoLink: string,
|
||||
title: {
|
||||
value: string,
|
||||
isEdit: boolean
|
||||
}
|
||||
},
|
||||
fonts: {
|
||||
header: FontOptions,
|
||||
tableOfContents: FontOptions,
|
||||
feeTitle: FontOptions,
|
||||
articleHeadline: FontOptions,
|
||||
source: FontOptions,
|
||||
author: FontOptions,
|
||||
date: FontOptions,
|
||||
articleContent: FontOptions
|
||||
},
|
||||
content: {
|
||||
language: languageCode,
|
||||
extract: {
|
||||
value: 'start',
|
||||
entities: [{
|
||||
value: 'start',
|
||||
label: 'Start of text extract'
|
||||
}, {
|
||||
value: 'context',
|
||||
label: 'Contextual extract'
|
||||
}, {
|
||||
value: 'no',
|
||||
label: 'No article extract'
|
||||
}]
|
||||
},
|
||||
highlightKeywords: {
|
||||
bold: boolean,
|
||||
color: rgbaString,
|
||||
colorPresets: [rgbaString]
|
||||
},
|
||||
showInfo: {
|
||||
sourceCountry: boolean,
|
||||
articleSentiment: boolean,
|
||||
articleCount: boolean,
|
||||
images: boolean,
|
||||
sharingOptions: boolean,
|
||||
sectionDivider: boolean,
|
||||
userComments: {
|
||||
value: 'no',
|
||||
entities: [{
|
||||
value: 'no',
|
||||
label: 'No User Comments'
|
||||
}, {
|
||||
value: 'with_author_date',
|
||||
label: 'User Comments with Author/Date'
|
||||
}, {
|
||||
value: 'without_author_date',
|
||||
label: 'User Comments without Author/Date'
|
||||
}]
|
||||
},
|
||||
tableOfContents: {
|
||||
types: {
|
||||
value: 'simple',
|
||||
entities: [{
|
||||
value: 'simple',
|
||||
label: 'Table of contents'
|
||||
}, {
|
||||
value: 'headlines',
|
||||
label: 'Table of contents with headlines'
|
||||
}, {
|
||||
value: 'no',
|
||||
label: 'No table of contents'
|
||||
}]
|
||||
},
|
||||
headlines: {
|
||||
value: null,
|
||||
entities: [{
|
||||
value: 'headline',
|
||||
label: 'Headline only'
|
||||
}, {
|
||||
value: 'headline_source_date',
|
||||
label: 'Headline | Source | Date'
|
||||
}, {
|
||||
value: 'source_headline_date',
|
||||
label: 'Source | Headline | Date'
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
colors: {
|
||||
background: {
|
||||
header: rgbaString,
|
||||
emailBody: rgbaString,
|
||||
accent: rgbaString
|
||||
},
|
||||
text: {
|
||||
header: rgbaString,
|
||||
articleHeadline: rgbaString,
|
||||
articleContent: rgbaString,
|
||||
author: rgbaString,
|
||||
publishDate: rgbaString,
|
||||
source: rgbaString
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
initActions () {
|
||||
this.actions = {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const themeForm = new ThemeForm();
|
||||
themeForm.init();
|
||||
|
||||
export default themeForm.reducers;
|
||||
*/
|
||||
@@ -0,0 +1,49 @@
|
||||
import * as api from '../../../../../api/themesApi'
|
||||
import ReduxModule from '../../../abstract/reduxModule'
|
||||
|
||||
const GET_DEFAULT_THEME = 'Get default theme'
|
||||
|
||||
export class Themes extends ReduxModule {
|
||||
|
||||
getNamespace () {
|
||||
return '[Themes]'
|
||||
}
|
||||
|
||||
getDefaultTheme = ({token, fulfilled}) => {
|
||||
return api
|
||||
.getDefaultItem(token)
|
||||
.then((data) => {
|
||||
fulfilled(data)
|
||||
return data
|
||||
})
|
||||
};
|
||||
|
||||
defineActions () {
|
||||
const getDefaultTheme = this.thunkAction(GET_DEFAULT_THEME, this.getDefaultTheme)
|
||||
return {
|
||||
getDefaultTheme
|
||||
}
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
isPending: false,
|
||||
themes: [],
|
||||
defaultTheme: null,
|
||||
activeId: ''
|
||||
}
|
||||
}
|
||||
|
||||
defineReducers () {
|
||||
return {
|
||||
[`${GET_DEFAULT_THEME} fulfilled`]: this.setReducer('defaultTheme')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const themes = new Themes()
|
||||
themes.init()
|
||||
export default themes
|
||||
|
||||
export const getDefaultTheme = themes.actions.getDefaultTheme
|
||||
@@ -0,0 +1,77 @@
|
||||
import {handleActions, createAction} from 'redux-actions'
|
||||
import {fromJS} from 'immutable'
|
||||
import {thunkAction} from '../../../utils/common'
|
||||
import * as api from '../../../../api/feedsApi'
|
||||
import {getSidebarCategories} from '../sidebar'
|
||||
import { getRestrictions } from '../../common/auth'
|
||||
|
||||
/** CONSTANTS **/
|
||||
const NS = '[Export]'
|
||||
const LOAD_EXPORTED_FEEDS = `${NS} Load exported feeds`
|
||||
const SHOW_EXPORT_POPUP = `${NS} Show export popup`
|
||||
const HIDE_EXPORT_POPUP = `${NS} Hide export popup`
|
||||
const UNEXPORT_FEED = `${NS} Unexport feed`
|
||||
|
||||
/** ACTIONS **/
|
||||
|
||||
const loadExportedFeeds = thunkAction(LOAD_EXPORTED_FEEDS, ({token, fulfilled}) => {
|
||||
return api
|
||||
.loadExportedFeeds(token)
|
||||
.then((data) => {
|
||||
fulfilled(data)
|
||||
})
|
||||
}, true)
|
||||
|
||||
const showExportPopup = createAction(SHOW_EXPORT_POPUP, (feed, exportFormat) => ({feed, exportFormat}))
|
||||
const hideExportPopup = createAction(HIDE_EXPORT_POPUP)
|
||||
|
||||
const unexportFeed = thunkAction(UNEXPORT_FEED, (feedId, {token, fulfilled, dispatch}) => {
|
||||
return api
|
||||
.toggleExportFeed(token, {export: false}, feedId)
|
||||
.then(() => {
|
||||
fulfilled()
|
||||
dispatch(getSidebarCategories())
|
||||
dispatch(getRestrictions())
|
||||
dispatch(loadExportedFeeds())
|
||||
})
|
||||
})
|
||||
|
||||
export const actions = {
|
||||
loadExportedFeeds,
|
||||
showExportPopup,
|
||||
hideExportPopup,
|
||||
unexportFeed
|
||||
}
|
||||
|
||||
//**** STATE ****//
|
||||
export const initialState = fromJS({
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
popupVisible: false,
|
||||
selectedFeed: null,
|
||||
exportFormat: ''
|
||||
})
|
||||
|
||||
export default handleActions({
|
||||
|
||||
[`${LOAD_EXPORTED_FEEDS} pending`]: (state, {payload: {isPending}}) => {
|
||||
return state.set('isLoading', isPending)
|
||||
},
|
||||
|
||||
[`${LOAD_EXPORTED_FEEDS} fulfilled`]: (state, {payload: data}) => {
|
||||
return state.set('tableData', data)
|
||||
},
|
||||
|
||||
[SHOW_EXPORT_POPUP]: (state, {payload: {feed, exportFormat}}) => {
|
||||
return state.merge({
|
||||
selectedFeed: feed,
|
||||
popupVisible: true,
|
||||
exportFormat
|
||||
})
|
||||
},
|
||||
|
||||
[HIDE_EXPORT_POPUP]: (state) => {
|
||||
return state.set('popupVisible', false)
|
||||
}
|
||||
|
||||
}, initialState)
|
||||
@@ -0,0 +1,117 @@
|
||||
import { getCurrentTimezone } from '../../../../../common/Timezones'
|
||||
import { createItem, updateItem } from '../../../../../api/notificationsApi'
|
||||
import {NotificationForm, THEME_TYPES} from './notificationForm'
|
||||
import {addAlert} from '../../../common/alerts'
|
||||
import {getRestrictions} from '../../../common/auth'
|
||||
import {switchShareSubScreen, NOTIFICATION_SUBSCREENS} from '../tabs'
|
||||
|
||||
export const EXTRAS = {
|
||||
CONTEXTUAL: 'context',
|
||||
START: 'start',
|
||||
NO: 'no'
|
||||
}
|
||||
|
||||
export class AlertForm extends NotificationForm {
|
||||
|
||||
getNamespace () {
|
||||
return '[Alert Form]'
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
name: 'New Alert',
|
||||
recipients: [],
|
||||
subject: '',
|
||||
automatedSubject: false,
|
||||
published: false,
|
||||
allowUnsubscribe: false,
|
||||
unsubscribeNotification: false,
|
||||
sources: [],
|
||||
content: {
|
||||
extract: EXTRAS.CONTEXTUAL,
|
||||
highlightKeywords: {
|
||||
highlight: false
|
||||
},
|
||||
showInfo: {
|
||||
sourceCountry: false,
|
||||
userComments: 'no'
|
||||
}
|
||||
},
|
||||
themeType: THEME_TYPES.PLAIN,
|
||||
sendWhenEmpty: false,
|
||||
timezone: getCurrentTimezone(),
|
||||
isEnabledTimezone: false,
|
||||
isDefaultTimezone: true,
|
||||
sendUntil: '',
|
||||
scheduling: {
|
||||
constants: {
|
||||
type: ['daily', 'weekly', 'monthly'],
|
||||
time: ['15m', '30m', '1h', '2h', '3h', '4h', '6h', '12h', 'once'],
|
||||
days: ['all', 'weekdays', 'weekends'],
|
||||
period: ['every', 'first', 'second', 'third', 'fourth', 'last'],
|
||||
day: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'],
|
||||
monthDay: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 'Last'],
|
||||
hour: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23],
|
||||
minute: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]
|
||||
},
|
||||
newTime: {
|
||||
type: 'daily',
|
||||
time: '15m',
|
||||
days: 'all',
|
||||
period: 'every',
|
||||
monthDay: 1,
|
||||
day: 'monday',
|
||||
hour: 13,
|
||||
minute: 0
|
||||
},
|
||||
times: []
|
||||
},
|
||||
showSaveAsPopup: false,
|
||||
sendHistory: {
|
||||
isOpen: false,
|
||||
isPending: false,
|
||||
isLoadingCompleted: false,
|
||||
page: 0,
|
||||
limit: 5,
|
||||
totalCount: 0,
|
||||
entities: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serialize (data, theme) {
|
||||
let serialized = super.serialize(data, theme)
|
||||
return {
|
||||
...serialized,
|
||||
notificationType: 'alert'
|
||||
}
|
||||
}
|
||||
|
||||
saveAlert = (isEdit, {dispatch, getState, token}) => {
|
||||
const data = getState().getIn(['appState', 'share', 'forms', 'alert'])
|
||||
const id = data.get('id')
|
||||
const theme = getState().getIn(['appState', 'share', 'themes', 'defaultTheme'])
|
||||
const alertData = this.serialize(data, theme)
|
||||
const promise = isEdit ? updateItem(token, alertData, id) : createItem(token, alertData)
|
||||
return promise
|
||||
.then((data) => {
|
||||
dispatch(getRestrictions())
|
||||
dispatch(addAlert({type: 'notice', transKey: 'alertSaved'}))
|
||||
dispatch(switchShareSubScreen('notifications', NOTIFICATION_SUBSCREENS.TABLES))
|
||||
})
|
||||
};
|
||||
|
||||
defineActions () {
|
||||
const actions = super.defineActions()
|
||||
const saveAlert = this.thunkAction('SAVE_ALERT', this.saveAlert)
|
||||
return {
|
||||
...actions,
|
||||
saveAlert
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new AlertForm()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,94 @@
|
||||
import {ReceiverForm} from './receiverForm'
|
||||
import {
|
||||
GROUP_FORM_TABLES, switchShareSubScreen, switchShareTable, RECEIVER_TABLES, RECEIVER_SUBSCREENS
|
||||
} from '../tabs'
|
||||
import {fromJS} from 'immutable'
|
||||
import * as api from '../../../../../api/groupsApi'
|
||||
import {addAlert} from '../../../common/alerts'
|
||||
|
||||
const SAVE_GROUP = 'Save group'
|
||||
|
||||
export class GroupForm extends ReceiverForm {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Group Form]'
|
||||
}
|
||||
|
||||
serialize (data) {
|
||||
return {
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
active: data.active,
|
||||
recipients: data.recipients,
|
||||
notifications: data.subscriptions
|
||||
}
|
||||
};
|
||||
|
||||
normalize (data) {
|
||||
let newState = this.getInitialState()
|
||||
newState = {
|
||||
...newState,
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
description: data.description || '',
|
||||
active: data.active,
|
||||
recipients: data.recipients,
|
||||
subscriptions: data.subscriptions.ids
|
||||
}
|
||||
return fromJS(newState)
|
||||
};
|
||||
|
||||
saveGroup = ({dispatch, fulfilled, getState, token}) => {
|
||||
const data = getState().getIn(['appState', 'share', 'forms', 'group']).toJS()
|
||||
const id = data.id
|
||||
|
||||
if (data.name) {
|
||||
const payload = this.serialize(data)
|
||||
const apiRequest = id ? api.updateItem(token, payload, id) : api.createItem(token, payload)
|
||||
return apiRequest.then(() => {
|
||||
fulfilled()
|
||||
dispatch(addAlert({type: 'notice', transKey: 'groupSaved'}))
|
||||
dispatch(switchShareSubScreen('recipients', RECEIVER_SUBSCREENS.TABLES))
|
||||
dispatch(switchShareTable('recipients', RECEIVER_TABLES.GROUPS))
|
||||
})
|
||||
|
||||
} else {
|
||||
dispatch(addAlert({type: 'error', transKey: 'groupNameEmpty'}))
|
||||
}
|
||||
};
|
||||
|
||||
defineActions () {
|
||||
const saveReceiver = this.thunkAction(SAVE_GROUP, this.saveGroup, true)
|
||||
|
||||
return {
|
||||
...super.defineActions(),
|
||||
saveReceiver,
|
||||
deleteReceiver: this.deleteGroup
|
||||
}
|
||||
}
|
||||
|
||||
getTableTabs () {
|
||||
return [GROUP_FORM_TABLES.RECIPIENTS, GROUP_FORM_TABLES.SUBSCRIPTIONS, GROUP_FORM_TABLES.EMAIL_HISTORY]
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
const state = super.getInitialState()
|
||||
return {
|
||||
name: '',
|
||||
description: '',
|
||||
creationDate: '',
|
||||
recipients: [],
|
||||
subscriptions: [],
|
||||
...state
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new GroupForm()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,18 @@
|
||||
import {NotificationForm} from './notificationForm'
|
||||
|
||||
export class NewsletterForm extends NotificationForm {
|
||||
|
||||
getNamespace () {
|
||||
return '[Newsletter Form]'
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new NewsletterForm()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,313 @@
|
||||
import {ReduxModule} from '../../../abstract/reduxModule'
|
||||
import {fromJS} from 'immutable'
|
||||
import { getItems as getReceiversApi } from '../../../../../api/receiversApi'
|
||||
import { getHistory as getHistoryApi } from '../../../../../api/notificationsApi'
|
||||
import {tokenInject} from '../../../../utils/common'
|
||||
import {addAlert} from '../../../common/alerts'
|
||||
|
||||
const ADD_SOURCE = 'ADD_SOURCE'
|
||||
const REMOVE_SOURCE = 'REMOVE_SOURCE'
|
||||
const MOVE_SOURCE = 'MOVE_SOURCE'
|
||||
const ADD_SCHEDULE = 'ADD_SCHEDULE'
|
||||
const REMOVE_SCHEDULE = 'REMOVE_SCHEDULE'
|
||||
const FILL_FORM = 'FILL_FORM'
|
||||
const HISTORY = 'HISTORY'
|
||||
const CHANGE_SCHEDULE = 'CHANGE_SCHEDULE'
|
||||
|
||||
export const THEME_TYPES = {
|
||||
PLAIN: 'plain',
|
||||
ENHANCED: 'enhanced'
|
||||
}
|
||||
|
||||
export class NotificationForm extends ReduxModule {
|
||||
|
||||
normalize (data, theme) {
|
||||
// console.log('notificationForm::normalize, input=', data)
|
||||
let newState = this.getInitialState()
|
||||
const automatic = data.automatic
|
||||
const notificationType = data.type
|
||||
const themeType = data.themeType
|
||||
const recipients = data.recipients
|
||||
const themeDiff = themeType === 'plain' ? data.plainDiff : data.enhancedDiff
|
||||
const immTheme = fromJS(theme[themeType])
|
||||
|
||||
const fieldsToDelete = ['recipients', 'automatic', 'plainDiff', 'enhancedDiff', 'owner', 'type']
|
||||
fieldsToDelete.forEach(field => delete data[field])
|
||||
|
||||
newState = {
|
||||
...newState,
|
||||
...data,
|
||||
sendUntil: data.sendUntil || '',
|
||||
notificationType
|
||||
}
|
||||
|
||||
newState.scheduling.times = automatic.map(time => {
|
||||
if (time.type === 'monthly') {
|
||||
time.monthDay = (time.day === 'last') ? 'Last' : parseInt(time.day)
|
||||
}
|
||||
return time
|
||||
})
|
||||
|
||||
newState.recipients = recipients.map(r => ({label: r.name, value: r.id}))
|
||||
|
||||
newState = fromJS(newState)
|
||||
|
||||
const paths = ['content:extract', 'content:highlightKeywords:highlight', 'content:showInfo:sourceCountry', 'content:showInfo:userComments']
|
||||
paths.forEach(path => {
|
||||
const immPath = path.split(':')
|
||||
const value = (themeDiff[path]) ? themeDiff[path] : immTheme.getIn(immPath)
|
||||
newState = newState.setIn(immPath, value)
|
||||
})
|
||||
|
||||
// console.log('notificationForm::normalize, output=', newState.toJS())
|
||||
return newState
|
||||
}
|
||||
|
||||
_serializeScheduleItem (time) {
|
||||
switch (time.type) {
|
||||
case 'daily':
|
||||
delete time.period
|
||||
delete time.day
|
||||
delete time.hour
|
||||
delete time.minute
|
||||
break
|
||||
case 'weekly':
|
||||
delete time.time
|
||||
delete time.days
|
||||
break
|
||||
case 'monthly':
|
||||
delete time.period
|
||||
delete time.time
|
||||
delete time.days
|
||||
time.day = (time.monthDay === 'Last') ? 'last' : time.monthDay.toString()
|
||||
break
|
||||
}
|
||||
delete time.monthDay
|
||||
|
||||
return time
|
||||
}
|
||||
|
||||
serialize (state, theme) {
|
||||
const data = state.toJS()
|
||||
console.log('notificationForm:serialize, input=', data)
|
||||
const scheduling = data.scheduling
|
||||
const themeType = data.themeType
|
||||
|
||||
const fieldsToDelete = ['scheduling', 'showSaveAsPopup', 'id', 'content', 'isEnabledTimezone', 'isDefaultTimezone', 'sendHistory', 'active']
|
||||
fieldsToDelete.forEach(field => delete data[field])
|
||||
|
||||
const automatic = scheduling.times.map(this._serializeScheduleItem)
|
||||
|
||||
const sources = data.sources.map(source => {
|
||||
return {
|
||||
type: source.type,
|
||||
id: source.id
|
||||
}
|
||||
})
|
||||
|
||||
const recipients = data.recipients.map(recipient => recipient.value)
|
||||
|
||||
const themeDiff = {}
|
||||
const paths = ['content:extract', 'content:highlightKeywords:highlight', 'content:showInfo:sourceCountry', 'content:showInfo:userComments']
|
||||
const immTheme = fromJS(theme[themeType])
|
||||
paths.forEach(path => {
|
||||
const immPath = path.split(':')
|
||||
const themeValue = immTheme.getIn(immPath)
|
||||
const stateValue = state.getIn(immPath)
|
||||
if (themeValue !== stateValue) {
|
||||
themeDiff[path] = stateValue
|
||||
}
|
||||
})
|
||||
const enhancedDiff = themeType === 'enhanced' ? themeDiff : {}
|
||||
const plainDiff = themeType === 'plain' ? themeDiff : {}
|
||||
|
||||
const alertData = {
|
||||
...data,
|
||||
name: data.name || 'New Alert',
|
||||
theme: theme.id,
|
||||
automatic,
|
||||
recipients,
|
||||
sources,
|
||||
enhancedDiff,
|
||||
plainDiff
|
||||
}
|
||||
console.log('notificationForm:serialize, output=', alertData)
|
||||
return alertData
|
||||
}
|
||||
|
||||
getHistory (notificationId, page, limit, {fulfilled, token}) {
|
||||
return getHistoryApi(token, {page, limit}, notificationId)
|
||||
.then((historyData) => {
|
||||
fulfilled(historyData)
|
||||
})
|
||||
}
|
||||
|
||||
getRecipients (filter) {
|
||||
return tokenInject((dispatch, getState, token) => {
|
||||
return getReceiversApi(token, {filter})
|
||||
.then((data) => {
|
||||
const options = data.map(recipient => {
|
||||
const label = (recipient.type === 'recipient')
|
||||
? `${recipient.name} <${recipient.email}>`
|
||||
: recipient.name
|
||||
return {value: recipient.id, label}
|
||||
})
|
||||
return {options}
|
||||
})
|
||||
.catch((errors) => {
|
||||
dispatch(addAlert(errors))
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
defineActions () {
|
||||
const changeName = this.set('NAME', 'name')
|
||||
const changeRecipients = this.set('RECIPIENTS', 'recipients')
|
||||
const changeSubject = this.set('SUBJECT', 'subject')
|
||||
const changeAutoSubject = this.set('AUTO_SUBJECT', 'automatedSubject')
|
||||
const changePublished = this.set('PUBLISHED', 'published')
|
||||
const changeAllowUnsubscribe = this.set('ALLOW_UNSUBSCRIBE', 'allowUnsubscribe')
|
||||
const changeUnsubscribeNotification = this.set('UNSUBSCRIBE_NOTIFICATION', 'unsubscribeNotification')
|
||||
const changeExtras = this.setIn('EXTRAS', ['content', 'extract'])
|
||||
const changeHighlightKeywords = this.setIn('HIGHLIGHT_KEYWORDS', ['content', 'highlightKeywords', 'highlight'])
|
||||
const changeShowSourceCountry = this.setIn('SHOW_SOURCE_COUNTRY', ['content', 'showInfo', 'sourceCountry'])
|
||||
const changeShowUserComments = this.setIn('SHOW_USER_COMMENTS', ['content', 'showInfo', 'userComments'])
|
||||
const changeThemeType = this.set('THEME_TYPE', 'themeType')
|
||||
const changeSendWhenEmpty = this.set('SEND_WHEN_EMPTY', 'sendWhenEmpty')
|
||||
const changeTimezone = this.set('TIMEZONE', 'timezone')
|
||||
const changeSendUntil = this.set('SEND_UNTIL', 'sendUntil')
|
||||
const toggleTimezone = this.toggle('TOGGLE_TIMEZONE', 'isEnabledTimezone')
|
||||
const toggleSaveAsPopup = this.toggle('TOGGLE_SAVE_AS_POPUP', 'showSaveAsPopup')
|
||||
const toggleHistory = this.toggleIn('TOGGLE_HISTORY', ['sendHistory', 'isOpen'])
|
||||
// TODO reset options for every type
|
||||
const changeScheduleType = this.setIn('SCHEDULE_TYPE', ['scheduling', 'newTime', 'type'])
|
||||
const changeNewSchedule = this.mergeIn('CHANGE_NEW_SCHEDULE', ['scheduling', 'newTime'])
|
||||
const clearForm = this.resetToInitialState('CLEAR')
|
||||
|
||||
const addSource = this.createAction(ADD_SOURCE, source => source)
|
||||
const removeSource = this.createAction(REMOVE_SOURCE, sourceId => sourceId)
|
||||
const moveSource = this.createAction(MOVE_SOURCE, (sourceId, isUp) => ({sourceId, isUp}))
|
||||
const addSchedule = this.createAction(ADD_SCHEDULE)
|
||||
const removeSchedule = this.createAction(REMOVE_SCHEDULE, id => id)
|
||||
const fillForm = this.createAction(FILL_FORM, (item, theme) => ({item, theme}))
|
||||
const changeExistingSchedule = this.createAction('CHANGE_SCHEDULE', (item, id) => ({item, id}))
|
||||
|
||||
this.setPending = this.set('LOADING', 'isLoading')
|
||||
|
||||
// const historyPending = this.setIn(`${HISTORY} pending`, ['sendHistory', 'isPending'])
|
||||
const getHistory = this.thunkAction(HISTORY, this.getHistory, true)
|
||||
|
||||
return {
|
||||
changeName,
|
||||
changeRecipients,
|
||||
changeSubject,
|
||||
changeAutoSubject,
|
||||
changeAllowUnsubscribe,
|
||||
changeUnsubscribeNotification,
|
||||
changeExtras,
|
||||
changeHighlightKeywords,
|
||||
changeShowSourceCountry,
|
||||
changeShowUserComments,
|
||||
changeThemeType,
|
||||
changeSendWhenEmpty,
|
||||
changePublished,
|
||||
addSource,
|
||||
removeSource,
|
||||
addSchedule,
|
||||
removeSchedule,
|
||||
moveSource,
|
||||
changeTimezone,
|
||||
toggleTimezone,
|
||||
changeScheduleType,
|
||||
changeNewSchedule,
|
||||
changeExistingSchedule,
|
||||
changeSendUntil,
|
||||
fillForm,
|
||||
clearForm,
|
||||
getRecipients: this.getRecipients,
|
||||
toggleSaveAsPopup,
|
||||
toggleHistory,
|
||||
getHistory
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
defineReducers () {
|
||||
|
||||
return {
|
||||
[ADD_SOURCE]: (state, {payload: source}) => {
|
||||
const sources = state.get('sources').push(fromJS(source))
|
||||
return state.set('sources', sources)
|
||||
},
|
||||
|
||||
[REMOVE_SOURCE]: (state, {payload: sourceId}) => {
|
||||
const sources = state.get('sources').filter(source => source.get('id') !== sourceId)
|
||||
return state.set('sources', sources)
|
||||
},
|
||||
|
||||
[MOVE_SOURCE]: (state, {payload}) => {
|
||||
const { sourceId, isUp } = payload
|
||||
let sources = state.get('sources')
|
||||
|
||||
const fromIndex = sources.findIndex(source => source.get('id') === sourceId)
|
||||
const toIndex = (isUp) ? fromIndex - 1 : fromIndex + 1
|
||||
|
||||
const isUpFail = isUp && (toIndex < 0)
|
||||
const isDownFail = !isUp && (toIndex >= sources.size)
|
||||
if (isUpFail || isDownFail) {
|
||||
return state
|
||||
}
|
||||
|
||||
const source = sources.get(fromIndex)
|
||||
sources = sources
|
||||
.splice(fromIndex, 1)
|
||||
.splice(toIndex, 0, source)
|
||||
|
||||
return state.set('sources', sources)
|
||||
},
|
||||
|
||||
[ADD_SCHEDULE]: (state) => {
|
||||
const path = ['scheduling', 'times']
|
||||
const item = state.getIn(['scheduling', 'newTime'])
|
||||
const items = state.getIn(path).push(item)
|
||||
return state.setIn(path, items)
|
||||
},
|
||||
|
||||
[REMOVE_SCHEDULE]: (state, {payload: id}) => {
|
||||
const path = ['scheduling', 'times']
|
||||
const items = state.getIn(path).filter((item, index) => index !== id)
|
||||
return state.setIn(path, items)
|
||||
},
|
||||
|
||||
[FILL_FORM]: (state, {payload}) => {
|
||||
const { item, theme } = payload
|
||||
return this.normalize(item, theme)
|
||||
},
|
||||
|
||||
[[`${HISTORY} fulfilled`]]: (state, {payload}) => {
|
||||
const { data, limit, page, totalCount } = payload
|
||||
const entities = state.getIn(['sendHistory', 'entities']).concat(data)
|
||||
return state.mergeIn(['sendHistory'], {
|
||||
entities,
|
||||
limit,
|
||||
page,
|
||||
totalCount,
|
||||
isLoadingCompleted: true
|
||||
})
|
||||
},
|
||||
|
||||
[[`${HISTORY} pending`]]: (state, {payload}) => {
|
||||
return state.mergeIn(['sendHistory'], {
|
||||
isPending: payload.isPending
|
||||
})
|
||||
},
|
||||
|
||||
[CHANGE_SCHEDULE]: (state, {payload: {item, id}}) => {
|
||||
return state.mergeIn(['scheduling', 'times', id], {
|
||||
item
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import {ReduxModule} from '../../../abstract/reduxModule'
|
||||
import {switchShareSubScreen} from '../tabs'
|
||||
|
||||
export const FILL_FORM = 'Fill form'
|
||||
const CHANGE_FIELD = 'Change field'
|
||||
const CHOOSE_TAB = 'Choose tab'
|
||||
const TOGGLE_ACTIVE = 'Toggle active'
|
||||
const CLEAR = 'Clear form'
|
||||
const TOGGLE_SUBSCRIPTION = 'Toggle subscription'
|
||||
const TOGGLE_GROUP = 'Toggle group'
|
||||
const TOGGLE_RECIPIENT = 'Toggle recipient'
|
||||
|
||||
const CONFIRM_DELETE = 'Confirm delete'
|
||||
const CANCEL_DELETE = 'Cancel delete'
|
||||
const DELETE_ITEMS = 'Delete receiver'
|
||||
|
||||
export class ReceiverForm extends ReduxModule {
|
||||
|
||||
constructor (api) {
|
||||
super()
|
||||
this.api = api
|
||||
}
|
||||
|
||||
getTableTabs () {
|
||||
//implement in subclasses
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
const tableTabs = this.getTableTabs()
|
||||
return {
|
||||
active: true,
|
||||
tabs: {
|
||||
active: tableTabs[0],
|
||||
all: tableTabs
|
||||
},
|
||||
id: null,
|
||||
isDeletePopupVisible: false
|
||||
}
|
||||
}
|
||||
|
||||
toggleArrayField (actionName, fieldName) {
|
||||
return this.createHandler(actionName,
|
||||
(id, turnOn) => ({id, turnOn}),
|
||||
(state, {payload: {id, turnOn}}) => {
|
||||
let array = state.get(fieldName) //immutable!
|
||||
if (turnOn) {
|
||||
if (!array.includes(id)) {
|
||||
array = array.push(id)
|
||||
}
|
||||
} else {
|
||||
array = array.filter((item) => item !== id)
|
||||
}
|
||||
return state.set(fieldName, array)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/** Delete only current item in form, function name is for compatibility with DeletePopup **/
|
||||
deleteItems = (ids, {token, fulfilled, getState, dispatch}) => {
|
||||
return this.api
|
||||
.deleteItems(token, {ids})
|
||||
.then(() => {
|
||||
dispatch(switchShareSubScreen('recipients', 'tables'))
|
||||
dispatch(this.cancelDelete())
|
||||
})
|
||||
};
|
||||
|
||||
defineActions () {
|
||||
|
||||
const chooseTableTab = this.setIn(CHOOSE_TAB, ['tabs', 'active'])
|
||||
const toggleActive = this.toggle(TOGGLE_ACTIVE, 'active')
|
||||
|
||||
const clearForm = this.resetToInitialState(CLEAR)
|
||||
const fillForm = this.createAction(FILL_FORM, item => item)
|
||||
|
||||
const changeField = this.setField(CHANGE_FIELD)
|
||||
const toggleSubscription = this.toggleArrayField(TOGGLE_SUBSCRIPTION, 'subscriptions')
|
||||
const toggleRecipient = this.toggleArrayField(TOGGLE_RECIPIENT, 'recipients')
|
||||
const toggleGroup = this.toggleArrayField(TOGGLE_GROUP, 'groups')
|
||||
|
||||
const confirmDelete = this.reset(CONFIRM_DELETE, 'isDeletePopupVisible', true)
|
||||
this.cancelDelete = this.reset(CANCEL_DELETE, 'isDeletePopupVisible', false)
|
||||
const deleteItems = this.thunkAction(DELETE_ITEMS, this.deleteItems)
|
||||
|
||||
return {
|
||||
clearForm,
|
||||
changeField,
|
||||
chooseTableTab,
|
||||
toggleActive,
|
||||
fillForm,
|
||||
toggleSubscription,
|
||||
toggleRecipient,
|
||||
toggleGroup,
|
||||
confirmDelete,
|
||||
cancelDelete: this.cancelDelete,
|
||||
deleteItems
|
||||
}
|
||||
}
|
||||
|
||||
defineReducers () {
|
||||
return {
|
||||
[FILL_FORM]: (state, {payload: item}) => {
|
||||
return this.normalize(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import {ReceiverForm} from './receiverForm'
|
||||
import {
|
||||
switchShareSubScreen, switchShareTable, RECEIVER_SUBSCREENS, RECEIVER_TABLES, RECIPIENT_FORM_TABLES
|
||||
} from '../tabs'
|
||||
import {fromJS} from 'immutable'
|
||||
import * as api from '../../../../../api/recipientsApi'
|
||||
import {addAlert} from '../../../common/alerts'
|
||||
|
||||
const SAVE_RECIPIENT = 'Save recipient'
|
||||
|
||||
export class RecipientForm extends ReceiverForm {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Recipient Form]'
|
||||
}
|
||||
|
||||
serialize (data) {
|
||||
return {
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
email: data.email,
|
||||
active: data.active,
|
||||
notifications: data.subscriptions,
|
||||
groups: data.groups
|
||||
}
|
||||
};
|
||||
|
||||
normalize (data) {
|
||||
let newState = this.getInitialState()
|
||||
newState = {
|
||||
...newState,
|
||||
id: data.id,
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
email: data.email,
|
||||
active: data.active,
|
||||
groups: data.groups.map(group => group.id),
|
||||
subscriptions: data.subscriptions.ids
|
||||
}
|
||||
return fromJS(newState)
|
||||
};
|
||||
|
||||
saveRecipient = ({dispatch, fulfilled, getState, token}) => {
|
||||
const data = getState().getIn(['appState', 'share', 'forms', 'recipient']).toJS()
|
||||
const id = data.id
|
||||
|
||||
if (data.firstName && data.lastName && data.email) {
|
||||
const payload = this.serialize(data)
|
||||
const apiRequest = id ? api.updateItem(token, payload, id) : api.createItem(token, payload)
|
||||
return apiRequest.then(() => {
|
||||
fulfilled()
|
||||
dispatch(addAlert({type: 'notice', transKey: 'recipientSaved'}))
|
||||
dispatch(switchShareSubScreen('recipients', RECEIVER_SUBSCREENS.TABLES))
|
||||
dispatch(switchShareTable('recipients', RECEIVER_TABLES.RECIPIENTS))
|
||||
})
|
||||
|
||||
} else {
|
||||
dispatch(addAlert({type: 'error', transKey: 'recipientNamesEmpty'}))
|
||||
}
|
||||
};
|
||||
|
||||
defineActions () {
|
||||
const saveReceiver = this.thunkAction(SAVE_RECIPIENT, this.saveRecipient, true)
|
||||
|
||||
return {
|
||||
...super.defineActions(),
|
||||
saveReceiver,
|
||||
deleteReceiver: this.deleteRecipient
|
||||
}
|
||||
}
|
||||
|
||||
getTableTabs () {
|
||||
return [RECIPIENT_FORM_TABLES.SUBSCRIPTIONS, RECIPIENT_FORM_TABLES.GROUPS, RECIPIENT_FORM_TABLES.EMAIL_HISTORY]
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
const state = super.getInitialState()
|
||||
return {
|
||||
...state,
|
||||
creationDate: '',
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
email: '',
|
||||
active: true,
|
||||
subscriptions: [],
|
||||
groups: []
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new RecipientForm()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,130 @@
|
||||
import {tokenInject} from '../../../utils/common'
|
||||
import {
|
||||
NOTIFICATION_SUBSCREENS, RECEIVER_SUBSCREENS, switchShareSubScreen,
|
||||
NOTIFICATION_TABLES
|
||||
} from './tabs'
|
||||
import { addAlert } from '../../common/alerts'
|
||||
import { getDefaultTheme } from './emailThemes/themes'
|
||||
|
||||
import myEmailsTable from './tables/myEmailsTable'
|
||||
import publishedEmailsTable from './tables/publishedEmailsTable'
|
||||
import emailsTable from './tables/emailsTable'
|
||||
|
||||
import alertForm from './forms/alertForm'
|
||||
import newsletterForm from './forms/newsletterForm'
|
||||
import recipientForm from './forms/recipientForm'
|
||||
import groupForm from './forms/groupForm'
|
||||
|
||||
import * as notificationsApi from '../../../../api/notificationsApi'
|
||||
|
||||
const tablePendingActions = {
|
||||
[NOTIFICATION_TABLES.MY_EMAILS]: myEmailsTable.asyncActionPending,
|
||||
[NOTIFICATION_TABLES.PUBLISHED]: publishedEmailsTable.asyncActionPending,
|
||||
emails: emailsTable.asyncActionPending
|
||||
}
|
||||
|
||||
//**** ACTIONS ****//
|
||||
|
||||
const loadTablePending = (type, isPending) => {
|
||||
return tablePendingActions[type](isPending)
|
||||
}
|
||||
|
||||
const startEditNotification = (notification, table, tab = 'notifications') => {
|
||||
return tokenInject((dispatch, getState, token) => {
|
||||
if (notification.type === 'alert') {
|
||||
|
||||
dispatch(loadTablePending(table, true))
|
||||
|
||||
dispatch(getDefaultTheme())
|
||||
.then((defaultTheme) => {
|
||||
return notificationsApi.getItem(token, null, notification.id)
|
||||
.then((fullNotification) => {
|
||||
dispatch(loadTablePending(table, false))
|
||||
dispatch(alertForm.actions.fillForm(fullNotification, defaultTheme))
|
||||
dispatch(switchShareSubScreen(tab, NOTIFICATION_SUBSCREENS.ALERT_FORM))
|
||||
})
|
||||
})
|
||||
.catch((errors) => {
|
||||
dispatch(loadTablePending(table, false))
|
||||
dispatch(addAlert(errors))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const startCreateNotification = (type, table, tab = 'notifications') => {
|
||||
return (dispatch, getState) => {
|
||||
|
||||
const recipient = getState().getIn(['common', 'auth', 'user', 'recipient']);
|
||||
if (!recipient) {
|
||||
return dispatch(addAlert('Please create at least one recipient from Manage Recipients to create an alert.'));
|
||||
}
|
||||
const myself = recipient.toJS()
|
||||
const defaultRecipient = {
|
||||
value: myself.id,
|
||||
label: `${myself.firstName} ${myself.lastName} <${myself.email}>`
|
||||
}
|
||||
|
||||
dispatch(loadTablePending(table, true))
|
||||
dispatch(getDefaultTheme())
|
||||
.then(() => {
|
||||
dispatch(loadTablePending(table, false))
|
||||
if (type === NOTIFICATION_SUBSCREENS.ALERT_FORM) {
|
||||
dispatch(alertForm.actions.clearForm())
|
||||
dispatch(alertForm.actions.changeRecipients([defaultRecipient]))
|
||||
dispatch(switchShareSubScreen(tab, NOTIFICATION_SUBSCREENS.ALERT_FORM))
|
||||
}
|
||||
else if (type === NOTIFICATION_SUBSCREENS.NEWSLETTER_FORM) {
|
||||
dispatch(newsletterForm.actions.clearForm())
|
||||
dispatch(switchShareSubScreen(tab, NOTIFICATION_SUBSCREENS.NEWSLETTER_FORM))
|
||||
}
|
||||
})
|
||||
.catch((errors) => {
|
||||
dispatch(loadTablePending(table, false))
|
||||
dispatch(addAlert(errors))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const startCreateRecipient = () => {
|
||||
return (dispatch) => {
|
||||
dispatch(switchShareSubScreen('recipients', RECEIVER_SUBSCREENS.RECIPIENT_FORM))
|
||||
dispatch(recipientForm.actions.clearForm())
|
||||
}
|
||||
}
|
||||
|
||||
const startCreateGroup = () => {
|
||||
return (dispatch) => {
|
||||
dispatch(switchShareSubScreen('recipients', RECEIVER_SUBSCREENS.GROUP_FORM))
|
||||
dispatch(groupForm.actions.clearForm())
|
||||
}
|
||||
}
|
||||
|
||||
const startEditRecipient = (item) => {
|
||||
console.log('start edit')
|
||||
return (dispatch) => {
|
||||
dispatch(switchShareSubScreen('recipients', RECEIVER_SUBSCREENS.RECIPIENT_FORM))
|
||||
dispatch(recipientForm.actions.clearForm())
|
||||
dispatch(recipientForm.actions.fillForm(item))
|
||||
}
|
||||
}
|
||||
|
||||
const startEditGroup = (item) => {
|
||||
return (dispatch) => {
|
||||
dispatch(switchShareSubScreen('recipients', RECEIVER_SUBSCREENS.GROUP_FORM))
|
||||
dispatch(groupForm.actions.clearForm())
|
||||
dispatch(groupForm.actions.fillForm(item))
|
||||
}
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
startEditNotification,
|
||||
startCreateNotification,
|
||||
startCreateRecipient,
|
||||
startCreateGroup,
|
||||
startEditRecipient,
|
||||
startEditGroup
|
||||
}
|
||||
|
||||
//**** This module has no state (: ****//
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import GenericTable from './genericTable'
|
||||
import * as api from '../../../../../api/notificationsApi'
|
||||
|
||||
class EmailFiltersTable extends GenericTable {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Email filters]'
|
||||
}
|
||||
|
||||
getItems = (token, payload) => {
|
||||
return this.api.getFilters(token, payload)
|
||||
};
|
||||
|
||||
getDataFromResponse (response) {
|
||||
return response['filters']
|
||||
}
|
||||
|
||||
getTableState (state) {
|
||||
return state.getIn(['appState', 'share', 'tables', 'emailFilters'])
|
||||
}
|
||||
|
||||
getLoadTableRequestPayload (tableState) {
|
||||
return {
|
||||
...super.getLoadTableRequestPayload(tableState),
|
||||
type: tableState.filterType
|
||||
}
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
...super.getInitialState(),
|
||||
filterType: 'owner'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new EmailFiltersTable()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,67 @@
|
||||
import GenericTable from './genericTable'
|
||||
import * as api from '../../../../../api/notificationsApi'
|
||||
|
||||
const SET_FILTER = 'Set filter'
|
||||
const CLEAR_FILTER = 'Clear filter'
|
||||
|
||||
class EmailsTable extends GenericTable {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
this.updateRestrictionsAfterDelete = true
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Emails]'
|
||||
}
|
||||
|
||||
getTableState (state) {
|
||||
return state.getIn(['appState', 'share', 'tables', 'emails'])
|
||||
}
|
||||
|
||||
getItems = (token, payload) => {
|
||||
return this.api.getAllItems(token, payload)
|
||||
}
|
||||
|
||||
getLoadTableRequestPayload (tableState) {
|
||||
const payload = super.getLoadTableRequestPayload(tableState)
|
||||
if (tableState.filter) {
|
||||
payload.filterId = tableState.filter.id
|
||||
payload.filterType = tableState.filter.type
|
||||
}
|
||||
delete payload.filter
|
||||
return payload
|
||||
}
|
||||
|
||||
defineActions () {
|
||||
|
||||
const setFilter = this.createAction(SET_FILTER)
|
||||
const clearFilter = this.createAction(CLEAR_FILTER)
|
||||
|
||||
return {
|
||||
...super.defineActions(),
|
||||
setFilter,
|
||||
clearFilter
|
||||
}
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
...super.getInitialState(),
|
||||
filter: null
|
||||
}
|
||||
}
|
||||
|
||||
defineReducers () {
|
||||
return {
|
||||
...super.defineReducers(),
|
||||
[SET_FILTER]: this.setReducer('filter'),
|
||||
[CLEAR_FILTER]: this.resetReducer('filter', null)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new EmailsTable()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,268 @@
|
||||
import ReduxModule from '../../../abstract/reduxModule'
|
||||
import { addAlert } from '../../../common/alerts'
|
||||
import {tokenInject} from '../../../../utils/common'
|
||||
import {getRestrictions} from '../../../common/auth'
|
||||
|
||||
const SELECT_TABLE_ROW = 'Select table row'
|
||||
const SELECT_TABLE_ALL_ROWS = 'Select all rows'
|
||||
const SET_TABLE_PARAMS = 'Set table parameters'
|
||||
const LOAD_TABLE = 'Load table'
|
||||
const CONFIRM_DELETE = 'Confirm delete'
|
||||
const CANCEL_DELETE = 'Cancel delete'
|
||||
const CHANGE_FILTERED = 'Change filtered'
|
||||
const TOGGLE_FIELD = 'Toggle field'
|
||||
const ASYNC_ACTION = 'Async action'
|
||||
const DELETE_ITEMS = 'Delete items'
|
||||
|
||||
export default class GenericTableModule extends ReduxModule {
|
||||
|
||||
constructor (api) {
|
||||
super()
|
||||
this.api = api
|
||||
this.updateRestrictionsAfterDelete = false
|
||||
}
|
||||
|
||||
/*
|
||||
state - full state
|
||||
return - table state
|
||||
*/
|
||||
getTableState (state) {
|
||||
//implement in subclasses
|
||||
}
|
||||
|
||||
asyncToggleFieldAction (apiMethod, optionName) {
|
||||
return (ids, optionValue) => {
|
||||
return tokenInject((dispatch, getState, token) => {
|
||||
const payload = {
|
||||
ids,
|
||||
[optionName]: optionValue
|
||||
}
|
||||
|
||||
dispatch(this.asyncActionPending(true))
|
||||
apiMethod(token, payload)
|
||||
.then(() => {
|
||||
dispatch(this.toggleField(ids, optionName, optionValue))
|
||||
dispatch(this.asyncActionPending(false))
|
||||
})
|
||||
.catch((error) => {
|
||||
dispatch(this.asyncActionPending(false))
|
||||
dispatch(addAlert(error))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_fixForDeleteFromLastPage (dispatch, getState, ids) {
|
||||
const tableState = this.getTableState(getState()).toJS()
|
||||
const totalPages = Math.ceil(tableState.totalCount / tableState.limit)
|
||||
if (tableState.page === totalPages && totalPages !== 1) { //we are on the last page
|
||||
const itemsOnLastPage = tableState.totalCount % tableState.limit
|
||||
const itemsToDelete = Object.keys(ids).length
|
||||
if (itemsOnLastPage === itemsToDelete) { //and we are deleting everything
|
||||
const newPage = tableState.page - 1
|
||||
dispatch(this.setTableParams({page: newPage}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deleteItems = (ids, {token, fulfilled, getState, dispatch}) => {
|
||||
return this.api
|
||||
.deleteItems(token, {ids})
|
||||
.then(() => {
|
||||
this._fixForDeleteFromLastPage(dispatch, getState, ids)
|
||||
const payload = this._getLoadPayload(getState)
|
||||
this.updateRestrictionsAfterDelete && dispatch(getRestrictions())
|
||||
return this.api
|
||||
.getItems(token, payload)
|
||||
.then((response) => {
|
||||
fulfilled(this.getDataFromResponse(response))
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
_getLoadPayload (getState) {
|
||||
const state = getState()
|
||||
const tableState = this.getTableState(state).toJS()
|
||||
return this.getLoadTableRequestPayload(tableState)
|
||||
}
|
||||
|
||||
getLoadTableRequestPayload (tableState) {
|
||||
const payload = {
|
||||
page: tableState.page,
|
||||
limit: tableState.limit,
|
||||
sortField: tableState.sortField,
|
||||
sortDirection: tableState.sortDirection
|
||||
}
|
||||
if (tableState.filter) {
|
||||
payload.filter = tableState.filter
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
getDataFromResponse (response) {
|
||||
return response['notifications']
|
||||
}
|
||||
|
||||
getItems = (token, payload) => {
|
||||
return this.api.getItems(token, payload)
|
||||
}
|
||||
|
||||
loadTable = (params, {dispatch, getState, token, fulfilled}) => {
|
||||
if (params) {
|
||||
dispatch(this.setTableParams(params))
|
||||
}
|
||||
const payload = this._getLoadPayload(getState)
|
||||
return this.getItems(token, payload)
|
||||
.then((response) => {
|
||||
fulfilled(this.getDataFromResponse(response))
|
||||
})
|
||||
};
|
||||
|
||||
defineActions () {
|
||||
|
||||
const selectTableRow = this.createAction(SELECT_TABLE_ROW, (itemId) => itemId)
|
||||
const selectTableAllRows = this.createAction(SELECT_TABLE_ALL_ROWS)
|
||||
const confirmDelete = this.createAction(CONFIRM_DELETE)
|
||||
const cancelDelete = this.createAction(CANCEL_DELETE)
|
||||
const changeTableFiltered = this.createAction(CHANGE_FILTERED)
|
||||
|
||||
const setTableParams = this.createAction(SET_TABLE_PARAMS, (params) => params)
|
||||
this.setTableParams = setTableParams
|
||||
const loadTable = this.thunkAction(LOAD_TABLE, this.loadTable, true)
|
||||
const deleteItems = this.thunkAction(DELETE_ITEMS, this.deleteItems, true)
|
||||
|
||||
this.asyncActionPending = this.createAction(`${ASYNC_ACTION} pending`, (value) => ({isPending: value}))
|
||||
this.toggleField = this.createAction(TOGGLE_FIELD, (ids, fieldName, fieldValue) => ({ids, fieldName, fieldValue}))
|
||||
|
||||
const toggleActive = this.asyncToggleFieldAction(this.api.activateItems, 'active')
|
||||
const togglePublish = this.asyncToggleFieldAction(this.api.publishItems, 'published')
|
||||
|
||||
return {
|
||||
loadTable,
|
||||
selectTableRow,
|
||||
selectTableAllRows,
|
||||
setTableParams,
|
||||
confirmDelete,
|
||||
cancelDelete,
|
||||
changeTableFiltered,
|
||||
toggleActive,
|
||||
togglePublish,
|
||||
deleteItems
|
||||
}
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
sortField: 'name',
|
||||
sortDirection: 'asc',
|
||||
data: [],
|
||||
count: 0,
|
||||
totalCount: 0,
|
||||
isLoading: false,
|
||||
isAllSelected: false,
|
||||
selectedIds: [],
|
||||
idsToDelete: {},
|
||||
isDeletePopupVisible: false
|
||||
}
|
||||
}
|
||||
|
||||
/** REDUCERS **/
|
||||
|
||||
onSelectTableRow (state, {payload: itemId}) {
|
||||
let selectedIds = state.get('selectedIds')
|
||||
const isSelected = selectedIds.includes(itemId)
|
||||
if (isSelected) {
|
||||
selectedIds = selectedIds.filter(id => id !== itemId)
|
||||
}
|
||||
else {
|
||||
selectedIds = selectedIds.push(itemId)
|
||||
}
|
||||
return state.merge({
|
||||
'selectedIds': selectedIds,
|
||||
'isAllSelected': false
|
||||
})
|
||||
}
|
||||
|
||||
onSelectAllTableRows (state) {
|
||||
const isAllSelected = state.get('isAllSelected')
|
||||
if (isAllSelected) { //then deselect all
|
||||
return state.merge({
|
||||
isAllSelected: false,
|
||||
selectedIds: []
|
||||
})
|
||||
}
|
||||
else { //select all currently loaded data
|
||||
const selectedIds = state.get('data').map(item => item.get('id'))
|
||||
return state.merge({
|
||||
isAllSelected: true,
|
||||
selectedIds
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onLoadFulfilled (state, {payload: response}) {
|
||||
return state.merge({
|
||||
data: response.data,
|
||||
count: response.count,
|
||||
totalCount: response.totalCount
|
||||
})
|
||||
}
|
||||
|
||||
onDeleteItemsFulfilled (state, {payload: response}) {
|
||||
return state.merge({
|
||||
data: response.data,
|
||||
count: response.count,
|
||||
totalCount: response.totalCount,
|
||||
selectedIds: []
|
||||
})
|
||||
};
|
||||
|
||||
onConfirmDelete (state, {payload: ids}) {
|
||||
return state.merge({
|
||||
isDeletePopupVisible: true,
|
||||
idsToDelete: ids
|
||||
})
|
||||
}
|
||||
|
||||
onCancelDelete (state) {
|
||||
return state.merge({
|
||||
isDeletePopupVisible: false,
|
||||
idsToDelete: {}
|
||||
})
|
||||
}
|
||||
|
||||
onAsyncActionPending (state, {payload: {isPending}}) {
|
||||
return state.merge({
|
||||
isLoading: isPending,
|
||||
isDeletePopupVisible: false //dirty hack, need to think 'bout it
|
||||
})
|
||||
}
|
||||
|
||||
onToggleField (state, {payload: {ids, fieldName, fieldValue}}) {
|
||||
let tableData = state.get('data')
|
||||
const newValues = {[fieldName]: fieldValue}
|
||||
tableData = tableData.map((item) => (ids.includes(item.get('id'))) ? item.merge(newValues) : item)
|
||||
return state.set('data', tableData)
|
||||
}
|
||||
|
||||
defineReducers () {
|
||||
return {
|
||||
[SELECT_TABLE_ROW]: this.onSelectTableRow,
|
||||
[SELECT_TABLE_ALL_ROWS]: this.onSelectAllTableRows,
|
||||
[SET_TABLE_PARAMS]: this.mergeReducer(),
|
||||
[`${LOAD_TABLE} pending`]: this.thunkPendingReducer('isLoading'),
|
||||
[`${LOAD_TABLE} fulfilled`]: this.onLoadFulfilled,
|
||||
[`${ASYNC_ACTION} pending`]: this.onAsyncActionPending,
|
||||
[`${DELETE_ITEMS} pending`]: this.onAsyncActionPending,
|
||||
[`${DELETE_ITEMS} fulfilled`]: this.onDeleteItemsFulfilled,
|
||||
[TOGGLE_FIELD]: this.onToggleField,
|
||||
[CONFIRM_DELETE]: this.onConfirmDelete,
|
||||
[CANCEL_DELETE]: this.onCancelDelete,
|
||||
[CHANGE_FILTERED]: this.setReducer('filtered')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import GenericTable from './genericTable'
|
||||
import * as api from '../../../../../api/groupsApi'
|
||||
|
||||
class GroupsTable extends GenericTable {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Groups table]'
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
const state = super.getInitialState()
|
||||
return {
|
||||
...state,
|
||||
filter: ''
|
||||
}
|
||||
}
|
||||
|
||||
getDataFromResponse (response) {
|
||||
return response['groups']
|
||||
}
|
||||
|
||||
getTableState (state) {
|
||||
return state.getIn(['appState', 'share', 'tables', 'groups'])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new GroupsTable()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,30 @@
|
||||
import GenericTable from './genericTable'
|
||||
import * as api from '../../../../../api/notificationsApi'
|
||||
|
||||
class MyEmailsTable extends GenericTable {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
this.updateRestrictionsAfterDelete = true
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[My Emails]'
|
||||
}
|
||||
|
||||
getTableState (state) {
|
||||
return state.getIn(['appState', 'share', 'tables', 'myEmails'])
|
||||
}
|
||||
|
||||
getLoadTableRequestPayload (tableState) {
|
||||
return {
|
||||
...super.getLoadTableRequestPayload(tableState),
|
||||
onlyPublished: false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new MyEmailsTable()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,38 @@
|
||||
import GenericTableModule from './genericTable'
|
||||
import * as api from '../../../../../api/notificationsApi'
|
||||
|
||||
class PublishedEmailsTable extends GenericTableModule {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
this.updateRestrictionsAfterDelete = true
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Published Emails]'
|
||||
}
|
||||
|
||||
getTableState (state) {
|
||||
return state.getIn(['appState', 'share', 'tables', 'publishedEmails'])
|
||||
}
|
||||
|
||||
getLoadTableRequestPayload (tableState) {
|
||||
return {
|
||||
...super.getLoadTableRequestPayload(tableState),
|
||||
onlyPublished: true
|
||||
}
|
||||
}
|
||||
|
||||
defineActions () {
|
||||
const toggleSubscribe = this.asyncToggleFieldAction(this.api.subscribeItems, 'subscribed')
|
||||
return {
|
||||
...super.defineActions(),
|
||||
toggleSubscribe
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new PublishedEmailsTable()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,34 @@
|
||||
import * as api from '../../../../../../api/receiversApi'
|
||||
import GenericTableModule from '../genericTable'
|
||||
|
||||
class EmailHistory extends GenericTableModule {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Email history]'
|
||||
}
|
||||
|
||||
getTableState (state) {
|
||||
return state.getIn(['appState', 'share', 'tables', 'receiverForm', 'emailHistory'])
|
||||
}
|
||||
|
||||
loadTable = (params, receiver, {dispatch, getState, token, fulfilled}) => {
|
||||
if (params) {
|
||||
dispatch(this.setTableParams(params))
|
||||
}
|
||||
const payload = this._getLoadPayload(getState)
|
||||
return this.api
|
||||
.getEmailHistory(token, payload, receiver.id)
|
||||
.then((response) => {
|
||||
fulfilled(response)
|
||||
})
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const instance = new EmailHistory()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,84 @@
|
||||
import {fromJS} from 'immutable'
|
||||
import GenericTableModule from '../genericTable'
|
||||
|
||||
const TOGGLE_SUBSCRIBED = 'Toggle subscribed'
|
||||
const TOGGLE_ENROLLED = 'Toggle enrolled'
|
||||
|
||||
export default class ReceiverFormTable extends GenericTableModule {
|
||||
|
||||
getDataFromResponse (response) {
|
||||
//implement in subclasses
|
||||
}
|
||||
|
||||
getLoadTableRequestPayload (tableState, receiver) {
|
||||
let payload = super.getLoadTableRequestPayload(tableState)
|
||||
if (tableState.filter) {
|
||||
payload.filter = tableState.filter
|
||||
}
|
||||
const statusFilter = tableState.statusFilter
|
||||
if (statusFilter) {
|
||||
payload.statusFilter = tableState.statusFilter
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
_getLoadPayload (getState, receiver) {
|
||||
const tableState = this.getTableState(getState()).toJS()
|
||||
return this.getLoadTableRequestPayload(tableState, receiver)
|
||||
}
|
||||
|
||||
loadTable = (params, receiver, {dispatch, getState, token, fulfilled}) => {
|
||||
if (params) {
|
||||
dispatch(this.setTableParams(params))
|
||||
}
|
||||
const payload = this._getLoadPayload(getState, receiver) // <-- difference from genericTable
|
||||
return this.api
|
||||
.getItems(token, payload)
|
||||
.then((response) => {
|
||||
fulfilled(this.getDataFromResponse(response, receiver))
|
||||
})
|
||||
};
|
||||
|
||||
addDataColumn (data, fieldName, ids = []) {
|
||||
data.forEach((item) => {
|
||||
item[fieldName] = ids.includes(item.id)
|
||||
})
|
||||
};
|
||||
|
||||
toggleDataField (actionName, fieldName) {
|
||||
return this.createHandler(
|
||||
actionName,
|
||||
(itemId, turnOn) => ({itemId, turnOn}),
|
||||
(state, {payload: {itemId, turnOn}}) => {
|
||||
const tableData = state.get('data').toJS()
|
||||
tableData.forEach((item) => {
|
||||
if (item.id === itemId) {
|
||||
item[fieldName] = turnOn
|
||||
}
|
||||
})
|
||||
return state.set('data', fromJS(tableData))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
defineActions () {
|
||||
const actions = super.defineActions()
|
||||
const toggleSubscribed = this.toggleDataField(TOGGLE_SUBSCRIBED, 'subscribed')
|
||||
const toggleEnrolled = this.toggleDataField(TOGGLE_ENROLLED, 'enrolled')
|
||||
|
||||
return {
|
||||
...actions,
|
||||
toggleSubscribed,
|
||||
toggleEnrolled
|
||||
}
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
...super.getInitialState(),
|
||||
filter: '',
|
||||
statusFilter: 'all'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import ReceiverFormTable from './receiverFormTable'
|
||||
import * as api from '../../../../../../api/groupsApi'
|
||||
|
||||
///api/v1/recipients/groups with recipientId
|
||||
|
||||
class ReceiverGroupsTable extends ReceiverFormTable {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Recipient form groups table]'
|
||||
}
|
||||
|
||||
getTableState (state) {
|
||||
return state.getIn(['appState', 'share', 'tables', 'receiverForm', 'groups'])
|
||||
}
|
||||
|
||||
getLoadTableRequestPayload (tableState, receiver) {
|
||||
let payload = super.getLoadTableRequestPayload(tableState)
|
||||
if (receiver) {
|
||||
payload.recipientId = receiver.id
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
getDataFromResponse (response, receiver) {
|
||||
const data = response.groups
|
||||
this.addDataColumn(data.data, 'enrolled', receiver.groups)
|
||||
return data
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new ReceiverGroupsTable()
|
||||
instance.init()
|
||||
export default instance
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
import ReceiverFormTable from './receiverFormTable'
|
||||
import * as api from '../../../../../../api/recipientsApi'
|
||||
|
||||
///api/v1/recipients with groupId
|
||||
|
||||
class ReceiverRecipientsTable extends ReceiverFormTable {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Group form recipients table]'
|
||||
}
|
||||
|
||||
getTableState (state) {
|
||||
return state.getIn(['appState', 'share', 'tables', 'receiverForm', 'recipients'])
|
||||
}
|
||||
|
||||
getLoadTableRequestPayload (tableState, receiver) {
|
||||
let payload = super.getLoadTableRequestPayload(tableState)
|
||||
if (receiver) {
|
||||
payload.groupId = receiver.id
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
getDataFromResponse (response, receiver) {
|
||||
const data = response['recipients']
|
||||
this.addDataColumn(data.data, 'enrolled', receiver.recipients)
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new ReceiverRecipientsTable()
|
||||
instance.init()
|
||||
export default instance
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import ReceiverFormTable from './receiverFormTable'
|
||||
import * as api from '../../../../../../api/notificationsApi'
|
||||
|
||||
class ReceiverSubscriptionsTable extends ReceiverFormTable {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Receiver form subscriptions table]'
|
||||
}
|
||||
|
||||
getTableState (state) {
|
||||
return state.getIn(['appState', 'share', 'tables', 'receiverForm', 'subscriptions'])
|
||||
}
|
||||
|
||||
getLoadTableRequestPayload (tableState, receiver) {
|
||||
let payload = super.getLoadTableRequestPayload(tableState)
|
||||
if (receiver) {
|
||||
payload.entityId = receiver.id
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
getDataFromResponse (response, receiver) {
|
||||
const data = response.notifications
|
||||
this.addDataColumn(data.data, 'subscribed', receiver.subscriptions)
|
||||
return data
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new ReceiverSubscriptionsTable()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,34 @@
|
||||
import GenericTable from './genericTable'
|
||||
import * as api from '../../../../../api/recipientsApi'
|
||||
|
||||
class RecipientsTable extends GenericTable {
|
||||
|
||||
constructor () {
|
||||
super(api)
|
||||
}
|
||||
|
||||
getNamespace () {
|
||||
return '[Recipients table]'
|
||||
}
|
||||
|
||||
getInitialState () {
|
||||
const state = super.getInitialState()
|
||||
return {
|
||||
...state,
|
||||
filter: ''
|
||||
}
|
||||
}
|
||||
|
||||
getTableState (state) {
|
||||
return state.getIn(['appState', 'share', 'tables', 'recipients'])
|
||||
}
|
||||
|
||||
getDataFromResponse (response) {
|
||||
return response['recipients']
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const instance = new RecipientsTable()
|
||||
instance.init()
|
||||
export default instance
|
||||
@@ -0,0 +1,87 @@
|
||||
import { createAction, handleActions } from 'redux-actions'
|
||||
import { fromJS } from 'immutable'
|
||||
|
||||
//**** CONSTANTS ****//
|
||||
const NS = '[Share tab]'
|
||||
const SWITCH_SUBSCREEN = `${NS} Switch subscreen`
|
||||
const SWITCH_TABLE = `${NS} Switch table`
|
||||
|
||||
//**** ACTIONS ****//
|
||||
export const switchShareSubScreen = createAction(SWITCH_SUBSCREEN, (type, subScreen) => ({type, subScreen}))
|
||||
export const switchShareTable = createAction(SWITCH_TABLE, (type, table) => ({type, table}))
|
||||
|
||||
export const actions = {
|
||||
switchShareSubScreen,
|
||||
switchShareTable
|
||||
}
|
||||
|
||||
/* TABS SUBSCREENS */
|
||||
export const NOTIFICATION_SUBSCREENS = {
|
||||
TABLES: 'tables',
|
||||
ALERT_FORM: 'alert',
|
||||
NEWSLETTER_FORM: 'newsletter'
|
||||
}
|
||||
|
||||
export const RECEIVER_SUBSCREENS = {
|
||||
TABLES: 'tables',
|
||||
RECIPIENT_FORM: 'recipient',
|
||||
GROUP_FORM: 'group'
|
||||
}
|
||||
|
||||
export const EMAILS_SUBSCREENS = {
|
||||
EMAILS_TABLE: 'table',
|
||||
ALERT_FORM: 'alert',
|
||||
NEWSLETTER_FORM: 'newsletter',
|
||||
FILTERS_TABLE: 'filters'
|
||||
}
|
||||
|
||||
/* TABLES IN 'tables' SUBSCREEN */
|
||||
export const NOTIFICATION_TABLES = {
|
||||
MY_EMAILS: 'myEmails',
|
||||
PUBLISHED: 'publishedEmails'
|
||||
}
|
||||
|
||||
export const RECEIVER_TABLES = {
|
||||
RECIPIENTS: 'recipients',
|
||||
GROUPS: 'groups'
|
||||
}
|
||||
|
||||
/* TABLES IN FORMS */
|
||||
export const RECIPIENT_FORM_TABLES = {
|
||||
EMAIL_HISTORY: 'emailHistory',
|
||||
SUBSCRIPTIONS: 'subscriptions',
|
||||
GROUPS: 'groups'
|
||||
}
|
||||
|
||||
export const GROUP_FORM_TABLES = {
|
||||
EMAIL_HISTORY: 'emailHistory',
|
||||
SUBSCRIPTIONS: 'subscriptions',
|
||||
RECIPIENTS: 'recipients'
|
||||
}
|
||||
|
||||
export const initialState = fromJS({
|
||||
notifications: {
|
||||
subScreenVisible: NOTIFICATION_SUBSCREENS.TABLES,
|
||||
tableVisible: 'myEmails'
|
||||
},
|
||||
recipients: {
|
||||
subScreenVisible: RECEIVER_SUBSCREENS.TABLES,
|
||||
tableVisible: 'recipients'
|
||||
},
|
||||
emails: {
|
||||
subScreenVisible: EMAILS_SUBSCREENS.EMAILS_TABLE
|
||||
}
|
||||
})
|
||||
|
||||
//**** REDUCERS ****//
|
||||
export default handleActions({
|
||||
[SWITCH_SUBSCREEN]: (state, {payload}) => {
|
||||
const { type, subScreen } = payload
|
||||
return state.setIn([type, 'subScreenVisible'], subScreen)
|
||||
},
|
||||
|
||||
[SWITCH_TABLE]: (state, {payload}) => {
|
||||
const { type, table } = payload
|
||||
return state.setIn([type, 'tableVisible'], table)
|
||||
}
|
||||
}, initialState)
|
||||
Reference in New Issue
Block a user