Skip to content

Commit

Permalink
Adds interface for localized push notifications (#769)
Browse files Browse the repository at this point in the history
* Adds interface for localized push notifications

- This is somewhat different from parse.com and probably more efficient

* Fix lint issues

* nits

* nit

* fixes compile issues

* cache node_modules
  • Loading branch information
flovilmart authored Oct 26, 2017
1 parent 161a06a commit 618ba05
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 46 deletions.
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

0 comments on commit 618ba05

Please sign in to comment.