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/__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/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/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 cc4ec5c2..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.11", + "version": "0.7.15", "dependencies": { "auth0-js": "^6.8.4", "isomorphic-fetch": "^2.2.1", diff --git a/src/actions/challenge-listing.js b/src/actions/challenge-listing.js new file mode 100644 index 00000000..e60f10f0 --- /dev/null +++ b/src/actions/challenge-listing.js @@ -0,0 +1,461 @@ +/** + * 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 + * When filter includes Data Science track, still should be + * included DEVELOP_MARATHON_MATCH sub track. + * @param filter + * @returns {string} + */ +function processFilter(filter) { + const newFilter = _.clone(filter); + if (_.has(filter, 'track') + && filter.track.includes(COMPETITION_TRACKS.DATA_SCIENCE.toUpperCase()) + && ((_.has(filter, 'subTrack') && !filter.subTrack.includes('DEVELOP_MARATHON_MATCH')) + || !_.has(filter, 'subTrack')) + ) { + 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; +} + +/** + * 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, + handle: user, + }; + }); +} + +/** + * 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]) => { + // 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 */ + } + }); + } + + 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/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/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/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..10d359c7 --- /dev/null +++ b/src/reducers/challenge-listing.js @@ -0,0 +1,861 @@ +/** + * 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, 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 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: newChallenges, + 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/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/challenges.js b/src/services/challenges.js index 604a2879..f9271f75 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 || [], @@ -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); } 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; } /** 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; 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