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); } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy