Skip to content

Adds interface for localized push notifications #769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ language: node_js
node_js:
- '6.10'
- '7.10'
cache:
directories:
- node_modules
deploy:
provider: npm
on:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Fix: Updating array of Dates now keeps it's type (was changing to array of ISO strings, issue #590), thanks to [David Riha](https://github.com/rihadavid)
* Fix: NaN displayed when filter input is empty or negative number (#749), thanks to [Miguel Serrrano](https://github.com/miguel-s)
* Fix: Addresses issue related to displaying iOS alert object containing title and body keys (#539), thanks to [Robert Martin del Campo](https://github.com/repertus)
* Feature: Adds support for localized push notifications if server version is high enough, thanks to [Florent Vilmart](https://github.com/flovilmart)

### 1.1.0

Expand Down
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,27 @@ You can give read only access to a user on a per-app basis:

With this configuration, user1 will have read only access to `myAppId1` and read/write access to `myAppId2`.

## Configuring Localized Push Notifications

With the latest version of the [dashboard](https://www.npmjs.com/package/parse-dashboard), it is possible to send localized messages for push notifications.
You can provide a list of locales or languages you want to support for your dashboard users.

```json
{
"apps": [
{
"serverURL": "http://localhost:1337/parse",
"appId": "myAppId",
"masterKey": "myMasterKey",
"appName": "My Parse Server App",
"iconName": "MyAppIcon.png",
"supportedPushLocales": ["en", "ru", "fr"]
}
],
"iconsFolder": "icons"
}
```

## Run with Docker

It is easy to use it with Docker. First build the image:
Expand Down
4 changes: 2 additions & 2 deletions src/dashboard/Data/Jobs/Jobs.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,11 @@ export default class Jobs extends TableView {
<EmptyState
title='Cloud Jobs'
description=
<div>
{<div>
<p>{'On this page you can create JobSchedule objects.'}</p>
<br/>
<JobScheduleReminder />
</div>
</div>}
icon='cloud-happy' />
);
} else {
Expand Down
65 changes: 25 additions & 40 deletions src/dashboard/Push/PushNew.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import Field from 'components/Field/Field.react';
import Fieldset from 'components/Fieldset/Fieldset.react';
import FieldStyles from 'components/Field/Field.scss';
import FlowView from 'components/FlowView/FlowView.react';
import getSiteDomain from 'lib/getSiteDomain';
import history from 'dashboard/history';
import joinWithFinal from 'lib/joinWithFinal';
import Label from 'components/Label/Label.react';
Expand Down Expand Up @@ -121,7 +120,6 @@ let LocalizedMessageField = ({
}

const XHR_KEY = 'PushNew';
const TRANSLATE_MORE_INFO_URL = '/docs/android/guide#push-notifications-push-localization';

@subscribeTo('Schema', 'schema')
@subscribeTo('PushAudiences', 'pushaudiences')
Expand Down Expand Up @@ -159,28 +157,18 @@ export default class PushNew extends DashboardView {
this.setState({ pushAudiencesFetched :true });
});

let {xhr, promise} = this.context.currentApp.isLocalizationAvailable();
this.xhrs.push(xhr);
promise.then(({ available }) => {
if (available) {
this.setState({ isLocalizationAvailable : true });
let {xhr, promise} = this.context.currentApp.fetchPushLocales();
this.xhrs.push(xhr);
promise.then(({ options }) => {
let filteredLocales = options.filter((locale) => {
if (locale === '' || locale === undefined) {
return false;
}
return true;
});
this.setState({
locales: filteredLocales,
availableLocales: filteredLocales
});
}).always(() => {
this.setState({ loadingLocale: false });
});
}
const available = this.context.currentApp.isLocalizationAvailable();
if (available) {
const locales = this.context.currentApp.fetchPushLocales();
const filteredLocales = locales.filter((locale) => !(locale === '' || locale === undefined));
this.setState({
isLocalizationAvailable: true,
locales: filteredLocales,
availableLocales: filteredLocales
});
}
this.setState({
loadingLocale: false
});
}

Expand All @@ -203,6 +191,18 @@ export default class PushNew extends DashboardView {
}

const push_time = extractPushTime(changes);

// Gather the translations, and inject into the payload
const needle = 'translation[';
Object.keys(changes).forEach((key) => {
// translations are stored as `tranlation[lang]` strings as keys,
// this is why we slice it this way
if (key.indexOf(needle) === 0) {
const locale = key.slice(needle.length, key.length - 1);
payload[`alert-${locale}`] = changes[key];
}
});

let body = {
data: payload,
where: changes.target || new Parse.Query(Parse.Installation),
Expand Down Expand Up @@ -530,16 +530,6 @@ export default class PushNew extends DashboardView {
setField('translation_enable', value || null);
}} />} />
);
if (fields.translation_enable) {
translationSegment.push(
<SliderWrap key='warning' direction={Directions.DOWN} expanded={fields.translation_enable} block={true}>
<div className={styles.warning}>
<span>In some cases a locale may not be available for a user, either because they are running an earlier version of the SDK or their client has sent up an invalid locale. In those cases, they will receive the default message.</span>
<a target='_blank' style={{ paddingLeft: '5px' }}href={getSiteDomain() + TRANSLATE_MORE_INFO_URL}>More info.</a>
</div>
</SliderWrap>
);
}
if (fields.translation_enable) {
//locales change based on existing selection

Expand Down Expand Up @@ -759,14 +749,9 @@ export default class PushNew extends DashboardView {
// localized message is empty
if (changes.translation_enable) {
this.state.localizedMessages.forEach((message) => {
if (changes.data_type === 'json') {
if (!isValidJSON(message.value)) {
invalidInputMessages.push(<span key='invalid-json'>Your <strong>message for {message.locale}</strong> is not valid JSON.</span>);
}
} else if (!message.value || message.value.trim() === '') {
if (!message.value || message.value.trim() === '') {
emptyInputMessages.push(`message for ${message.locale} locale`);
}

});
}

Expand Down
8 changes: 4 additions & 4 deletions src/lib/ParseApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export default class ParseApp {
serverInfo,
production,
iconName,
supportedPushLocales,
}) {
this.name = appName;
this.createdAt = created_at ? new Date(created_at) : new Date();
Expand All @@ -59,6 +60,7 @@ export default class ParseApp {
this.serverURL = serverURL;
this.serverInfo = serverInfo;
this.icon = iconName;
this.supportedPushLocales = supportedPushLocales;

this.settings = {
fields: {},
Expand Down Expand Up @@ -404,13 +406,11 @@ export default class ParseApp {
}

isLocalizationAvailable() {
let path = '/apps/' + this.slug + '/is_localization_available';
return AJAX.abortableGet(path);
return !!this.serverInfo.features.push.localization;
}

fetchPushLocales() {
let path = '/apps/' + this.slug + '/installation_column_options?column=localeIdentifier';
return AJAX.abortableGet(path);
return this.supportedPushLocales;
}

fetchPushLocaleDeviceCount(audienceId, where, locales) {
Expand Down