at the end of the day, it was inevitable
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import ExportFeedsTableRow from './ExportFeedsTableRow'
|
||||
import LoadersAdvanced from '../../../../common/Loader/Loader'
|
||||
import { Table, Card, CardBody } from 'reactstrap'
|
||||
|
||||
class ExportFeedsTable extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
tableData: PropTypes.array.isRequired,
|
||||
showPopup: PropTypes.func.isRequired,
|
||||
unexportFeed: PropTypes.func.isRequired,
|
||||
goToFeed: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
tableData,
|
||||
isLoading,
|
||||
showPopup,
|
||||
unexportFeed,
|
||||
goToFeed,
|
||||
t
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<Card className="main-card mb-3">
|
||||
{isLoading && <LoadersAdvanced />}
|
||||
<CardBody>
|
||||
<Table striped bordered className="mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t('exportTab.feedName')}</th>
|
||||
<th>{t('exportTab.exportWith')}</th>
|
||||
<th>{t('exportTab.actions')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{tableData.map((feed) => {
|
||||
return (
|
||||
<ExportFeedsTableRow
|
||||
key={feed.id}
|
||||
feed={feed}
|
||||
showPopup={showPopup}
|
||||
unexportFeed={unexportFeed}
|
||||
goToFeed={goToFeed}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</Table>
|
||||
</CardBody>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(ExportFeedsTable)
|
||||
@@ -0,0 +1,132 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Interpolate, translate } from 'react-i18next';
|
||||
import Select from 'react-select';
|
||||
import { Modal, ModalBody, ModalFooter, Button, ModalHeader } from 'reactstrap';
|
||||
|
||||
class ExportFeedsTableRow extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
feed: PropTypes.object.isRequired,
|
||||
showPopup: PropTypes.func.isRequired,
|
||||
unexportFeed: PropTypes.func.isRequired,
|
||||
goToFeed: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
format: 'rss',
|
||||
modal: false
|
||||
};
|
||||
}
|
||||
|
||||
showExportPopup = () => {
|
||||
this.props.showPopup(this.props.feed, this.state.format);
|
||||
};
|
||||
|
||||
toggle = () => {
|
||||
this.setState((prev) => ({ modal: !prev.modal }));
|
||||
};
|
||||
|
||||
exportOptions = [
|
||||
{ label: 'RSS 2.0', value: 'rss' },
|
||||
{ label: 'Atom 1.0', value: 'atom' },
|
||||
{ label: 'TSV', value: 'tsv' },
|
||||
{ label: 'HTML', value: 'html' }
|
||||
];
|
||||
|
||||
onChangeFormat = (format) => {
|
||||
this.setState({
|
||||
format: format
|
||||
});
|
||||
};
|
||||
|
||||
onDeleteClick = () => {
|
||||
this.setState({ modal: false });
|
||||
this.props.unexportFeed(this.props.feed.id);
|
||||
};
|
||||
|
||||
goToFeed = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.goToFeed(this.props.feed.id);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { feed, t } = this.props;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<Button
|
||||
color="link"
|
||||
className={`feed-icon font-size-lg p-0 feed-type-mixed ${feed.class}`}
|
||||
onClick={this.goToFeed}
|
||||
>
|
||||
{feed.name}
|
||||
</Button>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<Select
|
||||
options={this.exportOptions}
|
||||
value={this.state.format}
|
||||
simpleValue
|
||||
onChange={this.onChangeFormat}
|
||||
clearable={false}
|
||||
/>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<Button
|
||||
size="sm"
|
||||
color="primary"
|
||||
className="border-0 mr-2"
|
||||
onClick={this.showExportPopup}
|
||||
>
|
||||
{t('exportTab.export')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
outline
|
||||
size="sm"
|
||||
color="secondary"
|
||||
className="border-0"
|
||||
onClick={this.toggle}
|
||||
>
|
||||
{t('exportTab.delete')}
|
||||
</Button>
|
||||
|
||||
<Modal
|
||||
isOpen={this.state.modal}
|
||||
toggle={this.toggle}
|
||||
backdrop="static"
|
||||
>
|
||||
<ModalHeader toggle={this.toggle}>
|
||||
{t('exportTab.confirm')}
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<p>
|
||||
<Interpolate
|
||||
t={t}
|
||||
i18nKey="exportTab.exportDeleteMessage"
|
||||
feedName={feed.name}
|
||||
/>
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="light" onClick={this.toggle}>
|
||||
{t('common:commonWords.Cancel')}
|
||||
</Button>
|
||||
<Button color="danger" onClick={this.onDeleteClick}>
|
||||
{t('common:commonWords.Delete')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(ExportFeedsTableRow);
|
||||
@@ -0,0 +1,98 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { translate } from 'react-i18next';
|
||||
import config from '../../../../../appConfig';
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
ModalHeader,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Table
|
||||
} from 'reactstrap';
|
||||
|
||||
class ExportPopup extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
feed: PropTypes.object.isRequired,
|
||||
hidePopup: PropTypes.func.isRequired,
|
||||
exportFormat: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
hidePopup = () => {
|
||||
this.props.hidePopup();
|
||||
};
|
||||
|
||||
hidePopupFromOutside = (e) => {
|
||||
if (e.target === e.currentTarget) this.hidePopup();
|
||||
};
|
||||
|
||||
exportOptions = {
|
||||
rss: 'RSS 2.0',
|
||||
atom: 'Atom 1.0',
|
||||
tsv: 'TSV',
|
||||
html: 'HTML'
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t, feed, exportFormat } = this.props;
|
||||
|
||||
const href = `${config.apiUrl}/feed/${feed.id}.${exportFormat}`;
|
||||
|
||||
return (
|
||||
<Modal isOpen toggle={this.hidePopup} backdrop="static" size="lg">
|
||||
<ModalHeader toggle={this.hidePopup}>
|
||||
{this.exportOptions[exportFormat] + ' ' + t('exportTab.export')}
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<div className="mb-4">
|
||||
<p>{t('exportTab.exportPopup.line1')}</p>
|
||||
<p className="text-muted font-size-xs mb-2">
|
||||
({t('exportTab.exportPopup.line2')})
|
||||
</p>
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
className="font-weight-bold"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{href}
|
||||
</a>
|
||||
</div>
|
||||
<p className="mb-2">{t('exportTab.exportPopup.line3')}</p>
|
||||
<Table striped>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">n</th>
|
||||
<td>{t('exportTab.exportPopup.param1')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">ext</th>
|
||||
<td>{t('exportTab.exportPopup.param2')}</td>
|
||||
</tr>
|
||||
{exportFormat !== 'tsv' && (
|
||||
<tr>
|
||||
<th scope="row">img</th>
|
||||
<td>{t('exportTab.exportPopup.param3')}</td>
|
||||
</tr>
|
||||
)}
|
||||
{exportFormat !== 'tsv' && exportFormat !== 'html' && (
|
||||
<tr>
|
||||
<th scope="row">text_format</th>
|
||||
<td>{t('exportTab.exportPopup.param4')}</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</Table>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="light" onClick={this.hidePopup}>
|
||||
{t('exportTab.close')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(ExportPopup);
|
||||
@@ -0,0 +1,71 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import ExportFeedsTable from './ExportFeedsTable'
|
||||
import ExportPopup from './ExportPopup'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import reduxConnect from '../../../../../redux/utils/connect'
|
||||
import { compose } from 'redux'
|
||||
import { setDocumentData } from '../../../../../common/helper'
|
||||
|
||||
class ExportSubTab extends React.Component {
|
||||
static propTypes = {
|
||||
exportFeedsState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
setDocumentData('title', 'Export | Share')
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
setDocumentData('title')
|
||||
}
|
||||
|
||||
componentWillMount = () => {
|
||||
this.props.actions.loadExportedFeeds()
|
||||
};
|
||||
|
||||
goToFeed = (feedId) => {
|
||||
const {
|
||||
history,
|
||||
actions: { getFeedResults }
|
||||
} = this.props
|
||||
history.push('/app/search/search')
|
||||
getFeedResults({ page: 1 }, feedId)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t, exportFeedsState, actions } = this.props
|
||||
return (
|
||||
<div>
|
||||
<p className="text-muted mb-3">{t('exportTab.topMessage')}</p>
|
||||
|
||||
<ExportFeedsTable
|
||||
isLoading={exportFeedsState.isLoading}
|
||||
tableData={exportFeedsState.tableData}
|
||||
showPopup={actions.showExportPopup}
|
||||
unexportFeed={actions.unexportFeed}
|
||||
goToFeed={this.goToFeed}
|
||||
/>
|
||||
|
||||
{exportFeedsState.popupVisible && (
|
||||
<ExportPopup
|
||||
feed={exportFeedsState.selectedFeed}
|
||||
hidePopup={actions.hideExportPopup}
|
||||
exportFormat={exportFeedsState.exportFormat}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const applyDecorators = compose(
|
||||
withRouter,
|
||||
reduxConnect('exportFeedsState', ['appState', 'share', 'exportFeeds']),
|
||||
translate(['tabsContent'], { wait: true })
|
||||
)
|
||||
export default applyDecorators(ExportSubTab)
|
||||
@@ -0,0 +1,16 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import {AlertForm as BaseAlertForm} from '../NotificatoinsSubTab/forms/AlertForm'
|
||||
import {translate} from 'react-i18next'
|
||||
|
||||
export class AlertForm extends BaseAlertForm {
|
||||
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
state: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
switchShareSubScreen: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(AlertForm)
|
||||
@@ -0,0 +1,91 @@
|
||||
import React from 'react'
|
||||
import { translate } from 'react-i18next'
|
||||
import PropTypes from 'prop-types'
|
||||
import SortableTh from '../../../../common/Table/SortableTh'
|
||||
import { MyEmailsTable } from '../NotificatoinsSubTab/MyEmailsTable' // default export doesn't work
|
||||
import { ButtonGroup, Button } from 'reactstrap'
|
||||
|
||||
class EmailsTable extends MyEmailsTable {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
deleteSingleText: PropTypes.string.isRequired,
|
||||
deleteMultipleText: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
nameClickAction = (item) => {
|
||||
const { actions } = this.props
|
||||
actions.startEditNotification(item, 'emails', 'emails')
|
||||
};
|
||||
|
||||
defineColumns () {
|
||||
return {
|
||||
...super.defineColumns(),
|
||||
owner: {
|
||||
Header: <SortableTh title="manageEmailsTab.owner" />,
|
||||
accessor: (item) => item.owner.email,
|
||||
width: 170
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onRefreshButtonClick = () => {
|
||||
this.props.tableActions.loadTable({})
|
||||
};
|
||||
|
||||
getColumns () {
|
||||
return [
|
||||
'selectCheckbox',
|
||||
'name',
|
||||
'type',
|
||||
'owner',
|
||||
'published',
|
||||
'ScheduledTimes',
|
||||
'sourcesCount',
|
||||
'Recipients',
|
||||
'active',
|
||||
'delete'
|
||||
]
|
||||
}
|
||||
|
||||
getActionsPanel = () => {
|
||||
const { t } = this.props
|
||||
return (
|
||||
<ButtonGroup className="mb-3">
|
||||
<Button
|
||||
onClick={this.onActivateButtonClick}
|
||||
color="secondary"
|
||||
>
|
||||
<i className="fa fa-play fa-1px for-small mr-1"> </i>{" "}
|
||||
{t('notificationsTab.activate')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onPauseButtonClick}
|
||||
>
|
||||
<i className="fa fa-pause fa-1px for-small mr-1"> </i>{" "}
|
||||
{t('notificationsTab.pause')}
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onDeleteButtonClick}
|
||||
>
|
||||
<i className="fa fa-trash for-small mr-1"> </i>{" "}
|
||||
{t('notificationsTab.delete')}
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onRefreshButtonClick}
|
||||
>
|
||||
<i className="fa fa-refresh fa-1px for-small mr-1"> </i>{" "}
|
||||
{t('manageEmailsTab.refresh')}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(EmailsTable)
|
||||
@@ -0,0 +1,49 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {translate} from 'react-i18next'
|
||||
import {GenericTable} from '../common/GenericTable'
|
||||
import SortableTh from '../../../../common/Table/SortableTh'
|
||||
import {EMAILS_SUBSCREENS} from '../../../../../redux/modules/appState/share/tabs'
|
||||
|
||||
export class FiltersTable extends GenericTable {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
defineColumns () {
|
||||
|
||||
return {
|
||||
'name': {
|
||||
Header: <SortableTh title='manageEmailsTab.filter' />,
|
||||
accessor: 'name'
|
||||
},
|
||||
'notifications': {
|
||||
Header: <SortableTh title='manageEmailsTab.notifications' />,
|
||||
width: 270,
|
||||
accessor: 'notifications'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getColumns () {
|
||||
return ['name', 'notifications']
|
||||
}
|
||||
|
||||
onRowClick = (e, state, rowInfo) => {
|
||||
const { actions } = this.props
|
||||
const filter = {
|
||||
type: rowInfo.original.type,
|
||||
id: rowInfo.original.id,
|
||||
name: rowInfo.original.name
|
||||
}
|
||||
actions.shareTables.emails.setFilter(filter)
|
||||
actions.switchShareSubScreen('emails', EMAILS_SUBSCREENS.EMAILS_TABLE)
|
||||
actions.shareTables.emails.loadTable({})
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(FiltersTable)
|
||||
@@ -0,0 +1,74 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import Select from 'react-select'
|
||||
import { EMAILS_SUBSCREENS } from '../../../../../redux/modules/appState/share/tabs'
|
||||
import { Button } from 'reactstrap'
|
||||
|
||||
export class FiltersTopBar extends React.Component {
|
||||
static propTypes = {
|
||||
actions: PropTypes.object.isRequired,
|
||||
filterType: PropTypes.string.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
onSelectFilterType = (filterType) => {
|
||||
const { actions } = this.props
|
||||
actions.shareTables.emailFilters.loadTable({ filterType })
|
||||
};
|
||||
|
||||
clearFilters = () => {
|
||||
const { actions } = this.props
|
||||
actions.shareTables.emails.clearFilter()
|
||||
actions.switchShareSubScreen('emails', EMAILS_SUBSCREENS.EMAILS_TABLE)
|
||||
};
|
||||
|
||||
backToTable = () => {
|
||||
const { actions } = this.props
|
||||
actions.switchShareSubScreen('emails', EMAILS_SUBSCREENS.EMAILS_TABLE)
|
||||
}
|
||||
|
||||
filterTypes = [
|
||||
{ label: 'Owner', value: 'owner' },
|
||||
{ label: 'Recipient', value: 'recipient' },
|
||||
{ label: 'Feed', value: 'feed' }
|
||||
];
|
||||
|
||||
render () {
|
||||
const { t, filterType } = this.props
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Button className="btn-wide mb-2" size="sm" color="info" onClick={this.backToTable}>
|
||||
<i className="lnr lnr-chevron-left"> </i>
|
||||
</Button>
|
||||
<div className="notifications-topbar align-items-center">
|
||||
<div className="text-muted">{t('manageEmailsTab.emailFilter')}</div>
|
||||
<div className="d-flex align-items-center">
|
||||
<label className="mr-1">{t('manageEmailsTab.filterBy')}</label>
|
||||
<div style={{ minWidth: '150px' }}>
|
||||
<Select
|
||||
value={filterType}
|
||||
onChange={this.onSelectFilterType}
|
||||
options={this.filterTypes}
|
||||
simpleValue
|
||||
searchable={false}
|
||||
clearable={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
color="secondary"
|
||||
className="ml-2"
|
||||
onClick={this.clearFilters}
|
||||
>
|
||||
{t('manageEmailsTab.allEmails')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(FiltersTopBar)
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import TopBar from './TopBar';
|
||||
import EmailsTable from './EmailsTable';
|
||||
import reduxConnect from '../../../../../redux/utils/connect';
|
||||
import AlertForm from './AlertForm';
|
||||
import Navigation from './Navigation';
|
||||
import FiltersTable from './FiltersTable';
|
||||
import FiltersTopBar from './FiltersTopBar';
|
||||
import { EMAILS_SUBSCREENS } from '../../../../../redux/modules/appState/share/tabs';
|
||||
import { setDocumentData } from '../../../../../common/helper';
|
||||
|
||||
class ManageEmailsSubTab extends React.Component {
|
||||
static propTypes = {
|
||||
shareState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
setDocumentData('title', 'Manage Recipients | Share')
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
setDocumentData('title')
|
||||
}
|
||||
|
||||
render() {
|
||||
const { shareState, actions } = this.props;
|
||||
const { subScreenVisible } = shareState.tabs.emails;
|
||||
|
||||
return (
|
||||
<div className="notifications-tab">
|
||||
{subScreenVisible === EMAILS_SUBSCREENS.EMAILS_TABLE && (
|
||||
<div>
|
||||
<TopBar tableState={shareState.tables.emails} actions={actions} />
|
||||
<EmailsTable
|
||||
tableState={shareState.tables.emails}
|
||||
actions={actions}
|
||||
tableActions={actions.shareTables.emails}
|
||||
deleteSingleText="email"
|
||||
deleteMultipleText="emails"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(subScreenVisible === EMAILS_SUBSCREENS.ALERT_FORM ||
|
||||
subScreenVisible === EMAILS_SUBSCREENS.NEWSLETTER_FORM) && (
|
||||
<Navigation actions={actions} />
|
||||
)}
|
||||
|
||||
{subScreenVisible === EMAILS_SUBSCREENS.ALERT_FORM && (
|
||||
<AlertForm
|
||||
state={shareState.forms.alert}
|
||||
switchShareSubScreen={actions.switchShareSubScreen}
|
||||
actions={actions.shareForms.alert}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* {subScreenVisible === EMAILS_SUBSCREENS.NEWSLETTER_FORM &&
|
||||
<NewsletterForm
|
||||
state={shareState.forms.newsletter}
|
||||
switchShareSubScreen={actions.switchShareSubScreen}
|
||||
actions={actions.shareForms.newsletter}
|
||||
/>
|
||||
} */}
|
||||
|
||||
{subScreenVisible === EMAILS_SUBSCREENS.FILTERS_TABLE && (
|
||||
<Fragment>
|
||||
<FiltersTopBar
|
||||
actions={actions}
|
||||
filterType={shareState.tables.emailFilters.filterType}
|
||||
/>
|
||||
<FiltersTable
|
||||
actions={actions}
|
||||
tableState={shareState.tables.emailFilters}
|
||||
tableActions={actions.shareTables.emailFilters}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default reduxConnect('shareState', ['appState', 'share'])(
|
||||
ManageEmailsSubTab
|
||||
);
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import { EMAILS_SUBSCREENS } from '../../../../../redux/modules/appState/share/tabs'
|
||||
import { Button } from 'reactstrap'
|
||||
|
||||
class Navigation extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
backToTable = () => {
|
||||
this.props.actions.switchShareSubScreen(
|
||||
'emails',
|
||||
EMAILS_SUBSCREENS.EMAILS_TABLE
|
||||
)
|
||||
};
|
||||
|
||||
render () {
|
||||
|
||||
return (
|
||||
<Button className="btn-wide mb-2" size="sm" color="info" onClick={this.backToTable}>
|
||||
<i className="lnr lnr-chevron-left"> </i>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(Navigation)
|
||||
@@ -0,0 +1,14 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import {NewsletterForm as BaseNewsletterForm} from '../NotificatoinsSubTab/forms/NewsletterForm'
|
||||
import {translate} from 'react-i18next'
|
||||
|
||||
export class NewsletterForm extends BaseNewsletterForm {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
state: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(NewsletterForm)
|
||||
@@ -0,0 +1,72 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import { EMAILS_SUBSCREENS } from '../../../../../redux/modules/appState/share/tabs'
|
||||
import { Button } from 'reactstrap'
|
||||
|
||||
export class TopBar extends React.Component {
|
||||
static propTypes = {
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
onCreate = (type) => () => {
|
||||
const { actions } = this.props
|
||||
actions.startCreateNotification(type, 'emails', 'emails')
|
||||
};
|
||||
|
||||
goToFiltersTable = () => {
|
||||
const { actions } = this.props
|
||||
actions.switchShareSubScreen('emails', EMAILS_SUBSCREENS.FILTERS_TABLE)
|
||||
};
|
||||
|
||||
render () {
|
||||
const {
|
||||
t,
|
||||
tableState: { filter }
|
||||
} = this.props
|
||||
|
||||
const filterName = filter
|
||||
? `${filter.name} (${t('manageEmailsTab.' + filter.type)})`
|
||||
: t('manageEmailsTab.allEmails')
|
||||
|
||||
return (
|
||||
<div className="notifications-topbar">
|
||||
<p className="text-muted align-self-center">
|
||||
<strong>{t('manageEmailsTab.currentFilter') + ': '}</strong>{" "}
|
||||
{filterName}
|
||||
</p>
|
||||
<div>
|
||||
<Button
|
||||
className="btn-icon mr-2"
|
||||
onClick={this.goToFiltersTable}
|
||||
>
|
||||
<i className="lnr lnr-funnel btn-icon-wrapper" />
|
||||
{t('manageEmailsTab.selectFilter')}
|
||||
</Button>
|
||||
<div className="notifications-buttons">
|
||||
<Button
|
||||
color="primary"
|
||||
className="btn-icon"
|
||||
onClick={this.onCreate(EMAILS_SUBSCREENS.ALERT_FORM)}
|
||||
>
|
||||
<i className="lnr lnr-alarm btn-icon-wrapper" />
|
||||
{t('notificationsTab.newAlert')}
|
||||
</Button>
|
||||
{/* <Button
|
||||
color="primary"
|
||||
className="btn-icon"
|
||||
onClick={this.onCreate(EMAILS_SUBSCREENS.NEWSLETTER_FORM)}
|
||||
>
|
||||
<i className="lnr lnr-file-add btn-icon-wrapper" />
|
||||
{t('notificationsTab.newNewsletter')}
|
||||
</Button> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(TopBar)
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import ReceiversTable from './ReceiversTable'
|
||||
import SortableTh from '../../../../common/Table/SortableTh'
|
||||
import LinkCell from '../../../../common/Table/LinkCell'
|
||||
|
||||
class GroupsTable extends ReceiversTable {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
deleteSingleText: PropTypes.string.isRequired,
|
||||
deleteMultipleText: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
nameClickAction = (item) => {
|
||||
this.props.actions.startEditGroup(item)
|
||||
};
|
||||
|
||||
defineColumns () {
|
||||
//const {t} = this.props;
|
||||
const colDefs = super.defineColumns()
|
||||
return {
|
||||
...colDefs,
|
||||
'recipientsNumber': {
|
||||
Header: <SortableTh title='manageRecipientsTab.recipientsNumber' />,
|
||||
accessor: item => item.recipients.length || '',
|
||||
width: 140
|
||||
},
|
||||
'name': {
|
||||
Header: <SortableTh title='manageRecipientsTab.groupName' />,
|
||||
accessor: 'name',
|
||||
Cell: (row) => {
|
||||
return (
|
||||
<LinkCell item={row.original} onClick={this.nameClickAction}>
|
||||
{row.value}
|
||||
</LinkCell>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getColumns () {
|
||||
return ['selectCheckbox', 'name', 'recipientsNumber', 'subscriptions', 'creationDate', 'active']
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(GroupsTable)
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import TopBar from './TopBar'
|
||||
import RecipientsTable from './RecipientsTable'
|
||||
import { RECEIVER_TABLES, RECEIVER_SUBSCREENS } from '../../../../../redux/modules/appState/share/tabs'
|
||||
import {RecipientForm} from './forms/ReceiverForm'
|
||||
import GroupsTable from './GroupsTable'
|
||||
import {withRouter} from 'react-router-dom'
|
||||
import reduxConnect from '../../../../../redux/utils/connect'
|
||||
import {compose} from 'redux'
|
||||
import { setDocumentData } from '../../../../../common/helper'
|
||||
|
||||
class ManageRecipientsSubTab extends React.Component {
|
||||
static propTypes = {
|
||||
shareState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
setDocumentData('title', 'Manage Emails | Share')
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
setDocumentData('title')
|
||||
}
|
||||
|
||||
render () {
|
||||
|
||||
const { shareState, actions } = this.props
|
||||
const { subScreenVisible, tableVisible } = shareState.tabs.recipients
|
||||
const tableState = shareState.tables[tableVisible]
|
||||
|
||||
return (
|
||||
<div className="notifications-tab">
|
||||
|
||||
{subScreenVisible === RECEIVER_SUBSCREENS.TABLES &&
|
||||
<div>
|
||||
<TopBar
|
||||
tableVisible={tableVisible}
|
||||
tables={[RECEIVER_TABLES.RECIPIENTS, RECEIVER_TABLES.GROUPS]}
|
||||
actions={actions}
|
||||
/>
|
||||
|
||||
{tableVisible === RECEIVER_TABLES.RECIPIENTS &&
|
||||
<RecipientsTable
|
||||
tableState={tableState}
|
||||
actions={actions}
|
||||
tableActions={actions.shareTables[tableVisible]}
|
||||
deleteSingleText='recipient'
|
||||
deleteMultipleText='recipients'
|
||||
/>
|
||||
}
|
||||
{tableVisible === RECEIVER_TABLES.GROUPS &&
|
||||
<GroupsTable
|
||||
tableState={tableState}
|
||||
actions={actions}
|
||||
tableActions={actions.shareTables[tableVisible]}
|
||||
deleteSingleText='group'
|
||||
deleteMultipleText='groups'
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
{(subScreenVisible === RECEIVER_SUBSCREENS.RECIPIENT_FORM || subScreenVisible === RECEIVER_SUBSCREENS.GROUP_FORM) &&
|
||||
<RecipientForm
|
||||
formType={subScreenVisible}
|
||||
shareState={shareState}
|
||||
actions={actions}
|
||||
/>
|
||||
}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const applyDecorators = compose(
|
||||
withRouter,
|
||||
reduxConnect('shareState', ['appState', 'share'])
|
||||
)
|
||||
|
||||
export default applyDecorators(ManageRecipientsSubTab)
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
import React from 'react'
|
||||
import GenericTable from '../common/GenericTable'
|
||||
import SortableTh from '../../../../common/Table/SortableTh'
|
||||
import PropTypes from 'prop-types'
|
||||
import { ButtonGroup, Button } from 'reactstrap'
|
||||
import { convertUTCtoLocal } from '../../../../../common/helper'
|
||||
|
||||
class ReceiversTable extends GenericTable {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
deleteSingleText: PropTypes.string.isRequired,
|
||||
deleteMultipleText: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
onActivateButtonClick = () => {
|
||||
const { tableState, tableActions } = this.props
|
||||
tableActions.toggleActive(tableState.selectedIds, true)
|
||||
};
|
||||
|
||||
onPauseButtonClick = () => {
|
||||
const { tableState, tableActions } = this.props
|
||||
tableActions.toggleActive(tableState.selectedIds, false)
|
||||
};
|
||||
|
||||
togglerOnAction = (itemId) => {
|
||||
const { tableActions } = this.props
|
||||
tableActions.toggleActive([itemId], true)
|
||||
};
|
||||
|
||||
togglerOffAction = (itemId) => {
|
||||
const { tableActions } = this.props
|
||||
tableActions.toggleActive([itemId], false)
|
||||
};
|
||||
|
||||
getActionsPanel = () => {
|
||||
const { t } = this.props
|
||||
|
||||
return (
|
||||
<ButtonGroup className="mb-3">
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onActivateButtonClick}
|
||||
>
|
||||
<i className="fa fa-play mr-1 for-small" />
|
||||
{t('notificationsTab.activate')}
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onPauseButtonClick}
|
||||
>
|
||||
<i className="fa fa-pause for-small mr-1" />
|
||||
{t('notificationsTab.pause')}
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onDeleteButtonClick}
|
||||
>
|
||||
<i className="fa fa-trash for-small mr-1" />
|
||||
{t('notificationsTab.delete')}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
)
|
||||
};
|
||||
|
||||
_formatSubscriptions (subscriptions) {
|
||||
const { t } = this.props
|
||||
const result = []
|
||||
if (subscriptions.alert > 0) {
|
||||
result.push(`${subscriptions.alert} ${t('notificationsTab.alerts')}`)
|
||||
}
|
||||
if (subscriptions.newsletter > 0) {
|
||||
result.push(`${subscriptions.newsletter} ${t('notificationsTab.newsletters')}`)
|
||||
}
|
||||
return result.join(', ')
|
||||
}
|
||||
|
||||
defineColumns () {
|
||||
const { t } = this.props
|
||||
const colDefinitions = super.defineColumns()
|
||||
return {
|
||||
...colDefinitions,
|
||||
subscriptions: {
|
||||
sortable: false,
|
||||
Header: t('manageRecipientsTab.subscriptions'),
|
||||
accessor: (item) => this._formatSubscriptions(item.subscriptions),
|
||||
width: 170
|
||||
},
|
||||
creationDate: {
|
||||
Header: <SortableTh title="manageRecipientsTab.creationDate" />,
|
||||
accessor: (item) => convertUTCtoLocal(item.creationDate, 'DD MMM YYYY HH:mm'),
|
||||
width: 100
|
||||
},
|
||||
active: this.createTogglerColumn(
|
||||
'manageRecipientsTab.status',
|
||||
'active',
|
||||
'active',
|
||||
'paused',
|
||||
this.togglerOnAction,
|
||||
this.togglerOffAction
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ReceiversTable
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import ReceiversTable from './ReceiversTable'
|
||||
import SortableTh from '../../../../common/Table/SortableTh'
|
||||
import LinkCell from '../../../../common/Table/LinkCell'
|
||||
|
||||
class RecipientsTable extends ReceiversTable {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
deleteSingleText: PropTypes.string.isRequired,
|
||||
deleteMultipleText: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
nameClickAction = (item) => {
|
||||
this.props.actions.startEditRecipient(item)
|
||||
};
|
||||
|
||||
defineColumns () {
|
||||
const {t} = this.props
|
||||
const colDefs = super.defineColumns()
|
||||
return {
|
||||
...colDefs,
|
||||
'email': {
|
||||
Header: <SortableTh title='manageRecipientsTab.email' />,
|
||||
accessor: 'email',
|
||||
width: 170
|
||||
},
|
||||
'groups': {
|
||||
sortable: false,
|
||||
Header: t('manageRecipientsTab.groups'),
|
||||
accessor: item => item.groups.map(group => group.name).join(', '),
|
||||
width: 170
|
||||
},
|
||||
'name': {
|
||||
Header: <SortableTh title='manageRecipientsTab.name' />,
|
||||
accessor: 'name',
|
||||
Cell: (row) => {
|
||||
const {original} = row
|
||||
const name = `${original.firstName} ${original.lastName}`
|
||||
return (
|
||||
<LinkCell item={original} onClick={this.nameClickAction}>
|
||||
{name}
|
||||
</LinkCell>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getColumns () {
|
||||
return ['selectCheckbox', 'name', 'email', 'groups', 'subscriptions', 'creationDate', 'active']
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(RecipientsTable)
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
import { Button, Input, InputGroup, InputGroupAddon } from 'reactstrap'
|
||||
|
||||
const INPUT_THROTTLE_TIME = 300
|
||||
|
||||
export class TableFilter extends React.Component {
|
||||
static propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
onFilterRequest: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
constructor () {
|
||||
super()
|
||||
this.state = {
|
||||
value: ''
|
||||
}
|
||||
}
|
||||
|
||||
onFilter = (event) => {
|
||||
this._onFilterImpl(event.target.value)
|
||||
};
|
||||
|
||||
_onFilterImpl (filterValue) {
|
||||
const { onFilterRequest } = this.props
|
||||
this.setState({ value: filterValue })
|
||||
if (this.inputDelay) {
|
||||
clearTimeout(this.inputDelay)
|
||||
}
|
||||
this.inputDelay = setTimeout(() => {
|
||||
onFilterRequest(filterValue)
|
||||
}, INPUT_THROTTLE_TIME)
|
||||
}
|
||||
|
||||
onClear = () => {
|
||||
const value = this.state.value
|
||||
value && this._onFilterImpl('')
|
||||
};
|
||||
|
||||
render () {
|
||||
const { type } = this.props
|
||||
const value = this.state.value
|
||||
const hasValue = !!value
|
||||
const iconClasses = classnames('fa', {
|
||||
'fa-search': !hasValue,
|
||||
'fa-times': hasValue
|
||||
})
|
||||
|
||||
const placeholder = `Find ${type}`
|
||||
|
||||
return (
|
||||
<InputGroup className="mb-3">
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={this.onFilter}
|
||||
/>
|
||||
<InputGroupAddon addonType="append">
|
||||
<Button color="primary" onClick={this.onClear}>
|
||||
<i className={iconClasses}></i>
|
||||
</Button>
|
||||
</InputGroupAddon>
|
||||
{/* <button
|
||||
className="cw-grid__filter-button"
|
||||
type="button"
|
||||
onClick={this.onClear}
|
||||
>
|
||||
<i className={iconClasses} />
|
||||
</button> */}
|
||||
</InputGroup>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default TableFilter
|
||||
@@ -0,0 +1,77 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import TableFilter from './TableFilter'
|
||||
import TableSwitcher from '../common/TableSwitcher/TableSwitcher'
|
||||
import { Button } from 'reactstrap'
|
||||
|
||||
export class TopBar extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tables: PropTypes.array.isRequired,
|
||||
tableVisible: PropTypes.string.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
onNewRecipient = () => {
|
||||
const { actions } = this.props
|
||||
actions.startCreateRecipient()
|
||||
};
|
||||
|
||||
onNewGroup = () => {
|
||||
const { actions } = this.props
|
||||
actions.startCreateGroup()
|
||||
};
|
||||
|
||||
onFilterRequest = (filter) => {
|
||||
this.loadTable({ filter })
|
||||
};
|
||||
|
||||
loadTable = (params) => {
|
||||
const { tableVisible: type } = this.props
|
||||
this.props.actions.shareTables[type].loadTable(params || null)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t, tables, tableVisible, actions } = this.props
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="notifications-topbar align-items-center">
|
||||
<TableSwitcher
|
||||
tables={tables}
|
||||
tableVisible={tableVisible}
|
||||
subTab="recipients"
|
||||
switchTable={actions.switchShareTable}
|
||||
loadTable={this.loadTable}
|
||||
/>
|
||||
|
||||
<div className="notifications-buttons">
|
||||
<Button
|
||||
color="primary"
|
||||
className="btn-icon mr-2"
|
||||
onClick={this.onNewRecipient}
|
||||
>
|
||||
<i className="lnr lnr-location for-small btn-icon-wrapper" />
|
||||
{t('manageRecipientsTab.newRecipient')}
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
className="btn-icon"
|
||||
onClick={this.onNewGroup}
|
||||
>
|
||||
<i className="lnr lnr-users for-small btn-icon-wrapper" />
|
||||
{t('manageRecipientsTab.newGroup')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<TableFilter
|
||||
type={tableVisible}
|
||||
onFilterRequest={this.onFilterRequest}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(TopBar)
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import InputField from './InputField'
|
||||
import { Card, CardBody, CardTitle, Form, FormGroup, Input, Label } from 'reactstrap'
|
||||
|
||||
export class BasicGroupInfo extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
formActions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
onChangeFor = (field) => (event) => {
|
||||
const { formActions } = this.props
|
||||
formActions.changeField(field, event.target.value)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t, item } = this.props
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardBody>
|
||||
<CardTitle>{t('manageRecipientsTab.form.group.basicInfo')}</CardTitle>
|
||||
<Form>
|
||||
<InputField
|
||||
formType="group"
|
||||
field="name"
|
||||
value={item.name}
|
||||
onChangeFor={this.onChangeFor}
|
||||
/>
|
||||
|
||||
<FormGroup>
|
||||
<Label>
|
||||
{t('manageRecipientsTab.form.group.description')}
|
||||
</Label>
|
||||
<Input
|
||||
type="textarea"
|
||||
rows="5"
|
||||
onChange={this.onChangeFor('description')}
|
||||
value={item.description}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<hr />
|
||||
{!!item.recipients && (
|
||||
<p>
|
||||
{t('manageRecipientsTab.form.group.recipientsNumber')}:{' '}
|
||||
{item.recipients.length}
|
||||
</p>
|
||||
)}
|
||||
</CardBody>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(BasicGroupInfo)
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import InputField from './InputField'
|
||||
import { Card, CardBody, CardTitle, Form } from 'reactstrap'
|
||||
|
||||
export class BasicRecipientInfo extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
formActions: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
onChangeFor = (field) => (event) => {
|
||||
const { formActions } = this.props
|
||||
formActions.changeField(field, event.target.value)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { item, t } = this.props
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardBody>
|
||||
<CardTitle>{t('manageRecipientsTab.form.recipient.basicInfo')}</CardTitle>
|
||||
<Form>
|
||||
<InputField
|
||||
formType="recipient"
|
||||
field="firstName"
|
||||
value={item.firstName}
|
||||
onChangeFor={this.onChangeFor}
|
||||
/>
|
||||
|
||||
<InputField
|
||||
formType="recipient"
|
||||
field="lastName"
|
||||
value={item.lastName}
|
||||
onChangeFor={this.onChangeFor}
|
||||
/>
|
||||
|
||||
<InputField
|
||||
formType="recipient"
|
||||
field="email"
|
||||
value={item.email}
|
||||
onChangeFor={this.onChangeFor}
|
||||
/>
|
||||
</Form>
|
||||
</CardBody>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(BasicRecipientInfo)
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
|
||||
export class BreadCrumbs extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
onBack: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t, title, onBack } = this.props
|
||||
|
||||
return (
|
||||
<div>
|
||||
<a href="#" onClick={onBack}>
|
||||
{t('tableSwitcher.recipients')}
|
||||
</a>
|
||||
<span> > {title}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(BreadCrumbs)
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import Toggler from '../../../../../common/Table/Toggler'
|
||||
import { Button, Card, CardBody, CardTitle, Label } from 'reactstrap'
|
||||
import { convertUTCtoLocal } from '../../../../../../common/helper'
|
||||
|
||||
export class FormTopBar extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
formType: PropTypes.string.isRequired,
|
||||
receiver: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
togglerAction = () => {
|
||||
const { actions, formType } = this.props
|
||||
actions.shareForms[formType].toggleActive()
|
||||
}
|
||||
|
||||
onBack = () => {
|
||||
this.props.actions.switchShareSubScreen('recipients', 'tables')
|
||||
}
|
||||
|
||||
onDelete = () => {
|
||||
const { formType, actions } = this.props
|
||||
actions.shareForms[formType].confirmDelete()
|
||||
}
|
||||
|
||||
onSave = () => {
|
||||
const { actions, formType } = this.props
|
||||
actions.shareForms[formType].saveReceiver()
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t, formType, receiver } = this.props
|
||||
const hasItem = !!receiver.id
|
||||
const trPath = 'manageRecipientsTab.form'
|
||||
let title = t(`${trPath}.${formType}.unsaved`)
|
||||
if (hasItem) {
|
||||
title =
|
||||
formType === 'group'
|
||||
? receiver.name
|
||||
: `${receiver.firstName} ${receiver.lastName}`
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Button
|
||||
className="btn-wide mb-3"
|
||||
size="sm"
|
||||
color="info"
|
||||
onClick={this.onBack}
|
||||
>
|
||||
<i className="lnr lnr-chevron-left"> </i>
|
||||
</Button>
|
||||
|
||||
<Card className="main-card mb-3">
|
||||
<CardBody>
|
||||
<CardTitle>{title}</CardTitle>
|
||||
|
||||
<div className="d-flex justify-content-between flex-wrap align-items-center">
|
||||
<div>
|
||||
<Label className="mr-2">
|
||||
{t(`${trPath}.${formType}.nameStatus`)}
|
||||
</Label>
|
||||
<Toggler
|
||||
id={receiver.id}
|
||||
turnOnAction={this.togglerAction}
|
||||
turnOffAction={this.togglerAction}
|
||||
state={receiver.active}
|
||||
enabledText="active"
|
||||
disabledText="paused"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{hasItem && (
|
||||
<Button
|
||||
color="danger"
|
||||
className="btn-icon mr-2"
|
||||
onClick={this.onDelete}
|
||||
>
|
||||
<i className="lnr lnr-trash btn-icon-wrapper"></i>
|
||||
{t(`${trPath}.${formType}.deleteButton`)}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
color="secondary"
|
||||
className="btn-icon mr-2"
|
||||
onClick={this.onBack}
|
||||
>
|
||||
<i className="lnr lnr-cross btn-icon-wrapper"></i>
|
||||
{t(`${trPath}.cancel`)}
|
||||
</Button>
|
||||
<Button
|
||||
color="success"
|
||||
className="btn-icon mr-2"
|
||||
onClick={this.onSave}
|
||||
>
|
||||
<i className="lnr lnr-checkmark-circle btn-icon-wrapper" />
|
||||
{t(`${trPath}.save`)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{hasItem && receiver.creationDate && (
|
||||
<p className="mt-1">
|
||||
{t(`${trPath}.${formType}.creationDate`)}:
|
||||
{convertUTCtoLocal(receiver.creationDate, 'DD MMM YYYY HH:mm')}
|
||||
</p>
|
||||
)}
|
||||
</CardBody>
|
||||
</Card>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(FormTopBar)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import { FormGroup, Input, Label } from 'reactstrap'
|
||||
|
||||
export class InputField extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
formType: PropTypes.string.isRequired,
|
||||
field: PropTypes.string.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChangeFor: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t, formType, field, value, onChangeFor } = this.props
|
||||
const trPath = `manageRecipientsTab.form.${formType}`
|
||||
|
||||
return (
|
||||
<FormGroup>
|
||||
<Label>{t(`${trPath}.${field}`)}</Label>
|
||||
<Input type="text" onChange={onChangeFor(field)} value={value} />
|
||||
</FormGroup>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(InputField)
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import FormTopBar from './FormTopBar'
|
||||
import BasicRecipientInfo from './BasicRecipientInfo'
|
||||
import BasicGroupInfo from './BasicGroupInfo'
|
||||
import TablesTabs from './TablesTabs'
|
||||
import EmailHistoryTable from './tables/EmailHistoryTable'
|
||||
import DeletePopup from '../../common/DeletePopup'
|
||||
import {
|
||||
RECIPIENT_FORM_TABLES,
|
||||
GROUP_FORM_TABLES,
|
||||
RECEIVER_SUBSCREENS
|
||||
} from '../../../../../../redux/modules/appState/share/tabs'
|
||||
import ReceiverSubscriptionsTable from './tables/ReceiverSubscriptionsTable'
|
||||
import ReceiverGroupsTable from './tables/ReceiverGroupsTable'
|
||||
import ReceiverRecipientsTable from './tables/ReceiverRecipientsTable'
|
||||
import { Card, CardBody, CardHeader, Col, Nav, Row } from 'reactstrap'
|
||||
|
||||
export class RecipientForm extends React.Component {
|
||||
static propTypes = {
|
||||
formType: PropTypes.string.isRequired,
|
||||
shareState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
chooseTableTab = (tab) => {
|
||||
const { actions, formType } = this.props
|
||||
actions.shareForms[formType].chooseTableTab(tab)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { formType, shareState, actions } = this.props
|
||||
const formState = shareState.forms[formType] // receiver
|
||||
const formActions = actions.shareForms[formType]
|
||||
|
||||
let allTabs = formState.tabs.all
|
||||
if (!formState.id) {
|
||||
allTabs = allTabs.filter(
|
||||
(tab) => tab !== RECIPIENT_FORM_TABLES.EMAIL_HISTORY
|
||||
)
|
||||
}
|
||||
const activeTab = formState.tabs.active
|
||||
|
||||
const tableState = shareState.tables.receiverForm[activeTab]
|
||||
const tableActions = actions.shareTables.receiverForm[activeTab]
|
||||
|
||||
const deleteText =
|
||||
formType === RECEIVER_SUBSCREENS.GROUP_FORM ? 'group' : 'recipient'
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<FormTopBar
|
||||
formType={formType}
|
||||
receiver={formState}
|
||||
actions={actions}
|
||||
/>
|
||||
|
||||
<Row>
|
||||
<Col lg="4">
|
||||
{formType === RECEIVER_SUBSCREENS.RECIPIENT_FORM && (
|
||||
<BasicRecipientInfo item={formState} formActions={formActions} />
|
||||
)}
|
||||
|
||||
{formType === RECEIVER_SUBSCREENS.GROUP_FORM && (
|
||||
<BasicGroupInfo item={formState} formActions={formActions} />
|
||||
)}
|
||||
</Col>
|
||||
|
||||
<Col lg="8">
|
||||
<Card className="mb-3">
|
||||
<CardHeader>
|
||||
<Nav justified>
|
||||
<TablesTabs
|
||||
tabs={allTabs}
|
||||
activeTab={activeTab}
|
||||
chooseTableTab={this.chooseTableTab}
|
||||
/>
|
||||
</Nav>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
{activeTab === RECIPIENT_FORM_TABLES.SUBSCRIPTIONS && (
|
||||
<ReceiverSubscriptionsTable
|
||||
tableState={tableState}
|
||||
actions={actions}
|
||||
tableActions={tableActions}
|
||||
receiver={formState}
|
||||
formActions={formActions}
|
||||
/>
|
||||
)}
|
||||
|
||||
{activeTab === RECIPIENT_FORM_TABLES.GROUPS && (
|
||||
<ReceiverGroupsTable
|
||||
tableState={tableState}
|
||||
actions={actions}
|
||||
tableActions={tableActions}
|
||||
receiver={formState}
|
||||
formActions={formActions}
|
||||
/>
|
||||
)}
|
||||
|
||||
{activeTab === RECIPIENT_FORM_TABLES.EMAIL_HISTORY && (
|
||||
<EmailHistoryTable
|
||||
type={activeTab}
|
||||
tableState={tableState}
|
||||
actions={actions}
|
||||
tableActions={tableActions}
|
||||
receiver={formState}
|
||||
/>
|
||||
)}
|
||||
|
||||
{activeTab === GROUP_FORM_TABLES.RECIPIENTS && (
|
||||
<ReceiverRecipientsTable
|
||||
tableState={tableState}
|
||||
actions={actions}
|
||||
tableActions={tableActions}
|
||||
receiver={formState}
|
||||
formActions={formActions}
|
||||
/>
|
||||
)}
|
||||
</CardBody>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{formState.isDeletePopupVisible && (
|
||||
<DeletePopup
|
||||
actions={formActions}
|
||||
idsToDelete={[formState.id]}
|
||||
deleteSingleText={deleteText}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(RecipientForm)
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import { NavItem, NavLink } from 'reactstrap'
|
||||
|
||||
export class TablesTabs extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tabs: PropTypes.array.isRequired,
|
||||
activeTab: PropTypes.string.isRequired,
|
||||
chooseTableTab: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
chooseTableTab = (tab) => () => {
|
||||
this.props.chooseTableTab(tab)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t, tabs, activeTab } = this.props
|
||||
|
||||
return tabs.map((tab, i) => (
|
||||
<NavItem key={tab}>
|
||||
<NavLink
|
||||
key={`table-tab-${i}`}
|
||||
active={tab === activeTab}
|
||||
onClick={this.chooseTableTab(tab)}
|
||||
>
|
||||
{t(`manageRecipientsTab.tables.${tab}`)}
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(TablesTabs)
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {translate} from 'react-i18next'
|
||||
import ReceiverFormTable from './ReceiverFormTable'
|
||||
import SortableTh from '../../../../../../common/Table/SortableTh'
|
||||
import { convertUTCtoLocal } from '../../../../../../../common/helper'
|
||||
|
||||
export class EmailHistoryTable extends ReceiverFormTable {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
receiver: PropTypes.object.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
defineColumns () {
|
||||
const {t} = this.props
|
||||
return {
|
||||
...super.defineColumns(),
|
||||
'ScheduledTimes': {
|
||||
sortable: false,
|
||||
Header: t('notificationsTab.ScheduledTimes'),
|
||||
accessor: item => this.scheduleFormat(item.schedule),
|
||||
width: 170
|
||||
},
|
||||
|
||||
'sentTime': {
|
||||
Header: <SortableTh title='notificationsTab.sentTime' />,
|
||||
accessor: item => convertUTCtoLocal(item.sentTime, 'DD MMM YYYY HH:mm'),
|
||||
width: 170
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getColumns () {
|
||||
return ['name', 'type', 'ScheduledTimes', 'sentTime']
|
||||
}
|
||||
|
||||
noCard () {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(EmailHistoryTable)
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import TableFilter from '../../TableFilter'
|
||||
import { Nav, NavItem, NavLink } from 'reactstrap'
|
||||
|
||||
class FormTableTopBar extends React.Component {
|
||||
static propTypes = {
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
statusFilter: PropTypes.string.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
yesText: PropTypes.string.isRequired,
|
||||
noText: PropTypes.string.isRequired,
|
||||
allText: PropTypes.string.isRequired,
|
||||
receiver: PropTypes.object.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
onFilterRequest = (filter) => {
|
||||
const { tableActions, receiver } = this.props
|
||||
tableActions.loadTable({ filter }, receiver)
|
||||
}
|
||||
|
||||
onStatusFilter = (statusFilter) => {
|
||||
return () => {
|
||||
const { tableActions, receiver } = this.props
|
||||
tableActions.loadTable({ statusFilter }, receiver)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
type,
|
||||
t,
|
||||
yesText,
|
||||
noText,
|
||||
allText,
|
||||
statusFilter,
|
||||
receiver
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div>
|
||||
{receiver.id && (
|
||||
<Nav pills justified>
|
||||
<NavItem>
|
||||
<NavLink
|
||||
className="d-block"
|
||||
active={statusFilter === 'all'}
|
||||
onClick={this.onStatusFilter('all')}
|
||||
>
|
||||
{t('manageRecipientsTab.' + allText)}
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
<NavItem>
|
||||
<NavLink
|
||||
className="d-block"
|
||||
active={statusFilter === 'yes'}
|
||||
onClick={this.onStatusFilter('yes')}
|
||||
>
|
||||
{t('manageRecipientsTab.' + yesText)}
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
<NavItem>
|
||||
<NavLink
|
||||
className="d-block"
|
||||
active={statusFilter === 'no'}
|
||||
onClick={this.onStatusFilter('no')}
|
||||
>
|
||||
{t('manageRecipientsTab.' + noText)}
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
</Nav>
|
||||
)}
|
||||
|
||||
<TableFilter type={type} onFilterRequest={this.onFilterRequest} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(FormTableTopBar)
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import GenericTable from '../../../common/GenericTable'
|
||||
import SortableTh from '../../../../../../common/Table/SortableTh'
|
||||
|
||||
class ReceiverFormTable extends GenericTable {
|
||||
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
receiver: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
fetchData = (page, pageSize, sorted) => {
|
||||
const { tableActions, receiver } = this.props
|
||||
const params = {
|
||||
page: page + 1,
|
||||
limit: pageSize
|
||||
}
|
||||
if (sorted.length) {
|
||||
const sortedField = sorted[0]
|
||||
params['sortField'] = sortedField.id
|
||||
params['sortDirection'] = sortedField.desc ? 'desc' : 'asc'
|
||||
}
|
||||
tableActions.loadTable(params, receiver)
|
||||
};
|
||||
|
||||
defineColumns () {
|
||||
const {t} = this.props
|
||||
const colDefs = super.defineColumns()
|
||||
return {
|
||||
...colDefs,
|
||||
'active': {
|
||||
Header: <SortableTh title='notificationsTab.status' />,
|
||||
accessor: item => item.active ? t('notificationsTab.active') : t('notificationsTab.paused'),
|
||||
width: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ReceiverFormTable
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {translate} from 'react-i18next'
|
||||
import ReceiverFormTable from './ReceiverFormTable'
|
||||
import SortableTh from '../../../../../../common/Table/SortableTh'
|
||||
import LinkCell from '../../../../../../common/Table/LinkCell'
|
||||
import FormTableTopBar from './FormTableTopBar'
|
||||
|
||||
export class ReceiverGroupsTable extends ReceiverFormTable {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
receiver: PropTypes.object.isRequired,
|
||||
formActions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
togglerOnAction = (itemId) => {
|
||||
this.props.formActions.toggleGroup(itemId, true)
|
||||
this.props.tableActions.toggleEnrolled(itemId, true)
|
||||
};
|
||||
|
||||
togglerOffAction = (itemId) => {
|
||||
this.props.formActions.toggleGroup(itemId, false)
|
||||
this.props.tableActions.toggleEnrolled(itemId, false)
|
||||
};
|
||||
|
||||
_formatSubscriptions (subscriptions) {
|
||||
console.log('format subsc', subscriptions)
|
||||
const result = []
|
||||
if (subscriptions.alert > 0) {
|
||||
result.push(`${subscriptions.alert} Alerts`)
|
||||
}
|
||||
if (subscriptions.newsletter > 0) {
|
||||
result.push(`${subscriptions.newsletter} Newsletters`)
|
||||
}
|
||||
return result.join(', ')
|
||||
};
|
||||
|
||||
_formatRecipients (number) {
|
||||
if (number) {
|
||||
if (number === 1) {
|
||||
return '1 Recipient'
|
||||
} else {
|
||||
return number + ' Recipients'
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
defineColumns () {
|
||||
const {t} = this.props
|
||||
return {
|
||||
...super.defineColumns(),
|
||||
'groupName': {
|
||||
Header: <SortableTh title='manageRecipientsTab.groupName' />,
|
||||
accessor: 'name',
|
||||
Cell: (row) => {
|
||||
return (
|
||||
<LinkCell item={row.original} onClick={this.nameClickAction}>
|
||||
{row.value}
|
||||
</LinkCell>
|
||||
)
|
||||
}
|
||||
},
|
||||
'enrolled': this.createTogglerColumn('manageRecipientsTab.form.recipient.enroll', 'enrolled', 'yes', 'no', this.togglerOnAction, this.togglerOffAction),
|
||||
'subscriptions': {
|
||||
sortable: false,
|
||||
Header: t('manageRecipientsTab.subscriptions'),
|
||||
accessor: item => this._formatSubscriptions(item.subscriptions),
|
||||
width: 170
|
||||
},
|
||||
'recipients': {
|
||||
sortable: false,
|
||||
Header: t('manageRecipientsTab.recipients'),
|
||||
accessor: item => this._formatRecipients(item.recipients.length),
|
||||
width: 170
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getColumns () {
|
||||
return ['groupName', 'subscriptions', 'recipients', 'active', 'enrolled']
|
||||
}
|
||||
|
||||
noCard () {
|
||||
return true
|
||||
}
|
||||
|
||||
getActionsPanel () {
|
||||
const {tableState, tableActions, receiver} = this.props
|
||||
return (
|
||||
<FormTableTopBar
|
||||
tableActions={tableActions}
|
||||
statusFilter={tableState.statusFilter}
|
||||
receiver={receiver}
|
||||
type="groups"
|
||||
yesText="Enrolled"
|
||||
noText="NotEnrolled"
|
||||
allText="All"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(ReceiverGroupsTable)
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {translate} from 'react-i18next'
|
||||
import ReceiverFormTable from './ReceiverFormTable'
|
||||
import SortableTh from '../../../../../../common/Table/SortableTh'
|
||||
import FormTableTopBar from './FormTableTopBar'
|
||||
import { convertUTCtoLocal } from '../../../../../../../common/helper'
|
||||
|
||||
export class ReceiverRecipientsTable extends ReceiverFormTable {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
receiver: PropTypes.object.isRequired,
|
||||
formActions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
togglerOnAction = (itemId) => {
|
||||
this.props.formActions.toggleRecipient(itemId, true)
|
||||
this.props.tableActions.toggleEnrolled(itemId, true)
|
||||
};
|
||||
|
||||
togglerOffAction = (itemId) => {
|
||||
this.props.formActions.toggleRecipient(itemId, false)
|
||||
this.props.tableActions.toggleEnrolled(itemId, false)
|
||||
};
|
||||
|
||||
defineColumns () {
|
||||
const {t} = this.props
|
||||
return {
|
||||
...super.defineColumns(),
|
||||
'enrolled': this.createTogglerColumn('manageRecipientsTab.form.recipient.enroll', 'enrolled', 'yes', 'no', this.togglerOnAction, this.togglerOffAction),
|
||||
'name': {
|
||||
Header: <SortableTh title='manageRecipientsTab.name' />,
|
||||
accessor: item => `${item.firstName} ${item.lastName}`
|
||||
},
|
||||
'email': {
|
||||
Header: <SortableTh title='manageRecipientsTab.email' />,
|
||||
accessor: 'email',
|
||||
width: 170
|
||||
},
|
||||
'addedDate': {
|
||||
Header: t('manageRecipientsTab.form.group.addedDate'),
|
||||
accessor: item => item.creationDate ? convertUTCtoLocal(item.creationDate, 'DD MMM YYYY HH:mm') : '',
|
||||
width: 170
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getColumns () {
|
||||
return ['name', 'email', 'addedDate', 'active', 'enrolled']
|
||||
}
|
||||
|
||||
noCard () {
|
||||
return true
|
||||
}
|
||||
|
||||
getActionsPanel () {
|
||||
const {tableState, tableActions, receiver} = this.props
|
||||
return (
|
||||
<FormTableTopBar
|
||||
tableActions={tableActions}
|
||||
statusFilter={tableState.statusFilter}
|
||||
receiver={receiver}
|
||||
type="recipients"
|
||||
yesText="Enrolled"
|
||||
noText="NotEnrolled"
|
||||
allText="All"
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(ReceiverRecipientsTable)
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {translate} from 'react-i18next'
|
||||
import ReceiverFormTable from './ReceiverFormTable'
|
||||
import FormTableTopBar from './FormTableTopBar'
|
||||
|
||||
export class ReceiverSubscriptionsTable extends ReceiverFormTable {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
receiver: PropTypes.object.isRequired,
|
||||
formActions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
togglerOnAction = (itemId) => {
|
||||
this.props.formActions.toggleSubscription(itemId, true)
|
||||
this.props.tableActions.toggleSubscribed(itemId, true)
|
||||
};
|
||||
|
||||
togglerOffAction = (itemId) => {
|
||||
this.props.formActions.toggleSubscription(itemId, false)
|
||||
this.props.tableActions.toggleSubscribed(itemId, false)
|
||||
};
|
||||
|
||||
defineColumns () {
|
||||
return {
|
||||
...super.defineColumns(),
|
||||
'subscribed': this.createTogglerColumn('notificationsTab.action', 'subscribed', 'subscribed', 'unsubscribed', this.togglerOnAction, this.togglerOffAction)
|
||||
}
|
||||
}
|
||||
|
||||
getColumns () {
|
||||
return ['name', 'type', 'ScheduledTimes', 'active', 'subscribed']
|
||||
}
|
||||
|
||||
noCard () {
|
||||
return true
|
||||
}
|
||||
|
||||
getActionsPanel () {
|
||||
const {tableState, tableActions, receiver} = this.props
|
||||
return (
|
||||
<FormTableTopBar
|
||||
tableActions={tableActions}
|
||||
statusFilter={tableState.statusFilter}
|
||||
receiver={receiver}
|
||||
type="subscriptions"
|
||||
yesText="Subscribed"
|
||||
noText="Unsubscribed"
|
||||
allText="All"
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(ReceiverSubscriptionsTable)
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import GenericTable from '../common/GenericTable'
|
||||
import { translate } from 'react-i18next'
|
||||
import PropTypes from 'prop-types'
|
||||
import { NOTIFICATION_TABLES } from '../../../../../redux/modules/appState/share/tabs'
|
||||
import SortableTh from '../../../../common/Table/SortableTh'
|
||||
import { ButtonGroup, Button } from 'reactstrap'
|
||||
|
||||
export class MyEmailsTable extends GenericTable {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
restrictions: PropTypes.object,
|
||||
deleteSingleText: PropTypes.string.isRequired,
|
||||
deleteMultipleText: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
togglerOnAction = (itemId) => {
|
||||
this.props.tableActions.toggleActive([itemId], true)
|
||||
};
|
||||
|
||||
togglerOffAction = (itemId) => {
|
||||
this.props.tableActions.toggleActive([itemId], false)
|
||||
};
|
||||
|
||||
nameClickAction = (item) => {
|
||||
const { actions } = this.props
|
||||
actions.startEditNotification(item, NOTIFICATION_TABLES.MY_EMAILS)
|
||||
};
|
||||
|
||||
onPublishButtonClick = () => {
|
||||
const { tableState, tableActions } = this.props
|
||||
tableActions.togglePublish(tableState.selectedIds, true)
|
||||
};
|
||||
|
||||
onUnPublishButtonClick = () => {
|
||||
const { tableState, tableActions } = this.props
|
||||
tableActions.togglePublish(tableState.selectedIds, false)
|
||||
};
|
||||
|
||||
_recipientsFormat (recipients) {
|
||||
if (recipients.length === 1) {
|
||||
return recipients[0].email
|
||||
}
|
||||
return `${recipients.length} ${this.props.t(
|
||||
'notificationsTab.recipients'
|
||||
)}`
|
||||
}
|
||||
|
||||
defineColumns () {
|
||||
const { t } = this.props
|
||||
|
||||
const colDefinitions = super.defineColumns()
|
||||
return {
|
||||
...colDefinitions,
|
||||
active: this.createTogglerColumn(
|
||||
'notificationsTab.action',
|
||||
'active',
|
||||
'active',
|
||||
'paused',
|
||||
this.togglerOnAction,
|
||||
this.togglerOffAction
|
||||
),
|
||||
Recipients: {
|
||||
sortable: false,
|
||||
Header: t('notificationsTab.Recipients'),
|
||||
accessor: (item) => this._recipientsFormat(item.recipients),
|
||||
width: 110
|
||||
},
|
||||
published: {
|
||||
Header: <SortableTh title="notificationsTab.published" />,
|
||||
accessor: (item) =>
|
||||
item.published
|
||||
? t('common:commonWords.Yes')
|
||||
: t('common:commonWords.No'),
|
||||
width: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getColumns () {
|
||||
return [
|
||||
'selectCheckbox',
|
||||
'name',
|
||||
'type',
|
||||
'published',
|
||||
'ScheduledTimes',
|
||||
'sourcesCount',
|
||||
'Recipients',
|
||||
'active',
|
||||
'delete'
|
||||
]
|
||||
}
|
||||
|
||||
getActionsPanel () {
|
||||
const { t, restrictions } = this.props
|
||||
return (
|
||||
<Fragment>
|
||||
{this.getRestrictions(restrictions)}
|
||||
|
||||
<ButtonGroup className="mb-3">
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onActivateButtonClick}
|
||||
>
|
||||
<i className="fa fa-play for-small mr-1"> </i>{" "}
|
||||
{t('notificationsTab.activate')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onPauseButtonClick}
|
||||
>
|
||||
<i className="fa fa-pause for-small mr-1"> </i>{" "}
|
||||
{t('notificationsTab.pause')}
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onDeleteButtonClick}
|
||||
>
|
||||
<i className="fa fa-trash for-small mr-1"> </i>{" "}
|
||||
{t('notificationsTab.delete')}
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onPublishButtonClick}
|
||||
>
|
||||
<i className="fa fa-upload for-small mr-1"> </i>{" "}
|
||||
{t('notificationsTab.publish')}
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={this.onUnPublishButtonClick}
|
||||
>
|
||||
<i className="fa fa-ban for-small mr-1"> </i>{" "}
|
||||
{t('notificationsTab.unpublish')}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(MyEmailsTable)
|
||||
@@ -0,0 +1,26 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import { Button } from 'reactstrap'
|
||||
|
||||
class Navigation extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
backToTables = () => {
|
||||
this.props.actions.switchShareSubScreen('notifications', 'tables')
|
||||
};
|
||||
|
||||
render () {
|
||||
|
||||
return (
|
||||
<Button className="btn-wide mb-2" size="sm" color="info" onClick={this.backToTables}>
|
||||
<i className="lnr lnr-chevron-left"> </i>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(Navigation)
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import TopBar from './TopBar'
|
||||
import Navigation from './Navigation'
|
||||
import AlertForm from './forms/AlertForm'
|
||||
import {NOTIFICATION_TABLES, NOTIFICATION_SUBSCREENS} from '../../../../../redux/modules/appState/share/tabs'
|
||||
import MyEmailsTable from './MyEmailsTable'
|
||||
import PublishedEmailsTable from './PublishedEmailsTable'
|
||||
import {withRouter} from 'react-router-dom'
|
||||
import reduxConnect from '../../../../../redux/utils/connect'
|
||||
import {compose} from 'redux'
|
||||
import { setDocumentData } from '../../../../../common/helper'
|
||||
|
||||
class NotificationsSubTab extends React.Component {
|
||||
static propTypes = {
|
||||
store: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
_shareState = () => this.props.store.appState.share;
|
||||
|
||||
_authState = () => this.props.store.common.auth;
|
||||
|
||||
componentDidMount() {
|
||||
setDocumentData('title', 'Alerts | Share')
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
setDocumentData('title')
|
||||
}
|
||||
|
||||
render () {
|
||||
const { actions } = this.props
|
||||
|
||||
const shareState = this._shareState()
|
||||
const {user: {restrictions}} = this._authState()
|
||||
|
||||
const { subScreenVisible, tableVisible } = shareState.tabs.notifications
|
||||
|
||||
return (
|
||||
<div className="notifications-tab">
|
||||
|
||||
{subScreenVisible === NOTIFICATION_SUBSCREENS.TABLES &&
|
||||
<div>
|
||||
<TopBar
|
||||
tables={[NOTIFICATION_TABLES.MY_EMAILS, NOTIFICATION_TABLES.PUBLISHED]}
|
||||
tableVisible={tableVisible}
|
||||
actions={actions}
|
||||
/>
|
||||
|
||||
{tableVisible === NOTIFICATION_TABLES.MY_EMAILS &&
|
||||
<MyEmailsTable
|
||||
tableState={shareState.tables[tableVisible]}
|
||||
restrictions={restrictions && restrictions.limits}
|
||||
actions={actions}
|
||||
tableActions={actions.shareTables[tableVisible]}
|
||||
deleteSingleText='alert'
|
||||
deleteMultipleText='alerts'
|
||||
/>
|
||||
}
|
||||
|
||||
{tableVisible === NOTIFICATION_TABLES.PUBLISHED &&
|
||||
<PublishedEmailsTable
|
||||
tableState={shareState.tables[tableVisible]}
|
||||
restrictions={restrictions && restrictions.limits}
|
||||
actions={actions}
|
||||
tableActions={actions.shareTables[tableVisible]}
|
||||
deleteSingleText='alert'
|
||||
deleteMultipleText='alerts'
|
||||
/>
|
||||
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
{(subScreenVisible === NOTIFICATION_SUBSCREENS.ALERT_FORM || subScreenVisible === NOTIFICATION_SUBSCREENS.NEWSLETTER_FORM) &&
|
||||
<Navigation actions={actions} />
|
||||
}
|
||||
|
||||
{subScreenVisible === NOTIFICATION_SUBSCREENS.ALERT_FORM &&
|
||||
<AlertForm
|
||||
state={shareState.forms.alert}
|
||||
switchShareSubScreen={actions.switchShareSubScreen}
|
||||
actions={actions.shareForms.alert}
|
||||
/>
|
||||
}
|
||||
|
||||
{/* {subScreenVisible === NOTIFICATION_SUBSCREENS.NEWSLETTER_FORM &&
|
||||
<NewsletterForm
|
||||
state={shareState.forms.newsletter}
|
||||
switchShareSubScreen={actions.switchShareSubScreen}
|
||||
actions={actions.shareForms.newsletter}
|
||||
/>
|
||||
} */}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const applyDecorators = compose(
|
||||
withRouter,
|
||||
reduxConnect()
|
||||
)
|
||||
|
||||
export default applyDecorators(NotificationsSubTab)
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import GenericTable from '../common/GenericTable'
|
||||
import {NOTIFICATION_TABLES} from '../../../../../redux/modules/appState/share/tabs'
|
||||
import SortableTh from '../../../../common/Table/SortableTh'
|
||||
import { Button, ButtonGroup } from 'reactstrap'
|
||||
|
||||
class PublishedEmailsTable extends GenericTable {
|
||||
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
restrictions: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
deleteSingleText: PropTypes.string.isRequired,
|
||||
deleteMultipleText: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
onSubscribeButtonClick = () => {
|
||||
const { tableState, tableActions } = this.props
|
||||
tableActions.toggleSubscribe(tableState.selectedIds, true)
|
||||
};
|
||||
|
||||
onUnSubscribeButtonClick = () => {
|
||||
const { tableState, tableActions } = this.props
|
||||
tableActions.toggleSubscribe(tableState.selectedIds, false)
|
||||
};
|
||||
|
||||
togglerOnAction = (itemId) => {
|
||||
this.props.tableActions.toggleSubscribe([itemId], true)
|
||||
};
|
||||
|
||||
togglerOffAction = (itemId) => {
|
||||
const {tableState, tableActions, actions} = this.props
|
||||
const notification = tableState.data.find(item => item.id === itemId)
|
||||
if (notification.allowUnsubscribe) {
|
||||
tableActions.toggleSubscribe([itemId], false)
|
||||
} else {
|
||||
actions.addAlert({type: 'error', transKey: 'cannotUnsubscribe'})
|
||||
}
|
||||
};
|
||||
|
||||
nameClickAction = (item) => {
|
||||
const { actions } = this.props
|
||||
actions.startEditNotification(item, NOTIFICATION_TABLES.PUBLISHED)
|
||||
};
|
||||
|
||||
defineColumns () {
|
||||
const {t} = this.props
|
||||
const colDefinitions = super.defineColumns()
|
||||
return {
|
||||
...colDefinitions,
|
||||
'subscribed': this.createTogglerColumn('notificationsTab.action', 'subscribed', 'subscribed', 'unsubscribed', this.togglerOnAction, this.togglerOffAction),
|
||||
'active': {
|
||||
Header: <SortableTh title='notificationsTab.status' />,
|
||||
accessor: item => item.active ? t('notificationsTab.active') : t('notificationsTab.paused'),
|
||||
width: 100
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getColumns () {
|
||||
return ['selectCheckbox', 'name', 'type', 'owner', 'ScheduledTimes', 'active', 'subscribed']
|
||||
}
|
||||
|
||||
getActionsPanel () {
|
||||
const {t, restrictions} = this.props
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{this.getRestrictions(restrictions)}
|
||||
|
||||
<ButtonGroup className="mb-3">
|
||||
<Button onClick={this.onSubscribeButtonClick}>
|
||||
<i className="fa fa-envelope for-small mr-1" /> {t('notificationsTab.subscribe')}
|
||||
</Button>
|
||||
<Button onClick={this.onUnSubscribeButtonClick}>
|
||||
<i className="fa fa-times for-small mr-1" /> {t('notificationsTab.unsubscribe')}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(PublishedEmailsTable)
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import TableSwitcher from '../common/TableSwitcher/TableSwitcher'
|
||||
import { NOTIFICATION_SUBSCREENS } from '../../../../../redux/modules/appState/share/tabs'
|
||||
import { Button } from 'reactstrap'
|
||||
class TopBar extends React.Component {
|
||||
static propTypes = {
|
||||
actions: PropTypes.object.isRequired,
|
||||
tables: PropTypes.array.isRequired,
|
||||
tableVisible: PropTypes.string.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
onCreate = (type) => () => {
|
||||
const { actions, tableVisible } = this.props
|
||||
actions.startCreateNotification(type, tableVisible)
|
||||
}
|
||||
|
||||
loadTable = (type) => {
|
||||
this.props.actions.shareTables[type].loadTable(null)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t, tables, tableVisible, actions } = this.props
|
||||
|
||||
return (
|
||||
<div className="notifications-topbar">
|
||||
<div className="notifications-topbar_buttons_wrap">
|
||||
<TableSwitcher
|
||||
tables={tables}
|
||||
tableVisible={tableVisible}
|
||||
subTab="notifications"
|
||||
switchTable={actions.switchShareTable}
|
||||
loadTable={this.loadTable}
|
||||
/>
|
||||
|
||||
<div className="notifications-buttons">
|
||||
<Button className="btn-icon" color="primary" onClick={this.onCreate(NOTIFICATION_SUBSCREENS.ALERT_FORM)}>
|
||||
<i className="lnr lnr-alarm btn-icon-wrapper"></i>
|
||||
{t('notificationsTab.newAlert')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(TopBar)
|
||||
+399
@@ -0,0 +1,399 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { translate } from 'react-i18next';
|
||||
import {
|
||||
timezones,
|
||||
getCurrentTimezone
|
||||
} from '../../../../../../common/Timezones';
|
||||
import Select from 'react-select';
|
||||
import moment from 'moment';
|
||||
import DatePicker from 'react-datepicker';
|
||||
import RecipientsSelect from './RecipientsSelect';
|
||||
import CheckboxField from './CheckboxField';
|
||||
import RadioField from './RadioField';
|
||||
import BooleanRadioGroup from './BooleanRadioGroup';
|
||||
import SourcesDropTarget from './sources/SourcesDropTarget';
|
||||
import Sources from './sources/Sources';
|
||||
import Scheduling from './scheduling/Scheduling';
|
||||
import SaveAsPopup from './SaveAsPopup';
|
||||
import History from './History';
|
||||
import { EXTRAS } from '../../../../../../redux/modules/appState/share/forms/alertForm';
|
||||
import { THEME_TYPES } from '../../../../../../redux/modules/appState/share/forms/notificationForm';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardBody,
|
||||
CardTitle,
|
||||
Col,
|
||||
Container,
|
||||
CustomInput,
|
||||
Form,
|
||||
FormGroup,
|
||||
Input,
|
||||
Label
|
||||
} from 'reactstrap';
|
||||
|
||||
export class AlertForm extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
state: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
switchShareSubScreen: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
changeName = (event) => {
|
||||
this.props.actions.changeName(event.target.value);
|
||||
};
|
||||
|
||||
changeSubject = (event) => {
|
||||
this.props.actions.changeSubject(event.target.value);
|
||||
};
|
||||
|
||||
changeAutoSubject = () => {
|
||||
const { state, actions } = this.props;
|
||||
actions.changeAutoSubject(!state.automatedSubject);
|
||||
};
|
||||
|
||||
changeRecipient = (value) => {
|
||||
this.props.actions.changeRecipients(value.split(','));
|
||||
};
|
||||
|
||||
changeTimezone = (zone) => {
|
||||
this.props.actions.changeTimezone(zone.value);
|
||||
};
|
||||
|
||||
toggleTimezone = () => {
|
||||
const { state, actions } = this.props;
|
||||
if (state.isEnabledTimezone) {
|
||||
actions.changeTimezone(getCurrentTimezone());
|
||||
}
|
||||
actions.toggleTimezone();
|
||||
};
|
||||
|
||||
changeSendUntil = (value) => {
|
||||
const sendUntil = value ? moment(value).format('YYYY-MM-DD') : '';
|
||||
this.props.actions.changeSendUntil(sendUntil);
|
||||
};
|
||||
|
||||
cancel = () => {
|
||||
this.props.switchShareSubScreen('notifications', 'tables');
|
||||
};
|
||||
|
||||
create = () => {
|
||||
const { state, actions } = this.props;
|
||||
const isEdit = !!state.id;
|
||||
actions.saveAlert(isEdit);
|
||||
};
|
||||
|
||||
edit = (name) => {
|
||||
const { actions } = this.props;
|
||||
actions.changeName(name);
|
||||
actions.saveAlert(false);
|
||||
};
|
||||
|
||||
showSaveAsPopup = () => {
|
||||
this.props.actions.toggleSaveAsPopup();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { state, actions, t } = this.props;
|
||||
const isEdit = !!state.id;
|
||||
const name = state.name;
|
||||
|
||||
const extract = state.content.extract;
|
||||
const userComments = state.content.showInfo.userComments;
|
||||
|
||||
const sendUntil = !state.sendUntil
|
||||
? state.sendUntil
|
||||
: moment(state.sendUntil).toDate();
|
||||
|
||||
return (
|
||||
<Card className="main-card mb-3">
|
||||
<CardBody>
|
||||
<CardTitle>
|
||||
{isEdit
|
||||
? t('notificationsTab.form.editAlert')
|
||||
: t('notificationsTab.form.createAlert')}
|
||||
</CardTitle>
|
||||
<div className="share-tab-form-container">
|
||||
<Container>
|
||||
<Form>
|
||||
<FormGroup row>
|
||||
<Label sm={2}>{t('notificationsTab.form.name')}</Label>
|
||||
<Col sm={10}>
|
||||
<Input
|
||||
type="text"
|
||||
title={t('notificationsTab.form.nameTooltip')}
|
||||
value={name}
|
||||
onChange={this.changeName}
|
||||
/>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
<RecipientsSelect t={t} state={state} actions={actions} />
|
||||
|
||||
<CheckboxField
|
||||
label={t('notificationsTab.form.automatedEmail')}
|
||||
additionalLabel={t(
|
||||
'notificationsTab.form.automatedEmailDesc'
|
||||
)}
|
||||
value={state.automatedSubject}
|
||||
onChange={this.changeAutoSubject}
|
||||
/>
|
||||
|
||||
{!state.automatedSubject && (
|
||||
<FormGroup row>
|
||||
<Label sm={2}>
|
||||
{t('notificationsTab.form.emailSubject')}
|
||||
</Label>
|
||||
<Col sm={10}>
|
||||
<Input
|
||||
type="text"
|
||||
title={t('notificationsTab.form.emailSubject')}
|
||||
value={state.subject}
|
||||
onChange={this.changeSubject}
|
||||
/>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
)}
|
||||
|
||||
<CheckboxField
|
||||
label={t('notificationsTab.form.publish')}
|
||||
additionalLabel={t('notificationsTab.form.publishDesc')}
|
||||
value={state.published}
|
||||
onChange={actions.changePublished}
|
||||
/>
|
||||
|
||||
<CheckboxField
|
||||
label={t('notificationsTab.form.unsubscribe')}
|
||||
additionalLabel={t('notificationsTab.form.unsubscribeDesc')}
|
||||
value={state.allowUnsubscribe}
|
||||
onChange={actions.changeAllowUnsubscribe}
|
||||
/>
|
||||
|
||||
<CheckboxField
|
||||
label={t('notificationsTab.form.notifications')}
|
||||
additionalLabel={t('notificationsTab.form.notificationsDesc')}
|
||||
value={state.unsubscribeNotification}
|
||||
onChange={actions.changeUnsubscribeNotification}
|
||||
/>
|
||||
|
||||
<FormGroup row>
|
||||
<Label sm={2}>{t('notificationsTab.form.feeds')}</Label>
|
||||
<Col sm={10}>
|
||||
<Sources
|
||||
sources={state.sources}
|
||||
removeSource={actions.removeSource}
|
||||
moveSource={actions.moveSource}
|
||||
/>
|
||||
<SourcesDropTarget addSource={actions.addSource} />
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup row>
|
||||
<Label sm={2}>{t('notificationsTab.form.options')}</Label>
|
||||
<Col sm={10}>
|
||||
<FormGroup row>
|
||||
<Col sm={2}>
|
||||
{t('notificationsTab.form.articleExtracts')}
|
||||
</Col>
|
||||
<Col sm={10}>
|
||||
<div className="d-flex">
|
||||
<RadioField
|
||||
label={t(
|
||||
'notificationsTab.form.contextualExtracts'
|
||||
)}
|
||||
name="articleExtracts"
|
||||
checkedValue={extract}
|
||||
value={EXTRAS.CONTEXTUAL}
|
||||
onChange={actions.changeExtras}
|
||||
/>
|
||||
|
||||
<RadioField
|
||||
label={t('notificationsTab.form.startExtracts')}
|
||||
name="articleExtracts"
|
||||
checkedValue={extract}
|
||||
value={EXTRAS.START}
|
||||
onChange={actions.changeExtras}
|
||||
/>
|
||||
|
||||
<RadioField
|
||||
label={t('notificationsTab.form.noExtracts')}
|
||||
name="articleExtracts"
|
||||
checkedValue={extract}
|
||||
value={EXTRAS.NO}
|
||||
onChange={actions.changeExtras}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
<BooleanRadioGroup
|
||||
mainLabel={t('notificationsTab.form.highlightKeywords')}
|
||||
name="highlightKeywords"
|
||||
value={state.content.highlightKeywords.highlight}
|
||||
onChange={actions.changeHighlightKeywords}
|
||||
/>
|
||||
|
||||
<BooleanRadioGroup
|
||||
mainLabel={t('notificationsTab.form.showSourceCountry')}
|
||||
name="showSourceCountry"
|
||||
value={state.content.showInfo.sourceCountry}
|
||||
onChange={actions.changeShowSourceCountry}
|
||||
/>
|
||||
|
||||
<FormGroup row>
|
||||
<Col sm={2}>
|
||||
{t('notificationsTab.form.showUserComments')}
|
||||
</Col>
|
||||
<Col sm={10}>
|
||||
<div className="d-flex">
|
||||
<RadioField
|
||||
label={t('common:commonWords.Yes')}
|
||||
name="showUserComments"
|
||||
checkedValue={userComments}
|
||||
value="with_author_date"
|
||||
onChange={actions.changeShowUserComments}
|
||||
/>
|
||||
|
||||
<RadioField
|
||||
label={t('common:commonWords.No')}
|
||||
name="showUserComments"
|
||||
checkedValue={userComments}
|
||||
value="no"
|
||||
onChange={actions.changeShowUserComments}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup row>
|
||||
<Col sm={2}>{t('notificationsTab.form.layout')}</Col>
|
||||
<Col sm={10}>
|
||||
<div className="d-flex">
|
||||
<RadioField
|
||||
label={t('notificationsTab.form.enhancedHtml')}
|
||||
name="themeType"
|
||||
checkedValue={state.themeType}
|
||||
value={THEME_TYPES.ENHANCED}
|
||||
onChange={actions.changeThemeType}
|
||||
/>
|
||||
|
||||
<RadioField
|
||||
label={t('notificationsTab.form.plainHtml')}
|
||||
name="themeType"
|
||||
checkedValue={state.themeType}
|
||||
value={THEME_TYPES.PLAIN}
|
||||
onChange={actions.changeThemeType}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
<BooleanRadioGroup
|
||||
mainLabel={t('notificationsTab.form.sendWhenEmpty')}
|
||||
name="sendWhenEmpty"
|
||||
value={state.sendWhenEmpty}
|
||||
onChange={actions.changeSendWhenEmpty}
|
||||
/>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup row>
|
||||
<Label sm={2}>{t('notificationsTab.form.timezone')}</Label>
|
||||
<Col sm={10}>
|
||||
<Select
|
||||
value={state.timezone}
|
||||
options={timezones}
|
||||
clearable={false}
|
||||
disabled={!state.isEnabledTimezone}
|
||||
onChange={this.changeTimezone}
|
||||
/>
|
||||
<CustomInput
|
||||
id="toggleTimezone"
|
||||
type="checkbox"
|
||||
className="mt-1"
|
||||
checked={state.isEnabledTimezone}
|
||||
onChange={this.toggleTimezone}
|
||||
label={t('notificationsTab.form.change')}
|
||||
/>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup row>
|
||||
<Label sm={2}>{t('notificationsTab.form.automatic')}</Label>
|
||||
<Col sm={10}>
|
||||
<Scheduling state={state.scheduling} actions={actions} />
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup row>
|
||||
<Label sm={2}>{t('notificationsTab.form.sendUntil')}</Label>
|
||||
<Col sm={4}>
|
||||
<DatePicker
|
||||
className="form-control"
|
||||
wrapperClassName="position-relative z-index-0"
|
||||
dateFormat="yyyy-MM-dd"
|
||||
placeholderText={t('notificationsTab.form.selectDate')}
|
||||
selected={sendUntil}
|
||||
minDate={moment()}
|
||||
onChange={this.changeSendUntil}
|
||||
/>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
{isEdit && (
|
||||
<Fragment>
|
||||
<hr />
|
||||
<History
|
||||
notificationId={state.id}
|
||||
state={state.sendHistory}
|
||||
actions={actions}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
<div className="text-right mb-3">
|
||||
<Button
|
||||
className="btn-icon"
|
||||
color="secondary"
|
||||
onClick={this.cancel}
|
||||
>
|
||||
<i className="lnr lnr-cross btn-icon-wrapper" />{' '}
|
||||
{t('notificationsTab.form.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
className="btn-icon ml-2"
|
||||
color="success"
|
||||
onClick={this.create}
|
||||
>
|
||||
<i className="lnr lnr-checkmark-circle btn-icon-wrapper" />
|
||||
{t('notificationsTab.form.save')}
|
||||
</Button>
|
||||
<Button
|
||||
className="btn-icon ml-2"
|
||||
color="success"
|
||||
onClick={this.showSaveAsPopup}
|
||||
>
|
||||
<i className="lnr lnr-checkmark-circle btn-icon-wrapper" />
|
||||
{t('notificationsTab.form.saveAs')}
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</Container>
|
||||
|
||||
{state.showSaveAsPopup && (
|
||||
<SaveAsPopup
|
||||
name={name}
|
||||
togglePopup={actions.toggleSaveAsPopup}
|
||||
onSubmit={this.edit}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(AlertForm);
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import RadioField from './RadioField'
|
||||
import { Col, FormGroup } from 'reactstrap'
|
||||
import { translate } from 'react-i18next'
|
||||
|
||||
export class BooleanRadioGroup extends React.PureComponent {
|
||||
static propTypes = {
|
||||
mainLabel: PropTypes.string.isRequired,
|
||||
trueLabel: PropTypes.string,
|
||||
falseLabel: PropTypes.string,
|
||||
name: PropTypes.string.isRequired,
|
||||
value: PropTypes.bool,
|
||||
onChange: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
onChange = (event) => {
|
||||
const { onChange } = this.props
|
||||
let value = event.target.value
|
||||
if (value === 'true' || value === 'false') {
|
||||
value = value === 'true'
|
||||
}
|
||||
|
||||
onChange(value)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
trueLabel = this.props.t('commonWords.Yes'),
|
||||
falseLabel = this.props.t('commonWords.No'),
|
||||
mainLabel,
|
||||
name,
|
||||
value,
|
||||
onChange
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<FormGroup row>
|
||||
<Col sm={2}>{mainLabel}</Col>
|
||||
<Col sm={10}>
|
||||
<div className="d-flex">
|
||||
<RadioField
|
||||
label={trueLabel}
|
||||
name={name}
|
||||
checkedValue={value}
|
||||
value
|
||||
onChange={onChange}
|
||||
/>
|
||||
|
||||
<RadioField
|
||||
label={falseLabel}
|
||||
name={name}
|
||||
checkedValue={value}
|
||||
value={false}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['common'], { wait: true })(BooleanRadioGroup)
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Col, CustomInput, FormGroup, Label } from 'reactstrap'
|
||||
|
||||
export class CheckboxField extends React.PureComponent {
|
||||
static propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
additionalLabel: PropTypes.string.isRequired,
|
||||
value: PropTypes.bool.isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
onChange = () => {
|
||||
const { onChange, value } = this.props
|
||||
onChange(!value)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { label, additionalLabel, value } = this.props
|
||||
|
||||
return (
|
||||
<FormGroup row>
|
||||
<Label sm={2}>{label}</Label>
|
||||
<Col sm={10}>
|
||||
<CustomInput
|
||||
id={label}
|
||||
type="checkbox"
|
||||
checked={value}
|
||||
onChange={this.onChange}
|
||||
label={additionalLabel}
|
||||
/>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CheckboxField
|
||||
@@ -0,0 +1,82 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
import { Button, Collapse, ListGroup, ListGroupItem } from 'reactstrap'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faSpinner } from '@fortawesome/free-solid-svg-icons'
|
||||
import { translate } from 'react-i18next'
|
||||
import { convertUTCtoLocal } from '../../../../../../common/helper'
|
||||
|
||||
export class History extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
notificationId: PropTypes.number.isRequired,
|
||||
state: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
onToggle = () => {
|
||||
const { state, actions } = this.props
|
||||
if (!state.isOpen && !state.isLoadingCompleted) {
|
||||
this.showMore()
|
||||
}
|
||||
actions.toggleHistory()
|
||||
}
|
||||
|
||||
showMore = () => {
|
||||
const { notificationId, state, actions } = this.props
|
||||
actions.getHistory(notificationId, state.page + 1, state.limit)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { state, t } = this.props
|
||||
const isOpen = state.isOpen
|
||||
const label = isOpen ? t('notificationsTab.history.hideSendHistory') : t('notificationsTab.history.showSendHistory')
|
||||
const iconClasses = classnames('lnr mr-2', {
|
||||
'lnr-chevron-right': !isOpen,
|
||||
'lnr-chevron-down': isOpen
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="history">
|
||||
<Button
|
||||
color="link"
|
||||
className="p-0 font-size-md"
|
||||
onClick={this.onToggle}
|
||||
>
|
||||
<i className={iconClasses} />
|
||||
{label}
|
||||
</Button>
|
||||
<Collapse isOpen={isOpen}>
|
||||
{state.isLoadingCompleted && (
|
||||
<div className="mt-3 ml-4">
|
||||
<p className="text-muted mb-1">{t('notificationsTab.history.sentTime')}</p>
|
||||
<ListGroup>
|
||||
{state.entities.map((entity, i) => (
|
||||
<ListGroupItem
|
||||
className="col-sm-6 p-2"
|
||||
key={`history-date-${i}`}
|
||||
>
|
||||
{convertUTCtoLocal(entity.date, 'DD MMM YYYY HH:mm')}
|
||||
</ListGroupItem>
|
||||
))}
|
||||
</ListGroup>
|
||||
{!state.isPending && state.entities.length < state.totalCount && (
|
||||
<Button color="link" onClick={this.showMore}>
|
||||
{t('notificationsTab.history.showMore')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{state.isPending && (
|
||||
<p className="ml-4 mt-3">
|
||||
<FontAwesomeIcon icon={faSpinner} className="mr-2" pulse /> {t('notificationsTab.history.loading')}
|
||||
</p>
|
||||
)}
|
||||
</Collapse>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(History)
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import { Card, CardBody, CardTitle, Col, Form, FormGroup, Input, Label } from 'reactstrap'
|
||||
|
||||
export class NewsletterForm extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
state: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
changeName = (event) => {
|
||||
this.props.actions.changeName(event.target.value)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { state, t } = this.props
|
||||
|
||||
return (
|
||||
<Card className="main-card mb-3">
|
||||
<CardBody>
|
||||
<CardTitle>{t('notificationsTab.newsLetter.createNewsletter')}</CardTitle>
|
||||
<Form>
|
||||
<FormGroup row>
|
||||
<Label sm={2}>{t('notificationsTab.newsLetter.name')}</Label>
|
||||
<Col sm={10}>
|
||||
<Input type="text" value={state.name} onChange={this.changeName} />
|
||||
</Col>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</CardBody>
|
||||
</Card>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
export default translate(['tabsContent'], { wait: true })(NewsletterForm)
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { CustomInput } from 'reactstrap'
|
||||
|
||||
export class RadioField extends React.PureComponent {
|
||||
static propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
checkedValue: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.bool
|
||||
]),
|
||||
value: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.bool
|
||||
]),
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
onChange = (event) => {
|
||||
const { onChange } = this.props
|
||||
let value = event.target.value
|
||||
if (value === 'true' || value === 'false') {
|
||||
value = value === 'true'
|
||||
}
|
||||
|
||||
onChange(value)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { label, name, checkedValue, value } = this.props
|
||||
|
||||
return (
|
||||
<CustomInput
|
||||
id={`${name}_${value}`}
|
||||
type="radio"
|
||||
className="mr-2"
|
||||
name={name}
|
||||
value={value}
|
||||
checked={checkedValue === value}
|
||||
onChange={this.onChange}
|
||||
label={label}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default RadioField
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Select from 'react-select'
|
||||
import { Col, FormGroup, Label } from 'reactstrap'
|
||||
|
||||
export class RecipientsSelect extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
state: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
loadOptions = (input) => {
|
||||
const { actions } = this.props
|
||||
return actions.getRecipients(input)
|
||||
};
|
||||
|
||||
changeRecipient = (value) => {
|
||||
const { actions } = this.props
|
||||
actions.changeRecipients(value)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { state, t } = this.props
|
||||
const recipients = state.recipients
|
||||
|
||||
return (
|
||||
<FormGroup row>
|
||||
<Label sm={2}>{t('notificationsTab.form.recipient')}</Label>
|
||||
<Col sm={10}>
|
||||
<Select.Async
|
||||
name="recipient-select"
|
||||
loadOptions={this.loadOptions}
|
||||
multi
|
||||
value={recipients}
|
||||
onChange={this.changeRecipient}
|
||||
/>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default RecipientsSelect
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
ModalHeader,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Label,
|
||||
FormGroup,
|
||||
Input
|
||||
} from 'reactstrap'
|
||||
|
||||
export class SaveAsPopup extends React.Component {
|
||||
static propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
togglePopup: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
name: `${props.name} (copy)`
|
||||
}
|
||||
}
|
||||
|
||||
hidePopup = () => {
|
||||
this.props.togglePopup()
|
||||
}
|
||||
|
||||
onSubmit = () => {
|
||||
this.props.onSubmit(this.state.name)
|
||||
this.hidePopup()
|
||||
}
|
||||
|
||||
handleChange = (e) => {
|
||||
const { name, value } = e.target
|
||||
this.setState({ [name]: value })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t } = this.props
|
||||
|
||||
return (
|
||||
<Modal isOpen toggle={this.hidePopup} backdrop="static">
|
||||
<ModalHeader toggle={this.hidePopup}>
|
||||
{t('notificationsTab.popup.saveAs')}
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<FormGroup>
|
||||
<Label>{t('notificationsTab.popup.saveAsPlaceholder')}</Label>
|
||||
<Input
|
||||
type="text"
|
||||
name="name"
|
||||
value={this.state.name}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="light" onClick={this.hidePopup}>
|
||||
{t('common:commonWords.Cancel')}
|
||||
</Button>
|
||||
<Button color="primary" onClick={this.onSubmit}>
|
||||
{t('notificationsTab.popup.save')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent', 'common'], { wait: true })(SaveAsPopup)
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import ScheduleSelectField from './ScheduleSelectField'
|
||||
import { IoIosCloseCircleOutline } from 'react-icons/io'
|
||||
|
||||
export class ScheduleOptions extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
id: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number
|
||||
]),
|
||||
type: PropTypes.string.isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
constants: PropTypes.object.isRequired,
|
||||
canDelete: PropTypes.bool,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onRemove: PropTypes.func
|
||||
};
|
||||
|
||||
onChange = (field, value) => {
|
||||
const { id, item, onChange } = this.props
|
||||
const newItem = {
|
||||
...item,
|
||||
[field]: value
|
||||
}
|
||||
onChange(id, newItem)
|
||||
};
|
||||
|
||||
onRemove = () => {
|
||||
const { id, canDelete, onRemove } = this.props
|
||||
if (canDelete && onRemove) {
|
||||
onRemove(id)
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t, id, type, item, canDelete = false, constants } = this.props
|
||||
const showTime = (type === 'daily' && item.time === 'once') || (type !== 'daily')
|
||||
|
||||
return (
|
||||
<div className="schedule-options">
|
||||
{id !== 'new' &&
|
||||
<div>{t(`notificationsTab.form.type.${type}`)} </div>
|
||||
}
|
||||
<p>Send</p>
|
||||
{type === 'daily' &&
|
||||
<div className="schedule-options__group">
|
||||
<ScheduleSelectField
|
||||
field='time'
|
||||
items={constants.time}
|
||||
value={item.time}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
|
||||
<ScheduleSelectField
|
||||
field='days'
|
||||
items={constants.days}
|
||||
value={item.days}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
{type === 'weekly' &&
|
||||
<div className="schedule-options__group">
|
||||
<ScheduleSelectField
|
||||
field='period'
|
||||
items={constants.period}
|
||||
value={item.period}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
|
||||
<ScheduleSelectField
|
||||
field='day'
|
||||
items={constants.day}
|
||||
value={item.day}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
{type === 'monthly' &&
|
||||
<div className="schedule-options__group">
|
||||
<ScheduleSelectField
|
||||
needTranslate={false}
|
||||
field='monthDay'
|
||||
items={constants.monthDay}
|
||||
value={item.monthDay}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
{(type === 'weekly' || type === 'monthly') &&
|
||||
<div>of the month </div>
|
||||
}
|
||||
|
||||
{showTime &&
|
||||
<div className="schedule-options__group">
|
||||
<span>at</span>
|
||||
<ScheduleSelectField
|
||||
needTranslate={false}
|
||||
field='hour'
|
||||
items={constants.hour}
|
||||
value={item.hour}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<span>:</span>
|
||||
<ScheduleSelectField
|
||||
needTranslate={false}
|
||||
field='minute'
|
||||
items={constants.minute}
|
||||
value={item.minute}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
{canDelete && (
|
||||
<button
|
||||
title="Remove"
|
||||
type="button"
|
||||
className="btn p-0"
|
||||
onClick={this.onRemove}
|
||||
>
|
||||
<IoIosCloseCircleOutline size={22} className="text-danger ml-2" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(ScheduleOptions)
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import Select from 'react-select'
|
||||
import classnames from 'classnames'
|
||||
import { padLeft, addOrdinalSuffix } from '../../../../../../../common/StringUtils'
|
||||
|
||||
export class ScheduleSelectField extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
needTranslate: PropTypes.bool,
|
||||
field: PropTypes.string.isRequired,
|
||||
items: PropTypes.array.isRequired,
|
||||
value: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number
|
||||
]),
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
paddingFields = ['hour', 'minute'];
|
||||
suffixFields = ['monthDay'];
|
||||
|
||||
onChange = (item) => {
|
||||
const { field, onChange } = this.props
|
||||
onChange(field, item.value)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t, needTranslate = true, items, value, field } = this.props
|
||||
const classes = classnames('schedule-select-field', `schedule-select-field--${field}`)
|
||||
const options = items.map(item => {
|
||||
let label = ''
|
||||
if (needTranslate) {
|
||||
label = t(`notificationsTab.form.${field}.${item}`)
|
||||
}
|
||||
else {
|
||||
label = (this.paddingFields.includes(field)) ? padLeft(item.toString(), 2) : item
|
||||
label = (this.suffixFields.includes(field)) ? addOrdinalSuffix(item) : label
|
||||
}
|
||||
return {
|
||||
value: item,
|
||||
label
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<Select
|
||||
className={classes}
|
||||
options={options}
|
||||
value={value}
|
||||
clearable={false}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(ScheduleSelectField)
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import TypeSelector from './TypeSelector'
|
||||
import ScheduleOptions from './ScheduleOptions'
|
||||
import { Button, ListGroup, ListGroupItem } from 'reactstrap'
|
||||
|
||||
export class Scheduling extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
state: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
onChange = (id, item) => {
|
||||
const { actions } = this.props
|
||||
if (id === 'new') {
|
||||
actions.changeNewSchedule(item)
|
||||
} else {
|
||||
actions.changeExistingSchedule(item, id)
|
||||
}
|
||||
};
|
||||
|
||||
addSchedule = () => {
|
||||
this.props.actions.addSchedule()
|
||||
};
|
||||
|
||||
removeSchedule = (id) => {
|
||||
this.props.actions.removeSchedule(id)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { state, actions, t } = this.props
|
||||
|
||||
const constants = state.constants
|
||||
const activeType = state.newTime.type
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<TypeSelector
|
||||
types={constants.type}
|
||||
activeType={activeType}
|
||||
onChange={actions.changeScheduleType}
|
||||
/>
|
||||
|
||||
<div className="new-schedule mb-3">
|
||||
<ScheduleOptions
|
||||
id="new"
|
||||
type={activeType}
|
||||
item={state.newTime}
|
||||
constants={constants}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={this.addSchedule}
|
||||
>
|
||||
{t('notificationsTab.form.add')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="schedule-list">
|
||||
<p className="text-muted mb-1">
|
||||
{t('notificationsTab.form.activeScheduledTimes')} <span>({state.times.length})</span>
|
||||
</p>
|
||||
|
||||
<ListGroup>
|
||||
{state.times.map((time, i) => {
|
||||
return (
|
||||
<ListGroupItem
|
||||
key={'schedule--added-time-' + i}
|
||||
>
|
||||
<ScheduleOptions
|
||||
id={i}
|
||||
type={time.type}
|
||||
item={time}
|
||||
canDelete
|
||||
constants={constants}
|
||||
onChange={this.onChange}
|
||||
onRemove={this.removeSchedule}
|
||||
/>
|
||||
</ListGroupItem>
|
||||
)
|
||||
})}
|
||||
</ListGroup>
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(Scheduling)
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import RadioField from '../RadioField'
|
||||
|
||||
export class TypeSelector extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
types: PropTypes.array.isRequired,
|
||||
activeType: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t, types, activeType, onChange } = this.props
|
||||
|
||||
return (
|
||||
<div className="d-flex mb-2">
|
||||
{types.map((type, i) => {
|
||||
return (
|
||||
<RadioField
|
||||
key={'schedule-type-' + i}
|
||||
label={t(`notificationsTab.form.type.${type}`)}
|
||||
name="schedule-type"
|
||||
checkedValue={activeType}
|
||||
value={type}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(TypeSelector)
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
import {
|
||||
IoIosArrowDropup,
|
||||
IoIosArrowDropdown,
|
||||
IoIosCloseCircleOutline
|
||||
} from 'react-icons/io'
|
||||
|
||||
export class Source extends React.Component {
|
||||
static propTypes = {
|
||||
source: PropTypes.object.isRequired,
|
||||
removeSource: PropTypes.func.isRequired,
|
||||
moveSource: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
onRemove = () => {
|
||||
const { source, removeSource } = this.props
|
||||
removeSource(source.id)
|
||||
}
|
||||
|
||||
onMoveUp = () => {
|
||||
const { source, moveSource } = this.props
|
||||
moveSource(source.id, true)
|
||||
}
|
||||
|
||||
onMoveDown = () => {
|
||||
const { source, moveSource } = this.props
|
||||
moveSource(source.id, false)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { source } = this.props
|
||||
|
||||
return (
|
||||
<div className="d-flex mr-2 mb-2">
|
||||
<p
|
||||
className={classnames(
|
||||
'd-flex align-items-center feed-icon',
|
||||
source.class
|
||||
)}
|
||||
>
|
||||
{source.name}
|
||||
</p>
|
||||
<div className="ml-sm-4">
|
||||
<button
|
||||
title="Up"
|
||||
type="button"
|
||||
className="btn p-0"
|
||||
onClick={this.onMoveUp}
|
||||
>
|
||||
<IoIosArrowDropup size={22} className="text-secondary ml-2" />
|
||||
</button>
|
||||
<button
|
||||
title="Down"
|
||||
type="button"
|
||||
className="btn p-0"
|
||||
onClick={this.onMoveDown}
|
||||
>
|
||||
<IoIosArrowDropdown size={22} className="text-secondary ml-2" />
|
||||
</button>
|
||||
<button
|
||||
title="Remove"
|
||||
type="button"
|
||||
className="btn p-0"
|
||||
onClick={this.onRemove}
|
||||
>
|
||||
<IoIosCloseCircleOutline size={22} className="text-danger ml-2" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Source
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Source from './Source'
|
||||
|
||||
export class Sources extends React.Component {
|
||||
static propTypes = {
|
||||
sources: PropTypes.array.isRequired,
|
||||
removeSource: PropTypes.func.isRequired,
|
||||
moveSource: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
const { sources, removeSource, moveSource } = this.props
|
||||
|
||||
return (
|
||||
<div>
|
||||
{sources.map((source, i) => {
|
||||
return (
|
||||
<Source
|
||||
key={'dragged-source-item-' + i}
|
||||
source={source}
|
||||
removeSource={removeSource}
|
||||
moveSource={moveSource}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Sources
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { compose } from 'redux'
|
||||
import { DropTarget } from 'react-dnd'
|
||||
import { translate } from 'react-i18next'
|
||||
|
||||
const target = {
|
||||
drop (props, monitor) {
|
||||
const item = monitor.getItem()
|
||||
props.addSource(item.feed)
|
||||
},
|
||||
|
||||
canDrop (props, monitor) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
export class SourcesDropTargetClass extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
connectDropTarget: PropTypes.func.isRequired,
|
||||
addSource: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
const { connectDropTarget, t } = this.props
|
||||
|
||||
return connectDropTarget(
|
||||
<div className='dropzone-wrapper dropzone-wrapper-sm'>
|
||||
<p className="dropzone-content">{t('notificationsTab.form.dragFeed')}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const SourcesDropTarget = compose(
|
||||
DropTarget('feed', target, (connect, monitor) => ({
|
||||
connectDropTarget: connect.dropTarget(),
|
||||
itemType: monitor.getItemType()
|
||||
})),
|
||||
translate(['tabsContent'], { wait: true })
|
||||
)(SourcesDropTargetClass)
|
||||
|
||||
export default SourcesDropTarget
|
||||
@@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Redirect, Route, Switch, withRouter } from 'react-router-dom';
|
||||
import SubTabWrapper from '../../AppHeader/SubTabWrapper';
|
||||
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
|
||||
import NotificationsSubTab from './NotificatoinsSubTab/NotificationsSubTab';
|
||||
import ManageRecipientsSubTab from './ManageRecipientsSubTub/ManageRecipientsSubTab';
|
||||
import ManageEmailsSubTab from './ManageEmailsSubTab/ManageEmailsSubTab';
|
||||
import ExportSubTab from './ExportSubTab/ExportSubTab';
|
||||
|
||||
class ShareTab extends React.Component {
|
||||
static propTypes = {
|
||||
activeTabName: PropTypes.string,
|
||||
subTabs: PropTypes.any,
|
||||
match: PropTypes.object,
|
||||
isMaster: PropTypes.bool
|
||||
};
|
||||
|
||||
render() {
|
||||
const { subTabs, isMaster, match, activeTabName } = this.props;
|
||||
return (
|
||||
<CSSTransitionGroup
|
||||
component="div"
|
||||
transitionName="TabsAnimation"
|
||||
transitionAppear
|
||||
transitionAppearTimeout={0}
|
||||
transitionEnter={false}
|
||||
transitionLeave={false}
|
||||
>
|
||||
<SubTabWrapper activeTabName={activeTabName} subTabs={subTabs}>
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path={`${match.url}/notifications`}
|
||||
component={NotificationsSubTab}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`${match.url}/export`}
|
||||
component={ExportSubTab}
|
||||
/>
|
||||
{isMaster
|
||||
? [
|
||||
<Route
|
||||
exact
|
||||
key={`${match.url}/manage-recipients`}
|
||||
path={`${match.url}/manage-recipients`}
|
||||
component={ManageRecipientsSubTab}
|
||||
/>,
|
||||
<Route
|
||||
exact
|
||||
key={`${match.url}/manage-emails`}
|
||||
path={`${match.url}/manage-emails`}
|
||||
component={ManageEmailsSubTab}
|
||||
/>
|
||||
]
|
||||
: null}
|
||||
<Redirect to={`${match.url}/notifications`} />
|
||||
</Switch>
|
||||
</SubTabWrapper>
|
||||
</CSSTransitionGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(ShareTab);
|
||||
@@ -0,0 +1,60 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate, Interpolate } from 'react-i18next'
|
||||
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'
|
||||
|
||||
export class DeletePopup extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
idsToDelete: PropTypes.array.isRequired,
|
||||
deleteSingleText: PropTypes.string.isRequired,
|
||||
deleteMultipleText: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
hidePopup = () => {
|
||||
const { actions } = this.props
|
||||
actions.cancelDelete()
|
||||
}
|
||||
|
||||
onSubmit = () => {
|
||||
const { actions, idsToDelete } = this.props
|
||||
actions.deleteItems(idsToDelete)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t, idsToDelete, deleteSingleText, deleteMultipleText } = this.props
|
||||
const length = Object.keys(idsToDelete).length
|
||||
|
||||
return (
|
||||
<Modal isOpen toggle={this.hidePopup} backdrop="static">
|
||||
<ModalHeader toggle={this.hidePopup}>
|
||||
{t('common:commonWords.Confirm')}
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<p>
|
||||
{length === 1 ? (
|
||||
t('tabsContent:deletePopup.' + deleteSingleText)
|
||||
) : (
|
||||
<Interpolate
|
||||
i18nKey={'tabsContent:deletePopup.' + deleteMultipleText}
|
||||
count={length}
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button color="light" onClick={this.hidePopup}>
|
||||
{t('common:commonWords.Cancel')}
|
||||
</Button>
|
||||
<Button color="danger" onClick={this.onSubmit}>
|
||||
{t('common:commonWords.Delete')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['common', 'tabsContent'], { wait: true })(DeletePopup)
|
||||
@@ -0,0 +1,299 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Table from '../../../../common/Table/Table'
|
||||
import LinkCell from '../../../../common/Table/LinkCell'
|
||||
import CheckboxCell from '../../../../common/Table/CheckboxCell'
|
||||
import SortableTh from '../../../../common/Table/SortableTh'
|
||||
import DeletePopup from './DeletePopup'
|
||||
import Toggler from '../../../../common/Table/Toggler'
|
||||
import { addOrdinalSuffix, padLeft } from '../../../../../common/StringUtils'
|
||||
import DeleteButton from '../../../../common/Table/DeleteButton'
|
||||
import Restrictions from '../../../../common/Restrictions/Restrictions'
|
||||
|
||||
export class GenericTable extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
tableActions: PropTypes.object.isRequired,
|
||||
deleteSingleText: PropTypes.string.isRequired,
|
||||
deleteMultipleText: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
onDeleteButtonClick = () => {
|
||||
const { tableState, tableActions } = this.props
|
||||
tableActions.confirmDelete(tableState.selectedIds)
|
||||
};
|
||||
|
||||
fetchData = (page, pageSize, sorted) => {
|
||||
const { tableActions } = this.props
|
||||
const params = {
|
||||
page: page + 1,
|
||||
limit: pageSize
|
||||
}
|
||||
if (sorted.length) {
|
||||
const sortedField = sorted[0]
|
||||
params['sortField'] = sortedField.id
|
||||
params['sortDirection'] = sortedField.desc ? 'desc' : 'asc'
|
||||
}
|
||||
tableActions.loadTable(params)
|
||||
};
|
||||
|
||||
selectAllAction = () => {
|
||||
const { tableActions } = this.props
|
||||
tableActions.selectTableAllRows()
|
||||
};
|
||||
|
||||
selectRowAction = (itemId) => {
|
||||
const { tableActions } = this.props
|
||||
tableActions.selectTableRow(itemId)
|
||||
};
|
||||
|
||||
deleteRowAction = (itemId) => {
|
||||
const { tableActions } = this.props
|
||||
tableActions.confirmDelete([itemId])
|
||||
};
|
||||
|
||||
nameClickAction = (item) => {
|
||||
//implement in subclasses
|
||||
};
|
||||
|
||||
onActivateButtonClick = () => {
|
||||
const { tableState, tableActions } = this.props
|
||||
tableActions.toggleActive(tableState.selectedIds, true)
|
||||
};
|
||||
|
||||
onPauseButtonClick = () => {
|
||||
const { tableState, tableActions } = this.props
|
||||
tableActions.toggleActive(tableState.selectedIds, false)
|
||||
};
|
||||
|
||||
scheduleFormat (schedules) {
|
||||
const { t } = this.props
|
||||
if (!schedules) {
|
||||
return ''
|
||||
} else if (schedules.length === 0) {
|
||||
return 'n/a'
|
||||
} else if (schedules.length === 1) {
|
||||
const schedule = schedules[0]
|
||||
if (schedule.type === 'daily') {
|
||||
const time = t(`notificationsTab.form.time.${schedule.time}`)
|
||||
const days = t(`notificationsTab.form.days.${schedule.days}`)
|
||||
return `${days}, ${time}`
|
||||
} else if (schedule.type === 'weekly') {
|
||||
const period = t(`notificationsTab.form.period.${schedule.period}`)
|
||||
const day = t(`notificationsTab.form.day.${schedule.day}`)
|
||||
const hour = padLeft(schedule.hour.toString(), 2)
|
||||
const minute = padLeft(schedule.minute.toString(), 2)
|
||||
return `${period} ${day}, ${hour}:${minute}`
|
||||
} else if (schedule.type === 'monthly') {
|
||||
const monthDay = addOrdinalSuffix(schedule.day)
|
||||
const hour = padLeft(schedule.hour.toString(), 2)
|
||||
const minute = padLeft(schedule.minute.toString(), 2)
|
||||
return `${monthDay} of the month, ${hour}:${minute}`
|
||||
}
|
||||
return ''
|
||||
} else {
|
||||
return (
|
||||
schedules.length + ' ' + this.props.t('notificationsTab.scheduledTimes')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
getRestrictions (restrictions) {
|
||||
if (!restrictions) return null
|
||||
return (
|
||||
<Restrictions restrictions={restrictions} restrictionsIds={['alerts', 'webFeeds']} />
|
||||
)
|
||||
}
|
||||
|
||||
getActionsPanel () {
|
||||
//implement in subclasess
|
||||
}
|
||||
|
||||
defineColumns () {
|
||||
const { t, tableState } = this.props
|
||||
|
||||
return {
|
||||
selectCheckbox: {
|
||||
accessor: '',
|
||||
sortable: false,
|
||||
width: 45,
|
||||
className: 'cw-center-cell',
|
||||
headerClassName: 'cw-center-cell',
|
||||
Header: () => {
|
||||
return (
|
||||
<CheckboxCell
|
||||
checked={tableState.isAllSelected}
|
||||
onChange={this.selectAllAction}
|
||||
/>
|
||||
)
|
||||
},
|
||||
Cell: ({ original }) => {
|
||||
const isSelected = tableState.selectedIds.includes(original.id)
|
||||
return (
|
||||
<CheckboxCell
|
||||
id={original.id}
|
||||
checked={isSelected}
|
||||
onChange={this.selectRowAction}
|
||||
/>
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
name: {
|
||||
Header: <SortableTh title="notificationsTab.name" />,
|
||||
accessor: 'name',
|
||||
Cell: ({ original }) => {
|
||||
return (
|
||||
<LinkCell item={original} onClick={this.nameClickAction}>
|
||||
{original.name}
|
||||
</LinkCell>
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
type: {
|
||||
Header: <SortableTh title="notificationsTab.type" />,
|
||||
accessor: (item) => t(`notificationsTab.${item.type}`),
|
||||
width: 100
|
||||
},
|
||||
|
||||
owner: {
|
||||
Header: <SortableTh title="notificationsTab.owner" />,
|
||||
accessor: (item) => item.owner.email,
|
||||
width: 170
|
||||
},
|
||||
|
||||
ScheduledTimes: {
|
||||
sortable: false,
|
||||
Header: t('notificationsTab.ScheduledTimes'),
|
||||
accessor: (item) => this.scheduleFormat(item.automatic),
|
||||
width: 170
|
||||
},
|
||||
|
||||
sourcesCount: {
|
||||
Header: <SortableTh title="notificationsTab.contents" />,
|
||||
accessor: (item) =>
|
||||
`${item.sourcesCount} ${t('notificationsTab.chartsFeeds')}`,
|
||||
width: 170
|
||||
},
|
||||
|
||||
delete: {
|
||||
sortable: false,
|
||||
Header: t('common:commonWords.Delete'),
|
||||
accessor: '',
|
||||
width: 65,
|
||||
className: 'cw-center-cell',
|
||||
headerClassName: 'cw-center-cell',
|
||||
Cell: ({ original }) => {
|
||||
return (
|
||||
<DeleteButton id={original.id} onDelete={this.deleteRowAction} />
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createTogglerColumn (
|
||||
title,
|
||||
toggleField,
|
||||
enabledText,
|
||||
disabledText,
|
||||
togglerOnAction,
|
||||
togglerOffAction
|
||||
) {
|
||||
const { t } = this.props
|
||||
return {
|
||||
Header: t(title),
|
||||
sortable: false,
|
||||
accessor: toggleField,
|
||||
width: 180,
|
||||
Cell: ({ original }) => {
|
||||
return (
|
||||
<Toggler
|
||||
id={original.id}
|
||||
turnOnAction={togglerOnAction}
|
||||
turnOffAction={togglerOffAction}
|
||||
state={original[toggleField]}
|
||||
enabledText={enabledText}
|
||||
disabledText={disabledText}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getColumns () {
|
||||
//implement in subclasses
|
||||
//should return array of string
|
||||
}
|
||||
|
||||
_fixColDefs (colDefs) {
|
||||
for (let colId in colDefs) {
|
||||
let colDef = colDefs[colId]
|
||||
if (typeof colDef.accessor !== 'string' && !colDef.id) {
|
||||
colDef.id = colId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
noCard () {
|
||||
// inherited class will return value
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
tableActions,
|
||||
tableState,
|
||||
deleteSingleText,
|
||||
deleteMultipleText
|
||||
} = this.props
|
||||
|
||||
const cols = this.getColumns()
|
||||
const colDefinitions = this.defineColumns()
|
||||
const noCard = this.noCard()
|
||||
this._fixColDefs(colDefinitions)
|
||||
const columns = cols
|
||||
.map((columnId) => {
|
||||
const col = colDefinitions[columnId]
|
||||
if (!col) {
|
||||
console.error(this.displayName, ': cannot find column', columnId)
|
||||
}
|
||||
return col
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{this.getActionsPanel()}
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
data={tableState.data}
|
||||
totalCount={tableState.totalCount}
|
||||
limit={tableState.limit}
|
||||
page={tableState.page}
|
||||
isLoading={tableState.isLoading}
|
||||
onFetchData={this.fetchData}
|
||||
onRowClick={this.onRowClick}
|
||||
noCard={noCard}
|
||||
/>
|
||||
|
||||
{tableState.isDeletePopupVisible && (
|
||||
<DeletePopup
|
||||
actions={tableActions}
|
||||
idsToDelete={tableState.idsToDelete}
|
||||
deleteSingleText={deleteSingleText}
|
||||
deleteMultipleText={deleteMultipleText}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default GenericTable
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import TableSwitcherItem from './TableSwitcherItem'
|
||||
import { ButtonGroup } from 'reactstrap'
|
||||
|
||||
export class TableSwitcher extends React.Component {
|
||||
static propTypes = {
|
||||
tables: PropTypes.array.isRequired,
|
||||
tableVisible: PropTypes.string.isRequired,
|
||||
subTab: PropTypes.string.isRequired,
|
||||
switchTable: PropTypes.func.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
onTableClick = (item) => {
|
||||
const { subTab, switchTable } = this.props
|
||||
switchTable(subTab, item)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { tables, tableVisible } = this.props
|
||||
|
||||
return (
|
||||
<ButtonGroup className="bg-white">
|
||||
{tables.map((table, i) => {
|
||||
return (
|
||||
<TableSwitcherItem
|
||||
key={`tables-switcher__table-${i}`}
|
||||
tableVisible={tableVisible}
|
||||
table={table}
|
||||
onClick={this.onTableClick}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</ButtonGroup>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(TableSwitcher)
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import { Button } from 'reactstrap'
|
||||
|
||||
export class TableSwitcherItem extends React.PureComponent {
|
||||
static propTypes = {
|
||||
table: PropTypes.string.isRequired,
|
||||
tableVisible: PropTypes.string.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
onClick = () => {
|
||||
const { onClick, table } = this.props
|
||||
onClick(table)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t, table, tableVisible } = this.props
|
||||
|
||||
return (
|
||||
<Button
|
||||
outline
|
||||
color="info"
|
||||
onClick={this.onClick}
|
||||
active={tableVisible === table}
|
||||
>
|
||||
{t(`tableSwitcher.${table}`)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(TableSwitcherItem)
|
||||
Reference in New Issue
Block a user