+ location={this.props.location}
+ pageExitWarning={pageExitWarning}>
diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js
index a07f29b1..e7f11141 100644
--- a/js/constants/api_urls.js
+++ b/js/constants/api_urls.js
@@ -72,6 +72,9 @@ let ApiUrls = {
'users_username': AppConstants.apiEndpoint + 'users/username/',
'users_profile': AppConstants.apiEndpoint + 'users/profile/',
'wallet_settings': AppConstants.apiEndpoint + 'users/wallet_settings/',
+ 'webhook': AppConstants.apiEndpoint + 'webhooks/${webhook_id}/',
+ 'webhooks': AppConstants.apiEndpoint + 'webhooks/',
+ 'webhooks_events': AppConstants.apiEndpoint + 'webhooks/events/',
'whitelabel_settings': AppConstants.apiEndpoint + 'whitelabel/settings/${subdomain}/',
'delete_s3_file': AppConstants.serverUrl + 's3/delete/',
'prize_list': AppConstants.apiEndpoint + 'prize/'
diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js
index 4415a91a..a58a8cc6 100644
--- a/js/constants/application_constants.js
+++ b/js/constants/application_constants.js
@@ -114,9 +114,6 @@ const constants = {
},
'twitter': {
'sdkUrl': 'https://platform.twitter.com/widgets.js'
- },
- 'fartscroll': {
- 'sdkUrl': 'http://code.onion.com/fartscroll.js'
}
};
diff --git a/js/sources/webhook_source.js b/js/sources/webhook_source.js
new file mode 100644
index 00000000..5351c89c
--- /dev/null
+++ b/js/sources/webhook_source.js
@@ -0,0 +1,46 @@
+'use strict';
+
+import requests from '../utils/requests';
+
+import WebhookActions from '../actions/webhook_actions';
+
+
+const WebhookSource = {
+ lookupWebhooks: {
+ remote() {
+ return requests.get('webhooks');
+ },
+ local(state) {
+ return state.webhooks && !Object.keys(state.webhooks).length ? state : {};
+ },
+ success: WebhookActions.successFetchWebhooks,
+ error: WebhookActions.errorWebhooks,
+ shouldFetch(state) {
+ return state.webhookMeta.invalidateCache || state.webhooks && !Object.keys(state.webhooks).length;
+ }
+ },
+
+ lookupWebhookEvents: {
+ remote() {
+ return requests.get('webhooks_events');
+ },
+ local(state) {
+ return state.webhookEvents && !Object.keys(state.webhookEvents).length ? state : {};
+ },
+ success: WebhookActions.successFetchWebhookEvents,
+ error: WebhookActions.errorWebhookEvents,
+ shouldFetch(state) {
+ return state.webhookEventsMeta.invalidateCache || state.webhookEvents && !Object.keys(state.webhookEvents).length;
+ }
+ },
+
+ performRemoveWebhook: {
+ remote(state) {
+ return requests.delete('webhook', {'webhook_id': state.webhookMeta.idToDelete });
+ },
+ success: WebhookActions.successRemoveWebhook,
+ error: WebhookActions.errorWebhooks
+ }
+};
+
+export default WebhookSource;
\ No newline at end of file
diff --git a/js/stores/webhook_store.js b/js/stores/webhook_store.js
new file mode 100644
index 00000000..7dfcc61d
--- /dev/null
+++ b/js/stores/webhook_store.js
@@ -0,0 +1,88 @@
+'use strict';
+
+import { alt } from '../alt';
+import WebhookActions from '../actions/webhook_actions';
+
+import WebhookSource from '../sources/webhook_source';
+
+class WebhookStore {
+ constructor() {
+ this.webhooks = [];
+ this.webhookEvents = [];
+ this.webhookMeta = {
+ invalidateCache: false,
+ err: null,
+ idToDelete: null
+ };
+ this.webhookEventsMeta = {
+ invalidateCache: false,
+ err: null
+ };
+
+ this.bindActions(WebhookActions);
+ this.registerAsync(WebhookSource);
+ }
+
+ onFetchWebhooks(invalidateCache) {
+ this.webhookMeta.invalidateCache = invalidateCache;
+ this.getInstance().lookupWebhooks();
+ }
+
+ onSuccessFetchWebhooks({ webhooks }) {
+ this.webhookMeta.invalidateCache = false;
+ this.webhookMeta.err = null;
+ this.webhooks = webhooks;
+
+ this.webhookEventsMeta.invalidateCache = true;
+ this.getInstance().lookupWebhookEvents();
+ }
+
+ onFetchWebhookEvents(invalidateCache) {
+ this.webhookEventsMeta.invalidateCache = invalidateCache;
+ this.getInstance().lookupWebhookEvents();
+ }
+
+ onSuccessFetchWebhookEvents({ events }) {
+ this.webhookEventsMeta.invalidateCache = false;
+ this.webhookEventsMeta.err = null;
+
+ // remove all events that have already been used.
+ const usedEvents = this.webhooks
+ .reduce((tempUsedEvents, webhook) => {
+ tempUsedEvents.push(webhook.event.split('.')[0]);
+ return tempUsedEvents;
+ }, []);
+
+ this.webhookEvents = events.filter((event) => {
+ return usedEvents.indexOf(event) === -1;
+ });
+ }
+
+ onRemoveWebhook(id) {
+ this.webhookMeta.invalidateCache = true;
+ this.webhookMeta.idToDelete = id;
+
+ if(!this.getInstance().isLoading()) {
+ this.getInstance().performRemoveWebhook();
+ }
+ }
+
+ onSuccessRemoveWebhook() {
+ this.webhookMeta.idToDelete = null;
+ if(!this.getInstance().isLoading()) {
+ this.getInstance().lookupWebhooks();
+ }
+ }
+
+ onErrorWebhooks(err) {
+ console.logGlobal(err);
+ this.webhookMeta.err = err;
+ }
+
+ onErrorWebhookEvents(err) {
+ console.logGlobal(err);
+ this.webhookEventsMeta.err = err;
+ }
+}
+
+export default alt.createStore(WebhookStore, 'WebhookStore');
diff --git a/js/utils/inject_utils.js b/js/utils/inject_utils.js
index 174ac8b6..e9430a5e 100644
--- a/js/utils/inject_utils.js
+++ b/js/utils/inject_utils.js
@@ -12,16 +12,16 @@ let mapTag = {
css: 'link'
};
+let tags = {};
+
function injectTag(tag, src) {
- return Q.Promise((resolve, reject) => {
- if (isPresent(tag, src)) {
- resolve();
- } else {
+ if(!tags[src]) {
+ tags[src] = Q.Promise((resolve, reject) => {
let attr = mapAttr[tag];
let element = document.createElement(tag);
if (tag === 'script') {
- element.onload = () => resolve();
- element.onerror = () => reject();
+ element.onload = resolve;
+ element.onerror = reject;
} else {
resolve();
}
@@ -30,14 +30,10 @@ function injectTag(tag, src) {
if (tag === 'link') {
element.rel = 'stylesheet';
}
- }
- });
-}
+ });
+ }
-function isPresent(tag, src) {
- let attr = mapAttr[tag];
- let query = `head > ${tag}[${attr}="${src}"]`;
- return document.querySelector(query);
+ return tags[src];
}
function injectStylesheet(src) {
@@ -65,7 +61,6 @@ export const InjectInHeadUtils = {
* you don't want to embed everything inside the build file.
*/
- isPresent,
injectStylesheet,
injectScript,
inject
diff --git a/package.json b/package.json
index 63c6d1e0..9e1f624c 100644
--- a/package.json
+++ b/package.json
@@ -66,7 +66,7 @@
"gulp-uglify": "^1.2.0",
"gulp-util": "^3.0.4",
"harmonize": "^1.4.2",
- "history": "^1.11.1",
+ "history": "^1.13.1",
"invariant": "^2.1.1",
"isomorphic-fetch": "^2.0.2",
"jest-cli": "^0.4.0",
@@ -80,7 +80,7 @@
"react": "0.13.2",
"react-bootstrap": "0.25.1",
"react-datepicker": "^0.12.0",
- "react-router": "^1.0.0-rc3",
+ "react-router": "1.0.0",
"react-router-bootstrap": "^0.19.0",
"react-star-rating": "~1.3.2",
"react-textarea-autosize": "^2.5.2",
diff --git a/sass/ascribe_notification_list.scss b/sass/ascribe_notification_list.scss
index a09f7049..b5f46a4c 100644
--- a/sass/ascribe_notification_list.scss
+++ b/sass/ascribe_notification_list.scss
@@ -2,8 +2,9 @@ $break-small: 764px;
$break-medium: 991px;
$break-medium: 1200px;
-.notification-header,.notification-wrapper {
- width: 350px;
+.notification-header, .notification-wrapper {
+ min-width: 350px;
+ width: 100%;
}
.notification-header {
@@ -81,4 +82,4 @@ $break-medium: 1200px;
border: 1px solid #cccccc;
background-color: white;
margin-top: 1px;
-}
\ No newline at end of file
+}