diff --git a/.circleci/config.yml b/.circleci/config.yml index 0e161844..e8eac28e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -28,7 +28,7 @@ jobs: - attach_workspace: at: . - run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc - - run: npm publish + - run: npm publish --tag test-release # dont change anything workflows: version: 2 diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap index e518ab25..02658e98 100644 --- a/__tests__/__snapshots__/index.js.snap +++ b/__tests__/__snapshots__/index.js.snap @@ -303,6 +303,7 @@ Object { "SUBMISSION_END_DATE": "submissionEndDate", }, "default": undefined, + "getFilterUrl": [Function], "getService": [Function], "normalizeChallenge": [Function], }, @@ -378,9 +379,9 @@ Object { "DRAFT": "Draft", }, "COMPETITION_TRACKS": Object { - "DATA_SCIENCE": "Data Science", - "DESIGN": "Design", - "DEVELOP": "Development", + "DES": "Design", + "DEV": "Development", + "DS": "Data Science", "QA": "Quality Assurance", }, "OLD_COMPETITION_TRACKS": Object { diff --git a/package.json b/package.json index fcee4bb2..1bf653d3 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": "1.0.7", + "version": "1000.24.5", "dependencies": { "auth0-js": "^6.8.4", "config": "^3.2.0", diff --git a/src/reducers/challenge.js b/src/reducers/challenge.js index 7fb1dbd9..e706cb07 100644 --- a/src/reducers/challenge.js +++ b/src/reducers/challenge.js @@ -471,7 +471,7 @@ export function factory(options = {}) { const challengeDetails = _.get(res, 'payload', {}); const track = _.get(challengeDetails, 'track', ''); let checkpointsPromise = null; - if (track === COMPETITION_TRACKS.DESIGN) { + if (track === COMPETITION_TRACKS.DES) { const p = _.get(challengeDetails, 'phases', []) .filter(x => x.name === 'Checkpoint Review'); if (p.length && !p[0].isOpen) { diff --git a/src/services/challenges.js b/src/services/challenges.js index 5dc24d7f..e232274b 100644 --- a/src/services/challenges.js +++ b/src/services/challenges.js @@ -15,6 +15,43 @@ import { getApi } from './api'; import { getService as getMembersService } from './members'; import { getService as getSubmissionsService } from './submissions'; +export function getFilterUrl(backendFilter, frontFilter) { + const ff = _.clone(frontFilter); + // eslint-disable-next-line object-curly-newline + const { tags, tracks, types, groups, events } = ff; + delete ff.tags; + delete ff.tracks; + delete ff.types; + delete ff.communityId; + delete ff.groups; + delete ff.events; + + // console.log(ff); + + let urlFilter = qs.stringify(_.reduce(ff, (result, value, key) => { + // eslint-disable-next-line no-param-reassign + if (value) result[key] = value; + return result; + }, {})); + // console.log(urlFilter); + + const ftags = _.map(tags, val => `tags[]=${val}`).join('&'); + const ftracks = _.map(_.reduce(tracks, (result, value, key) => { + // eslint-disable-next-line no-unused-expressions + tracks[key] && result.push(key); + return result; + }, []), val => `tracks[]=${val}`).join('&'); + const ftypes = _.map(types, val => `types[]=${val}`).join('&'); + const fgroups = _.map(groups, val => `groups[]=${val}`).join('&'); + const fevents = _.map(events, val => `events[]=${val}`).join('&'); + if (ftags.length > 0) urlFilter += `&${ftags}`; + if (ftracks.length > 0) urlFilter += `&${ftracks}`; + if (ftypes.length > 0) urlFilter += `&${ftypes}`; + if (fgroups.length > 9) urlFilter += `&${fgroups}`; + if (fevents.length > 0) urlFilter += `&${fevents}`; + return urlFilter; +} + export const ORDER_BY = { SUBMISSION_END_DATE: 'submissionEndDate', }; @@ -133,27 +170,42 @@ class ChallengesService { */ const getChallenges = async ( endpoint, - filters = {}, - params = {}, + filter, ) => { - const query = { - ...filters, - ...params, - }; - const url = `${endpoint}?${qs.stringify(query)}`; - const res = await this.private.apiV5.get(url).then(checkErrorV5); + let res = {}; + if (_.some(filter.frontFilter.tracks, val => val)) { + const query = getFilterUrl(filter.backendFilter, filter.frontFilter); + const url = `${endpoint}?${query}`; + res = await this.private.apiV5.get(url).then(checkErrorV5); + } return { challenges: res.result || [], - totalCount: res.headers.get('x-total'), + totalCount: res.headers ? res.headers.get('x-total') : 0, meta: { - allChallengesCount: res.headers.get('x-total'), + allChallengesCount: res.headers ? res.headers.get('x-total') : 0, myChallengesCount: 0, ongoingChallengesCount: 0, openChallengesCount: 0, - totalCount: res.headers.get('x-total'), + totalCount: res.headers ? res.headers.get('x-total') : 0, }, }; }; + + const getChallengeDetails = async ( + endpoint, + legacyInfo, + ) => { + let query = ''; + if (legacyInfo) { + query = `legacyId=${legacyInfo.legacyId}`; + } + const url = `${endpoint}?${query}`; + const res = await this.private.apiV5.get(url).then(checkErrorV5); + return { + challenges: res.result || [], + }; + }; + /** * Private function being re-used in all methods related to getting * challenges. It handles query-related arguments in the uniform way: @@ -189,6 +241,7 @@ class ChallengesService { apiV2: getApi('V2', tokenV2), apiV3: getApi('V3', tokenV3), getChallenges, + getChallengeDetails, getMemberChallenges, tokenV2, tokenV3, @@ -327,10 +380,10 @@ class ChallengesService { // condition based on ROUTE used for Review Opportunities, change if needed if (/^[\d]{5,8}$/.test(challengeId)) { isLegacyChallenge = true; - challenge = await this.private.getChallenges('/challenges/', { legacyId: challengeId }) + challenge = await this.private.getChallengeDetails('/challenges/', { legacyId: challengeId }) .then(res => res.challenges[0] || {}); } else { - challenge = await this.private.getChallenges(`/challenges/${challengeId}`) + challenge = await this.private.getChallengeDetails(`/challenges/${challengeId}`) .then(res => res.challenges); } @@ -464,8 +517,8 @@ class ChallengesService { * @param {Object} params Optional. * @return {Promise} Resolves to the api response. */ - async getChallenges(filters, params) { - return this.private.getChallenges('/challenges/', filters, params) + async getChallenges(filter) { + return this.private.getChallenges('/challenges/', filter) .then((res) => { res.challenges.forEach(item => normalizeChallenge(item)); return res; @@ -642,7 +695,7 @@ class ChallengesService { let contentType; let url; - if (track === COMPETITION_TRACKS.DESIGN) { + if (track === COMPETITION_TRACKS.DES) { ({ api } = this.private); contentType = 'application/json'; url = '/submissions/'; // The submission info is contained entirely in the JSON body @@ -660,7 +713,7 @@ class ChallengesService { }, onProgress).then((res) => { const jres = JSON.parse(res); // Return result for Develop submission - if (track === COMPETITION_TRACKS.DEVELOP) { + if (track === COMPETITION_TRACKS.DEV) { return jres; } // Design Submission requires an extra "Processing" POST diff --git a/src/services/reviewOpportunities.js b/src/services/reviewOpportunities.js index 9f3cdf31..6e255a95 100644 --- a/src/services/reviewOpportunities.js +++ b/src/services/reviewOpportunities.js @@ -17,10 +17,10 @@ export function normalizeChallenges(opportunities) { * until receive API V5 update. */ _.map(opportunities, (opportunity) => { const { challenge } = opportunity; - challenge.track = COMPETITION_TRACKS.DEVELOP; + challenge.track = COMPETITION_TRACKS.DEV; if (challenge.technologies) { - if (challenge.technologies.includes(COMPETITION_TRACKS.DATA_SCIENCE)) { - challenge.track = COMPETITION_TRACKS.DATA_SCIENCE; + if (challenge.technologies.includes(COMPETITION_TRACKS.DS)) { + challenge.track = COMPETITION_TRACKS.DS; } } else if (challenge.subTrack === OLD_SUBTRACKS.TEST_SUITES || challenge.subTrack === OLD_SUBTRACKS.BUG_HUNT @@ -28,7 +28,7 @@ export function normalizeChallenges(opportunities) { || challenge.subTrack === OLD_COMPETITION_TRACKS.TESTING_COMPETITION) { challenge.track = COMPETITION_TRACKS.QA; } else if (challenge.track === OLD_COMPETITION_TRACKS.DESIGN) { - challenge.track = COMPETITION_TRACKS.DESIGN; + challenge.track = COMPETITION_TRACKS.DES; } return _.defaults(opportunity, { challenge }); }); diff --git a/src/utils/challenge/filter.js b/src/utils/challenge/filter.js index 117e0609..0728dc15 100644 --- a/src/utils/challenge/filter.js +++ b/src/utils/challenge/filter.js @@ -90,7 +90,7 @@ function filterByRegistrationOpen(challenge, state) { if (!registrationPhase || !registrationPhase.isOpen) { return false; } - if (challenge.track === COMPETITION_TRACKS.DESIGN) { + if (challenge.track === COMPETITION_TRACKS.DES) { const checkpointPhase = challengePhases.find(item => item.name === 'Checkpoint Submission')[0]; return !checkpointPhase || !checkpointPhase.isOpen; } @@ -147,7 +147,7 @@ function filterByStatus(challenge, state) { function filterByTags(challenge, state) { if (_.isEmpty(state.tags)) return true; const { platforms, tags } = challenge; - const str = `${platforms} ${tags}`.toLowerCase(); + const str = `${platforms.join(' ')} ${tags.join(' ')}`.toLowerCase(); return state.tags.some(tag => str.includes(tag.toLowerCase())); } @@ -158,19 +158,20 @@ function filterByEvents(challenge, state) { } function filterByText(challenge, state) { - if (!state.text) return true; + if (!state.name) return true; const str = `${challenge.name} ${challenge.tags} ${challenge.platforms} ${challenge.tags}` .toLowerCase(); - return str.includes(state.text.toLowerCase()); + return str.includes(state.name.toLowerCase()); } function filterByTrack(challenge, state) { - if (!state.tracks) return true; - return _.keys(state.tracks).some(track => challenge.track === track); + // if (!state.tracks) return true; + // eslint-disable-next-line max-len + return state.tracks[challenge.track] === true; } function filterByTypes(challenge, state) { - if (!state.types) return true; + if (state.types.length === 0) return true; return state.types.includes(challenge.typeId); } @@ -179,10 +180,10 @@ function filterByUpcoming(challenge, state) { return moment().isBefore(challenge.registrationStartDate); } -function filterByUsers(challenge, state) { - if (!state.userChallenges) return true; - return state.userChallenges.find(ch => challenge.id === ch); -} +// function filterByUsers(challenge, state) { +// if (!state.userChallenges) return true; +// return state.userChallenges.find(ch => challenge.id === ch); +// } /** * Returns clone of the state with the specified competition track added. @@ -223,7 +224,7 @@ export function getFilterFunction(state) { && filterByTags(challenge, state) && filterByEvents(challenge, state) && filterByTypes(challenge, state) - && filterByUsers(challenge, state) + // && filterByUsers(challenge, state) && filterByEndDate(challenge, state) && filterByStartDate(challenge, state) && filterByStarted(challenge, state) @@ -247,7 +248,14 @@ export function getFilterFunction(state) { */ export function getReviewOpportunitiesFilterFunction(state, validTypes) { return (opp) => { - const newType = _.find(validTypes, { name: opp.challenge.type }) || {}; + const trackAbbr = { + 'Data Science': 'DS', + Development: 'Dev', + Design: 'Des', + 'Quality Assurance': 'QA', + }; + // const newType = _.find(validTypes, { name: opp.challenge.type }) || {}; + const newType = _.find(validTypes, { name: opp.challenge.subTrack === 'FIRST_2_FINISH' ? 'First2Finish' : 'Challenge' }) || {}; // Review Opportunity objects have a challenge field which // is largely compatible with many of the existing filter functions @@ -256,21 +264,32 @@ export function getReviewOpportunitiesFilterFunction(state, validTypes) { ...opp.challenge, // This allows filterByText to search for Review Types and Challenge Titles name: `${opp.challenge.title} ${REVIEW_OPPORTUNITY_TYPES[opp.type]}`, - registrationStartDate: opp.startDate, // startDate of Review, not Challenge - submissionEndDate: opp.startDate, // Currently uses startDate for both date comparisons - communities: new Set([ // Used to filter by Track, and communities at a future date - opp.challenge.track.toLowerCase(), - ]), - typeId: newType.id, + // registrationStartDate: opp.startDate, // startDate of Review, not Challenge + // submissionEndDate: opp.startDate, // Currently uses startDate for both date comparisons + // communities: new Set([ // Used to filter by Track, and communities at a future date + // opp.challenge.track === 'QA' ? 'Dev' : trackAbbr[opp.challenge.track], + // ]), + track: trackAbbr[opp.challenge.track], + typeId: newType.abbreviation, tags: opp.challenge.technologies || [], platforms: opp.challenge.platforms || [], }; - + /** + console.log(challenge); + console.log(`=====`); + console.log(`11111`); + console.log(filterByTrack(challenge, state)); + console.log(filterByText(challenge, state)); + console.log(filterByTags(challenge, state)); + console.log(filterByEndDate(challenge, state)); + console.log(filterByStartDate(challenge, state)); + console.log(filterByReviewOpportunityType(opp, state)); + */ return ( filterByTrack(challenge, state) && filterByText(challenge, state) && filterByTags(challenge, state) - // && filterByTypes(challenge, state) + && filterByTypes(challenge, state) && filterByEndDate(challenge, state) && filterByStartDate(challenge, state) && filterByReviewOpportunityType(opp, state) diff --git a/src/utils/tc.js b/src/utils/tc.js index 4ea44255..cf0c470a 100644 --- a/src/utils/tc.js +++ b/src/utils/tc.js @@ -11,9 +11,9 @@ * uses upper-case literals to encode the tracks. At some point, we should * update it in this code as well! */ export const COMPETITION_TRACKS = { - DATA_SCIENCE: 'Data Science', - DESIGN: 'Design', - DEVELOP: 'Development', + DS: 'Data Science', + DES: 'Design', + DEV: 'Development', QA: 'Quality Assurance', };