From 77a7fc784b4dbf43462d60a7c7e1e35b8e1e1672 Mon Sep 17 00:00:00 2001
From: Huan Li
Date: Sun, 28 Apr 2019 00:03:01 +0800
Subject: [PATCH 01/15] Fix Server-side filtering on challenge listings
---
__tests__/__snapshots__/index.js.snap | 225 +++++++
docs/actions.challenge-listing.md | 271 ++++++++
docs/buckets.md | 50 ++
docs/index.md | 27 +-
docs/reducers.challenge-listing.md | 310 ++++++++++
docs/sort.md | 20 +
docs/tc.md | 17 +-
docs/url.md | 27 +
src/actions/challenge-listing.js | 450 ++++++++++++++
src/actions/index.js | 2 +
src/config/index.js | 4 +
src/index.js | 2 +-
src/reducers/challenge-listing.js | 848 ++++++++++++++++++++++++++
src/reducers/index.js | 3 +
src/services/challenges.js | 4 +-
src/utils/challenge/buckets.js | 153 +++++
src/utils/challenge/filter.js | 33 +
src/utils/challenge/sort.js | 84 +++
src/utils/index.js | 6 +
src/utils/tc.js | 47 ++
src/utils/url.js | 49 ++
21 files changed, 2625 insertions(+), 7 deletions(-)
create mode 100644 docs/actions.challenge-listing.md
create mode 100644 docs/buckets.md
create mode 100644 docs/reducers.challenge-listing.md
create mode 100644 docs/sort.md
create mode 100644 docs/url.md
create mode 100644 src/actions/challenge-listing.js
create mode 100644 src/config/index.js
create mode 100644 src/reducers/challenge-listing.js
create mode 100644 src/utils/challenge/buckets.js
create mode 100644 src/utils/challenge/sort.js
create mode 100644 src/utils/url.js
diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap
index 0542a66c..e7ee51bc 100644
--- a/__tests__/__snapshots__/index.js.snap
+++ b/__tests__/__snapshots__/index.js.snap
@@ -29,6 +29,31 @@ Object {
"updateChallengeDone": [Function],
"updateChallengeInit": [Function],
},
+ "challengeListing": Object {
+ "dropChallenges": [Function],
+ "expandTag": [Function],
+ "getActiveChallengesDone": [Function],
+ "getActiveChallengesInit": [Function],
+ "getAllActiveChallengesDone": [Function],
+ "getAllActiveChallengesInit": [Function],
+ "getChallengeSubtracksDone": [Function],
+ "getChallengeSubtracksInit": [Function],
+ "getChallengeTagsDone": [Function],
+ "getChallengeTagsInit": [Function],
+ "getMoreChallenges": [Function],
+ "getPastChallengesDone": [Function],
+ "getPastChallengesInit": [Function],
+ "getRestActiveChallengesDone": [Function],
+ "getRestActiveChallengesInit": [Function],
+ "getReviewOpportunitiesDone": [Function],
+ "getReviewOpportunitiesInit": [Function],
+ "getSrmsDone": [Function],
+ "getSrmsInit": [Function],
+ "selectCommunity": [Function],
+ "setDatepickerStatus": [Function],
+ "setFilter": [Function],
+ "setSort": [Function],
+ },
"direct": Object {
"dropAll": [Function],
"getProjectDetailsDone": [Function],
@@ -173,13 +198,145 @@ Object {
},
},
"challenge": Object {
+ "buckets": Object {
+ "BUCKETS": Object {
+ "ALL": "all",
+ "MY": "my",
+ "ONGOING": "ongoing",
+ "OPEN_FOR_REGISTRATION": "openForRegistration",
+ "PAST": "past",
+ "REVIEW_OPPORTUNITIES": "reviewOpportunities",
+ "SAVED_FILTER": "saved-filter",
+ "SAVED_REVIEW_OPPORTUNITIES_FILTER": "savedReviewOpportunitiesFilter",
+ "UPCOMING": "upcoming",
+ },
+ "BUCKET_DATA": Object {
+ "all": Object {
+ "filter": Object {
+ "started": true,
+ "status": Array [
+ "ACTIVE",
+ ],
+ },
+ "hideCount": false,
+ "name": "All Challenges",
+ "sorts": Array [],
+ },
+ "my": Object {
+ "filter": Object {
+ "started": true,
+ "status": Array [
+ "ACTIVE",
+ ],
+ },
+ "hideCount": false,
+ "name": "My Challenges",
+ "sorts": Array [
+ "most-recent",
+ "time-to-submit",
+ "num-registrants",
+ "num-submissions",
+ "prize-high-to-low",
+ "title-a-to-z",
+ ],
+ },
+ "ongoing": Object {
+ "filter": Object {
+ "registrationOpen": false,
+ "started": true,
+ "status": Array [
+ "ACTIVE",
+ ],
+ },
+ "hideCount": false,
+ "name": "Ongoing challenges",
+ "sorts": Array [
+ "most-recent",
+ "current-phase",
+ "title-a-to-z",
+ "prize-high-to-low",
+ ],
+ },
+ "openForRegistration": Object {
+ "filter": Object {
+ "registrationOpen": true,
+ "started": true,
+ "status": Array [
+ "ACTIVE",
+ ],
+ },
+ "hideCount": false,
+ "name": "Open for registration",
+ "sorts": Array [
+ "most-recent",
+ "time-to-register",
+ "time-to-submit",
+ "num-registrants",
+ "num-submissions",
+ "prize-high-to-low",
+ "title-a-to-z",
+ ],
+ },
+ "past": Object {
+ "filter": Object {
+ "status": Array [
+ "COMPLETED",
+ "PAST",
+ ],
+ },
+ "hideCount": true,
+ "name": "Past challenges",
+ "sorts": Array [
+ "most-recent",
+ "prize-high-to-low",
+ "title-a-to-z",
+ ],
+ },
+ "reviewOpportunities": Object {
+ "filter": Object {},
+ "hideCount": true,
+ "name": "Open for review",
+ "sorts": Array [
+ "review-opportunities-start-date",
+ "review-opportunities-payment",
+ "review-opportunities-title-a-to-z",
+ ],
+ },
+ "savedReviewOpportunitiesFilter": Object {
+ "filter": Object {},
+ "sorts": Array [
+ "review-opportunities-start-date",
+ "review-opportunities-payment",
+ "review-opportunities-title-a-to-z",
+ ],
+ },
+ "upcoming": Object {
+ "filter": Object {
+ "upcoming": true,
+ },
+ "hideCount": true,
+ "name": "Upcoming challenges",
+ "sorts": Array [
+ "most-recent",
+ "prize-high-to-low",
+ "title-a-to-z",
+ ],
+ },
+ },
+ "default": undefined,
+ "getBuckets": [Function],
+ "isReviewOpportunitiesBucket": [Function],
+ "registerBucket": [Function],
+ },
"filter": Object {
"addTrack": [Function],
"combine": [Function],
"default": undefined,
+ "filterByDate": [Function],
"getFilterFunction": [Function],
"getReviewOpportunitiesFilterFunction": [Function],
"mapToBackend": [Function],
+ "newMeta": [Function],
"removeTrack": [Function],
"setEndDate": [Function],
"setReviewOpportunityType": [Function],
@@ -188,6 +345,67 @@ Object {
"setTags": [Function],
"setText": [Function],
},
+ "sort": Object {
+ "SORTS": Object {
+ "CURRENT_PHASE": "current-phase",
+ "MOST_RECENT": "most-recent",
+ "NUM_REGISTRANTS": "num-registrants",
+ "NUM_SUBMISSIONS": "num-submissions",
+ "PRIZE_HIGH_TO_LOW": "prize-high-to-low",
+ "REVIEW_OPPORTUNITIES_PAYMENT": "review-opportunities-payment",
+ "REVIEW_OPPORTUNITIES_START_DATE": "review-opportunities-start-date",
+ "REVIEW_OPPORTUNITIES_TITLE_A_TO_Z": "review-opportunities-title-a-to-z",
+ "TIME_TO_REGISTER": "time-to-register",
+ "TIME_TO_SUBMIT": "time-to-submit",
+ "TITLE_A_TO_Z": "title-a-to-z",
+ },
+ "SORTS_DATA": Object {
+ "current-phase": Object {
+ "func": [Function],
+ "name": "Current phase",
+ },
+ "most-recent": Object {
+ "func": [Function],
+ "name": "Most recent",
+ },
+ "num-registrants": Object {
+ "func": [Function],
+ "name": "# of registrants",
+ },
+ "num-submissions": Object {
+ "func": [Function],
+ "name": "# of submissions",
+ },
+ "prize-high-to-low": Object {
+ "func": [Function],
+ "name": "Prize high to low",
+ },
+ "review-opportunities-payment": Object {
+ "func": [Function],
+ "name": "Payment",
+ },
+ "review-opportunities-start-date": Object {
+ "func": [Function],
+ "name": "Review start date",
+ },
+ "review-opportunities-title-a-to-z": Object {
+ "func": [Function],
+ "name": "Title A-Z",
+ },
+ "time-to-register": Object {
+ "func": [Function],
+ "name": "Time to register",
+ },
+ "time-to-submit": Object {
+ "func": [Function],
+ "name": "Time to submit",
+ },
+ "title-a-to-z": Object {
+ "func": [Function],
+ "name": "Title A-Z",
+ },
+ },
+ },
},
"errors": Object {
"ERROR_ICON_TYPES": Object {
@@ -227,6 +445,7 @@ Object {
"reducers": Object {
"auth": [Function],
"challenge": [Function],
+ "challengeListing": [Function],
"direct": [Function],
"errors": [Function],
"groups": [Function],
@@ -321,11 +540,17 @@ Object {
},
"getApiResponsePayload": [Function],
"getLookerApiResponsePayload": [Function],
+ "processSRM": [Function],
},
"time": Object {
"default": undefined,
"delay": [Function],
"formatDuration": [Function],
},
+ "url": Object {
+ "default": undefined,
+ "removeTrailingSlash": [Function],
+ "updateQuery": [Function],
+ },
}
`;
diff --git a/docs/actions.challenge-listing.md b/docs/actions.challenge-listing.md
new file mode 100644
index 00000000..85843947
--- /dev/null
+++ b/docs/actions.challenge-listing.md
@@ -0,0 +1,271 @@
+
+
+## actions.challenge-listing
+Actions related to Topcoder challenge-listing APIs.
+
+
+* [actions.challenge-listing](#module_actions.challenge-listing)
+ * [.dropChallenges(bucket)](#module_actions.challenge-listing.dropChallenges) ⇒ Action
+ * [.getMoreChallenges(bucket)](#module_actions.challenge-listing.getMoreChallenges) ⇒ Action
+ * [.getAllActiveChallengesInit(uuid)](#module_actions.challenge-listing.getAllActiveChallengesInit) ⇒ Action
+ * [.getAllActiveChallengesDone(uuid, tokenV3)](#module_actions.challenge-listing.getAllActiveChallengesDone) ⇒ Action
+ * [.getActiveChallengesInit(uuid, page, frontFilter, sort, bucket)](#module_actions.challenge-listing.getActiveChallengesInit) ⇒ Action
+ * [.getActiveChallengesDone(
+ uuid, page, backendFilter, tokenV3, frontFilter, sort, bucket,
+)](#module_actions.challenge-listing.getActiveChallengesDone) ⇒ Action
+ * [.getRestActiveChallengesInit(uuid)](#module_actions.challenge-listing.getRestActiveChallengesInit) ⇒ Action
+ * [.getRestActiveChallengesDone(
+ uuid, tokenV3, backendFilter, frontFilter, sort, bucket,
+)](#module_actions.challenge-listing.getRestActiveChallengesDone) ⇒ Action
+ * [.getChallengeSubtracksInit()](#module_actions.challenge-listing.getChallengeSubtrackInit) ⇒ Action
+ * [.getChallengeSubtracksDone()](#module_actions.challenge-listing.getChallengeSubtracksDone) ⇒ Action
+ * [.getChallengeTagsInit()](#module_actions.challenge-listing.getChallengeTagsInit) ⇒ Action
+ * [.getChallengeTagsDone()](#module_actions.challenge-listing.getChallengeTagsDone) ⇒ Action
+ * [.getPastChallengesInit(uuid, page, frontFilter, sort)](#module_actions.challenge-listing.getPastChallengesInit) ⇒ Action
+ * [.getPastChallengesDone(uuid, page, filter, tokenV3, frontFilter, sort)](#module_actions.challenge-listing.getPastChallengesDone) ⇒ Action
+ * [.getReviewOpportunitiesInit(uuid, page, sort)](#module_actions.challenge-listing.getReviewOpportunitiesInit) ⇒ Action
+ * [.getReviewOpportunitiesDone(uuid, page, tokenV3, sort, frontFilter)](#module_actions.challenge-listing.getReviewOpportunitiesDone) ⇒ Action
+ * [.getSrmsInit(uuid)](#module_actions.challenge-listing.getSrmsInit) ⇒ Action
+ * [.getSrmsDone(uuid, handle, params, tokenV3)](#module_actions.challenge-listing.getSrmsDone) ⇒ Action
+ * [.expandTag(id)](#module_actions.challenge-listing.expandTag) ⇒ Action
+ * [.selectCommunity()](#module_actions.challenge-listing.selectCommunity) ⇒ Action
+ * [.setFilter()](#module_actions.challenge-listing.setFilter) ⇒ Action
+ * [.setDatepickerStatus(status)](#module_actions.challenge-listing.setDatepickerStatus) ⇒ Action
+ * [.setSort(bucket, sort)](#module_actions.challenge-listing.setSort) ⇒ Action
+
+
+
+### actions.challenge-listing.dropChallenges(bucket) ⇒ Action
+Creates an action that drops from Redux store all challenges-list related loaded.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| bucket | String
| Bucket name |
+
+
+
+### actions.challenge-listing.getMoreChallenges(bucket) ⇒ Action
+Creates an action that get more challenges of bucket.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| bucket | String
| Bucket name |
+
+
+
+### actions.challenge-listing.getAllActiveChallengesInit(uuid) ⇒ Action
+Creates an action that signals beginning of all active challenges loading.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+
+
+
+### actions.challenge-listing.getAllActiveChallengesInit(uuid, tokenV3) ⇒ Action
+Creates an action that loads all active challenges.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+| tokenV3 | String
| Topcoder v3 auth token. |
+
+
+### actions.challenge-listing.getActiveChallengesInit(uuid, page, frontFilter, sort, bucket) ⇒ Action
+Creates an action that signals beginning of active challenges of bucket loading.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+| page | Number
| Page number of fetch data |
+| frontFilter | Object
| Filter Object from Client |
+| sort | String
| Sort name |
+| bucket | String
| Bucket name |
+
+
+
+### actions.challenge-listing.getActiveChallengesDone(
+ uuid, page, backendFilter, tokenV3, frontFilter, sort, bucket,
+) ⇒ Action
+Creates an action that loads active challenges of bucket.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+| page | Number
| Page number of fetch data |
+| backendFilter | Object
| Filter Object from Backend |
+| tokenV3 | String
| Topcoder v3 auth token |
+| frontFilter | Object
| Filter Object from Client |
+| sort | String
| Sort name |
+| bucket | String
| Bucket name |
+
+
+
+### actions.challenge-listing.getRestActiveChallengesInit(uuid) ⇒ Action
+Creates an action that signals beginning of rest active challenges of bucket loading.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+
+
+
+### actions.challenge-listing.getRestActiveChallengesDone(
+ uuid, tokenV3, backendFilter, frontFilter, sort, bucket,
+) ⇒ Action
+Creates an action that loads rest active challenges of bucket.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+| tokenV3 | String
| Topcoder v3 auth token |
+| backendFilter | Object
| Filter Object from Backend |
+| frontFilter | Object
| Filter Object from Client |
+| sort | String
| Sort name |
+| bucket | String
| Bucket name |
+
+
+
+### actions.challenge-listing.getChallengeSubtracksInit() ⇒ Action
+Creates an action that signals beginning of challenge substrcks loading.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+
+### actions.challenge-listing.getChallengeSubtracksDone()⇒ Action
+Creates an action that loads challenge substrcks.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+
+### actions.challenge-listing.getChallengeTagsInit() ⇒ Action
+Creates an action that signals beginning of challenge tags loading.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+
+### actions.challenge-listing.getChallengeTagsDone()⇒ Action
+Creates an action that loads challenge tags.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+
+### actions.challenge-listing.getPastChallengesInit(uuid, page, frontFilter, sort) ⇒ Action
+Creates an action that signals beginning of past challenges loading.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+| page | Number
| Page number of fetch data |
+| frontFilter | Object
| Filter Object from Client |
+| sort | String
| Sort name |
+
+
+
+### actions.challenge-listing.getPastChallengesDone(uuid, page, filter, tokenV3, frontFilter, sort) ⇒ Action
+Creates an action that loads past challenges.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+| page | Number
| Page number of fetch data |
+| filter | Object
| Filter Object from Backend |
+| tokenV3 | String
| Topcoder v3 auth token |
+| frontFilter | Object
| Filter Object from Client |
+| sort | String
| Sort name |
+
+
+
+### actions.challenge-listing.getReviewOpportunitiesInit(uuid, page, sort) ⇒ Action
+Creates an action that signals beginning of review opportunities loading.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+| page | Number
| Page number of fetch data |
+| sort | String
| Sort name |
+
+
+
+### actions.challenge-listing.getReviewOpportunitiesDone(uuid, page, tokenV3, sort, frontFilter) ⇒ Action
+Creates an action that loads review oportunites.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+| page | Number
| Page number of fetch data |
+| tokenV3 | String
| Topcoder v3 auth token |
+| sort | String
| Sort name |
+| frontFilter | Object
| Filter Object from Client |
+
+
+
+
+### actions.challenge-listing.getSrmsInit(uuid) ⇒ Action
+Creates an action that signals beginning of SRMs loading.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+
+
+### actions.challenge-listing.getSrmsDone(uuid, handle, params, tokenV3) ⇒ Action
+Creates an action that SRMs.
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uuid | String
| UUID of the operation (the same should be passed into the corresponding |
+| handle | String
| Topcoder member handle |
+| params | Object
| params of fetch data |
+| tokenV3 | String
| Topcoder v3 auth token |
+
+
+
+### actions.challenge-listing.expandTag(id) ⇒ Action
+Creates an action that set tag id
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| id | String
| Id of tag |
+
+
+
+### actions.challenge-listing.selectCommunity() ⇒ Action
+Creates an action that pass community id
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+
+### actions.challenge-listing.setFilter() ⇒ Action
+Creates an action that pass filter value
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+
+### actions.challenge-listing.setDatepickerStatus(status) ⇒ Action
+Creates an action that set Datepicker status
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| status | Boolean
| Status datapicker |
+
+
+
+### actions.challenge-listing.setSort(bucket, sort) ⇒ Action
+Creates an action that set sort of bucket
+**Kind**: static method of [actions.challenge-listing
](#module_actions.challenge-listing)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| bucket | String
| Bucket name |
+| sort | String
| Sort name |
diff --git a/docs/buckets.md b/docs/buckets.md
new file mode 100644
index 00000000..80072bd3
--- /dev/null
+++ b/docs/buckets.md
@@ -0,0 +1,50 @@
+
+
+## buckets
+Collection of buckets of challenge
+
+* [challenge_buckets](#module_challenge_buckets)
+ * [.BUCKETS](#module_challenge_buckets.BUCKETS)
+ * [.BUCKET_DATA](#module_challenge_buckets.BUCKET_DATA)
+ * [.getBuckets(res)](#module_challenge_buckets.getBuckets) ⇒ Promise
+ * [.isReviewOpportunitiesBucket(res)](#module_challenge_buckets.isReviewOpportunitiesBucket) ⇒ Promise
+ * [.registerBucket](#module_challenge_buckets.registerBucket)
+
+
+### challenge_buckets.BUCKETS
+Bucket types
+**Kind**: static constant of [challenge_buckets
](#module_challenge_buckets)
+
+
+
+### challenge_buckets.BUCKET_DATA
+The data of bucket
+**Kind**: static constant of [challenge_buckets
](#module_challenge_buckets)
+
+
+
+### challenge_buckets.getBuckets(userHandle) ⇒ Promise
+Returns configuration of all possible challenge buckets.
+**Kind**: static method of [challenge_buckets
](#module_challenge_buckets)
+**Returns**: Promise
- Resolves to the payload.
+
+| Param | Type |
+| --- | --- |
+| res | Object
|
+
+
+
+### challenge_buckets.isReviewOpportunitiesBucket(bucket) ⇒ Promise
+Tests if a given bucket is of any of the Review Opportunities types
+**Kind**: static method of [challenge_buckets
](#module_challenge_buckets)
+**Returns**: Promise
- Resolves to the payload.
+
+| Param | Type |
+| --- | --- |
+| res | Boolean
|
+
+
+### challenge_buckets.registerBucket(id, bucket) ⇒ Promise
+Registers a new bucket.
+**Kind**: static method of [challenge_buckets
](#module_challenge_buckets)
+
diff --git a/docs/index.md b/docs/index.md
index ec065107..185c46d5 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -9,6 +9,11 @@
actions.challenge
Actions related to Topcoder challenges APIs.
+
+
+actions.challenge-listing
+Actions related to Topcoder challenge-listing APIs.
+
actions.direct
Actions related to Direct API: access to projects, billing accounts,
@@ -71,6 +76,11 @@ actions and reducer; thus, this module.
Reducer for actions.challenge actions.
State segment managed by this reducer has the following strcuture:
+
+
+reducers.challenge-listing
+Reducer for actions.challenge-listing actions.
+
reducers.direct
Reducer for handling the results of Direct-related actions.
@@ -275,4 +285,19 @@ the proxy will forward them to the service only if LOG_ENTRIES_TOKEN is set).
Utility functions for time/date related stuff
-
+
+sort
+Collection of challenge sort.
+
+
+
+tc
+Collection of challenge buckets.
+
+
+
+
+url
+Collection of url function.
+
+
diff --git a/docs/reducers.challenge-listing.md b/docs/reducers.challenge-listing.md
new file mode 100644
index 00000000..ff80e6f4
--- /dev/null
+++ b/docs/reducers.challenge-listing.md
@@ -0,0 +1,310 @@
+
+
+## reducers.challenge-listing
+Reducer for [actions.challenge-listing](#module_actions.challenge-listing) actions.
+
+State segment managed by this reducer has the following strcuture:
+
+**Todo**
+
+- [ ] Document the structure.
+
+
+* [reducers.challenge-listing](#module_reducers.challenge-listing)
+ * _static_
+ * [.default](#module_reducers.challenge-listing.default)
+ * [.factory(options)](#module_reducers.challenge-listing.factory) ⇒ Promise
+ * _inner_
+ * [~dropChallenges(state, action)](#module_reducers.challenge-listing..dropChallenges) ⇒ Object
+ * [~getMoreChallenges(state, action)](#module_reducers.challenge-listing..getMoreChallenges) ⇒ Object
+ * [~expandTag(state, action)](#module_reducers.challenge-listing..expandTag) ⇒ Object
+ * [~getAllActiveChallengesInit(state, action)](#module_reducers.challenge-listing..onGetAllActiveChallengesInit) ⇒ Object
+ * [~getAllActiveChallengesDone(state, action)](#module_reducers.challenge-listing..onGetAllActiveChallengesDone) ⇒ Object
+ * [~getActiveChallengesInit(state, action)](#module_reducers.challenge-listing..getActiveChallengesInit) ⇒ Object
+ * [~getActiveChallengesDone(state, action)](#module_reducers.challenge-listing..getActiveChallengesDone) ⇒ Object
+ * [~getRestActiveChallengesInit(state, action)](#module_reducers.challenge-listing..getRestActiveChallengesInit) ⇒ Object
+ * [~getRestActiveChallengesDone(state, action)](#module_reducers.challenge-listing..getRestActiveChallengesDone) ⇒ Object
+ * [~getChallengeSubtracksInit()](#module_reducers.challenge-listing..getChallengeSubtracksInit) ⇒ Object
+ * [~getChallengeSubtracksDone(state, action)](#module_reducers.challenge-listing..getChallengeSubtracksDone) ⇒ Object
+ * [~getChallengeTagsInit()](#module_reducers.challenge-listing..getChallengeTagsInit) ⇒ Object
+ * [~getChallengeTagsDone(state, action)](#module_reducers.challenge-listing..getChallengeTagsDone) ⇒ Object
+ * [~getPastChallengesInit(state, action)](#module_reducers.challenge-listing..getPastChallengesInit) ⇒ Object
+ * [~getReviewOpportunitiesInit(state, action)](#module_reducers.challenge-listing..getReviewOpportunitiesInit) ⇒ Object
+ * [~getReviewOpportunitiesDone(state, action)](#module_reducers.challenge-listing..getReviewOpportunitiesDone) ⇒ Object
+ * [~getSrmsInit(state, action)](#module_reducers.challenge-listing..getSrmsInit) ⇒ Object
+ * [~getSrmsDone(state, action)](#module_reducers.challenge-listing..getSrmsDone) ⇒ Object
+ * [~selectCommunity(state, action)](#module_reducers.challenge-listing..selectCommunity) ⇒ Object
+ * [~setFilter(state, action)](#module_reducers.challenge-listing..setFilter) ⇒ Object
+ * [~setSort(state, action)](#module_reducers.challenge-listing..setSort) ⇒ Object
+ * [~setDatePickerStatus(state, action)](#module_reducers.challenge-listing..setDatePickerStatus) ⇒ Object
+ * [~create(initialState)](#module_reducers.challenge..create) ⇒ function
+
+
+### reducers.challenge-listing.default
+Reducer with default intial state.
+**Kind**: static property of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+
+### reducers.challenge-listing.factory() ⇒ Promise
+Factory which creates a new reducer with its initial state tailored to the
+given options object, if specified (for server-side rendering). If options
+object is not specified, it creates just the default reducer. Accepted options are:
+
+**Kind**: static method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Resolves**: Function(state, action): state
New reducer.
+
+
+### reducers.challenge-listing~dropChallenges(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/DROP_CHALLENGES action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getMoreChallenges(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_MORE_CHALLENGES action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~expandTag(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/EXPAND_TAG action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getAllActiveChallengesInit(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_ALL_ACTIVE_CHALLENGES_INIT action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getAllActiveChallengesDone(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_ALL_ACTIVE_CHALLENGES_DONE action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getActiveChallengesInit(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_ACTIVE_CHALLENGES_INIT action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getActiveChallengesDone(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_ACTIVE_CHALLENGES_DONE action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getRestActiveChallengesInit(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_REST_ACTIVE_CHALLENGES_INIT action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getRestActiveChallengesDone(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_REST_ACTIVE_CHALLENGES_DONE action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getChallengeSubtracksInit() ⇒ Object
+Handles CHALLENGE_LISTING/GET_CHALLENGE_SUBTRACKS_INIT action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+
+### reducers.challenge-listing~getChallengeSubtracksDone(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_CHALLENGE_SUBTRACKS_DONE action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getChallengeTagsInit() ⇒ Object
+Handles CHALLENGE_LISTING/GET_CHALLENGE_TAGS_INIT action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+
+### reducers.challenge-listing~getChallengeTagsDone(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_CHALLENGE_TAGS_DONE action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getPastChallengesInit(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_PAST_CHALLENGES_INIT action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getPastChallengesDone(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_PAST_CHALLENGES_DONE action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| state | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getReviewOpportunitiesInit(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_REVIEW_OPPORTUNITIES_INIT action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| uuid | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getReviewOpportunitiesDone(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_REVIEW_OPPORTUNITIES_DONE action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| uuid | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getSrmsInit(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_SRMS_INIT action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| uuid | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~getSrmsDone(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/GET_SRMS_DONE action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| uuid | Object
|
+| action | Object
|
+
+
+
+### reducers.challenge-listing~selectCommunity(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/SELECT_COMMUNITY action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| uuid | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~setFilter(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/SET_FILTER action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| uuid | Object
|
+| action | Object
|
+
+
+### reducers.challenge-listing~setDatePickerStatus(state, action) ⇒ Object
+Handles CHALLENGE_LISTING/SET_DATEPICKER_STATUS action.
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+
+**Returns**: Object
- New state
+
+| Param | Type |
+| --- | --- |
+| uuid | Object
|
+| action | Object
|
+
+
+
+
+### reducers.challenge-listing~create(initialState) ⇒ function
+Creates a new Challenge-listing reducer with the specified initial state.
+
+**Kind**: inner method of [reducers.challenge-listing
](#module_reducers.challenge-listing)
+**Returns**: function
- Challenge-listing reducer.
+
+| Param | Type | Description |
+| --- | --- | --- |
+| initialState | Object
| Optional. Initial state. |
+
diff --git a/docs/sort.md b/docs/sort.md
new file mode 100644
index 00000000..a7f21d61
--- /dev/null
+++ b/docs/sort.md
@@ -0,0 +1,20 @@
+
+
+## sort
+Collection of challenge list sort
+
+* [challenge_sort](#module_challenge_sort)
+ * [.SORTS](#module_challenge_sort.BSORTS)
+ * [.SORTS_DATA](#module_challenge_sort.SORTS_DATA)
+
+
+
+### challenge_sort.SORTS
+Sort types
+**Kind**: static constant of [challenge_sort
](#module_challenge_sort)
+
+
+
+### challenge_sort.SORTS_DATA
+The data of sort
+**Kind**: static constant of [challenge_sort
](#module_challenge_sort)
diff --git a/docs/tc.md b/docs/tc.md
index 8e060798..1345ed26 100644
--- a/docs/tc.md
+++ b/docs/tc.md
@@ -11,23 +11,34 @@ Collection of small Topcoder-related functions.
* [tc](#module_tc)
* [.REVIEW_OPPORTUNITY_TYPES](#module_tc.REVIEW_OPPORTUNITY_TYPES)
* [.getApiResponsePayload(res)](#module_tc.getApiResponsePayload) ⇒ Promise
+ * [.processSRM(res)](#module_tc.processSRM) ⇒ Promise
### tc.REVIEW_OPPORTUNITY_TYPES
Review Opportunity types
-**Kind**: static constant of [tc
](#module_tc)
+**Kind**: static constant of [tc
](#module_tc)
### tc.getApiResponsePayload(res) ⇒ Promise
-Gets payload from a standard success response from TC v2 API; or throws
+Gets payload from a standard success response from TC API; or throws
an error in case of a failure response.
-**Kind**: static method of [tc
](#module_tc)
+**Kind**: static method of [tc
](#module_tc)
**Returns**: Promise
- Resolves to the payload.
| Param | Type |
| --- | --- |
| res | Object
|
+
+### tc.processSRM(res) ⇒ Promise
+process srm to populate additional infomation
+
+**Kind**: static method of [tc
](#module_tc)
+**Returns**: Promise
- Resolves to the payload.
+
+| Param | Type |
+| --- | --- |
+| res | Object
|
diff --git a/docs/url.md b/docs/url.md
new file mode 100644
index 00000000..acdfb108
--- /dev/null
+++ b/docs/url.md
@@ -0,0 +1,27 @@
+
+
+## url
+Collection of url functions.
+
+* [url](#module_url)
+ * [.updateQuery](#module_url.updateQuery)
+ * [.removeTrailingSlash(res)](#module_url.removeTrailingSlash) ⇒ Promise
+
+
+### url.updateQuery
+If executed client-side (determined in this case by the presence of global
+ * window object), this function updates query section of URL; otherwise does
+ * nothing.
+**Kind**: static method of [tc
](#module_url)
+
+
+
+### url.removeTrailingSlash(res) ⇒ Promise
+Cleans/removes trailing slash from url
+**Kind**: static method of [url
](#module_url)
+**Returns**: Promise
- Resolves to the payload.
+
+| Param | Type |
+| --- | --- |
+| res | String
|
+
diff --git a/src/actions/challenge-listing.js b/src/actions/challenge-listing.js
new file mode 100644
index 00000000..d8acf22a
--- /dev/null
+++ b/src/actions/challenge-listing.js
@@ -0,0 +1,450 @@
+/**
+ * Challenge listing actions.
+ */
+
+import _ from 'lodash';
+import { createActions } from 'redux-actions';
+import { decodeToken } from 'tc-accounts';
+import 'isomorphic-fetch';
+import { processSRM, COMPETITION_TRACKS } from '../utils/tc';
+import { services } from '../services';
+import { errors } from '../utils';
+import * as filterUtil from '../utils/challenge/filter';
+import * as config from '../config';
+
+const { fireErrorMessage } = errors;
+const { getService } = services.challenge;
+const { getReviewOpportunitiesService } = services.reviewOpportunities;
+const { PAGE_SIZE, REVIEW_OPPORTUNITY_PAGE_SIZE } = config;
+
+/**
+ * Process filter
+ * Development challenges having Data Science tech tag, still should be
+ * included into data science track.
+ * @param filter
+ * @returns {string}
+ */
+function processFilter(filter) {
+ const newFilter = _.clone(filter);
+ if (_.has(filter, 'track')
+ && filter.track.includes(COMPETITION_TRACKS.DATA_SCIENCE.toUpperCase())
+ && !filter.track.includes(COMPETITION_TRACKS.DEVELOP.toUpperCase())
+ ) {
+ newFilter.track = `${newFilter.track},${COMPETITION_TRACKS.DEVELOP.toUpperCase()}`;
+ }
+ return newFilter;
+}
+
+/**
+ * Private. Loads from the backend all challenges matching some conditions.
+ * @param {Function} getter Given params object of shape { limit, offset }
+ * loads from the backend at most "limit" challenges, skipping the first
+ * "offset" ones. Returns loaded challenges as an array.
+ * @param {Number} page Optional. Next page of challenges to load.
+ * @param {Array} prev Optional. Challenges loaded so far.
+ */
+function getAll(getter, page = 0, prev) {
+ /* Amount of challenges to fetch in one API call. 50 is the current maximum
+ * amount of challenges the backend returns, event when the larger limit is
+ * explicitely required. */
+ return getter({
+ limit: PAGE_SIZE,
+ offset: page * PAGE_SIZE,
+ }).then((res) => {
+ if (res.challenges.length === 0) {
+ return prev || res;
+ }
+ // parse challenges and meta
+ let current = {};
+ if (prev) {
+ current.challenges = prev.challenges.concat(res.challenges);
+ current.meta = res.meta;
+ } else {
+ current = res;
+ }
+ return getAll(getter, 1 + page, current);
+ });
+}
+
+/**
+ * Gets possible challenge subtracks.
+ * @return {Promise}
+ */
+function getChallengeSubtracksDone() {
+ return getService()
+ .getChallengeSubtracks()
+ .then(res => res.sort((a, b) => a.name.localeCompare(b.name)));
+}
+
+/**
+ * Gets possible challenge tags (technologies).
+ * @return {Promise}
+ */
+function getChallengeTagsDone() {
+ return getService()
+ .getChallengeTags()
+ .then(res => res.map(item => item.name)
+ .sort((a, b) => a.localeCompare(b)));
+}
+
+/**
+ * Notifies about reloading of all active challenges. The UUID is stored in the
+ * state, and only challenges fetched by getAllActiveChallengesDone action with
+ * the same UUID will be accepted into the state.
+ * @param {String} uuid
+ * @param {String} page
+ * @param {Object} frontFilter
+ * @param {String} sort
+ * @param {String} bucket
+ * @return {String}
+ */
+function getActiveChallengesInit(uuid, page, frontFilter, sort, bucket) {
+ return {
+ uuid, page, frontFilter, sort, bucket,
+ };
+}
+
+/** TODO: Inspect if the 2 actions bellow can be removed?
+ * They do duplicate what is done in `getActiveChallengesDone` but fetch all challenges
+ * which was refactored in listing-improve
+ */
+function getAllActiveChallengesInit(uuid) {
+ return uuid;
+}
+function getAllActiveChallengesDone(uuid, tokenV3) {
+ const filter = { status: 'ACTIVE' };
+ const service = getService(tokenV3);
+ const calls = [
+ getAll(params => service.getChallenges(filter, params)),
+ ];
+ let user;
+ if (tokenV3) {
+ user = decodeToken(tokenV3).handle;
+ // Handle any errors on this endpoint so that the non-user specific challenges
+ // will still be loaded.
+ calls.push(getAll(params => service.getUserChallenges(user, filter, params)
+ .catch(() => ({ challenges: [] }))));
+ }
+ return Promise.all(calls).then(([ch, uch]) => {
+ /* uch array contains challenges where the user is participating in
+@@ -111,8 +124,8 @@ function getAllActiveChallengesDone(uuid, tokenV3) {
+ * challenges in an efficient way. */
+ if (uch) {
+ const map = {};
+ uch.challenges.forEach((item) => { map[item.id] = item; });
+ ch.challenges.forEach((item) => {
+ if (map[item.id]) {
+ /* It is fine to reassing, as the array we modifying is created just
+ * above within the same function. */
+ /* eslint-disable no-param-reassign */
+ item.users[user] = true;
+ item.userDetails = map[item.id].userDetails;
+ /* eslint-enable no-param-reassign */
+ }
+ });
+ }
+
+ return { uuid, challenges: ch.challenges };
+ });
+}
+
+/**
+ * Gets 1 page of active challenges (including marathon matches) from the backend.
+ * Once this action is completed any active challenges saved to the state before
+ * will be dropped, and the newly fetched ones will be stored there.
+ * Loading of all challenges wil start in background.
+ * @param {String} uuid
+ * @param {Number} page
+ * @param {Object} backendFilter Backend filter to use.
+ * @param {String} tokenV3 Optional. Topcoder auth token v3. Without token only
+ * public challenges will be fetched. With the token provided, the action will
+ * also fetch private challenges related to this user.
+ * @param {Object} frontFilter
+ * @param {String} sort
+ * @param {String} bucket
+
+ * @return {Promise}
+ */
+function getActiveChallengesDone(
+ uuid, page, backendFilter, tokenV3, frontFilter = {}, sort, bucket,
+) {
+ const filter = processFilter({
+ ...backendFilter,
+ status: 'ACTIVE',
+ });
+
+ const service = getService(tokenV3);
+ const calls = [
+ service.getChallenges(filter, {
+ limit: PAGE_SIZE,
+ offset: page * PAGE_SIZE,
+ }),
+ ];
+ let user;
+ if (tokenV3) {
+ user = decodeToken(tokenV3).handle;
+ // Handle any errors on this endpoint so that the non-user specific challenges
+ // will still be loaded.
+ calls.push(service.getUserChallenges(user, filter, {
+ limit: PAGE_SIZE,
+ offset: page * PAGE_SIZE,
+ }).catch(() => ({ challenges: [] })));
+ }
+ return Promise.all(calls).then(([ch, uch]) => {
+ /* uch array contains challenges where the user is participating in
+ * some role. The same challenge are already listed in res array, but they
+ * are not attributed to the user there. This block of code marks user
+ * challenges in an efficient way. */
+ if (uch) {
+ const map = {};
+ uch.challenges.forEach((item) => { map[item.id] = item; });
+ ch.challenges.forEach((item) => {
+ if (map[item.id]) {
+ /* It is fine to reassing, as the array we modifying is created just
+ * above within the same function. */
+ /* eslint-disable no-param-reassign */
+ item.users[user] = true;
+ item.userDetails = map[item.id].userDetails;
+ /* eslint-enable no-param-reassign */
+ }
+ });
+ }
+
+ let { challenges, meta } = ch;
+ // filter by date range and re-compute meta
+ // we can safely remove the next two lines when backend support date range
+ challenges = filterUtil.filterByDate(challenges, frontFilter);
+ meta = filterUtil.newMeta(meta, challenges, frontFilter);
+ return {
+ uuid,
+ handle: tokenV3 ? user : null,
+ challenges,
+ meta,
+ frontFilter,
+ sort,
+ bucket,
+ tokenV3,
+ };
+ });
+}
+
+/**
+ * Init loading of all challenges
+ * @param {String} uuid
+ */
+function getRestActiveChallengesInit(uuid) {
+ return { uuid };
+}
+
+/**
+ * Loading all challenges
+ * @param {String} uuid
+ * @param {String} tokenV3
+ * @param {Object} backendFilter
+ * @param {Object} frontFilter
+ * @param {String} sort
+ * @param {String} bucket
+ */
+function getRestActiveChallengesDone(
+ uuid, tokenV3, backendFilter, frontFilter, sort, bucket,
+) {
+ const filter = processFilter({
+ ...backendFilter,
+ status: 'ACTIVE',
+ });
+
+ const service = getService(tokenV3);
+ const calls = [
+ getAll(params => service.getChallenges(filter, params), 1),
+ ];
+ let user;
+ if (tokenV3) {
+ user = decodeToken(tokenV3).handle;
+ calls.push(getAll(params => service.getUserChallenges(user, filter, params)
+ .catch(() => ({ challenges: [] }))), 1);
+ }
+ return Promise.all(calls).then(([ch, uch]) => {
+ /* uch array contains challenges where the user is participating in
+ * some role. The same challenge are already listed in res array, but they
+ * are not attributed to the user there. This block of code marks user
+ * challenges in an efficient way. */
+ if (uch) {
+ const map = {};
+ uch.challenges.forEach((item) => { map[item.id] = item; });
+ ch.challenges.forEach((item) => {
+ if (map[item.id]) {
+ /* It is fine to reassing, as the array we modifying is created just
+ * above within the same function. */
+ /* eslint-disable no-param-reassign */
+ item.users[user] = true;
+ item.userDetails = map[item.id].userDetails;
+ /* eslint-enable no-param-reassign */
+ }
+ });
+ }
+
+ let { challenges } = ch;
+ // filter by date range and re-compute meta
+ // we can safely remove the next two lines when backend support date range
+ challenges = filterUtil.filterByDate(challenges, frontFilter);
+ const meta = filterUtil.newMeta(undefined, challenges, frontFilter);
+
+ return {
+ uuid,
+ handle: tokenV3 ? user : null,
+ challenges,
+ frontFilter,
+ meta,
+ sort,
+ bucket,
+ };
+ });
+}
+
+/**
+ * Notifies the state that we are about to load the specified page of past
+ * challenges.
+ * @param {String} uuid
+ * @param {Number} page
+ * @param {Object} frontFilter
+ * @param {String} sort
+ * @return {Object}
+ */
+function getPastChallengesInit(uuid, page, frontFilter, sort) {
+ return {
+ uuid,
+ page,
+ frontFilter,
+ sort,
+ };
+}
+
+/**
+ * Gets the specified page of past challenges (including MMs).
+ * @param {String} uuid
+ * @param {Number} page Page of challenges to fetch.
+ * @param {Object} filter Backend filter to use.
+ * @param {String} tokenV3 Optional. Topcoder auth token v3.
+ * @param {Object} frontFilter Optional. Original frontend filter.
+ * @param {String} sort
+ * @return {Object}
+ */
+function getPastChallengesDone(uuid, page, filter, tokenV3, frontFilter = {}, sort) {
+ const service = getService(tokenV3);
+ const newFilter = processFilter({
+ ...filter,
+ status: 'COMPLETED',
+ });
+ return service.getChallenges(newFilter, {
+ limit: PAGE_SIZE,
+ offset: page * PAGE_SIZE,
+ }).then(({ challenges }) => ({
+ uuid,
+ challenges,
+ frontFilter,
+ sort,
+ }));
+}
+
+/**
+ * Action to get a list of currently open Review Opportunities using V3 API
+ * @param {String} uuid Unique identifier for init/donen instance from shortid module
+ * @param {Number} page Page of review opportunities to fetch.
+ * @param {String} tokenV3 Optional.
+ * @param {String} sort Optional.
+ * @param {Object} frontFilter Optional.
+ * @return {Object} Action object
+ */
+function getReviewOpportunitiesDone(uuid, page, tokenV3, sort, frontFilter = {}) {
+ return getReviewOpportunitiesService(tokenV3)
+ .getReviewOpportunities(REVIEW_OPPORTUNITY_PAGE_SIZE, page * REVIEW_OPPORTUNITY_PAGE_SIZE)
+ .then(loaded => ({
+ uuid, loaded, sort, frontFilter,
+ }))
+ .catch((error) => {
+ fireErrorMessage('Error Getting Review Opportunities', error.content || error);
+ return Promise.reject(error);
+ });
+}
+
+/**
+ * Payload creator for the action that inits the loading of SRMs.
+ * @param {String} uuid
+ * @return {String}
+ */
+function getSrmsInit(uuid) {
+ return uuid;
+}
+
+/**
+ * Payload creator for the action that loads SRMs.
+ * @param {String} uuid
+ * @param {String} handle
+ * @param {Object} params
+ * @param {String} tokenV3
+ */
+function getSrmsDone(uuid, handle, params, tokenV3) {
+ const service = getService(tokenV3);
+ const promises = [service.getSrms(params)];
+ if (handle) {
+ promises.push(service.getUserSrms(handle, params));
+ }
+ return Promise.all(promises).then((data) => {
+ let srms = data[0];
+ const userSrms = data[1];
+ const userSrmsMap = {};
+ _.forEach(userSrms, (srm) => {
+ userSrmsMap[srm.id] = srm;
+ });
+ srms = _.map(srms, (srm) => {
+ if (userSrmsMap[srm.id]) {
+ return processSRM(srm);
+ }
+ return srm;
+ });
+ return { uuid, data: srms };
+ });
+}
+
+export default createActions({
+ CHALLENGE_LISTING: {
+ DROP_CHALLENGES: bucket => ({ bucket }),
+
+ GET_MORE_CHALLENGES: bucket => ({ bucket }),
+
+ GET_ALL_ACTIVE_CHALLENGES_INIT: getAllActiveChallengesInit,
+ GET_ALL_ACTIVE_CHALLENGES_DONE: getAllActiveChallengesDone,
+
+ GET_ACTIVE_CHALLENGES_INIT: getActiveChallengesInit,
+ GET_ACTIVE_CHALLENGES_DONE: getActiveChallengesDone,
+
+ GET_REST_ACTIVE_CHALLENGES_INIT: getRestActiveChallengesInit,
+ GET_REST_ACTIVE_CHALLENGES_DONE: getRestActiveChallengesDone,
+
+ GET_CHALLENGE_SUBTRACKS_INIT: _.noop,
+ GET_CHALLENGE_SUBTRACKS_DONE: getChallengeSubtracksDone,
+
+ GET_CHALLENGE_TAGS_INIT: _.noop,
+ GET_CHALLENGE_TAGS_DONE: getChallengeTagsDone,
+
+ GET_PAST_CHALLENGES_INIT: getPastChallengesInit,
+ GET_PAST_CHALLENGES_DONE: getPastChallengesDone,
+
+ GET_REVIEW_OPPORTUNITIES_INIT: (uuid, page, sort) => ({ uuid, page, sort }),
+ GET_REVIEW_OPPORTUNITIES_DONE: getReviewOpportunitiesDone,
+
+ GET_SRMS_INIT: getSrmsInit,
+ GET_SRMS_DONE: getSrmsDone,
+
+ EXPAND_TAG: id => id,
+
+ /* Pass in community ID. */
+ SELECT_COMMUNITY: _.identity,
+
+ SET_FILTER: _.identity,
+
+ SET_DATEPICKER_STATUS: status => ({ status }),
+
+ SET_SORT: (bucket, sort) => ({ bucket, sort }),
+ },
+});
diff --git a/src/actions/index.js b/src/actions/index.js
index 8b1a241b..db1d6f66 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -13,6 +13,7 @@ import reviewOpportunityActions from './reviewOpportunity';
import lookupActions from './lookup';
import settingsActions from './settings';
import lookerActions from './looker';
+import challengeListingActions from './challenge-listing';
export const actions = {
auth: authActions.auth,
@@ -30,6 +31,7 @@ export const actions = {
lookup: lookupActions.lookup,
settings: settingsActions.settings,
looker: lookerActions.looker,
+ challengeListing: challengeListingActions.challengeListing,
};
export default undefined;
diff --git a/src/config/index.js b/src/config/index.js
new file mode 100644
index 00000000..2a5ab790
--- /dev/null
+++ b/src/config/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+ PAGE_SIZE: 50,
+ REVIEW_OPPORTUNITY_PAGE_SIZE: 1000,
+};
diff --git a/src/index.js b/src/index.js
index a108716a..15b0e7d7 100644
--- a/src/index.js
+++ b/src/index.js
@@ -12,5 +12,5 @@ export { actions } from './actions';
export { services } from './services';
export {
- challenge, logger, errors, tc, time, mock,
+ challenge, logger, errors, tc, time, mock, url,
} from './utils';
diff --git a/src/reducers/challenge-listing.js b/src/reducers/challenge-listing.js
new file mode 100644
index 00000000..b1d87967
--- /dev/null
+++ b/src/reducers/challenge-listing.js
@@ -0,0 +1,848 @@
+/**
+ * Reducer for state.challengeListing.
+ */
+
+import _ from 'lodash';
+import { handleActions } from 'redux-actions';
+import moment from 'moment';
+import { updateQuery } from '../utils/url';
+import { SORTS_DATA } from '../utils/challenge/sort';
+import actions from '../actions/challenge-listing';
+import { logger, errors, challenge as challengeUtils } from '../utils';
+
+const { fireErrorMessage } = errors;
+const { filter: Filter } = challengeUtils;
+const { BUCKETS, BUCKET_DATA, getBuckets } = challengeUtils.buckets;
+
+/**
+ * Process challenge data for bucket
+ * @param handle user handle
+ * @param challenges all challenges
+ * @param loaded fetched challenges of bucket
+ * @param bucket bucket name
+ * @param sorts all sorts data
+ * @param sort sort name
+ * @param filter filter object
+ * @param frontFilter filter object
+ */
+function processBucketData(handle, challenges, loaded, bucket, sorts, sort, filter, frontFilter) {
+ const buckets = _.isEmpty(handle) ? BUCKET_DATA : getBuckets(handle);
+ const data = _.has(challenges, bucket) ? challenges[bucket]
+ .filter(filter)
+ .concat(loaded) : _.clone(loaded);
+
+ const finalFilters = {
+ ...frontFilter,
+ ...buckets[bucket].filter,
+ };
+
+ const bucketFilter = bucket !== BUCKETS.REVIEW_OPPORTUNITIES
+ ? Filter.getFilterFunction(finalFilters)
+ : Filter.getReviewOpportunitiesFilterFunction(finalFilters);
+ const filteredData = [];
+ for (let i = 0; i < data.length; i += 1) {
+ if (bucketFilter(data[i])) {
+ filteredData.push(data[i]);
+ }
+ }
+
+ if (bucket !== BUCKETS.ALL) {
+ if (!_.isEmpty(sort)) {
+ filteredData.sort(SORTS_DATA[sort].func);
+ return filteredData;
+ }
+
+ if (_.has(sorts, bucket)) {
+ filteredData.sort(SORTS_DATA[sorts[bucket]].func);
+ } else {
+ filteredData.sort(SORTS_DATA[BUCKET_DATA[bucket].sorts[0]].func);
+ }
+ }
+
+ return filteredData;
+}
+
+/**
+ * Check the challenges of bucket have been loaded all
+ * @param challenges all challenges
+ * @param bucket bucket name
+ * @param loaded loaded challenges this time
+ * @param data processed data
+ * @returns {boolean}
+ */
+function checkAllLoaded(challenges, bucket, loaded, data) {
+ let isAll = false;
+ if (loaded.length === 0) {
+ isAll = true;
+ } else if (!_.isEmpty(_.get(challenges, bucket))
+ && challenges[bucket].length === data.length) {
+ isAll = true;
+ }
+
+ return isAll;
+}
+
+/** TODO: Inspect if the 2 actions bellow can be removed?
+ * They do duplicate what is done in `getActiveChallengesDone` but fetch all challenges
+ * which was refactored in listing-improve
+ */
+function onGetAllActiveChallengesInit(state, { payload }) {
+ return { ...state, loadingActiveChallengesUUID: payload };
+}
+function onGetAllActiveChallengesDone(state, { error, payload }) {
+ if (error) {
+ logger.error(payload);
+ return state;
+ }
+ const { uuid, challenges: loaded } = payload;
+ if (uuid !== state.loadingActiveChallengesUUID) return state;
+ /* Once all active challenges are fetched from the API, we remove from the
+ * store any active challenges stored there previously, and also any
+ * challenges with IDs matching any challenges loaded now as active. */
+ const ids = new Set();
+ loaded.forEach(item => ids.add(item.id));
+ const challenges = state.challenges
+ .filter(item => item.status !== 'ACTIVE' && !ids.has(item.id))
+ .concat(loaded);
+
+ return {
+ ...state,
+ challenges,
+ lastUpdateOfActiveChallenges: Date.now(),
+ loadingActiveChallengesUUID: '',
+ };
+}
+
+/**
+ * Called when 1st page of ative challenges is loaded from `/challenges` api
+ * @param {*} state
+ * @param {*} param1
+ */
+function onGetActiveChallengesDone(state, { error, payload }) {
+ if (error) {
+ logger.error(payload);
+ return state;
+ }
+ const {
+ uuid, challenges: loaded, sort, bucket, tokenV3, handle, frontFilter,
+ meta,
+ } = payload;
+
+ /* Once all active challenges are fetched from the API, we remove from the
+ * store any active challenges stored there previously, and also any
+ * challenges with IDs matching any challenges loaded now as active. */
+ const ids = new Set();
+ loaded.forEach(item => ids.add(item.id));
+
+ let filter;
+ let newChallenges = {};
+ const otherState = {};
+ switch (bucket) {
+ case BUCKETS.ALL: {
+ if (uuid !== state.loadingActiveChallengesUUID) return state;
+ /* Fetching 0 page of active challenges also drops any active challenges
+ * loaded to the state before. */
+ filter = state.lastRequestedPageOfActiveChallenges
+ ? item => !ids.has(item.id)
+ : item => !ids.has(item.id) && item.status !== 'ACTIVE';
+
+ // my
+ const my = !_.isEmpty(tokenV3) ? processBucketData(
+ handle, state.challenges, loaded, BUCKETS.MY, state.sorts, sort, filter,
+ ) : [];
+ // open for registration
+ const open = processBucketData(
+ handle, state.challenges, loaded, BUCKETS.OPEN_FOR_REGISTRATION, state.sorts, sort, filter,
+ );
+ // ongoing
+ const ongoing = processBucketData(
+ handle, state.challenges, loaded, BUCKETS.ONGOING, state.sorts, sort, filter,
+ );
+ newChallenges = _.clone(state.challenges);
+ newChallenges[BUCKETS.MY] = my;
+ newChallenges[BUCKETS.OPEN_FOR_REGISTRATION] = open;
+ newChallenges[BUCKETS.ONGOING] = ongoing;
+ otherState.loadingActiveChallengesUUID = '';
+ otherState.meta = _.clone(meta);
+ }
+ break;
+ case BUCKETS.MY: {
+ if (uuid !== state.loadingMyChallengesUUID) return state;
+ /* Fetching 0 page of active challenges also drops any active challenges
+ * loaded to the state before. */
+ filter = state.lastRequestedPageOfMyChallenges
+ ? item => !ids.has(item.id)
+ : item => !ids.has(item.id) && item.status !== 'ACTIVE';
+
+ const data = processBucketData(
+ handle, state.challenges, loaded, bucket, state.sorts, sort, filter,
+ );
+ newChallenges = _.cloneDeep(state.challenges);
+ newChallenges[bucket] = data;
+ otherState.loadingMyChallengesUUID = '';
+ otherState.allMyChallengesLoaded = checkAllLoaded(state.challenges, bucket, loaded, data);
+ otherState.gettingMoreMyChallenges = !otherState.allMyChallengesLoaded;
+ otherState.meta = _.clone(meta);
+ /* TODO Due to the meta of backend response is currently not correct,
+/* so should update counts after fetch all challenges of bucket */
+ if (_.get(meta, 'myChallengesCount') !== data.length && otherState.allMyChallengesLoaded) {
+ otherState.meta.myChallengesCount = data.length;
+ otherState.meta.allChallengesCount = meta.allChallengesCount
+ + data.length - meta.myChallengesCount;
+ }
+ }
+ break;
+ case BUCKETS.OPEN_FOR_REGISTRATION: {
+ if (uuid !== state.loadingOpenChallengesUUID) return state;
+ /* Fetching 0 page of active challenges also drops any active challenges
+ * loaded to the state before. */
+ filter = state.lastRequestedPageOfOpenChallenges
+ ? item => !ids.has(item.id)
+ : item => !ids.has(item.id) && item.status !== 'ACTIVE';
+
+ const data = processBucketData(
+ handle, state.challenges, loaded, bucket, state.sorts, sort, filter,
+ );
+
+ newChallenges = _.cloneDeep(state.challenges);
+ newChallenges[bucket] = data;
+ otherState.loadingOpenChallengesUUID = '';
+ otherState.allOpenChallengesLoaded = checkAllLoaded(state.challenges, bucket, loaded, data);
+ otherState.gettingMoreOpenChallenges = !otherState.allOpenChallengesLoaded;
+ otherState.meta = _.clone(meta);
+ /* TODO Due to the meta of backend response is currently not correct,
+ /* so should update counts after fetch all challenges of bucket */
+ if (_.get(meta, 'openChallengesCount') !== data.length && otherState.allOpenChallengesLoaded) {
+ otherState.meta.openChallengesCount = data.length;
+ otherState.meta.allChallengesCount = meta.allChallengesCount
+ + data.length - meta.openChallengesCount;
+ }
+ }
+ break;
+ case BUCKETS.ONGOING: {
+ if (uuid !== state.loadingOnGoingChallengesUUID) return state;
+ /* Fetching 0 page of active challenges also drops any active challenges
+ * loaded to the state before. */
+ filter = state.lastRequestedPageOfOnGoingChallenges
+ ? item => !ids.has(item.id)
+ : item => !ids.has(item.id) && item.status !== 'ACTIVE';
+
+ const data = processBucketData(
+ handle, state.challenges, loaded, bucket, state.sorts, sort, filter,
+ );
+ newChallenges = _.cloneDeep(state.challenges);
+ newChallenges[bucket] = data;
+ otherState.loadingOnGoingChallengesUUID = '';
+ otherState.allOnGoingChallengesLoaded = checkAllLoaded(state.challenges,
+ bucket, loaded, data);
+ otherState.gettingMoreOnGoingChallenges = !otherState.allOnGoingChallengesLoaded;
+ /* TODO Due to the meta of backend response is currently not correct,
+ /* so should update counts after fetch all challenges of bucket */
+ otherState.meta = _.clone(meta);
+ if (_.get(meta, 'ongoingChallengesCount') !== data.length && otherState.allOnGoingChallengesLoaded) {
+ otherState.meta.ongoingChallengesCount = data.length;
+ otherState.meta.allChallengesCount = meta.allChallengesCount
+ + data.length - meta.ongoingChallengesCount;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // all challenges used for other components like sub communities
+ newChallenges[BUCKETS.ALL] = processBucketData(
+ handle, state.challenges, loaded, BUCKETS.ALL, null, null, filter, frontFilter,
+ );
+
+ return {
+ ...state,
+ ...otherState,
+ challenges: newChallenges,
+ lastUpdateOfActiveChallenges: Date.now(),
+ };
+}
+
+/**
+ * Called when loading of 1st page of active challenges is started
+ * @param {*} state
+ * @param {*} param1
+ */
+function onGetActiveChallengesInit(state, { payload }) {
+ const { page, bucket, uuid } = payload;
+ const otherState = {};
+ switch (bucket) {
+ case BUCKETS.ALL:
+ otherState.loadingActiveChallengesUUID = uuid;
+ otherState.lastRequestedPageOfActiveChallenges = page;
+ break;
+ case BUCKETS.MY:
+ otherState.loadingMyChallengesUUID = uuid;
+ otherState.lastRequestedPageOfMyChallenges = page;
+ break;
+ case BUCKETS.OPEN_FOR_REGISTRATION:
+ otherState.loadingOpenChallengesUUID = uuid;
+ otherState.lastRequestedPageOfOpenChallenges = page;
+ break;
+ case BUCKETS.ONGOING:
+ otherState.loadingOnGoingChallengesUUID = uuid;
+ otherState.lastRequestedPageOfOnGoingChallenges = page;
+ break;
+ default:
+ break;
+ }
+
+ return {
+ ...state,
+ ...otherState,
+ };
+}
+function onGetRestActiveChallengesInit(state, { payload }) {
+ return {
+ ...state,
+ loadingRestActiveChallengesUUID: payload.uuid,
+ };
+}
+
+/**
+ * Called when all challenges are loaded
+ * @param {*} state
+ * @param {*} param1
+ */
+function onGetRestActiveChallengesDone(state, { error, payload }) {
+ if (error) {
+ logger.error(payload);
+ return state;
+ }
+ const {
+ uuid, challenges: loaded, meta: newMeta, sort, bucket, handle, frontFilter,
+ } = payload;
+ if (uuid !== state.loadingRestActiveChallengesUUID) return state;
+
+ /* Once all active challenges are fetched from the API, we remove from the
+ * store any active challenges stored there previously, and also any
+ * challenges with IDs matching any challenges loaded now as active. */
+ const ids = new Set();
+ loaded.forEach(item => ids.add(item.id));
+
+ /* Fetching 0 page of active challenges also drops any active challenges
+ * loaded to the state before. */
+ const filter = item => !ids.has(item.id);
+
+ const otherState = {};
+ let newChallenges = {};
+ switch (bucket) {
+ case BUCKETS.MY:
+ case BUCKETS.OPEN_FOR_REGISTRATION:
+ case BUCKETS.ONGOING: {
+ const data = processBucketData(
+ handle, state.challenges, loaded, bucket, state.sorts, sort, filter, frontFilter,
+ );
+ newChallenges = _.cloneDeep(state.challenges);
+ newChallenges[bucket] = data;
+ switch (bucket) {
+ case BUCKETS.MY:
+ otherState.allMyChallengesLoaded = true;
+ otherState.gettingMoreMyChallenges = false;
+ break;
+ case BUCKETS.OPEN_FOR_REGISTRATION:
+ otherState.allOpenChallengesLoaded = true;
+ otherState.gettingMoreOpenChallenges = false;
+ break;
+ case BUCKETS.ONGOING:
+ otherState.allOnGoingChallengesLoaded = true;
+ otherState.gettingMoreOnGoingChallenges = false;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ const meta = newMeta || state.meta;
+
+ return {
+ ...state,
+ challenges: newChallenges,
+ ...otherState,
+ meta,
+ lastUpdateOfActiveChallenges: Date.now(),
+ lastRequestedPageOfActiveChallenges: -1,
+ loadingRestActiveChallengesUUID: '',
+ };
+}
+
+/**
+ * Handles CHALLENGE_LISTING/GET_CHALLENGE_SUBTRACKS_DONE action.
+ * @param {Object} state
+ * @param {Object} action
+ * @return {Object}
+ */
+function onGetChallengeSubtracksDone(state, action) {
+ if (action.error) logger.error(action.payload);
+ return {
+ ...state,
+ challengeSubtracks: action.error ? [] : action.payload,
+ challengeSubtracksMap: action.error ? {} : _.keyBy(action.payload, 'subTrack'),
+ loadingChallengeSubtracks: false,
+ };
+}
+
+/**
+ * Handles CHALLENGE_LISTING/GET_CHALLENGE_TAGS_DONE action.
+ * @param {Object} state
+ * @param {Object} action
+ * @return {Object}
+ */
+function onGetChallengeTagsDone(state, action) {
+ if (action.error) logger.error(action.payload);
+ return {
+ ...state,
+ challengeTags: action.error ? [] : action.payload,
+ loadingChallengeTags: false,
+ };
+}
+
+function onGetPastChallengesInit(state, action) {
+ const { frontFilter, page, uuid } = action.payload;
+ const tracks = frontFilter && frontFilter.tracks;
+ if (tracks && _.isEmpty(tracks)) {
+ return {
+ ...state,
+ allPastChallengesLoaded: true,
+ loadingPastChallengesUUID: '',
+ };
+ }
+
+ return {
+ ...state,
+ lastRequestedPageOfPastChallenges: page,
+ loadingPastChallengesUUID: uuid,
+ };
+}
+
+function onGetPastChallengesDone(state, { error, payload }) {
+ if (error) {
+ logger.error(payload);
+ return state;
+ }
+ const {
+ uuid, challenges: loaded, frontFilter, sort,
+ } = payload;
+ if (uuid !== state.loadingPastChallengesUUID) return state;
+
+ const ids = new Set();
+ loaded.forEach(item => ids.add(item.id));
+
+ /* Fetching 0 page of past challenges also drops any past challenges
+ * loaded to the state before. */
+ const filter = state.lastRequestedPageOfPastChallenges
+ ? item => !ids.has(item.id)
+ : item => !ids.has(item.id) && item.status !== 'COMPLETED' && item.status !== 'PAST';
+
+ const pasts = processBucketData(
+ null, state.challenges, loaded, BUCKETS.PAST, state.sorts, sort, filter, frontFilter,
+ );
+
+ let keepPastPlaceholders = false;
+ if (loaded.length) {
+ const ff = Filter.getFilterFunction(frontFilter);
+ keepPastPlaceholders = pasts.filter(ff).length
+ - (_.has(state.challenges, BUCKETS.PAST)
+ ? state.challenges[BUCKETS.PAST].filter(ff).length : 0) < 10;
+ }
+
+ const newChallenges = _.cloneDeep(state.challenges);
+ newChallenges[BUCKETS.PAST] = pasts;
+
+ return {
+ ...state,
+ allPastChallengesLoaded: loaded.length === 0,
+ challenges: newChallenges,
+ keepPastPlaceholders,
+ loadingPastChallengesUUID: '',
+ };
+}
+
+function onSelectCommunity(state, { payload }) {
+ updateQuery({ communityId: payload || undefined });
+ return {
+ ...state,
+ selectedCommunityId: payload,
+
+ /* Page numbers of past/upcoming challenges depend on the filters. To keep
+ * the code simple we just reset them each time a filter is modified.
+ * (This community selection defines community-specific filter for
+ * challenges). */
+ allPastChallengesLoaded: false,
+ lastRequestedPageOfPastChallenges: -1,
+ };
+}
+
+/**
+ * @param {Object} state
+ * @param {Object} action
+ * @return {Object}
+ */
+function onSetFilter(state, { payload }) {
+ /* Validation of filter parameters: they may come from URL query, thus
+ * validation is not a bad idea. As you may note, at the moment we do not
+ * do it very carefully (many params are not validated). */
+ const filter = _.clone(payload);
+ if (_.isPlainObject(filter.tags)) {
+ filter.tags = _.values(filter.tags);
+ }
+ if (_.isPlainObject(filter.subtracks)) {
+ filter.subtracks = _.values(filter.subtracks);
+ }
+ if (filter.startDate && !moment(filter.startDate).isValid()) {
+ delete filter.startDate;
+ }
+ if (filter.endDate && !moment(filter.endDate).isValid()) {
+ delete filter.endDate;
+ }
+
+ /* Update of URL and generation of the state. */
+ updateQuery({ filter });
+ return {
+ ...state,
+ filter,
+
+ /* Page numbers of past/upcoming challenges depend on the filters. To keep
+ * the code simple we just reset them each time a filter is modified. */
+ allPastChallengesLoaded: false,
+ lastRequestedPageOfPastChallenges: -1,
+ };
+}
+
+/**
+ * Handles CHALLENGE_LISTING/GET_REVIEW_OPPORTUNITIES_INIT action.
+ * @param {Object} state
+ * @param {Object} action Payload will be page, uuid
+ * @return {Object} New state
+ */
+function onGetReviewOpportunitiesInit(state, { payload }) {
+ return {
+ ...state,
+ lastRequestedPageOfReviewOpportunities: payload.page,
+ loadingReviewOpportunitiesUUID: payload.uuid,
+ };
+}
+
+/**
+ * Handles CHALLENGE_LISTING/GET_REVIEW_OPPORTUNITIES_DONE action.
+ * @param {Object} state
+ * @param {Object} action Payload will be JSON from api call and UUID
+ * @return {Object} New state
+ */
+function onGetReviewOpportunitiesDone(state, { payload, error }) {
+ if (error) {
+ return state;
+ }
+
+ const {
+ uuid,
+ loaded,
+ sort,
+ frontFilter,
+ } = payload;
+
+ if (uuid !== state.loadingReviewOpportunitiesUUID) return state;
+
+ const ids = new Set();
+ loaded.forEach(item => ids.add(item.id));
+
+ const filter = item => !ids.has(item.id);
+
+ const reviewOpportunities = processBucketData(
+ null, state, loaded, BUCKETS.REVIEW_OPPORTUNITIES,
+ state.sorts, sort, filter, frontFilter,
+ );
+
+ return {
+ ...state,
+ reviewOpportunities,
+ loadingReviewOpportunitiesUUID: '',
+ allReviewOpportunitiesLoaded: loaded.length === 0,
+ };
+}
+
+/**
+ * Inits the loading of SRMs.
+ * @param {Object} state
+ * @param {String} payload Operation UUID.
+ * @return {Object} New state.
+ */
+function onGetSrmsInit(state, { payload }) {
+ return {
+ ...state,
+ srms: {
+ ...state.srms,
+ loadingUuid: payload,
+ },
+ };
+}
+
+/**
+ * Handles loaded SRMs.
+ * @param {Object} state
+ * @param {Object} action
+ * @return {Object} New state.
+ */
+function onGetSrmsDone(state, { error, payload }) {
+ if (error) {
+ logger.error('Failed to load SRMs', payload);
+ fireErrorMessage('Failed to load SRMs', '');
+ return state;
+ }
+
+ const { uuid, data } = payload;
+ if (state.srms.loadingUuid !== uuid) return state;
+ return {
+ ...state,
+ srms: {
+ data,
+ loadingUuid: '',
+ timestamp: Date.now(),
+ },
+ };
+}
+
+/**
+ * Creates a new Challenge Listing reducer with the specified initial state.
+ * @param {Object} initialState Optional. Initial state.
+ * @return Challenge Listing reducer.
+ */
+function create(initialState) {
+ const a = actions.challengeListing;
+ return handleActions({
+ [a.dropChallenges]: (state, { payload }) => {
+ const { bucket } = payload;
+ const otherState = {};
+ switch (bucket) {
+ case BUCKETS.REVIEW_OPPORTUNITIES:
+ otherState.lastRequestedPageOfReviewOpportunities = -1;
+ otherState.reviewOpportunities = [];
+ otherState.allReviewOpportunitiesLoaded = false;
+ break;
+ case BUCKETS.PAST:
+ otherState.challenges = _.cloneDeep(state.challenges);
+ otherState.lastRequestedPageOfPastChallenges = -1;
+ otherState.challenges.past = [];
+ otherState.allPastChallengesLoaded = false;
+ break;
+ default:
+ otherState.challenges = {};
+ otherState.allMyChallengesLoaded = false;
+ otherState.allOnGoingChallengesLoaded = false;
+ otherState.allOpenChallengesLoaded = false;
+ otherState.allActiveChallengesLoaded = false;
+ otherState.allPastChallengesLoaded = false;
+ otherState.allReviewOpportunitiesLoaded = false;
+ otherState.lastRequestedPageOfActiveChallenges = -1;
+ otherState.lastRequestedPageOfMyChallenges = -1;
+ otherState.lastRequestedPageOfOpenChallenges = -1;
+ otherState.lastRequestedPageOfOnGoingChallenges = -1;
+ otherState.lastRequestedPageOfPastChallenges = -1;
+ otherState.lastRequestedPageOfReviewOpportunities = -1;
+ otherState.lastUpdateOfActiveChallenges = -1;
+ otherState.loadingActiveChallengesUUID = '';
+ otherState.loadingMyChallengesUUID = '';
+ otherState.loadingOpenChallengesUUID = '';
+ otherState.loadingOnGoingChallengesUUID = '';
+ otherState.loadingRestActiveChallengesUUID = '';
+ otherState.loadingPastChallengesUUID = '';
+ otherState.loadingReviewOpportunitiesUUID = '';
+ otherState.reviewOpportunities = [];
+ otherState.meta = {
+ allChallengesCount: 0,
+ myChallengesCount: 0,
+ ongoingChallengesCount: 0,
+ openChallengesCount: 0,
+ totalCount: 0,
+ };
+ break;
+ }
+
+ return ({
+ ...state,
+ ...otherState,
+ });
+ },
+
+ [a.getMoreChallenges]: (state, { payload }) => {
+ const { bucket } = payload;
+ const otherState = {};
+ switch (bucket) {
+ case BUCKETS.MY:
+ otherState.gettingMoreMyChallenges = true;
+ break;
+ case BUCKETS.ONGOING:
+ otherState.gettingMoreOnGoingChallenges = true;
+ break;
+ case BUCKETS.OPEN_FOR_REGISTRATION:
+ otherState.gettingMoreOpenChallenges = true;
+ break;
+ default:
+ break;
+ }
+ return ({
+ ...state,
+ ...otherState,
+ });
+ },
+
+ [a.expandTag]: (state, { payload }) => ({
+ ...state,
+ expandedTags: [...state.expandedTags, payload],
+ }),
+
+ [a.getAllActiveChallengesInit]: onGetAllActiveChallengesInit,
+ [a.getAllActiveChallengesDone]: onGetAllActiveChallengesDone,
+
+ [a.getActiveChallengesInit]: onGetActiveChallengesInit,
+ [a.getActiveChallengesDone]: onGetActiveChallengesDone,
+
+ [a.getRestActiveChallengesInit]: onGetRestActiveChallengesInit,
+ [a.getRestActiveChallengesDone]: onGetRestActiveChallengesDone,
+
+ [a.getChallengeSubtracksInit]: state => ({
+ ...state,
+ loadingChallengeSubtracks: true,
+ }),
+ [a.getChallengeSubtracksDone]: onGetChallengeSubtracksDone,
+
+ [a.getChallengeTagsInit]: state => ({
+ ...state,
+ loadingChallengeTags: true,
+ }),
+ [a.getChallengeTagsDone]: onGetChallengeTagsDone,
+
+ [a.getPastChallengesInit]: onGetPastChallengesInit,
+ [a.getPastChallengesDone]: onGetPastChallengesDone,
+
+ [a.getReviewOpportunitiesInit]: onGetReviewOpportunitiesInit,
+ [a.getReviewOpportunitiesDone]: onGetReviewOpportunitiesDone,
+
+ [a.getSrmsInit]: onGetSrmsInit,
+ [a.getSrmsDone]: onGetSrmsDone,
+
+ [a.selectCommunity]: onSelectCommunity,
+
+ [a.setFilter]: onSetFilter,
+ [a.setSort]: (state, { payload }) => {
+ const otherState = {};
+ switch (payload.bucket) {
+ case BUCKETS.PAST:
+ otherState.lastRequestedPageOfPastChallenges = -1;
+ break;
+ case BUCKETS.MY:
+ case BUCKETS.OPEN_FOR_REGISTRATION:
+ case BUCKETS.ONGOING:
+ otherState.lastRequestedPageOfActiveChallenges = -1;
+ break;
+ case BUCKETS.REVIEW_OPPORTUNITIES:
+ otherState.lastRequestedPageOfReviewOpportunities = -1;
+ break;
+ default:
+ break;
+ }
+ return ({
+ ...state,
+ ...otherState,
+ sorts: {
+ ...state.sorts,
+ [payload.bucket]: payload.sort,
+ },
+ });
+ },
+
+ [a.setDatePickerStatus]: (state, { payload }) => {
+ const { status } = payload;
+ return ({
+ ...state,
+ datepickerOpen: status,
+ });
+ },
+ }, _.defaults(_.clone(initialState) || {}, {
+ allMyChallengesLoaded: false,
+ allOnGoingChallengesLoaded: false,
+ allOpenChallengesLoaded: false,
+ allActiveChallengesLoaded: false,
+ allPastChallengesLoaded: false,
+ allReviewOpportunitiesLoaded: false,
+
+ challenges: {},
+ challengeSubtracks: [],
+ challengeSubtracksMap: {},
+ challengeTags: [],
+
+ expandedTags: [],
+
+ gettingMoreChallenges: false,
+ gettingMoreMyChallenges: false,
+ gettingMoreOnGoingChallenges: false,
+ gettingMoreOpenChallenges: false,
+
+ filter: {},
+
+ keepPastPlaceholders: false,
+
+ lastRequestedPageOfActiveChallenges: -1,
+ lastRequestedPageOfMyChallenges: -1,
+ lastRequestedPageOfOnGoingChallenges: -1,
+ lastRequestedPageOfOpenChallenges: -1,
+ lastRequestedPageOfPastChallenges: -1,
+ lastRequestedPageOfReviewOpportunities: -1,
+ lastUpdateOfActiveChallenges: 0,
+
+ loadingActiveChallengesUUID: '',
+ loadingMyChallengesUUID: '',
+ loadingOnGoingChallengesUUID: '',
+ loadingOpenChallengesUUID: '',
+ loadingRestActiveChallengesUUID: '',
+ loadingPastChallengesUUID: '',
+ loadingReviewOpportunitiesUUID: '',
+
+ loadingChallengeSubtracks: false,
+ loadingChallengeTags: false,
+
+ reviewOpportunities: [],
+
+ selectedCommunityId: '',
+
+ sorts: {},
+
+ srms: {
+ data: [],
+ loadingUuid: '',
+ timestamp: 0,
+ },
+
+ meta: {
+ allChallengesCount: 0,
+ myChallengesCount: 0,
+ ongoingChallengesCount: 0,
+ openChallengesCount: 0,
+ totalCount: 0,
+ },
+
+ datepickerOpen: false,
+ }));
+}
+
+/**
+ * The factory creates the new reducer with initial state tailored to the given
+ * ExpressJS HTTP request, if specified (for server-side rendering). If no HTTP
+ * request is specified, it creates the default reducer.
+ * @return {Promise} Resolves to the new reducer.
+ */
+export function factory() {
+ return Promise.resolve(create());
+}
+
+/* Default reducer with empty initial state. */
+export default create();
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 15fd144c..aee34c61 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -22,6 +22,7 @@ import settings, { factory as settingsFactory }
from './settings';
import looker, { factory as lookerFactory }
from './looker';
+import challengeListing, { factory as challengeListingFactory } from './challenge-listing';
export function factory(options) {
@@ -41,6 +42,7 @@ export function factory(options) {
mySubmissionsManagement: mySubmissionsManagementFactory(options),
settings: settingsFactory(options),
looker: lookerFactory(options),
+ challengeListing: challengeListingFactory(options),
});
}
@@ -60,4 +62,5 @@ export default ({
mySubmissionsManagement,
settings,
looker,
+ challengeListing,
});
diff --git a/src/services/challenges.js b/src/services/challenges.js
index 604a2879..04244726 100644
--- a/src/services/challenges.js
+++ b/src/services/challenges.js
@@ -244,10 +244,10 @@ class ChallengesService {
params = {},
) => {
const query = {
- filter: qs.stringify(filters, { encode: false }),
+ filter: qs.stringify(filters, { encode: false }).replace('&', '%26'),
...params,
};
- const url = `${endpoint}?${qs.stringify(query)}`;
+ const url = `${endpoint}?${qs.stringify(query, { encode: false })}`;
const res = await this.private.api.get(url).then(checkError);
return {
challenges: res.content || [],
diff --git a/src/utils/challenge/buckets.js b/src/utils/challenge/buckets.js
new file mode 100644
index 00000000..d9e9221c
--- /dev/null
+++ b/src/utils/challenge/buckets.js
@@ -0,0 +1,153 @@
+/**
+ * Standard challenge buckets
+ */
+
+import _ from 'lodash';
+import { SORTS } from './sort';
+
+export const BUCKETS = {
+ ALL: 'all',
+ MY: 'my',
+ OPEN_FOR_REGISTRATION: 'openForRegistration',
+ ONGOING: 'ongoing',
+ PAST: 'past',
+ SAVED_FILTER: 'saved-filter',
+ UPCOMING: 'upcoming',
+ REVIEW_OPPORTUNITIES: 'reviewOpportunities',
+ SAVED_REVIEW_OPPORTUNITIES_FILTER: 'savedReviewOpportunitiesFilter',
+};
+
+export const BUCKET_DATA = {
+ [BUCKETS.ALL]: {
+ filter: {
+ started: true,
+ status: ['ACTIVE'],
+ },
+ hideCount: false,
+ name: 'All Challenges',
+ sorts: [],
+ },
+ [BUCKETS.MY]: {
+ filter: {
+ started: true,
+ status: ['ACTIVE'],
+ },
+ hideCount: false,
+ name: 'My Challenges',
+ sorts: [
+ SORTS.MOST_RECENT,
+ SORTS.TIME_TO_SUBMIT,
+ SORTS.NUM_REGISTRANTS,
+ SORTS.NUM_SUBMISSIONS,
+ SORTS.PRIZE_HIGH_TO_LOW,
+ SORTS.TITLE_A_TO_Z,
+ ],
+ },
+ [BUCKETS.OPEN_FOR_REGISTRATION]: {
+ filter: {
+ registrationOpen: true,
+ started: true,
+ status: ['ACTIVE'],
+ },
+ hideCount: false,
+ name: 'Open for registration',
+ sorts: [
+ SORTS.MOST_RECENT,
+ SORTS.TIME_TO_REGISTER,
+ SORTS.TIME_TO_SUBMIT,
+ SORTS.NUM_REGISTRANTS,
+ SORTS.NUM_SUBMISSIONS,
+ SORTS.PRIZE_HIGH_TO_LOW,
+ SORTS.TITLE_A_TO_Z,
+ ],
+ },
+ [BUCKETS.ONGOING]: {
+ filter: {
+ registrationOpen: false,
+ started: true,
+ status: ['ACTIVE'],
+ },
+ hideCount: false,
+ name: 'Ongoing challenges',
+ sorts: [
+ SORTS.MOST_RECENT,
+ SORTS.CURRENT_PHASE,
+ SORTS.TITLE_A_TO_Z,
+ SORTS.PRIZE_HIGH_TO_LOW,
+ ],
+ },
+ [BUCKETS.UPCOMING]: {
+ filter: {
+ upcoming: true,
+ },
+ hideCount: true,
+ name: 'Upcoming challenges',
+ sorts: [
+ SORTS.MOST_RECENT,
+ SORTS.PRIZE_HIGH_TO_LOW,
+ SORTS.TITLE_A_TO_Z,
+ ],
+ },
+ [BUCKETS.PAST]: {
+ filter: { status: ['COMPLETED', 'PAST'] },
+ hideCount: true,
+ name: 'Past challenges',
+ sorts: [
+ SORTS.MOST_RECENT,
+ SORTS.PRIZE_HIGH_TO_LOW,
+ SORTS.TITLE_A_TO_Z,
+ ],
+ },
+ [BUCKETS.REVIEW_OPPORTUNITIES]: {
+ filter: {},
+ hideCount: true,
+ name: 'Open for review',
+ sorts: [
+ SORTS.REVIEW_OPPORTUNITIES_START_DATE,
+ SORTS.REVIEW_OPPORTUNITIES_PAYMENT,
+ SORTS.REVIEW_OPPORTUNITIES_TITLE_A_TO_Z,
+ ],
+ },
+ [BUCKETS.SAVED_REVIEW_OPPORTUNITIES_FILTER]: {
+ filter: {},
+ sorts: [
+ SORTS.REVIEW_OPPORTUNITIES_START_DATE,
+ SORTS.REVIEW_OPPORTUNITIES_PAYMENT,
+ SORTS.REVIEW_OPPORTUNITIES_TITLE_A_TO_Z,
+ ],
+ },
+};
+
+/**
+ * Returns configuration of all possible challenge buckets.
+ * @param {String} userHandle Handle of the authenticated
+ * user to filter out My Challenges.
+ */
+export function getBuckets(userHandle) {
+ const res = _.cloneDeep(BUCKET_DATA);
+ res[BUCKETS.MY].filter.users = [userHandle];
+ return res;
+}
+
+/**
+ * Tests if a given bucket is of any of the Review Opportunities types
+ * @param {String} bucket The bucket in question
+ * @return {Boolean} True if the bucket contains Review Opportunities
+ */
+export const isReviewOpportunitiesBucket = bucket => (
+ bucket === BUCKETS.REVIEW_OPPORTUNITIES || bucket === BUCKETS.SAVED_REVIEW_OPPORTUNITIES_FILTER);
+
+/**
+ * Registers a new bucket.
+ * @param {String} id
+ * @param {Object} bucket
+ */
+export function registerBucket(id, bucket) {
+ if (BUCKET_DATA[id]) {
+ throw new Error('Bucket ID clush with an existing bucket');
+ }
+ BUCKETS[id] = id;
+ BUCKET_DATA[id] = bucket;
+}
+
+export default undefined;
diff --git a/src/utils/challenge/filter.js b/src/utils/challenge/filter.js
index 28e00654..bdd343af 100644
--- a/src/utils/challenge/filter.js
+++ b/src/utils/challenge/filter.js
@@ -177,6 +177,39 @@ function filterByUsers(challenge, state) {
return state.users.find(user => challenge.users[user]);
}
+/**
+ * [filterByDate filter challenges by date reange]
+ * @param {[type]} challenges input challenges
+ * @param {[type]} filter filter including startDate and endDate
+ * @return {[type]} filtered challenges array
+ */
+export function filterByDate(challenges, filter) {
+ let cs = challenges.filter(c => filterByStartDate(c, filter));
+ cs = cs.filter(c => filterByEndDate(c, filter));
+ return cs;
+}
+
+/**
+ * [newMeta compute new meta via challenges and filter]
+ * @param {[type]} meta old meta
+ * @param {[type]} challenges input challenges
+ * @param {[type]} filter filter including startDate and end endDate
+ * @return {[type]} new meta
+ */
+export function newMeta(meta, challenges, filter) {
+ if (!filter.startDate && !filter.endDate) {
+ return meta;
+ }
+ const m = {
+ };
+ m.allChallengesCount = challenges.length;
+ m.openChallengesCount = challenges.filter(c => c.registrationOpen === 'Yes').length;
+ m.ongoingChallengesCount = m.allChallengesCount - m.openChallengesCount;
+ m.myChallengesCount = challenges.filter(c => c.user && !_.isEmpty(c.user)).length;
+ m.totalCount = challenges.length;
+ return m;
+}
+
/**
* Returns clone of the state with the specified competition track added.
* @param {Object} state
diff --git a/src/utils/challenge/sort.js b/src/utils/challenge/sort.js
new file mode 100644
index 00000000..4091b0c0
--- /dev/null
+++ b/src/utils/challenge/sort.js
@@ -0,0 +1,84 @@
+/**
+ * Collection of compare function to sort challenges in different ways.
+ */
+
+import moment from 'moment';
+import { sumBy } from 'lodash';
+
+export const SORTS = {
+ CURRENT_PHASE: 'current-phase',
+ MOST_RECENT: 'most-recent',
+ NUM_REGISTRANTS: 'num-registrants',
+ NUM_SUBMISSIONS: 'num-submissions',
+ PRIZE_HIGH_TO_LOW: 'prize-high-to-low',
+ TIME_TO_REGISTER: 'time-to-register',
+ TIME_TO_SUBMIT: 'time-to-submit',
+ TITLE_A_TO_Z: 'title-a-to-z',
+ REVIEW_OPPORTUNITIES_TITLE_A_TO_Z: 'review-opportunities-title-a-to-z',
+ REVIEW_OPPORTUNITIES_PAYMENT: 'review-opportunities-payment',
+ REVIEW_OPPORTUNITIES_START_DATE: 'review-opportunities-start-date',
+};
+
+export const SORTS_DATA = {
+ [SORTS.CURRENT_PHASE]: {
+ func: (a, b) => a.status.localeCompare(b.status),
+ name: 'Current phase',
+ },
+ [SORTS.MOST_RECENT]: {
+ func: (a, b) => moment(b.registrationStartDate).diff(a.registrationStartDate),
+ name: 'Most recent',
+ },
+ [SORTS.NUM_REGISTRANTS]: {
+ func: (a, b) => b.numRegistrants - a.numRegistrants,
+ name: '# of registrants',
+ },
+ [SORTS.NUM_SUBMISSIONS]: {
+ func: (a, b) => b.numSubmissions - a.numSubmissions,
+ name: '# of submissions',
+ },
+ [SORTS.PRIZE_HIGH_TO_LOW]: {
+ func: (a, b) => b.totalPrize - a.totalPrize,
+ name: 'Prize high to low',
+ },
+ [SORTS.TIME_TO_REGISTER]: {
+ func: (a, b) => moment(a.registrationEndDate || a.submissionEndDate)
+ .diff(b.registrationEndDate || b.submissionEndDate),
+ name: 'Time to register',
+ },
+ [SORTS.TIME_TO_SUBMIT]: {
+ func: (a, b) => {
+ function nextSubEndDate(o) {
+ if (o.checkpointSubmissionEndDate && moment(o.checkpointSubmissionEndDate).isAfter()) {
+ return o.checkpointSubmissionEndDate;
+ }
+ return o.submissionEndDate;
+ }
+
+ const aDate = nextSubEndDate(a);
+ const bDate = nextSubEndDate(b);
+
+ if (moment(aDate).isBefore()) return 1;
+ if (moment(bDate).isBefore()) return -1;
+
+ return moment(aDate).diff(bDate);
+ },
+ name: 'Time to submit',
+ },
+ [SORTS.TITLE_A_TO_Z]: {
+ func: (a, b) => a.name.localeCompare(b.name),
+ name: 'Title A-Z',
+ },
+ [SORTS.REVIEW_OPPORTUNITIES_TITLE_A_TO_Z]: {
+ func: (a, b) => a.challenge.title.localeCompare(b.challenge.title),
+ name: 'Title A-Z',
+ },
+ [SORTS.REVIEW_OPPORTUNITIES_PAYMENT]: {
+ func: (a, b) => sumBy(b.payments, 'payment') - sumBy(a.payments, 'payment'),
+ name: 'Payment',
+ },
+ [SORTS.REVIEW_OPPORTUNITIES_START_DATE]: {
+ // This will implicitly use moment#valueOf
+ func: (a, b) => moment(a.startDate) - moment(b.startDate),
+ name: 'Review start date',
+ },
+};
diff --git a/src/utils/index.js b/src/utils/index.js
index b63d63b8..e7e4ff52 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -7,9 +7,14 @@ import * as time from './time';
import * as mock from './mock';
import * as errors from './errors';
import * as filter from './challenge/filter';
+import * as buckets from './challenge/buckets';
+import * as sort from './challenge/sort';
+import * as url from './url';
const challenge = {
filter,
+ buckets,
+ sort,
};
export {
@@ -19,4 +24,5 @@ export {
time,
mock,
errors,
+ url,
};
diff --git a/src/utils/tc.js b/src/utils/tc.js
index 77fce85a..08309d16 100644
--- a/src/utils/tc.js
+++ b/src/utils/tc.js
@@ -4,6 +4,9 @@
* @todo More TC-related utils should be moved here from Community-app.
*/
+import _ from 'lodash';
+import moment from 'moment';
+
/**
* Codes of the Topcoder communities.
*/
@@ -60,3 +63,47 @@ export async function getLookerApiResponsePayload(res) {
status: x.status,
};
}
+
+/**
+ * process srm to populate additional infomation
+ * adopt from topcoder-app repo
+ * @param {Object} s srm to process
+ * @return {Object} processed srm
+ */
+export function processSRM(s) {
+ const srm = _.cloneDeep(s);
+ srm.userStatus = 'registered';
+ if (Array.isArray(srm.rounds) && srm.rounds.length) {
+ if (srm.rounds[0].userSRMDetails && srm.rounds[0].userSRMDetails.rated) {
+ srm.result = srm.rounds[0].userSRMDetails;
+ }
+ if (srm.rounds[0].codingStartAt) {
+ srm.codingStartAt = srm.rounds[0].codingStartAt;
+ }
+ if (srm.rounds[0].codingEndAt) {
+ srm.codingEndAt = srm.rounds[0].codingEndAt;
+ }
+ if (srm.rounds[0].registrationStartAt) {
+ srm.registrationStartAt = srm.rounds[0].registrationStartAt;
+ }
+ if (srm.rounds[0].registrationEndAt) {
+ srm.registrationEndAt = srm.rounds[0].registrationEndAt;
+ }
+ }
+
+ // determines if the current phase is registration
+ let start = moment(srm.registrationStartAt).unix();
+ let end = moment(srm.registrationEndAt).unix();
+ let now = moment().unix();
+ if (start <= now && end >= now) {
+ srm.currentPhase = 'REGISTRATION';
+ }
+ // determines if the current phase is coding
+ start = moment(srm.codingStartAt).unix();
+ end = moment(srm.codingEndAt).unix();
+ now = moment().unix();
+ if (start <= now && end >= now) {
+ srm.currentPhase = 'CODING';
+ }
+ return srm;
+}
diff --git a/src/utils/url.js b/src/utils/url.js
new file mode 100644
index 00000000..73154aa7
--- /dev/null
+++ b/src/utils/url.js
@@ -0,0 +1,49 @@
+/**
+ * Various URL-related functions.
+ */
+
+/* global window */
+
+import _ from 'lodash';
+import qs from 'qs';
+import { isomorphy } from 'topcoder-react-utils';
+
+/**
+ * If executed client-side (determined in this case by the presence of global
+ * window object), this function updates query section of URL; otherwise does
+ * nothing.
+ * @param {Object} update Specifies the update to make. Current query will be
+ * parsed into JS object, then update will be merged into that object, and the
+ * result will be pushed back to the query section of URL. I.e. to unset some
+ * field of the query, that field should be explicitely mentioned inside
+ * 'update' as undefined.
+ */
+export function updateQuery(update) {
+ if (isomorphy.isServerSide()) return;
+
+ let query = qs.parse(window.location.search.slice(1));
+
+ /* _.merge won't work here, because it just ignores the fields explicitely
+ * set as undefined in the objects to be merged, rather than deleting such
+ * fields in the target object. */
+ _.forIn(update, (value, key) => {
+ if (_.isUndefined(value)) delete query[key];
+ else query[key] = value;
+ });
+ query = `?${qs.stringify(query, { encodeValuesOnly: true })}`;
+ window.history.replaceState(window.history.state, '', query);
+}
+
+/**
+ * Cleans/removes trailing slash from url
+ *
+ * @param {String} url The url to clean
+ * @return {String}
+ */
+export function removeTrailingSlash(url) {
+ return url.charAt(url.length - 1) === '/'
+ ? url.slice(0, -1)
+ : url;
+}
+
+export default undefined;
From c76aaa1ec7203a8ce2f709d3bc3ebb32cb6e8add Mon Sep 17 00:00:00 2001
From: Huan Li
Date: Sun, 28 Apr 2019 00:13:04 +0800
Subject: [PATCH 02/15] Update _tests_/_snapshots_
---
__tests__/__snapshots__/index.js.snap | 3 +++
1 file changed, 3 insertions(+)
diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap
index e7ee51bc..0386661f 100644
--- a/__tests__/__snapshots__/index.js.snap
+++ b/__tests__/__snapshots__/index.js.snap
@@ -426,14 +426,17 @@ Object {
"countReset": [Function],
"debug": [Function],
"dir": [Function],
+ "dirxml": [Function],
"error": [Function],
"group": [Function],
"groupCollapsed": [Function],
"groupEnd": [Function],
"info": [Function],
"log": [Function],
+ "table": [Function],
"time": [Function],
"timeEnd": [Function],
+ "timeLog": [Function],
"trace": [Function],
"warn": [Function],
},
From fc0f961f699d138e434bf361a25069e84dfbf729 Mon Sep 17 00:00:00 2001
From: Huan Li
Date: Sun, 28 Apr 2019 10:28:35 +0800
Subject: [PATCH 03/15] Update _tests_/_snapshots
---
__tests__/__snapshots__/index.js.snap | 3 ---
1 file changed, 3 deletions(-)
diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap
index 0386661f..e7ee51bc 100644
--- a/__tests__/__snapshots__/index.js.snap
+++ b/__tests__/__snapshots__/index.js.snap
@@ -426,17 +426,14 @@ Object {
"countReset": [Function],
"debug": [Function],
"dir": [Function],
- "dirxml": [Function],
"error": [Function],
"group": [Function],
"groupCollapsed": [Function],
"groupEnd": [Function],
"info": [Function],
"log": [Function],
- "table": [Function],
"time": [Function],
"timeEnd": [Function],
- "timeLog": [Function],
"trace": [Function],
"warn": [Function],
},
From af685a23e9eaf6cb6f63b40de045e2e1604f8279 Mon Sep 17 00:00:00 2001
From: Sushil
Date: Mon, 29 Apr 2019 15:32:15 +0530
Subject: [PATCH 04/15] upgrading topcoder-react-lib version
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index cc4ec5c2..d65f4707 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
"lint:js": "./node_modules/.bin/eslint --ext .js,.jsx .",
"test": "npm run lint && npm run jest"
},
- "version": "0.7.11",
+ "version": "0.7.12",
"dependencies": {
"auth0-js": "^6.8.4",
"isomorphic-fetch": "^2.2.1",
From e91a940c1bb79887c9a26c5dbe06874b48fa9ea8 Mon Sep 17 00:00:00 2001
From: Huan Li
Date: Tue, 30 Apr 2019 22:14:01 +0800
Subject: [PATCH 05/15] Update filter object when fetch challenges.
If filter's track has DATA_SCIENCE, should add subTrack DEVELOP_MARATHON_MATCH and remove DS track from filter object.
---
src/actions/challenge-listing.js | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/actions/challenge-listing.js b/src/actions/challenge-listing.js
index d8acf22a..ad872794 100644
--- a/src/actions/challenge-listing.js
+++ b/src/actions/challenge-listing.js
@@ -19,8 +19,8 @@ const { PAGE_SIZE, REVIEW_OPPORTUNITY_PAGE_SIZE } = config;
/**
* Process filter
- * Development challenges having Data Science tech tag, still should be
- * included into data science track.
+ * When filter includes Data Science track, still should be
+ * included DEVELOP_MARATHON_MATCH sub track.
* @param filter
* @returns {string}
*/
@@ -28,9 +28,15 @@ function processFilter(filter) {
const newFilter = _.clone(filter);
if (_.has(filter, 'track')
&& filter.track.includes(COMPETITION_TRACKS.DATA_SCIENCE.toUpperCase())
- && !filter.track.includes(COMPETITION_TRACKS.DEVELOP.toUpperCase())
+ && ((_.has(filter, 'subTrack') && !filter.subTrack.includes('DEVELOP_MARATHON_MATCH'))
+ || !_.has(filter, 'subTrack'))
) {
- newFilter.track = `${newFilter.track},${COMPETITION_TRACKS.DEVELOP.toUpperCase()}`;
+ newFilter.subTrack = `${_.has(filter, 'subTrack') ? `${newFilter.subTrack},DEVELOP_MARATHON_MATCH` : 'DEVELOP_MARATHON_MATCH'}`;
+ newFilter.track = _.remove(filter.track.split(','), item => item.toUpperCase() !== COMPETITION_TRACKS.DATA_SCIENCE.toUpperCase()).join(',');
+
+ if (_.isEmpty(newFilter.track)) {
+ delete newFilter.track;
+ }
}
return newFilter;
}
From f8f8bd8ee609c0303c254fdf5b96b7044b352413 Mon Sep 17 00:00:00 2001
From: Thomas Kranitsas
Date: Tue, 30 Apr 2019 17:23:05 +0300
Subject: [PATCH 06/15] Bump npm version
---
package-lock.json | 1634 +++++++++++++++++++++++++++++++++++++++++----
package.json | 2 +-
2 files changed, 1515 insertions(+), 121 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index c1a94426..1a483aee 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "topcoder-react-lib",
- "version": "0.7.11",
+ "version": "0.7.13",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -714,8 +714,7 @@
"abab": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz",
- "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==",
- "dev": true
+ "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w=="
},
"abbrev": {
"version": "1.1.1",
@@ -735,8 +734,7 @@
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
- "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
- "dev": true
+ "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
},
"acorn-dynamic-import": {
"version": "3.0.0",
@@ -852,6 +850,16 @@
"integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=",
"dev": true
},
+ "align-text": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+ "requires": {
+ "kind-of": "^3.0.2",
+ "longest": "^1.0.1",
+ "repeat-string": "^1.5.2"
+ }
+ },
"alphanum-sort": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
@@ -861,8 +869,7 @@
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
- "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
- "dev": true
+ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
},
"ansi-colors": {
"version": "3.2.1",
@@ -925,6 +932,216 @@
"default-require-extensions": "^1.0.0"
}
},
+ "appirio-tech-api-schemas": {
+ "version": "5.0.70",
+ "resolved": "https://registry.npmjs.org/appirio-tech-api-schemas/-/appirio-tech-api-schemas-5.0.70.tgz",
+ "integrity": "sha1-3RtCG/rw8PSokKRTgHSlVYDQy8s=",
+ "requires": {
+ "auto-config-fake-server": "2.x.x"
+ }
+ },
+ "appirio-tech-client-app-layer": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/appirio-tech-client-app-layer/-/appirio-tech-client-app-layer-0.1.3.tgz",
+ "integrity": "sha1-uO5YdHMM2r209RE8NMQvwOsxoOs=",
+ "requires": {
+ "axios": "^0.8.1",
+ "history": "^1.17.0",
+ "html-webpack-plugin": "^1.7.0",
+ "humps": "^0.6.0",
+ "isomorphic-fetch": "^2.1.1",
+ "jwt-decode": "^1.4.0",
+ "lodash": "^4.0.0",
+ "normalizr": "^1.0.0",
+ "q": "^1.4.1",
+ "react": "^0.14.0",
+ "react-dom": "^0.14.0",
+ "react-redux": "^4.0.0",
+ "react-router": "^1.0.3",
+ "redux": "^3.0.0",
+ "redux-form": "^4.1.0",
+ "redux-logger": "^2.4.0",
+ "redux-router": "^1.0.0-beta3",
+ "redux-thunk": "^0.1.0"
+ },
+ "dependencies": {
+ "hoist-non-react-statics": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz",
+ "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==",
+ "requires": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "prop-types": {
+ "version": "15.7.2",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
+ "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.8.1"
+ }
+ },
+ "react": {
+ "version": "0.14.9",
+ "resolved": "https://registry.npmjs.org/react/-/react-0.14.9.tgz",
+ "integrity": "sha1-kRCmSXxJ1EuhwO3TF67CnC4NkdE=",
+ "requires": {
+ "envify": "^3.0.0",
+ "fbjs": "^0.6.1"
+ }
+ },
+ "react-dom": {
+ "version": "0.14.9",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-0.14.9.tgz",
+ "integrity": "sha1-BQZKPc8PsYgKOyv8nVjFXY2fYpM="
+ },
+ "react-is": {
+ "version": "16.8.6",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
+ "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
+ },
+ "react-redux": {
+ "version": "4.4.10",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-4.4.10.tgz",
+ "integrity": "sha512-tjL0Bmpkj75Td0k+lXlF8Fc8a9GuXFv/3ahUOCXExWs/jhsKiQeTffdH0j5byejCGCRL4tvGFYlrwBF1X/Aujg==",
+ "requires": {
+ "create-react-class": "^15.5.1",
+ "hoist-non-react-statics": "^3.3.0",
+ "invariant": "^2.0.0",
+ "lodash": "^4.17.11",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.7.2"
+ }
+ },
+ "redux-thunk": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-0.1.0.tgz",
+ "integrity": "sha1-jjR2BoCLNb+Kkn30YW9v7RAYJuU="
+ }
+ }
+ },
+ "appirio-tech-react-components": {
+ "version": "github:appirio-tech/react-components#c32437a192c886dfbd2d4f9847d46ec1a34b5cc4",
+ "from": "github:appirio-tech/react-components#feature/connectv2",
+ "requires": {
+ "appirio-tech-api-schemas": "^5.0.69",
+ "appirio-tech-client-app-layer": "^0.1.3",
+ "classnames": "^2.2.3",
+ "coffee-script": "^1.12.7",
+ "coffeescript": "^1.12.7",
+ "formsy-react": "^0.19.5",
+ "isomorphic-fetch": "^2.2.1",
+ "libphonenumber-js": "^1.4.6",
+ "lodash": "^4.0.0",
+ "moment": "^2.11.2",
+ "react": "^15.3.1",
+ "react-addons-pure-render-mixin": "^15.3.1",
+ "react-addons-update": "^15.3.1",
+ "react-avatar": "^2.2.0",
+ "react-datetime": "^2.0.2",
+ "react-dom": "^15.3.1",
+ "react-dropzone": "^3.5.3",
+ "react-popper": "^0.7.5",
+ "react-redux": "^4.4.5",
+ "react-router-dom": "^4.2.2",
+ "react-select": "^0.9.1",
+ "react-switch-button": "^1.1.2",
+ "react-textarea-autosize": "^5.2.1",
+ "react-transition-group": "^2.2.1",
+ "redux-thunk": "^2.1.0",
+ "tc-ui": "git+https://github.com/appirio-tech/tc-ui.git#feature/connectv2",
+ "uncontrollable": "^4.0.1"
+ },
+ "dependencies": {
+ "coffeescript": {
+ "version": "1.12.7",
+ "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.7.tgz",
+ "integrity": "sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA=="
+ },
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "fbjs": {
+ "version": "0.8.17",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
+ "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
+ "requires": {
+ "core-js": "^1.0.0",
+ "isomorphic-fetch": "^2.1.1",
+ "loose-envify": "^1.0.0",
+ "object-assign": "^4.1.0",
+ "promise": "^7.1.1",
+ "setimmediate": "^1.0.5",
+ "ua-parser-js": "^0.7.18"
+ }
+ },
+ "hoist-non-react-statics": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz",
+ "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==",
+ "requires": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "react": {
+ "version": "15.6.2",
+ "resolved": "https://registry.npmjs.org/react/-/react-15.6.2.tgz",
+ "integrity": "sha1-26BDSrQ5z+gvEI8PURZjkIF5qnI=",
+ "requires": {
+ "create-react-class": "^15.6.0",
+ "fbjs": "^0.8.9",
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.0",
+ "prop-types": "^15.5.10"
+ }
+ },
+ "react-dom": {
+ "version": "15.6.2",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.6.2.tgz",
+ "integrity": "sha1-Qc+t9pO3V/rycIRDodH9WgK+9zA=",
+ "requires": {
+ "fbjs": "^0.8.9",
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.0",
+ "prop-types": "^15.5.10"
+ }
+ },
+ "react-is": {
+ "version": "16.8.6",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
+ "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
+ },
+ "react-redux": {
+ "version": "4.4.10",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-4.4.10.tgz",
+ "integrity": "sha512-tjL0Bmpkj75Td0k+lXlF8Fc8a9GuXFv/3ahUOCXExWs/jhsKiQeTffdH0j5byejCGCRL4tvGFYlrwBF1X/Aujg==",
+ "requires": {
+ "create-react-class": "^15.5.1",
+ "hoist-non-react-statics": "^3.3.0",
+ "invariant": "^2.0.0",
+ "lodash": "^4.17.11",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.7.2"
+ },
+ "dependencies": {
+ "prop-types": {
+ "version": "15.7.2",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
+ "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.8.1"
+ }
+ }
+ }
+ }
+ }
+ },
"aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
@@ -1060,6 +1277,11 @@
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
"dev": true
},
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -1149,6 +1371,11 @@
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
"dev": true
},
+ "ast-types": {
+ "version": "0.9.6",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz",
+ "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk="
+ },
"ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
@@ -1161,6 +1388,11 @@
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
"dev": true
},
+ "async": {
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
+ "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E="
+ },
"async-each": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
@@ -1182,8 +1414,7 @@
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
- "dev": true
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"atob": {
"version": "2.1.2",
@@ -1191,6 +1422,14 @@
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"dev": true
},
+ "attr-accept": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-1.1.3.tgz",
+ "integrity": "sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ==",
+ "requires": {
+ "core-js": "^2.5.0"
+ }
+ },
"auth0-js": {
"version": "6.8.4",
"resolved": "http://registry.npmjs.org/auth0-js/-/auth0-js-6.8.4.tgz",
@@ -1199,6 +1438,7 @@
"Base64": "~0.1.3",
"json-fallback": "0.0.1",
"jsonp": "~0.0.4",
+ "qs": "git+https://github.com/jfromaniello/node-querystring.git#fix_ie7_bug_with_arrays",
"reqwest": "^1.1.4",
"trim": "~0.0.1",
"winchan": "^0.1.1",
@@ -1207,10 +1447,18 @@
"dependencies": {
"qs": {
"version": "git+https://github.com/jfromaniello/node-querystring.git#5d96513991635e3e22d7aa54a8584d6ce97cace8",
- "from": "git+https://github.com/jfromaniello/node-querystring.git#5d96513991635e3e22d7aa54a8584d6ce97cace8"
+ "from": "git+https://github.com/jfromaniello/node-querystring.git#fix_ie7_bug_with_arrays"
}
}
},
+ "auto-config-fake-server": {
+ "version": "2.0.604",
+ "resolved": "https://registry.npmjs.org/auto-config-fake-server/-/auto-config-fake-server-2.0.604.tgz",
+ "integrity": "sha1-FY5RTIR5nRQ5iNw/w7mpkwnNhkY=",
+ "requires": {
+ "sinon": "2.0.0-pre"
+ }
+ },
"autoprefixer": {
"version": "8.6.5",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-8.6.5.tgz",
@@ -1237,6 +1485,14 @@
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
"dev": true
},
+ "axios": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.8.1.tgz",
+ "integrity": "sha1-4Or+wPNGE5Un3Dt5/cv/gDSiQEU=",
+ "requires": {
+ "follow-redirects": "0.0.7"
+ }
+ },
"axobject-query": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
@@ -3187,8 +3443,7 @@
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
- "dev": true
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"base": {
"version": "0.11.2",
@@ -3262,6 +3517,11 @@
"resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
"integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA="
},
+ "base62": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/base62/-/base62-1.2.8.tgz",
+ "integrity": "sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA=="
+ },
"base64-js": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
@@ -3309,8 +3569,12 @@
"bluebird": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz",
- "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==",
- "dev": true
+ "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg=="
+ },
+ "blueimp-tmpl": {
+ "version": "2.5.7",
+ "resolved": "https://registry.npmjs.org/blueimp-tmpl/-/blueimp-tmpl-2.5.7.tgz",
+ "integrity": "sha1-M/sSwTnWVRKuQK+9ji3vjZ25ZJA="
},
"bn.js": {
"version": "4.11.8",
@@ -3358,11 +3622,20 @@
}
}
},
+ "bourbon": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/bourbon/-/bourbon-4.3.4.tgz",
+ "integrity": "sha1-TaOAAp6SwMj5dkx3lFGhNLEefMM="
+ },
+ "bourbon-neat": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/bourbon-neat/-/bourbon-neat-1.7.2.tgz",
+ "integrity": "sha1-oiixJ0R53iR20yszFTEHylBTzz0="
+ },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -3638,11 +3911,19 @@
"integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
"dev": true
},
+ "camel-case": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-1.2.2.tgz",
+ "integrity": "sha1-Gsp8TRlTWaLOmVV5NDPG5VQlEfI=",
+ "requires": {
+ "sentence-case": "^1.1.1",
+ "upper-case": "^1.1.1"
+ }
+ },
"camelcase": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
- "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
- "dev": true
+ "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk="
},
"camelcase-keys": {
"version": "2.1.0",
@@ -3733,6 +4014,15 @@
"integrity": "sha512-Jt9tIBkRc9POUof7QA/VwWd+58fKkEEfI+/t1/eOlxKM7ZhrczNzMFefge7Ai+39y1pR/pP6cI19guHy3FSLmw==",
"dev": true
},
+ "center-align": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+ "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+ "requires": {
+ "align-text": "^0.1.3",
+ "lazy-cache": "^1.0.3"
+ }
+ },
"chalk": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
@@ -3743,6 +4033,29 @@
"supports-color": "^5.3.0"
}
},
+ "change-case": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/change-case/-/change-case-2.3.1.tgz",
+ "integrity": "sha1-LE/ePwY7tB0AzWjg1aCdthy+iU8=",
+ "requires": {
+ "camel-case": "^1.1.1",
+ "constant-case": "^1.1.0",
+ "dot-case": "^1.1.0",
+ "is-lower-case": "^1.1.0",
+ "is-upper-case": "^1.1.0",
+ "lower-case": "^1.1.1",
+ "lower-case-first": "^1.0.0",
+ "param-case": "^1.1.0",
+ "pascal-case": "^1.1.0",
+ "path-case": "^1.1.0",
+ "sentence-case": "^1.1.1",
+ "snake-case": "^1.1.0",
+ "swap-case": "^1.1.0",
+ "title-case": "^1.1.0",
+ "upper-case": "^1.1.1",
+ "upper-case-first": "^1.1.0"
+ }
+ },
"character-entities": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.2.tgz",
@@ -3773,6 +4086,11 @@
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
"dev": true
},
+ "charenc": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+ "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
+ },
"chokidar": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
@@ -3893,6 +4211,30 @@
}
}
},
+ "classnames": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
+ "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
+ },
+ "clean-css": {
+ "version": "3.4.28",
+ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz",
+ "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=",
+ "requires": {
+ "commander": "2.8.x",
+ "source-map": "0.4.x"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
+ "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
+ "requires": {
+ "graceful-readlink": ">= 1.0.0"
+ }
+ }
+ }
+ },
"cli-cursor": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
@@ -3908,6 +4250,16 @@
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
"dev": true
},
+ "cliui": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+ "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+ "requires": {
+ "center-align": "^0.1.1",
+ "right-align": "^0.1.1",
+ "wordwrap": "0.0.2"
+ }
+ },
"clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
@@ -3989,6 +4341,11 @@
}
}
},
+ "coffee-script": {
+ "version": "1.12.7",
+ "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz",
+ "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw=="
+ },
"collapse-white-space": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.4.tgz",
@@ -4069,7 +4426,6 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
"integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
- "dev": true,
"requires": {
"delayed-stream": "~1.0.0"
}
@@ -4124,6 +4480,14 @@
"typical": "^2.6.1"
}
},
+ "commander": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+ "requires": {
+ "graceful-readlink": ">= 1.0.0"
+ }
+ },
"common-sequence": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-1.0.2.tgz",
@@ -4136,11 +4500,26 @@
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
"dev": true
},
+ "commoner": {
+ "version": "0.10.8",
+ "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz",
+ "integrity": "sha1-NPw2cs0kOT6LtH5wyqApOBH08sU=",
+ "requires": {
+ "commander": "^2.5.0",
+ "detective": "^4.3.1",
+ "glob": "^5.0.15",
+ "graceful-fs": "^4.1.2",
+ "iconv-lite": "^0.4.5",
+ "mkdirp": "^0.5.0",
+ "private": "^0.1.6",
+ "q": "^1.1.2",
+ "recast": "^0.11.17"
+ }
+ },
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
- "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
- "dev": true
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"compressible": {
"version": "2.0.15",
@@ -4182,14 +4561,12 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "dev": true
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz",
"integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=",
- "dev": true,
"requires": {
"inherits": "~2.0.1",
"readable-stream": "~2.0.0",
@@ -4236,6 +4613,15 @@
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true
},
+ "constant-case": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-1.1.2.tgz",
+ "integrity": "sha1-jsLKW6ND4Aqjjb9OIA/VrJB+/WM=",
+ "requires": {
+ "snake-case": "^1.1.0",
+ "upper-case": "^1.1.1"
+ }
+ },
"constants-browserify": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
@@ -4291,6 +4677,11 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
+ "cookiejar": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz",
+ "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA=="
+ },
"copy-concurrently": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
@@ -4319,8 +4710,7 @@
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cosmiconfig": {
"version": "4.0.0",
@@ -4399,6 +4789,37 @@
"sha.js": "^2.4.8"
}
},
+ "create-react-class": {
+ "version": "15.6.3",
+ "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.3.tgz",
+ "integrity": "sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg==",
+ "requires": {
+ "fbjs": "^0.8.9",
+ "loose-envify": "^1.3.1",
+ "object-assign": "^4.1.1"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "fbjs": {
+ "version": "0.8.17",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
+ "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
+ "requires": {
+ "core-js": "^1.0.0",
+ "isomorphic-fetch": "^2.1.1",
+ "loose-envify": "^1.0.0",
+ "object-assign": "^4.1.0",
+ "promise": "^7.1.1",
+ "setimmediate": "^1.0.5",
+ "ua-parser-js": "^0.7.18"
+ }
+ }
+ }
+ },
"cross-spawn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
@@ -4410,6 +4831,11 @@
"which": "^1.2.9"
}
},
+ "crypt": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+ "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
+ },
"crypto-browserify": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
@@ -4955,8 +5381,7 @@
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
- "dev": true
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
"decamelize-keys": {
"version": "1.1.0",
@@ -4974,6 +5399,11 @@
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
"dev": true
},
+ "deep-diff": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.4.tgz",
+ "integrity": "sha1-qsXDmVIjar5fA3ojSQYLoBsArkg="
+ },
"deep-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
@@ -5083,8 +5513,7 @@
"defined": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
- "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
- "dev": true
+ "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM="
},
"del": {
"version": "2.2.2",
@@ -5112,8 +5541,7 @@
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
- "dev": true
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"delegates": {
"version": "1.0.0",
@@ -5156,6 +5584,15 @@
"integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=",
"dev": true
},
+ "detective": {
+ "version": "4.7.1",
+ "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz",
+ "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==",
+ "requires": {
+ "acorn": "^5.2.1",
+ "defined": "^1.0.0"
+ }
+ },
"diff": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
@@ -5228,6 +5665,14 @@
"esutils": "^2.0.2"
}
},
+ "dom-helpers": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
+ "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
+ "requires": {
+ "@babel/runtime": "^7.1.2"
+ }
+ },
"dom-serializer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
@@ -5297,6 +5742,14 @@
"resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz",
"integrity": "sha1-WTKJDcn04vGeXrAqIAJuXl78j1g="
},
+ "dot-case": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-1.1.2.tgz",
+ "integrity": "sha1-HnOCaQDeKNbeVIC8HeMdCEKwa+w=",
+ "requires": {
+ "sentence-case": "^1.1.2"
+ }
+ },
"dot-prop": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
@@ -5405,6 +5858,15 @@
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
"dev": true
},
+ "envify": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/envify/-/envify-3.4.1.tgz",
+ "integrity": "sha1-1xIjKejfFoi6dxsSUBkXyc5cvOg=",
+ "requires": {
+ "jstransform": "^11.0.3",
+ "through": "~2.3.4"
+ }
+ },
"errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
@@ -5891,6 +6353,11 @@
"acorn-jsx": "^3.0.0"
}
},
+ "esprima-fb": {
+ "version": "15001.1.0-dev-harmony-fb",
+ "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz",
+ "integrity": "sha1-MKlHMDxrjV6VW+4rmbHSMyBqaQE="
+ },
"esquery": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
@@ -6088,8 +6555,7 @@
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
- "dev": true
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"extend-shallow": {
"version": "3.0.2",
@@ -6141,8 +6607,7 @@
"fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
- "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
- "dev": true
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
},
"fast-glob": {
"version": "2.2.3",
@@ -6488,8 +6953,7 @@
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
- "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
- "dev": true
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
},
"fast-levenshtein": {
"version": "2.0.6",
@@ -6512,6 +6976,30 @@
"bser": "^2.0.0"
}
},
+ "fbjs": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.1.tgz",
+ "integrity": "sha1-lja3cF9bqWhNRLcveDISVK/IYPc=",
+ "requires": {
+ "core-js": "^1.0.0",
+ "loose-envify": "^1.0.0",
+ "promise": "^7.0.3",
+ "ua-parser-js": "^0.7.9",
+ "whatwg-fetch": "^0.9.0"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "whatwg-fetch": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz",
+ "integrity": "sha1-DjaExsuZlbQ+/J3wPkw2XZX9nMA="
+ }
+ }
+ },
"feature-policy": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.1.0.tgz",
@@ -6572,6 +7060,11 @@
}
}
},
+ "file-type": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz",
+ "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ=="
+ },
"filename-regex": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
@@ -6604,6 +7097,49 @@
}
}
},
+ "filestack-js": {
+ "version": "1.14.6",
+ "resolved": "https://registry.npmjs.org/filestack-js/-/filestack-js-1.14.6.tgz",
+ "integrity": "sha512-mcME182eOUy3OyU0F9rcATQf3/YY3N1suXYVv3hcS1RxeVHIIkM9XI6N9Qg5t04y0qOGud9xv/GO+oKhreCSIw==",
+ "requires": {
+ "abab": "^2.0.0",
+ "ajv": "^6.5.5",
+ "file-type": "^8.1.0",
+ "filestack-loader": "^3.0.4",
+ "is-svg": "^3.0.0",
+ "isutf8": "^2.0.2",
+ "spark-md5": "^3.0.0",
+ "superagent": "^3.8.3",
+ "tcomb-validation": "^3.4.1",
+ "tslib": "^1.9.3"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
+ "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "is-svg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz",
+ "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==",
+ "requires": {
+ "html-comment-regex": "^1.1.0"
+ }
+ }
+ }
+ },
+ "filestack-loader": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/filestack-loader/-/filestack-loader-3.0.4.tgz",
+ "integrity": "sha512-b6uOCWHd1gM0+5KBA1rA4qfEgTqyTr5umLM4bBWT4z98WUwxa6KzCiq+z0VnR4rN+NCx6kyZ/wLXjGcPU32TxQ=="
+ },
"fill-range": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
@@ -6731,7 +7267,31 @@
"resolved": "https://registry.npmjs.org/flux-standard-action/-/flux-standard-action-2.0.3.tgz",
"integrity": "sha512-HR2IjMkqJreoFm1Hx7hmMAtUFeo+ad8hPMYPo8o3YSWjbSq0sMwuXMbv4giB3TXngYB7+svkAJewQwwvwsE6xw==",
"requires": {
- "lodash": "^4.0.0"
+ "lodash": "^4.0.0"
+ }
+ },
+ "follow-redirects": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz",
+ "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=",
+ "requires": {
+ "debug": "^2.2.0",
+ "stream-consume": "^0.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
},
"for-in": {
@@ -6759,13 +7319,38 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
+ "form-data-to-object": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/form-data-to-object/-/form-data-to-object-0.2.0.tgz",
+ "integrity": "sha1-96jmjd2RChEApl4lrGpIQUP/gWg="
+ },
+ "formatio": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz",
+ "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=",
+ "requires": {
+ "samsam": "~1.1"
+ }
+ },
+ "formidable": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz",
+ "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg=="
+ },
+ "formsy-react": {
+ "version": "0.19.5",
+ "resolved": "https://registry.npmjs.org/formsy-react/-/formsy-react-0.19.5.tgz",
+ "integrity": "sha1-dgpXrAETRC499MMJw2ON2SlX544=",
+ "requires": {
+ "form-data-to-object": "^0.2.0"
+ }
+ },
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
@@ -7510,6 +8095,18 @@
"assert-plus": "^1.0.0"
}
},
+ "glob": {
+ "version": "5.0.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
"glob-base": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
@@ -7646,8 +8243,12 @@
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
- "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
- "dev": true
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
+ },
+ "graceful-readlink": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+ "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
},
"growly": {
"version": "1.3.0",
@@ -7865,6 +8466,11 @@
"minimalistic-assert": "^1.0.1"
}
},
+ "he": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.0.0.tgz",
+ "integrity": "sha1-baWyZdfyw7XkgHSRaODhWdBXKNo="
+ },
"helmet": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-3.14.0.tgz",
@@ -7907,6 +8513,17 @@
"resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.0.0.tgz",
"integrity": "sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys="
},
+ "history": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/history/-/history-1.17.0.tgz",
+ "integrity": "sha1-xUg8qlodH+oAoafY0ZuHQBZxHSk=",
+ "requires": {
+ "deep-equal": "^1.0.0",
+ "invariant": "^2.0.0",
+ "query-string": "^3.0.0",
+ "warning": "^2.0.0"
+ }
+ },
"hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@@ -7952,8 +8569,7 @@
"html-comment-regex": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz",
- "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==",
- "dev": true
+ "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ=="
},
"html-encoding-sniffer": {
"version": "1.0.2",
@@ -7970,12 +8586,45 @@
"integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=",
"dev": true
},
+ "html-minifier": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-1.5.0.tgz",
+ "integrity": "sha1-vrBf2cw0CUWGXBD0Cu30aa9LFTQ=",
+ "requires": {
+ "change-case": "2.3.x",
+ "clean-css": "3.4.x",
+ "commander": "2.9.x",
+ "concat-stream": "1.5.x",
+ "he": "1.0.x",
+ "ncname": "1.0.x",
+ "relateurl": "0.2.x",
+ "uglify-js": "2.6.x"
+ }
+ },
"html-tags": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz",
"integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=",
"dev": true
},
+ "html-webpack-plugin": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-1.7.0.tgz",
+ "integrity": "sha1-zQxzx5G9DIxFsk4wAb4zSmt0KXs=",
+ "requires": {
+ "bluebird": "^3.0.5",
+ "blueimp-tmpl": "^2.5.5",
+ "html-minifier": "^1.0.0",
+ "lodash": "^3.10.1"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
+ }
+ }
+ },
"htmlparser2": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.0.tgz",
@@ -8040,6 +8689,11 @@
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
"dev": true
},
+ "humps": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/humps/-/humps-0.6.0.tgz",
+ "integrity": "sha1-phchA4bwRF0SLOtNlBSho5saHpQ="
+ },
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -8174,7 +8828,6 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
@@ -8304,8 +8957,7 @@
"is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
- "dev": true
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
},
"is-builtin-module": {
"version": "1.0.0",
@@ -8440,6 +9092,14 @@
"integrity": "sha512-but/G3sapV3MNyqiDBLrOi4x8uCIw0RY3o/Vb5GT0sMFHrVV7731wFSVy41T5FO1og7G0gXLJh0MkgPRouko/A==",
"dev": true
},
+ "is-lower-case": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz",
+ "integrity": "sha1-fhR75HaNxGbbO/shzGCzHmrWk5M=",
+ "requires": {
+ "lower-case": "^1.1.0"
+ }
+ },
"is-number": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
@@ -8540,6 +9200,11 @@
"integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
"dev": true
},
+ "is-retina": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-retina/-/is-retina-1.0.3.tgz",
+ "integrity": "sha1-10AbKGvqKuN/Ykd1iN5QTQuGR+M="
+ },
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
@@ -8575,6 +9240,14 @@
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
"dev": true
},
+ "is-upper-case": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz",
+ "integrity": "sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8=",
+ "requires": {
+ "upper-case": "^1.1.0"
+ }
+ },
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
@@ -8607,8 +9280,7 @@
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
@@ -8776,6 +9448,11 @@
"handlebars": "^4.0.3"
}
},
+ "isutf8": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/isutf8/-/isutf8-2.0.3.tgz",
+ "integrity": "sha512-ucppMz9qxhSceRJ8bP5SfdMdXukV718zXVgeSznBXkDGHbIcN5nptCPnosZhsN959eATLCD3751fo8tD86hM2Q=="
+ },
"jest": {
"version": "23.6.0",
"resolved": "https://registry.npmjs.org/jest/-/jest-23.6.0.tgz",
@@ -9487,8 +10164,7 @@
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@@ -9536,6 +10212,25 @@
"verror": "1.10.0"
}
},
+ "jstransform": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz",
+ "integrity": "sha1-CaeJk+CuTU70SH9hVakfYZDLQiM=",
+ "requires": {
+ "base62": "^1.1.0",
+ "commoner": "^0.10.1",
+ "esprima-fb": "^15001.1.0-dev-harmony-fb",
+ "object-assign": "^2.0.0",
+ "source-map": "^0.4.2"
+ },
+ "dependencies": {
+ "object-assign": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
+ "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo="
+ }
+ }
+ },
"jsx-ast-utils": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz",
@@ -9550,11 +10245,18 @@
"resolved": "https://registry.npmjs.org/just-curry-it/-/just-curry-it-3.1.0.tgz",
"integrity": "sha512-mjzgSOFzlrurlURaHVjnQodyPNvrHrf1TbQP2XU9NSqBtHQPuHZ+Eb6TAJP7ASeJN9h9K0KXoRTs8u6ouHBKvg=="
},
+ "jwt-decode": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-1.5.1.tgz",
+ "integrity": "sha1-vajYcxubc57otKMaDQJcqUrpLTs=",
+ "requires": {
+ "Base64": "~0.1.3"
+ }
+ },
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
"requires": {
"is-buffer": "^1.1.5"
}
@@ -9590,6 +10292,11 @@
"webpack-sources": "^1.1.0"
}
},
+ "lazy-cache": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+ "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4="
+ },
"lcid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
@@ -9641,6 +10348,23 @@
"type-check": "~0.3.2"
}
},
+ "libphonenumber-js": {
+ "version": "1.7.15",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.7.15.tgz",
+ "integrity": "sha512-FYqkPqPc8ZBAeGiCuU/4eKqvCyBP281DtayXoc+9XuRhgARn+CCTvy30VjfCevPROQkVxZKe2SfWj4d/3VrmVw==",
+ "requires": {
+ "minimist": "^1.2.0",
+ "semver-compare": "^1.0.0",
+ "xml2js": "^0.4.17"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
"load-json-file": {
"version": "2.0.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
@@ -9909,6 +10633,16 @@
"chalk": "^2.0.1"
}
},
+ "lolex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz",
+ "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE="
+ },
+ "longest": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+ "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="
+ },
"longest-streak": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.2.tgz",
@@ -9933,6 +10667,19 @@
"signal-exit": "^3.0.0"
}
},
+ "lower-case": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
+ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw="
+ },
+ "lower-case-first": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz",
+ "integrity": "sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E=",
+ "requires": {
+ "lower-case": "^1.1.2"
+ }
+ },
"lru-cache": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
@@ -10027,6 +10774,16 @@
"integrity": "sha512-3Zs9P/0zzwTob2pdgT0CHZuMbnSUSp8MB1bddfm+HDmnFWHGT4jvEZRf+2RuPoa+cjdn/z25SEt5gFTqdhvJAg==",
"dev": true
},
+ "md5": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
+ "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=",
+ "requires": {
+ "charenc": "~0.0.1",
+ "crypt": "~0.0.1",
+ "is-buffer": "~1.1.1"
+ }
+ },
"md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@@ -10311,7 +11068,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -10319,8 +11075,7 @@
"minimist": {
"version": "0.0.8",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
- "dev": true
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"minimist-options": {
"version": "3.0.2",
@@ -10393,7 +11148,6 @@
"version": "0.5.1",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
- "dev": true,
"requires": {
"minimist": "0.0.8"
}
@@ -10541,6 +11295,14 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
+ "ncname": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz",
+ "integrity": "sha1-W1etGLHKCShk72Kwse2BlPODtxw=",
+ "requires": {
+ "xml-char-classes": "^1.0.0"
+ }
+ },
"negotiator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
@@ -10563,6 +11325,14 @@
"resolved": "https://registry.npmjs.org/nocache/-/nocache-2.0.0.tgz",
"integrity": "sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA="
},
+ "node-bourbon": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/node-bourbon/-/node-bourbon-4.2.8.tgz",
+ "integrity": "sha1-5ETx8JQ0q3ZQ6jGMKOLhA9P5Qs0=",
+ "requires": {
+ "bourbon": "^4.2.6"
+ }
+ },
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
@@ -10709,6 +11479,15 @@
}
}
},
+ "node-neat": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/node-neat/-/node-neat-1.7.2.tgz",
+ "integrity": "sha1-OEcpELgV4mG4sbmbpRmZRGWhXCE=",
+ "requires": {
+ "bourbon-neat": "1.7.2",
+ "node-bourbon": "^4.2.3"
+ }
+ },
"node-notifier": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz",
@@ -10896,6 +11675,21 @@
}
}
},
+ "normalizr": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/normalizr/-/normalizr-1.4.1.tgz",
+ "integrity": "sha1-qjh8JGXxNhHK86rkK6+Y9wXoos4=",
+ "requires": {
+ "lodash": "^3.10.0"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
+ }
+ }
+ },
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@@ -11094,7 +11888,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
"requires": {
"wrappy": "1"
}
@@ -11291,6 +12084,14 @@
}
}
},
+ "param-case": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/param-case/-/param-case-1.1.2.tgz",
+ "integrity": "sha1-3LCRpDwlm5Io8cNB57akTqC/l0M=",
+ "requires": {
+ "sentence-case": "^1.1.2"
+ }
+ },
"parse-asn1": {
"version": "5.1.1",
"resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
@@ -11355,6 +12156,15 @@
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
},
+ "pascal-case": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-1.1.2.tgz",
+ "integrity": "sha1-Pl1kogBDgwp8STRMLXS0G+DJyZs=",
+ "requires": {
+ "camel-case": "^1.1.1",
+ "upper-case-first": "^1.1.0"
+ }
+ },
"pascalcase": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
@@ -11367,6 +12177,14 @@
"integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=",
"dev": true
},
+ "path-case": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/path-case/-/path-case-1.1.2.tgz",
+ "integrity": "sha1-UM5roNO+090LXCqcRVNpdDRAlRQ=",
+ "requires": {
+ "sentence-case": "^1.1.2"
+ }
+ },
"path-dirname": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
@@ -11382,8 +12200,7 @@
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "dev": true
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-is-inside": {
"version": "1.0.2",
@@ -11509,6 +12326,11 @@
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
"dev": true
},
+ "popper.js": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.15.0.tgz",
+ "integrity": "sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA=="
+ },
"posix-character-classes": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
@@ -13827,8 +14649,7 @@
"private": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
- "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
- "dev": true
+ "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
},
"process": {
"version": "0.5.2",
@@ -13839,8 +14660,7 @@
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
- "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
- "dev": true
+ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
},
"progress": {
"version": "2.0.1",
@@ -13848,6 +14668,14 @@
"integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==",
"dev": true
},
+ "promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "requires": {
+ "asap": "~2.0.3"
+ }
+ },
"promise-inflight": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@@ -13938,8 +14766,7 @@
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"pure-color": {
"version": "1.3.0",
@@ -13949,14 +14776,21 @@
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
- "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
- "dev": true
+ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
},
+ "query-string": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-3.0.3.tgz",
+ "integrity": "sha1-ri4UtNBQcdTpuetIc8NbDc1C5jg=",
+ "requires": {
+ "strict-uri-encode": "^1.0.0"
+ }
+ },
"querystring": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
@@ -14069,6 +14903,76 @@
"scheduler": "^0.10.0"
}
},
+ "react-addons-pure-render-mixin": {
+ "version": "15.6.2",
+ "resolved": "https://registry.npmjs.org/react-addons-pure-render-mixin/-/react-addons-pure-render-mixin-15.6.2.tgz",
+ "integrity": "sha1-a4P0C2s27kBzXL1hJes/E84c3ck=",
+ "requires": {
+ "fbjs": "^0.8.4",
+ "object-assign": "^4.1.0"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "fbjs": {
+ "version": "0.8.17",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
+ "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
+ "requires": {
+ "core-js": "^1.0.0",
+ "isomorphic-fetch": "^2.1.1",
+ "loose-envify": "^1.0.0",
+ "object-assign": "^4.1.0",
+ "promise": "^7.1.1",
+ "setimmediate": "^1.0.5",
+ "ua-parser-js": "^0.7.18"
+ }
+ }
+ }
+ },
+ "react-addons-update": {
+ "version": "15.6.2",
+ "resolved": "https://registry.npmjs.org/react-addons-update/-/react-addons-update-15.6.2.tgz",
+ "integrity": "sha1-5TdTxbNIh5dFEMiC1/sHWFHV5QQ=",
+ "requires": {
+ "fbjs": "^0.8.9",
+ "object-assign": "^4.1.0"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "fbjs": {
+ "version": "0.8.17",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
+ "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
+ "requires": {
+ "core-js": "^1.0.0",
+ "isomorphic-fetch": "^2.1.1",
+ "loose-envify": "^1.0.0",
+ "object-assign": "^4.1.0",
+ "promise": "^7.1.1",
+ "setimmediate": "^1.0.5",
+ "ua-parser-js": "^0.7.18"
+ }
+ }
+ }
+ },
+ "react-avatar": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/react-avatar/-/react-avatar-2.5.1.tgz",
+ "integrity": "sha512-bwH5pWY6uxaKZt+IZBfD+SU3Dpy3FaKbmAzrOI4N8SATUPLXOdGaJHWUl6Vl8hHSwWSsoLh/m7xYHdnn0lofZw==",
+ "requires": {
+ "babel-runtime": ">=5.0.0",
+ "is-retina": "^1.0.3",
+ "md5": "^2.0.0"
+ }
+ },
"react-base16-styling": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.5.3.tgz",
@@ -14096,6 +15000,24 @@
}
}
},
+ "react-datetime": {
+ "version": "2.16.3",
+ "resolved": "https://registry.npmjs.org/react-datetime/-/react-datetime-2.16.3.tgz",
+ "integrity": "sha512-amWfb5iGEiyqjLmqCLlPpu2oN415jK8wX1qoTq7qn6EYiU7qQgbNHglww014PT4O/3G5eo/3kbJu/M/IxxTyGw==",
+ "requires": {
+ "create-react-class": "^15.5.2",
+ "object-assign": "^3.0.0",
+ "prop-types": "^15.5.7",
+ "react-onclickoutside": "^6.5.0"
+ },
+ "dependencies": {
+ "object-assign": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
+ "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I="
+ }
+ }
+ },
"react-dock": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/react-dock/-/react-dock-0.2.4.tgz",
@@ -14116,6 +15038,15 @@
"scheduler": "^0.10.0"
}
},
+ "react-dropzone": {
+ "version": "3.13.4",
+ "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-3.13.4.tgz",
+ "integrity": "sha1-hNomgVxAM5aRxJtFRMLvehaRLMw=",
+ "requires": {
+ "attr-accept": "^1.0.3",
+ "prop-types": "^15.5.7"
+ }
+ },
"react-helmet": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-5.2.0.tgz",
@@ -14141,6 +15072,11 @@
"shallowequal": "^1.0.2"
}
},
+ "react-input-autosize": {
+ "version": "0.6.13",
+ "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-0.6.13.tgz",
+ "integrity": "sha1-OG/3qdLD3AFsJlvy5Z05cFD2Wvc="
+ },
"react-is": {
"version": "16.6.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.0.tgz",
@@ -14157,11 +15093,32 @@
"react-base16-styling": "^0.5.1"
}
},
+ "react-lazy-cache": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/react-lazy-cache/-/react-lazy-cache-3.0.1.tgz",
+ "integrity": "sha1-DcZNON8XZ+93Z4xclBkAZMsRsM0=",
+ "requires": {
+ "deep-equal": "^1.0.1"
+ }
+ },
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
- "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
- "dev": true
+ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+ },
+ "react-onclickoutside": {
+ "version": "6.8.0",
+ "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.8.0.tgz",
+ "integrity": "sha512-5Q4Rn7QLEoh7WIe66KFvYIpWJ49GeHoygP1/EtJyZjXKgrWH19Tf0Ty3lWyQzrEEDyLOwUvvmBFSE3dcDdvagA=="
+ },
+ "react-popper": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-0.7.5.tgz",
+ "integrity": "sha512-ya9dhhGCf74JTOB2uyksEHhIGw7w9tNZRUJF73lEq2h4H5JT6MBa4PdT4G+sx6fZwq+xKZAL/sVNAIuojPn7Dg==",
+ "requires": {
+ "popper.js": "^1.12.5",
+ "prop-types": "^15.5.10"
+ }
},
"react-pure-render": {
"version": "1.0.2",
@@ -14206,6 +15163,15 @@
}
}
},
+ "react-router": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-1.0.3.tgz",
+ "integrity": "sha1-mA7KoFW4bkfIZUjCMq4FqIpB8Lc=",
+ "requires": {
+ "invariant": "^2.0.0",
+ "warning": "^2.0.0"
+ }
+ },
"react-router-dom": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz",
@@ -14265,6 +15231,15 @@
}
}
},
+ "react-select": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/react-select/-/react-select-0.9.1.tgz",
+ "integrity": "sha1-4yKi0KBjlqSCBrBVPfXsR9Fgg7o=",
+ "requires": {
+ "classnames": "^2.2.0",
+ "react-input-autosize": "^0.6.2"
+ }
+ },
"react-side-effect": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-1.1.5.tgz",
@@ -14274,16 +15249,40 @@
"shallowequal": "^1.0.1"
}
},
+ "react-switch-button": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/react-switch-button/-/react-switch-button-1.1.2.tgz",
+ "integrity": "sha1-jOhPaUa046k3PnttasjngNl/L08="
+ },
"react-test-renderer": {
"version": "16.6.0",
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.6.0.tgz",
"integrity": "sha512-w+Y3YT7OX1LP5KO7HCd0YR34Ol1qmISHaooPNMRYa6QzmwtcWhEGuZPr34wO8UCBIokswuhyLQUq7rjPDcEtJA==",
"dev": true,
"requires": {
- "object-assign": "^4.1.1",
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.6.2",
+ "react-is": "^16.6.0",
+ "scheduler": "^0.10.0"
+ }
+ },
+ "react-textarea-autosize": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-5.2.1.tgz",
+ "integrity": "sha512-bx6z2I35aapr71ggw2yZIA4qhmqeTa4ZVsSaTeFvtf9kfcZppDBh2PbMt8lvbdmzEk7qbSFhAxR9vxEVm6oiMg==",
+ "requires": {
+ "prop-types": "^15.6.0"
+ }
+ },
+ "react-transition-group": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
+ "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
+ "requires": {
+ "dom-helpers": "^3.4.0",
+ "loose-envify": "^1.4.0",
"prop-types": "^15.6.2",
- "react-is": "^16.6.0",
- "scheduler": "^0.10.0"
+ "react-lifecycles-compat": "^3.0.4"
}
},
"read-pkg": {
@@ -14311,7 +15310,6 @@
"version": "2.0.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
"integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
- "dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
@@ -14632,6 +15630,29 @@
"util.promisify": "^1.0.0"
}
},
+ "recast": {
+ "version": "0.11.23",
+ "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz",
+ "integrity": "sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=",
+ "requires": {
+ "ast-types": "0.9.6",
+ "esprima": "~3.1.0",
+ "private": "~0.1.5",
+ "source-map": "~0.5.0"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+ "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
"reconnect-core": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/reconnect-core/-/reconnect-core-1.3.0.tgz",
@@ -14843,6 +15864,32 @@
"base16": "^1.0.0"
}
},
+ "redux-form": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/redux-form/-/redux-form-4.2.2.tgz",
+ "integrity": "sha1-uK43pAcJBvRdvTCwcinxoQvyXLA=",
+ "requires": {
+ "deep-equal": "^1.0.1",
+ "hoist-non-react-statics": "^1.0.5",
+ "is-promise": "^2.1.0",
+ "react-lazy-cache": "^3.0.1"
+ },
+ "dependencies": {
+ "hoist-non-react-statics": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz",
+ "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs="
+ }
+ }
+ },
+ "redux-logger": {
+ "version": "2.10.2",
+ "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-2.10.2.tgz",
+ "integrity": "sha1-PFpfCm8yV3wd6t9mVfJX+CxsOTc=",
+ "requires": {
+ "deep-diff": "0.3.4"
+ }
+ },
"redux-promise": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/redux-promise/-/redux-promise-0.6.0.tgz",
@@ -14852,6 +15899,19 @@
"is-promise": "^2.1.0"
}
},
+ "redux-router": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/redux-router/-/redux-router-1.0.0.tgz",
+ "integrity": "sha1-PBZ240Qb7FD+jZJFfAF8tjaZM08=",
+ "requires": {
+ "deep-equal": "^1.0.1"
+ }
+ },
+ "redux-thunk": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
+ "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
+ },
"referrer-policy": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.1.0.tgz",
@@ -14956,6 +16016,11 @@
}
}
},
+ "relateurl": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
+ "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
+ },
"remark": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/remark/-/remark-9.0.0.tgz",
@@ -15043,8 +16108,7 @@
"repeat-string": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
- "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
- "dev": true
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
},
"repeating": {
"version": "2.0.1",
@@ -15292,6 +16356,14 @@
"integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=",
"dev": true
},
+ "right-align": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+ "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+ "requires": {
+ "align-text": "^0.1.1"
+ }
+ },
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
@@ -15385,6 +16457,11 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
+ "samsam": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz",
+ "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc="
+ },
"sane": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/sane/-/sane-2.5.2.tgz",
@@ -15923,8 +17000,7 @@
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
- "dev": true
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"scheduler": {
"version": "0.10.0",
@@ -15966,6 +17042,11 @@
"resolved": "http://registry.npmjs.org/semver/-/semver-5.1.0.tgz",
"integrity": "sha1-hfLPhVBGXE3wAM99hvawVBBqueU="
},
+ "semver-compare": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w="
+ },
"send": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
@@ -16006,6 +17087,14 @@
}
}
},
+ "sentence-case": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-1.1.3.tgz",
+ "integrity": "sha1-gDSq/CFFdy06vhUJqkLJ4QQtwTk=",
+ "requires": {
+ "lower-case": "^1.1.1"
+ }
+ },
"serialize-javascript": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz",
@@ -16073,8 +17162,7 @@
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
- "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
- "dev": true
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"setprototypeof": {
"version": "1.1.0",
@@ -16150,6 +17238,18 @@
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
+ "sinon": {
+ "version": "2.0.0-pre",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.0.0-pre.tgz",
+ "integrity": "sha1-GCk7APsvFVyZ6OW0bjH36t4ygV0=",
+ "requires": {
+ "formatio": "1.1.1",
+ "lolex": "1.3.2",
+ "samsam": "1.1.2",
+ "text-encoding": "0.5.2",
+ "util": ">=0.10.3 <1"
+ }
+ },
"sisteransi": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-0.1.1.tgz",
@@ -16171,6 +17271,14 @@
"is-fullwidth-code-point": "^2.0.0"
}
},
+ "snake-case": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-1.1.2.tgz",
+ "integrity": "sha1-DC8l4wUVjZoY09l3BmGH/vilpmo=",
+ "requires": {
+ "sentence-case": "^1.1.2"
+ }
+ },
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -16341,7 +17449,6 @@
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
- "dev": true,
"requires": {
"amdefine": ">=0.0.4"
}
@@ -16382,6 +17489,11 @@
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
"dev": true
},
+ "spark-md5": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.0.tgz",
+ "integrity": "sha1-NyIifFTi+vJLHcbZM8wUTm9xv+8="
+ },
"spdx-correct": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz",
@@ -16544,6 +17656,11 @@
}
}
},
+ "stream-consume": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz",
+ "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg=="
+ },
"stream-each": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
@@ -16620,8 +17737,7 @@
"strict-uri-encode": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
- "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
- "dev": true
+ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
},
"string-hash": {
"version": "1.1.3",
@@ -16686,8 +17802,7 @@
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
- "dev": true
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
},
"stringify-entities": {
"version": "1.3.2",
@@ -17165,6 +18280,60 @@
}
}
},
+ "superagent": {
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz",
+ "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==",
+ "requires": {
+ "component-emitter": "^1.2.0",
+ "cookiejar": "^2.1.0",
+ "debug": "^3.1.0",
+ "extend": "^3.0.0",
+ "form-data": "^2.3.1",
+ "formidable": "^1.2.0",
+ "methods": "^1.1.1",
+ "mime": "^1.4.1",
+ "qs": "^6.5.1",
+ "readable-stream": "^2.3.5"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -17194,6 +18363,15 @@
"whet.extend": "~0.9.9"
}
},
+ "swap-case": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz",
+ "integrity": "sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM=",
+ "requires": {
+ "lower-case": "^1.1.1",
+ "upper-case": "^1.1.1"
+ }
+ },
"symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
@@ -17298,8 +18476,10 @@
"angular-messages": "^1.5.2",
"appirio-tech-ng-iso-constants": "^1.0.6",
"appirio-tech-ng-ui-components": "^2.2.4",
+ "appirio-tech-react-components": "github:appirio-tech/react-components#feature/connectv2",
"auth0-js": "^9.6.1",
"babel-polyfill": "^6.7.4",
+ "filestack-js": "^1.13.2",
"isomorphic-fetch": "^2.2.1",
"lodash": "^4.6.1",
"ng-onload": "^0.2.1",
@@ -17576,30 +18756,6 @@
}
}
},
- "appirio-tech-react-components": {
- "version": "github:appirio-tech/react-components#3ede60d1876aa38ecaf92fc67a8953b7654cdeff",
- "from": "github:appirio-tech/react-components#3ede60d1876aa38ecaf92fc67a8953b7654cdeff",
- "requires": {
- "appirio-tech-api-schemas": "^5.0.69",
- "classnames": "^2.2.3",
- "coffee-script": "^1.12.7",
- "isomorphic-fetch": "^2.2.1",
- "lodash": "^4.0.0",
- "moment": "^2.11.2",
- "react": "^15.3.1",
- "react-dom": "^15.3.1",
- "react-redux": "^4.4.5",
- "react-router-dom": "^4.2.2",
- "react-select": "^0.9.1"
- },
- "dependencies": {
- "moment": {
- "version": "2.24.0",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
- "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
- }
- }
- },
"appirio-tech-webpack-config": {
"version": "0.3.20",
"resolved": "https://registry.npmjs.org/appirio-tech-webpack-config/-/appirio-tech-webpack-config-0.3.20.tgz",
@@ -25368,6 +26524,137 @@
}
}
},
+ "tc-ui": {
+ "version": "git+https://github.com/appirio-tech/tc-ui.git#e577a0e704136f1e9ecce92ce4c0626aab932691",
+ "from": "git+https://github.com/appirio-tech/tc-ui.git#feature/connectv2",
+ "requires": {
+ "classnames": "^2.2.3",
+ "lodash": "^4.0.0",
+ "moment": "^2.11.2",
+ "node-neat": "~1.7.1-beta1",
+ "react": "^0.14.7",
+ "react-datetime": "^2.0.2",
+ "react-dom": "^0.14.7",
+ "react-dropzone": "^3.3.2",
+ "react-redux": "^4.2.1",
+ "react-router": "^2.0.0-rc6",
+ "react-select": "^0.9.1",
+ "redux": "^3.3.1"
+ },
+ "dependencies": {
+ "history": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/history/-/history-2.1.2.tgz",
+ "integrity": "sha1-SqLeiXoOSGfkU5hDvm7Nsphr/ew=",
+ "requires": {
+ "deep-equal": "^1.0.0",
+ "invariant": "^2.0.0",
+ "query-string": "^3.0.0",
+ "warning": "^2.0.0"
+ },
+ "dependencies": {
+ "warning": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-2.1.0.tgz",
+ "integrity": "sha1-ISINnGOvx3qMkhEeARr3Bc4MaQE=",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ }
+ }
+ },
+ "hoist-non-react-statics": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz",
+ "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==",
+ "requires": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "prop-types": {
+ "version": "15.7.2",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
+ "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.8.1"
+ }
+ },
+ "react": {
+ "version": "0.14.9",
+ "resolved": "https://registry.npmjs.org/react/-/react-0.14.9.tgz",
+ "integrity": "sha1-kRCmSXxJ1EuhwO3TF67CnC4NkdE=",
+ "requires": {
+ "envify": "^3.0.0",
+ "fbjs": "^0.6.1"
+ }
+ },
+ "react-dom": {
+ "version": "0.14.9",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-0.14.9.tgz",
+ "integrity": "sha1-BQZKPc8PsYgKOyv8nVjFXY2fYpM="
+ },
+ "react-is": {
+ "version": "16.8.6",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
+ "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
+ },
+ "react-redux": {
+ "version": "4.4.10",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-4.4.10.tgz",
+ "integrity": "sha512-tjL0Bmpkj75Td0k+lXlF8Fc8a9GuXFv/3ahUOCXExWs/jhsKiQeTffdH0j5byejCGCRL4tvGFYlrwBF1X/Aujg==",
+ "requires": {
+ "create-react-class": "^15.5.1",
+ "hoist-non-react-statics": "^3.3.0",
+ "invariant": "^2.0.0",
+ "lodash": "^4.17.11",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.7.2"
+ }
+ },
+ "react-router": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-2.8.1.tgz",
+ "integrity": "sha1-c+lJH2zrMW0Pd5gpCBhj43juTtc=",
+ "requires": {
+ "history": "^2.1.2",
+ "hoist-non-react-statics": "^1.2.0",
+ "invariant": "^2.2.1",
+ "loose-envify": "^1.2.0",
+ "warning": "^3.0.0"
+ },
+ "dependencies": {
+ "hoist-non-react-statics": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz",
+ "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs="
+ }
+ }
+ },
+ "warning": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
+ "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ }
+ }
+ },
+ "tcomb": {
+ "version": "3.2.29",
+ "resolved": "https://registry.npmjs.org/tcomb/-/tcomb-3.2.29.tgz",
+ "integrity": "sha512-di2Hd1DB2Zfw6StGv861JoAF5h/uQVu/QJp2g8KVbtfKnoHdBQl5M32YWq6mnSYBQ1vFFrns5B1haWJL7rKaOQ=="
+ },
+ "tcomb-validation": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/tcomb-validation/-/tcomb-validation-3.4.1.tgz",
+ "integrity": "sha512-urVVMQOma4RXwiVCa2nM2eqrAomHROHvWPuj6UkDGz/eb5kcy0x6P0dVt6kzpUZtYMNoAqJLWmz1BPtxrtjtrA==",
+ "requires": {
+ "tcomb": "^3.0.0"
+ }
+ },
"temp-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/temp-path/-/temp-path-1.0.0.tgz",
@@ -25477,6 +26764,11 @@
"typical": "^2.6.1"
}
},
+ "text-encoding": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.5.2.tgz",
+ "integrity": "sha1-hbRmCBnwiHd2CUZVUWkP6hN9gko="
+ },
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -25492,8 +26784,7 @@
"through": {
"version": "2.3.8",
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
- "dev": true
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"through2": {
"version": "2.0.3",
@@ -25552,6 +26843,15 @@
"setimmediate": "^1.0.4"
}
},
+ "title-case": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/title-case/-/title-case-1.1.2.tgz",
+ "integrity": "sha1-+uSmrlRr+iLQg6DuqRCkDRLtT1o=",
+ "requires": {
+ "sentence-case": "^1.1.1",
+ "upper-case": "^1.0.3"
+ }
+ },
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -25797,8 +27097,7 @@
"tslib": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
- "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
- "dev": true
+ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
},
"tty-browserify": {
"version": "0.0.0",
@@ -25842,14 +27141,41 @@
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
- "dev": true
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"typical": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz",
"integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0="
},
+ "ua-parser-js": {
+ "version": "0.7.19",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz",
+ "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ=="
+ },
+ "uglify-js": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz",
+ "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=",
+ "requires": {
+ "async": "~0.2.6",
+ "source-map": "~0.5.1",
+ "uglify-to-browserify": "~1.0.0",
+ "yargs": "~3.10.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "uglify-to-browserify": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+ "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc="
+ },
"uglifyjs-webpack-plugin": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz",
@@ -25890,6 +27216,14 @@
}
}
},
+ "uncontrollable": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-4.1.0.tgz",
+ "integrity": "sha1-4DWCkSUuGGUiLZCTmxny9J+Bwak=",
+ "requires": {
+ "invariant": "^2.1.0"
+ }
+ },
"underscore": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
@@ -26115,11 +27449,23 @@
"integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==",
"dev": true
},
+ "upper-case": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
+ "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
+ },
+ "upper-case-first": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz",
+ "integrity": "sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=",
+ "requires": {
+ "upper-case": "^1.1.1"
+ }
+ },
"uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
- "dev": true,
"requires": {
"punycode": "^2.1.0"
}
@@ -26169,11 +27515,18 @@
"integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=",
"dev": true
},
+ "util": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
+ "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
+ "requires": {
+ "inherits": "2.0.3"
+ }
+ },
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"util.promisify": {
"version": "1.0.0",
@@ -26308,6 +27661,14 @@
"makeerror": "1.0.x"
}
},
+ "warning": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-2.1.0.tgz",
+ "integrity": "sha1-ISINnGOvx3qMkhEeARr3Bc4MaQE=",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"watch": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz",
@@ -27404,11 +28765,15 @@
"resolved": "http://registry.npmjs.org/winchan/-/winchan-0.1.4.tgz",
"integrity": "sha1-iPoSQRzVQutiYBjDihlry7F5k7s="
},
+ "window-size": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+ "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0="
+ },
"wordwrap": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
- "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
- "dev": true
+ "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8="
},
"wordwrapjs": {
"version": "3.0.0",
@@ -27463,8 +28828,7 @@
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"write": {
"version": "0.2.1",
@@ -27506,12 +28870,31 @@
"resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.1.0.tgz",
"integrity": "sha512-rx3GzJlgEeZ08MIcDsU2vY2B1QEriUKJTSiNHHUIem6eg9pzVOr2TL3Y4Pd6TMAM5D5azGjcxqI62piITBDHVg=="
},
+ "xml-char-classes": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz",
+ "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0="
+ },
"xml-name-validator": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
"dev": true
},
+ "xml2js": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
+ "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
+ "requires": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~9.0.1"
+ }
+ },
+ "xmlbuilder": {
+ "version": "9.0.7",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
+ "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
+ },
"xmlcreate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz",
@@ -27544,6 +28927,17 @@
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
"dev": true
},
+ "yargs": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+ "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+ "requires": {
+ "camelcase": "^1.0.2",
+ "cliui": "^2.1.0",
+ "decamelize": "^1.0.0",
+ "window-size": "0.1.0"
+ }
+ },
"yargs-parser": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz",
diff --git a/package.json b/package.json
index d65f4707..b8be6639 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
"lint:js": "./node_modules/.bin/eslint --ext .js,.jsx .",
"test": "npm run lint && npm run jest"
},
- "version": "0.7.12",
+ "version": "0.7.13",
"dependencies": {
"auth0-js": "^6.8.4",
"isomorphic-fetch": "^2.2.1",
From 89780586ac052c463c0fae973d005a0f2f1bbe7a Mon Sep 17 00:00:00 2001
From: suppermancool
Date: Fri, 3 May 2019 23:56:34 +0700
Subject: [PATCH 07/15] code 30090056
code 30090056
---
src/actions/challenge-listing.js | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/actions/challenge-listing.js b/src/actions/challenge-listing.js
index ad872794..6011c2c9 100644
--- a/src/actions/challenge-listing.js
+++ b/src/actions/challenge-listing.js
@@ -191,10 +191,9 @@ function getActiveChallengesDone(
user = decodeToken(tokenV3).handle;
// Handle any errors on this endpoint so that the non-user specific challenges
// will still be loaded.
- calls.push(service.getUserChallenges(user, filter, {
- limit: PAGE_SIZE,
- offset: page * PAGE_SIZE,
- }).catch(() => ({ challenges: [] })));
+ calls.push(getAll(
+ params => service.getUserChallenges(user, filter, params).catch(() => ({ challenges: [] })),
+ ));
}
return Promise.all(calls).then(([ch, uch]) => {
/* uch array contains challenges where the user is participating in
From e95c91b693a7e1b90e6cba62bcfc56d8ad34930a Mon Sep 17 00:00:00 2001
From: suppermancool
Date: Sat, 4 May 2019 00:00:24 +0700
Subject: [PATCH 08/15] update nap shot
update nap shot
---
__tests__/__snapshots__/index.js.snap | 3 +++
1 file changed, 3 insertions(+)
diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap
index e7ee51bc..0386661f 100644
--- a/__tests__/__snapshots__/index.js.snap
+++ b/__tests__/__snapshots__/index.js.snap
@@ -426,14 +426,17 @@ Object {
"countReset": [Function],
"debug": [Function],
"dir": [Function],
+ "dirxml": [Function],
"error": [Function],
"group": [Function],
"groupCollapsed": [Function],
"groupEnd": [Function],
"info": [Function],
"log": [Function],
+ "table": [Function],
"time": [Function],
"timeEnd": [Function],
+ "timeLog": [Function],
"trace": [Function],
"warn": [Function],
},
From c5828ccd2758438578783bd5d8b7eeee4fb1cc7b Mon Sep 17 00:00:00 2001
From: suppermancool
Date: Sat, 4 May 2019 09:47:41 +0700
Subject: [PATCH 09/15] code 30090056
code 30090056
---
src/actions/challenge-listing.js | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/src/actions/challenge-listing.js b/src/actions/challenge-listing.js
index 6011c2c9..2e9c0d08 100644
--- a/src/actions/challenge-listing.js
+++ b/src/actions/challenge-listing.js
@@ -191,31 +191,33 @@ function getActiveChallengesDone(
user = decodeToken(tokenV3).handle;
// Handle any errors on this endpoint so that the non-user specific challenges
// will still be loaded.
- calls.push(getAll(
- params => service.getUserChallenges(user, filter, params).catch(() => ({ challenges: [] })),
- ));
+ calls.push(service.getUserChallenges(user, filter, {
+ limit: PAGE_SIZE,
+ offset: page * PAGE_SIZE,
+ }).catch(() => ({ challenges: [] })));
}
return Promise.all(calls).then(([ch, uch]) => {
+ let fullCH = ch;
/* uch array contains challenges where the user is participating in
* some role. The same challenge are already listed in res array, but they
* are not attributed to the user there. This block of code marks user
* challenges in an efficient way. */
if (uch) {
const map = {};
- uch.challenges.forEach((item) => { map[item.id] = item; });
- ch.challenges.forEach((item) => {
- if (map[item.id]) {
- /* It is fine to reassing, as the array we modifying is created just
- * above within the same function. */
- /* eslint-disable no-param-reassign */
- item.users[user] = true;
- item.userDetails = map[item.id].userDetails;
- /* eslint-enable no-param-reassign */
- }
+ uch.challenges.forEach((item) => {
+ map[item.id] = item;
+ /* eslint-disable no-param-reassign */
+ item.users[user] = true;
+ item.userDetails = map[item.id].userDetails;
+ /* eslint-enable no-param-reassign */
});
}
- let { challenges, meta } = ch;
+ if (uch) {
+ fullCH = uch;
+ }
+ let { challenges } = fullCH;
+ let { meta } = ch;
// filter by date range and re-compute meta
// we can safely remove the next two lines when backend support date range
challenges = filterUtil.filterByDate(challenges, frontFilter);
From b382b4a071c9d1513135630cedfb8eb34408d282 Mon Sep 17 00:00:00 2001
From: Vigneshkumar Chinnachamy M
Date: Thu, 9 May 2019 00:29:09 +0530
Subject: [PATCH 10/15] update email preferences to use v5 api
---
.../actions/__snapshots__/profile.js.snap | 1 +
.../reducers/__snapshots__/profile.js.snap | 12 ++++----
__tests__/reducers/profile.js | 2 +-
config/test.js | 1 +
src/actions/profile.js | 2 +-
src/reducers/profile.js | 4 +--
src/services/user.js | 28 +++++++++----------
7 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/__tests__/actions/__snapshots__/profile.js.snap b/__tests__/actions/__snapshots__/profile.js.snap
index b784f238..7cfcbef7 100644
--- a/__tests__/actions/__snapshots__/profile.js.snap
+++ b/__tests__/actions/__snapshots__/profile.js.snap
@@ -166,6 +166,7 @@ Object {
},
},
"handle": "tcscoder",
+ "preferences": Object {},
},
"type": "PROFILE/SAVE_EMAIL_PREFERENCES_DONE",
}
diff --git a/__tests__/reducers/__snapshots__/profile.js.snap b/__tests__/reducers/__snapshots__/profile.js.snap
index a76358ad..da9208ec 100644
--- a/__tests__/reducers/__snapshots__/profile.js.snap
+++ b/__tests__/reducers/__snapshots__/profile.js.snap
@@ -740,7 +740,7 @@ Object {
"deletingPhoto": false,
"deletingWebLink": false,
"emailPreferences": Object {
- "TOPCODER_NL_DATA": true,
+ "Dev Newsletter": true,
},
"externalLinks": Array [
Object {
@@ -939,7 +939,7 @@ Object {
"deletingPhoto": false,
"deletingWebLink": false,
"emailPreferences": Object {
- "TOPCODER_NL_DATA": true,
+ "Dev Newsletter": true,
},
"externalLinks": Array [
Object {
@@ -989,7 +989,7 @@ Object {
"deletingPhoto": false,
"deletingWebLink": false,
"emailPreferences": Object {
- "TOPCODER_NL_DATA": true,
+ "Dev Newsletter": true,
},
"externalLinks": Array [
Object {
@@ -1926,7 +1926,7 @@ Object {
"deletingPhoto": false,
"deletingWebLink": false,
"emailPreferences": Object {
- "TOPCODER_NL_DATA": true,
+ "Dev Newsletter": true,
},
"externalLinks": Array [
Object {
@@ -2125,7 +2125,7 @@ Object {
"deletingPhoto": false,
"deletingWebLink": false,
"emailPreferences": Object {
- "TOPCODER_NL_DATA": true,
+ "Dev Newsletter": true,
},
"externalLinks": Array [
Object {
@@ -2175,7 +2175,7 @@ Object {
"deletingPhoto": false,
"deletingWebLink": false,
"emailPreferences": Object {
- "TOPCODER_NL_DATA": true,
+ "Dev Newsletter": true,
},
"externalLinks": Array [
Object {
diff --git a/__tests__/reducers/profile.js b/__tests__/reducers/profile.js
index 0992cf13..3e9c5ea8 100644
--- a/__tests__/reducers/profile.js
+++ b/__tests__/reducers/profile.js
@@ -33,7 +33,7 @@ const mockActions = {
deleteWebLinkInit: mockAction('DELETE_WEB_LINK_INIT'),
deleteWebLinkDone: mockAction('DELETE_WEB_LINK_DONE', { handle, data: webLink }),
saveEmailPreferencesInit: mockAction('SAVE_EMAIL_PREFERENCES_INIT'),
- saveEmailPreferencesDone: mockAction('SAVE_EMAIL_PREFERENCES_DONE', { handle, data: { subscriptions: { TOPCODER_NL_DATA: true } } }),
+ saveEmailPreferencesDone: mockAction('SAVE_EMAIL_PREFERENCES_DONE', { handle, preferences: { 'Dev Newsletter': true } }),
linkExternalAccountInit: mockAction('LINK_EXTERNAL_ACCOUNT_INIT'),
linkExternalAccountDone: mockAction('LINK_EXTERNAL_ACCOUNT_DONE', { handle, data: linkedAccount2 }),
unlinkExternalAccountInit: mockAction('UNLINK_EXTERNAL_ACCOUNT_INIT'),
diff --git a/config/test.js b/config/test.js
index 30d81af5..919351db 100644
--- a/config/test.js
+++ b/config/test.js
@@ -2,6 +2,7 @@ module.exports = {
API: {
V2: 'https://api.topcoder-dev.com/v2',
V3: 'https://api.topcoder-dev.com/v3',
+ V5: 'https://api.topcoder-dev.com/v5',
},
dummyConfigKey: 'Dummy config value',
};
diff --git a/src/actions/profile.js b/src/actions/profile.js
index 21643c99..dd1a88c0 100644
--- a/src/actions/profile.js
+++ b/src/actions/profile.js
@@ -397,7 +397,7 @@ function saveEmailPreferencesInit() {}
function saveEmailPreferencesDone(profile, tokenV3, preferences) {
const service = getUserService(tokenV3);
return service.saveEmailPreferences(profile, preferences)
- .then(res => ({ data: res, handle: profile.handle }));
+ .then(res => ({ data: res, handle: profile.handle, preferences }));
}
/**
diff --git a/src/reducers/profile.js b/src/reducers/profile.js
index 8ca03fdf..1cfe741e 100644
--- a/src/reducers/profile.js
+++ b/src/reducers/profile.js
@@ -434,13 +434,13 @@ function onSaveEmailPreferencesDone(state, { payload, error }) {
return newState;
}
- if (newState.profileForHandle !== payload.handle || !payload.data) {
+ if (newState.profileForHandle !== payload.handle) {
return newState;
}
return {
...newState,
- emailPreferences: payload.data.subscriptions,
+ emailPreferences: payload.preferences,
};
}
diff --git a/src/services/user.js b/src/services/user.js
index 802f5af3..2fa7c0f6 100644
--- a/src/services/user.js
+++ b/src/services/user.js
@@ -114,6 +114,7 @@ class User {
this.private = {
api: getApi('V3', tokenV3),
apiV2: getApi('V2', tokenV2),
+ apiV5: getApi('V5', tokenV3),
tokenV2,
tokenV3,
};
@@ -174,10 +175,10 @@ class User {
* @returns {Promise} Resolves to the email preferences result
*/
async getEmailPreferences(userId) {
- const url = `/users/${userId}/preferences/email`;
- const res = await this.private.api.get(url);
- const x = (await res.json()).result;
- return x.content;
+ const url = `/users/${userId}/preferences`;
+ const res = await this.private.apiV5.get(url);
+ const x = (await res.json());
+ return x.email;
}
/**
@@ -193,18 +194,17 @@ class User {
const settings = {
firstName,
lastName,
- subscriptions: {},
+ createdBy: String(userId),
+ updatedBy: String(userId),
+ subscriptions: preferences,
};
- if (!preferences) {
- settings.subscriptions.TOPCODER_NL_GEN = true;
- } else {
- settings.subscriptions = preferences;
- }
- const url = `/users/${userId}/preferences/email`;
-
- const res = await this.private.api.putJson(url, { param: settings });
- return getApiResponsePayload(res);
+ const url = `/users/${userId}/preferences`;
+ const res = await this.private.apiV5.putJson(
+ url,
+ { email: settings, objectId: String(userId) },
+ );
+ return res;
}
/**
From a78ae4d552ae0cacc910e9f814f2bdb586aa4c6a Mon Sep 17 00:00:00 2001
From: Thomas Kranitsas
Date: Fri, 10 May 2019 12:24:55 +0300
Subject: [PATCH 11/15] Fix tests
---
__tests__/__snapshots__/index.js.snap | 3 ---
1 file changed, 3 deletions(-)
diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap
index 0386661f..e7ee51bc 100644
--- a/__tests__/__snapshots__/index.js.snap
+++ b/__tests__/__snapshots__/index.js.snap
@@ -426,17 +426,14 @@ Object {
"countReset": [Function],
"debug": [Function],
"dir": [Function],
- "dirxml": [Function],
"error": [Function],
"group": [Function],
"groupCollapsed": [Function],
"groupEnd": [Function],
"info": [Function],
"log": [Function],
- "table": [Function],
"time": [Function],
"timeEnd": [Function],
- "timeLog": [Function],
"trace": [Function],
"warn": [Function],
},
From dbabfda8dbcab62af5f9de813a4f4fa68d89ab67 Mon Sep 17 00:00:00 2001
From: Sushil
Date: Fri, 10 May 2019 16:13:07 +0530
Subject: [PATCH 12/15] bump npm version
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index b8be6639..d0fa7e8c 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
"lint:js": "./node_modules/.bin/eslint --ext .js,.jsx .",
"test": "npm run lint && npm run jest"
},
- "version": "0.7.13",
+ "version": "0.7.14",
"dependencies": {
"auth0-js": "^6.8.4",
"isomorphic-fetch": "^2.2.1",
From ea9c3e35d157de6d7cd430da607896ffc5601568 Mon Sep 17 00:00:00 2001
From: Huan Li
Date: Fri, 24 May 2019 11:56:48 +0800
Subject: [PATCH 13/15] Fixed issues of server-side filtering on challenge
listings
---
src/actions/challenge-listing.js | 30 +++++++++++++++++-------------
src/reducers/challenge-listing.js | 23 ++++++++++++++++++-----
2 files changed, 35 insertions(+), 18 deletions(-)
diff --git a/src/actions/challenge-listing.js b/src/actions/challenge-listing.js
index 2e9c0d08..e60f10f0 100644
--- a/src/actions/challenge-listing.js
+++ b/src/actions/challenge-listing.js
@@ -150,7 +150,11 @@ function getAllActiveChallengesDone(uuid, tokenV3) {
});
}
- return { uuid, challenges: ch.challenges };
+ return {
+ uuid,
+ challenges: ch.challenges,
+ handle: user,
+ };
});
}
@@ -197,27 +201,27 @@ function getActiveChallengesDone(
}).catch(() => ({ challenges: [] })));
}
return Promise.all(calls).then(([ch, uch]) => {
- let fullCH = ch;
+ // let fullCH = ch;
/* uch array contains challenges where the user is participating in
* some role. The same challenge are already listed in res array, but they
* are not attributed to the user there. This block of code marks user
* challenges in an efficient way. */
if (uch) {
const map = {};
- uch.challenges.forEach((item) => {
- map[item.id] = item;
- /* eslint-disable no-param-reassign */
- item.users[user] = true;
- item.userDetails = map[item.id].userDetails;
- /* eslint-enable no-param-reassign */
+ uch.challenges.forEach((item) => { map[item.id] = item; });
+ ch.challenges.forEach((item) => {
+ if (map[item.id]) {
+ /* It is fine to reassing, as the array we modifying is created just
+ * above within the same function. */
+ /* eslint-disable no-param-reassign */
+ item.users[user] = true;
+ item.userDetails = map[item.id].userDetails;
+ /* eslint-enable no-param-reassign */
+ }
});
}
- if (uch) {
- fullCH = uch;
- }
- let { challenges } = fullCH;
- let { meta } = ch;
+ let { challenges, meta } = ch;
// filter by date range and re-compute meta
// we can safely remove the next two lines when backend support date range
challenges = filterUtil.filterByDate(challenges, frontFilter);
diff --git a/src/reducers/challenge-listing.js b/src/reducers/challenge-listing.js
index b1d87967..10d359c7 100644
--- a/src/reducers/challenge-listing.js
+++ b/src/reducers/challenge-listing.js
@@ -94,20 +94,33 @@ function onGetAllActiveChallengesDone(state, { error, payload }) {
logger.error(payload);
return state;
}
- const { uuid, challenges: loaded } = payload;
+ const {
+ uuid, challenges: loaded, handle,
+ } = payload;
if (uuid !== state.loadingActiveChallengesUUID) return state;
/* Once all active challenges are fetched from the API, we remove from the
* store any active challenges stored there previously, and also any
* challenges with IDs matching any challenges loaded now as active. */
const ids = new Set();
loaded.forEach(item => ids.add(item.id));
- const challenges = state.challenges
- .filter(item => item.status !== 'ACTIVE' && !ids.has(item.id))
- .concat(loaded);
+
+ const filter = item => !ids.has(item.id) && item.status !== 'ACTIVE';
+ // BUCKET.MY
+ const my = processBucketData(
+ handle, state.challenges, loaded, BUCKETS.MY, null, null, filter, {},
+ );
+ // BUCKET.ALL
+ const all = processBucketData(
+ handle, state.challenges, loaded, BUCKETS.ALL, null, null, filter, {},
+ );
+
+ const newChallenges = _.cloneDeep(state.challenges);
+ newChallenges[BUCKETS.ALL] = all;
+ newChallenges[BUCKETS.MY] = my;
return {
...state,
- challenges,
+ challenges: newChallenges,
lastUpdateOfActiveChallenges: Date.now(),
loadingActiveChallengesUUID: '',
};
From 3a520fff5b8aa633c0a2f1d23f21adc83bb7c0f2 Mon Sep 17 00:00:00 2001
From: Sushil Shinde
Date: Mon, 27 May 2019 16:20:44 +0530
Subject: [PATCH 14/15] Updating NPM version for prod release to 0.7.15
Updating NPM version for prod release to 0.7.15
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index d0fa7e8c..a8163f0b 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
"lint:js": "./node_modules/.bin/eslint --ext .js,.jsx .",
"test": "npm run lint && npm run jest"
},
- "version": "0.7.14",
+ "version": "0.7.15",
"dependencies": {
"auth0-js": "^6.8.4",
"isomorphic-fetch": "^2.2.1",
From 1c00f798fd0527a195de68b7275d39dc1e2476c5 Mon Sep 17 00:00:00 2001
From: rashmi73
Date: Fri, 7 Jun 2019 02:11:25 +0530
Subject: [PATCH 15/15] issue 2359 fix
---
src/actions/members.js | 3 ++-
src/services/challenges.js | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/actions/members.js b/src/actions/members.js
index 38b25a1c..de57f20e 100644
--- a/src/actions/members.js
+++ b/src/actions/members.js
@@ -339,7 +339,8 @@ async function getUserMarathonDone(
uuid, handle, tokenV3, pageNum, pageSize,
refresh,
) {
- const filter = { status: 'PAST', isRatedForMM: 'true' };
+ const filter = { status: 'COMPLETED', track: 'DATA_SCIENCE',
+ subTrack: 'MARATHON_MATCH,DEVELOP_MARATHON_MATCH' };
const params = {};
params.orderBy = 'endDate desc';
params.limit = pageSize;
diff --git a/src/services/challenges.js b/src/services/challenges.js
index 04244726..f9271f75 100644
--- a/src/services/challenges.js
+++ b/src/services/challenges.js
@@ -461,7 +461,7 @@ class ChallengesService {
* @return {Promise} Resolves to the api response.
*/
getUserMarathonMatches(username, filters, params) {
- const endpoint = `/members/${username.toLowerCase()}/mms/`;
+ const endpoint = `/members/${username.toLowerCase()}/challenges/`;
return this.private.getChallenges(endpoint, filters, params);
}