Skip to content

Commit

Permalink
FEATURE: preview recepients list
Browse files Browse the repository at this point in the history
  • Loading branch information
dimaip committed Jan 3, 2019
1 parent 92dd421 commit 92fa8b9
Show file tree
Hide file tree
Showing 11 changed files with 331 additions and 63 deletions.
28 changes: 26 additions & 2 deletions Classes/Psmb/Newsletter/Controller/NewsletterController.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function getSubscriptionsAction($nodeType) {
});
}
$subscriptionsJsonArray = array_map(function ($item) {
return ['label' => $item['label'], 'value' => $item['identifier']];
return ['label' => isset($item['label']) ? $item['label'] : '', 'value' => $item['identifier']];
}, $subscriptions);
$this->view->assign('value', array_values($subscriptionsJsonArray));
}
Expand All @@ -86,20 +86,44 @@ public function getSubscriptionsAction($nodeType) {
*
* @param string $subscription Subscription id to send newsletter to
* @param NodeInterface $node Node of the current newsletter item
* @param array $dataSourceAdditionalArguments
* @return void
*/
public function sendAction($subscription, NodeInterface $node)
public function sendAction($subscription, NodeInterface $node, array $dataSourceAdditionalArguments = null)
{
$subscriptions = array_filter($this->subscriptions, function ($item) use ($subscription) {
return $item['identifier'] == $subscription;
});
array_walk($subscriptions, function ($subscription) use ($node) {
$subscription['isSendFromUi'] = true;
if ($dataSourceAdditionalArguments) {
$subscription['dataSourceAdditionalArguments'] = $dataSourceAdditionalArguments;
}
$this->sendLettersForSubscription($subscription, $node);
});
$this->view->assign('value', ['status' => 'success']);
}

/**
* Registers a new subscriber
*
* @param string $subscription Subscription id to send newsletter to
* @param array $dataSourceAdditionalArguments
* @return void
*/
public function previewAction($subscription, $dataSourceAdditionalArguments = null)
{
$subscriptions = array_filter($this->subscriptions, function ($item) use ($subscription) {
return $item['identifier'] == $subscription;
});
$subscription = reset($subscriptions);
if ($dataSourceAdditionalArguments) {
$subscription['dataSourceAdditionalArguments'] = $dataSourceAdditionalArguments;
}
$subscribers = $this->subscribersService->getSubscribers($subscription);
$this->view->assign('value', $subscribers);
}

/**
* Sends a test letter for subscription
*
Expand Down
9 changes: 7 additions & 2 deletions Classes/Psmb/Newsletter/Service/DataSource/JsonDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ public function getData(array $subscription)
if (!isset($subscription['dataSourceOptions']['uri'])) {
throw new \Exception('dataSourceOptions.uri must be set for the Json datasource' . print_r($subscription, 1));
}
$response = file_get_contents($subscription['dataSourceOptions']['uri']);
$uri = $subscription['dataSourceOptions']['uri'];
if (isset($subscription['dataSourceAdditionalArguments'])) {
$uri .= strpos($uri, '?') === false ? '?' : '&';
$uri .= http_build_query($subscription['dataSourceAdditionalArguments']);
}
$response = file_get_contents($uri);
return json_decode($response, true);
}
}
}
14 changes: 14 additions & 0 deletions Configuration/NodeTypes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,17 @@
label: 'Newsletter view'
group: newsletter
view: Psmb.Newsletter/Views/NewsletterView
# viewOptions:
# dataSourceAdditionalArguments:
# startDate: 'ClientEval:node.properties.sampleProperty'
# properties:
# sampleProperty:
# type: DateTime
# ui:
# label: 'Жертвователи с'
# reloadIfChanged: true
# inspector:
# group: newsletter
# position: 1
# editorOptions:
# format: 'Y-m-d'
1 change: 0 additions & 1 deletion Configuration/Settings.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

Flowpack:
JobQueue:
Common:
Expand Down
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,42 @@ Psmb:

Alternatively you may provide your custom datasources. See implementation of JsonDataSource.php to see how to do that.

It is also possible to provide some additional arguments for the datasource that would be filled from other properties of a node.
Here is an example NodeTypes.yaml for this:

```
'Psmb.Newsletter:NewsletterMixin':
abstract: true
ui:
inspector:
tabs:
newsletter:
label: i18n
position: 100
icon: icon-send
groups:
newsletter:
label: i18n
tab: newsletter
views:
newsletter:
viewOptions:
dataSourceAdditionalArguments:
sampleArgument: 'ClientEval:node.properties.sampleProperty'
properties:
sampleProperty:
type: DateTime
ui:
label: 'Subscribers since'
inspector:
group: newsletter
position: 1
editorOptions:
format: 'Y-m-d'
```

Then the dataSourceAdditionalArguments would be passed to a datasource. You may check out how Json datasource handles it.

## Acknowledgements

This is my first Flow package, and it wouldn't have been possible without a support of the community by answering dozens of n00b questions on Slack, by Christian Müller in particular.
93 changes: 72 additions & 21 deletions Resources/Private/NewsletterView/src/ConfirmationDialog.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,78 @@
import React from 'react';
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {Button, Dialog} from '@neos-project/react-ui-components';

const ConfirmationDialog = ({isOpen, translate, close, send}) => {
return (
<Dialog
isOpen={isOpen}
title={translate('Psmb.Newsletter:Main:js.testConfirmationTitle')}
onRequestClose={close}
actions={[
<Button onClick={close} style="clean">{translate('Neos.Neos:Main:cancel')}</Button>,
<Button onClick={send} style="brand">{translate('Psmb.Newsletter:Main:js.send')}</Button>
]}
>
<div style={{padding: '16px'}}>{translate('Psmb.Newsletter:Main:js.confirmationDescription')}</div>
</Dialog>
);
};
ConfirmationDialog.propTypes = {
isOpen: PropTypes.bool,
translate: PropTypes.func.isRequired,
close: PropTypes.func.isRequired,
send: PropTypes.func.isRequired
class ConfirmationDialog extends PureComponent {
static propTypes = {
isOpen: PropTypes.bool,
translate: PropTypes.func.isRequired,
close: PropTypes.func.isRequired,
send: PropTypes.func.isRequired,
subscription: PropTypes.string.isRequired,
dataSourceAdditionalArguments: PropTypes.object
};

state = {
isLoading: false,
subscribers: []
};

componentDidUpdate(prevProps) {
if (this.props.subscription !== prevProps.subscription || (prevProps.isOpen === false && this.props.isOpen === true)) {
this.fetchPreview();
}
}

fetchPreview() {
if (this.props.subscription && this.props.isOpen) {
this.setState({isLoading: true, subscribers: []});
const dataSourceAdditionalArguments = this.props.dataSourceAdditionalArguments;
const data = new URLSearchParams();
if (dataSourceAdditionalArguments) {
Object.keys(dataSourceAdditionalArguments).forEach(option => {
data.set('dataSourceAdditionalArguments[' + option + ']', dataSourceAdditionalArguments[option]);
});
}
fetch(`/newsletter/preview?subscription=${this.props.subscription}&${data.toString()}`, {
credentials: 'include'
})
.then(response => response.json())
.then(subscribers => {
this.setState({subscribers, isLoading: false});
});
}
}
render() {
const {isOpen, translate, close, send} = this.props;

const keys = this.state.subscribers[0] ? Object.keys(this.state.subscribers[0]) : [];
return (
<Dialog
isOpen={isOpen}
title={translate('Psmb.Newsletter:Main:js.confirmationTitle')}
onRequestClose={close}
actions={[
<Button onClick={close} style="clean">{translate('Neos.Neos:Main:cancel')}</Button>,
<Button onClick={send} style="brand">{translate('Psmb.Newsletter:Main:js.send')}</Button>
]}
>
<div style={{padding: '16px'}}>
<div>{translate('Psmb.Newsletter:Main:js.confirmationDescription')}</div>
{this.state.isLoading ? translate('Psmb.Newsletter:Main:js.loading') : (
<div>
<div style={{padding: '16px 0'}}>{translate('Psmb.Newsletter:Main:js.recepients')}: <strong>{this.state.subscribers.length}</strong></div>
<table>
<tr>{keys.map(key => <th>{key}</th>)}</tr>
{this.state.subscribers.map(subscriber => {
return <tr>{keys.map(key => <td>{subscriber[key]}</td>)}</tr>;
})}
</table>
</div>
)}
</div>
</Dialog>
);
}
};

export default ConfirmationDialog;
11 changes: 9 additions & 2 deletions Resources/Private/NewsletterView/src/NewsletterView.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const fetchSubscriptions = nodeType => fetch(`/newsletter/getSubscriptions?nodeT
credentials: 'include'
}).then(response => response.json());

const sendNewsletter = (focusedNodeContextPath, subscription, isTest, email) => {
const sendEndpointUrl = isTest ? '/newsletter/testSend' : '/newsletter/send';
const sendNewsletter = (focusedNodeContextPath, subscription, isTest, email, dataSourceAdditionalArguments) => {
let sendEndpointUrl = isTest ? '/newsletter/testSend' : '/newsletter/send';
const csrfToken = document.getElementById('appContainer').dataset.csrfToken;
const data = new URLSearchParams();
data.set('node', focusedNodeContextPath.replace(/user-.+\;/, 'live;'));
Expand All @@ -22,6 +22,11 @@ const sendNewsletter = (focusedNodeContextPath, subscription, isTest, email) =>
if (isTest && email) {
data.set('email', email);
}
if (dataSourceAdditionalArguments) {
Object.keys(dataSourceAdditionalArguments).forEach(option => {
data.set('dataSourceAdditionalArguments[' + pair[0] + ']', dataSourceAdditionalArguments[option]);
});
}
return fetch(sendEndpointUrl, {
credentials: 'include',
method: 'POST',
Expand Down Expand Up @@ -126,6 +131,8 @@ export default class NewsletterView extends Component {
translate={this.props.i18nRegistry.translate.bind(this.props.i18nRegistry)}
close={() => this.toggleConfirmationDialog(false)}
send={this.sendNewsletter}
subscription={this.state.selectedSubscription}
dataSourceAdditionalArguments={this.props.options && this.props.options.dataSourceAdditionalArguments}
/>
</div>
);
Expand Down
3 changes: 3 additions & 0 deletions Resources/Private/Translations/en/Main.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
<source>Loading...</source>
</trans-unit>

<trans-unit id="js.recepients" xml:space="preserve">
<source>Total number of recepients</source>
</trans-unit>
<trans-unit id="js.confirmationTitle" xml:space="preserve">
<source>Send Newsletter</source>
</trans-unit>
Expand Down
4 changes: 4 additions & 0 deletions Resources/Private/Translations/ru/Main.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
<target>Загрузка...</target>
</trans-unit>

<trans-unit id="js.recepients" xml:space="preserve">
<target>Общее количество адресатов</target>
</trans-unit>

<trans-unit id="js.confirmationTitle" xml:space="preserve">
<source>Send newsletter</source>
<target>Отправить рассылку</target>
Expand Down
Loading

0 comments on commit 92fa8b9

Please sign in to comment.