Skip to content

Commit 618ba05

Browse files
authored
Adds interface for localized push notifications (#769)
* 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
1 parent 161a06a commit 618ba05

File tree

6 files changed

+56
-46
lines changed

6 files changed

+56
-46
lines changed

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ language: node_js
22
node_js:
33
- '6.10'
44
- '7.10'
5+
cache:
6+
directories:
7+
- node_modules
58
deploy:
69
provider: npm
710
on:

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* 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)
77
* Fix: NaN displayed when filter input is empty or negative number (#749), thanks to [Miguel Serrrano](https://github.com/miguel-s)
88
* 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)
9+
* Feature: Adds support for localized push notifications if server version is high enough, thanks to [Florent Vilmart](https://github.com/flovilmart)
910

1011
### 1.1.0
1112

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,27 @@ You can give read only access to a user on a per-app basis:
359359

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

362+
## Configuring Localized Push Notifications
363+
364+
With the latest version of the [dashboard](https://www.npmjs.com/package/parse-dashboard), it is possible to send localized messages for push notifications.
365+
You can provide a list of locales or languages you want to support for your dashboard users.
366+
367+
```json
368+
{
369+
"apps": [
370+
{
371+
"serverURL": "http://localhost:1337/parse",
372+
"appId": "myAppId",
373+
"masterKey": "myMasterKey",
374+
"appName": "My Parse Server App",
375+
"iconName": "MyAppIcon.png",
376+
"supportedPushLocales": ["en", "ru", "fr"]
377+
}
378+
],
379+
"iconsFolder": "icons"
380+
}
381+
```
382+
362383
## Run with Docker
363384

364385
It is easy to use it with Docker. First build the image:

src/dashboard/Data/Jobs/Jobs.react.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,11 @@ export default class Jobs extends TableView {
202202
<EmptyState
203203
title='Cloud Jobs'
204204
description=
205-
<div>
205+
{<div>
206206
<p>{'On this page you can create JobSchedule objects.'}</p>
207207
<br/>
208208
<JobScheduleReminder />
209-
</div>
209+
</div>}
210210
icon='cloud-happy' />
211211
);
212212
} else {

src/dashboard/Push/PushNew.react.js

Lines changed: 25 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import Field from 'components/Field/Field.react';
1717
import Fieldset from 'components/Fieldset/Fieldset.react';
1818
import FieldStyles from 'components/Field/Field.scss';
1919
import FlowView from 'components/FlowView/FlowView.react';
20-
import getSiteDomain from 'lib/getSiteDomain';
2120
import history from 'dashboard/history';
2221
import joinWithFinal from 'lib/joinWithFinal';
2322
import Label from 'components/Label/Label.react';
@@ -121,7 +120,6 @@ let LocalizedMessageField = ({
121120
}
122121

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

126124
@subscribeTo('Schema', 'schema')
127125
@subscribeTo('PushAudiences', 'pushaudiences')
@@ -159,28 +157,18 @@ export default class PushNew extends DashboardView {
159157
this.setState({ pushAudiencesFetched :true });
160158
});
161159

162-
let {xhr, promise} = this.context.currentApp.isLocalizationAvailable();
163-
this.xhrs.push(xhr);
164-
promise.then(({ available }) => {
165-
if (available) {
166-
this.setState({ isLocalizationAvailable : true });
167-
let {xhr, promise} = this.context.currentApp.fetchPushLocales();
168-
this.xhrs.push(xhr);
169-
promise.then(({ options }) => {
170-
let filteredLocales = options.filter((locale) => {
171-
if (locale === '' || locale === undefined) {
172-
return false;
173-
}
174-
return true;
175-
});
176-
this.setState({
177-
locales: filteredLocales,
178-
availableLocales: filteredLocales
179-
});
180-
}).always(() => {
181-
this.setState({ loadingLocale: false });
182-
});
183-
}
160+
const available = this.context.currentApp.isLocalizationAvailable();
161+
if (available) {
162+
const locales = this.context.currentApp.fetchPushLocales();
163+
const filteredLocales = locales.filter((locale) => !(locale === '' || locale === undefined));
164+
this.setState({
165+
isLocalizationAvailable: true,
166+
locales: filteredLocales,
167+
availableLocales: filteredLocales
168+
});
169+
}
170+
this.setState({
171+
loadingLocale: false
184172
});
185173
}
186174

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

205193
const push_time = extractPushTime(changes);
194+
195+
// Gather the translations, and inject into the payload
196+
const needle = 'translation[';
197+
Object.keys(changes).forEach((key) => {
198+
// translations are stored as `tranlation[lang]` strings as keys,
199+
// this is why we slice it this way
200+
if (key.indexOf(needle) === 0) {
201+
const locale = key.slice(needle.length, key.length - 1);
202+
payload[`alert-${locale}`] = changes[key];
203+
}
204+
});
205+
206206
let body = {
207207
data: payload,
208208
where: changes.target || new Parse.Query(Parse.Installation),
@@ -530,16 +530,6 @@ export default class PushNew extends DashboardView {
530530
setField('translation_enable', value || null);
531531
}} />} />
532532
);
533-
if (fields.translation_enable) {
534-
translationSegment.push(
535-
<SliderWrap key='warning' direction={Directions.DOWN} expanded={fields.translation_enable} block={true}>
536-
<div className={styles.warning}>
537-
<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>
538-
<a target='_blank' style={{ paddingLeft: '5px' }}href={getSiteDomain() + TRANSLATE_MORE_INFO_URL}>More info.</a>
539-
</div>
540-
</SliderWrap>
541-
);
542-
}
543533
if (fields.translation_enable) {
544534
//locales change based on existing selection
545535

@@ -759,14 +749,9 @@ export default class PushNew extends DashboardView {
759749
// localized message is empty
760750
if (changes.translation_enable) {
761751
this.state.localizedMessages.forEach((message) => {
762-
if (changes.data_type === 'json') {
763-
if (!isValidJSON(message.value)) {
764-
invalidInputMessages.push(<span key='invalid-json'>Your <strong>message for {message.locale}</strong> is not valid JSON.</span>);
765-
}
766-
} else if (!message.value || message.value.trim() === '') {
752+
if (!message.value || message.value.trim() === '') {
767753
emptyInputMessages.push(`message for ${message.locale} locale`);
768754
}
769-
770755
});
771756
}
772757

src/lib/ParseApp.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export default class ParseApp {
3939
serverInfo,
4040
production,
4141
iconName,
42+
supportedPushLocales,
4243
}) {
4344
this.name = appName;
4445
this.createdAt = created_at ? new Date(created_at) : new Date();
@@ -59,6 +60,7 @@ export default class ParseApp {
5960
this.serverURL = serverURL;
6061
this.serverInfo = serverInfo;
6162
this.icon = iconName;
63+
this.supportedPushLocales = supportedPushLocales;
6264

6365
this.settings = {
6466
fields: {},
@@ -404,13 +406,11 @@ export default class ParseApp {
404406
}
405407

406408
isLocalizationAvailable() {
407-
let path = '/apps/' + this.slug + '/is_localization_available';
408-
return AJAX.abortableGet(path);
409+
return !!this.serverInfo.features.push.localization;
409410
}
410411

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

416416
fetchPushLocaleDeviceCount(audienceId, where, locales) {

0 commit comments

Comments
 (0)