diff --git a/.circleci/config.yml b/.circleci/config.yml index 349c4c5d3c..586627f01d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -343,6 +343,7 @@ workflows: branches: only: - develop + - feature/recommended-challenges-update # This is alternate dev env for parallel testing - "build-test": context : org-global @@ -371,6 +372,7 @@ workflows: branches: only: - develop + - feature/recommended-challenges-update # Production builds are exectuted # when PR is merged to the master # Don't change anything in this configuration diff --git a/package.json b/package.json index 47838d7999..0c1ebd93b8 100644 --- a/package.json +++ b/package.json @@ -150,7 +150,7 @@ "supertest": "^3.1.0", "tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6.3", "tc-ui": "^1.0.12", - "topcoder-react-lib": "1.2.1", + "topcoder-react-lib": "1000.28.3", "topcoder-react-ui-kit": "2.0.1", "topcoder-react-utils": "0.7.8", "turndown": "^4.0.2", diff --git a/src/assets/images/icon-not-found.svg b/src/assets/images/icon-not-found.svg new file mode 100644 index 0000000000..eb39f3e40d --- /dev/null +++ b/src/assets/images/icon-not-found.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/shared/components/SortingSelectBar/style.scss b/src/shared/components/SortingSelectBar/style.scss index 9d98296594..768994e45e 100644 --- a/src/shared/components/SortingSelectBar/style.scss +++ b/src/shared/components/SortingSelectBar/style.scss @@ -24,7 +24,7 @@ $down-arrow-size: $base-unit; font-size: 13px; line-height: 13px; margin: 0; - padding: 0 0 0 10px; + padding: 4.5px 0 4.5px 10px; border: none; text-transform: none; } diff --git a/src/shared/components/challenge-listing/ChallengeCard/index.jsx b/src/shared/components/challenge-listing/ChallengeCard/index.jsx index 8ffc8fb7de..71d4064b00 100644 --- a/src/shared/components/challenge-listing/ChallengeCard/index.jsx +++ b/src/shared/components/challenge-listing/ChallengeCard/index.jsx @@ -49,7 +49,7 @@ function ChallengeCard({ const registrationPhase = (challenge.phases || []).filter(phase => phase.name === 'Registration')[0]; const isRegistrationOpen = registrationPhase ? registrationPhase.isOpen : false; - const isRecommendedChallenge = challenge.jaccard_index; + const isRecommendedChallenge = !!challenge.jaccard_index; return (
diff --git a/src/shared/components/challenge-listing/Filters/FiltersPanel/index.jsx b/src/shared/components/challenge-listing/Filters/FiltersPanel/index.jsx index b39254214c..7e354fb936 100644 --- a/src/shared/components/challenge-listing/Filters/FiltersPanel/index.jsx +++ b/src/shared/components/challenge-listing/Filters/FiltersPanel/index.jsx @@ -306,7 +306,7 @@ export default function FiltersPanel({ const recommendedCheckboxTip = (
-

Shows available challenges
that match your skills

+

Show the best challenges for you.

); diff --git a/src/shared/components/challenge-listing/Listing/Bucket/index.jsx b/src/shared/components/challenge-listing/Listing/Bucket/index.jsx index cc4898d94d..a4fd9bca1a 100644 --- a/src/shared/components/challenge-listing/Listing/Bucket/index.jsx +++ b/src/shared/components/challenge-listing/Listing/Bucket/index.jsx @@ -9,7 +9,7 @@ import PT from 'prop-types'; // import qs from 'qs'; import React, { useRef } from 'react'; // import { config } from 'topcoder-react-utils'; -import Sort, { SORTS } from 'utils/challenge-listing/sort'; +import Sort from 'utils/challenge-listing/sort'; import { NO_LIVE_CHALLENGES_CONFIG, BUCKETS, BUCKET_DATA, isRecommendedChallengeType, } from 'utils/challenge-listing/buckets'; @@ -18,6 +18,7 @@ import Waypoint from 'react-waypoint'; // import { challenge as challengeUtils } from 'topcoder-react-lib'; import CardPlaceholder from '../../placeholders/ChallengeCard'; import ChallengeCard from '../../ChallengeCard'; +import NoRecommenderChallengeCard from '../../NoRecommenderChallengeCard'; import './style.scss'; // const COLLAPSED_SIZE = 10; @@ -53,9 +54,6 @@ export default function Bucket({ isLoggedIn, setSearchText, }) { - const activeBucketData = isRecommendedChallengeType(bucket, filterState) - ? [SORTS.BEST_MATCH] : BUCKET_DATA[bucket].sorts.filter(item => item !== 'bestMatch'); - const refs = useRef([]); refs.current = []; const addToRefs = (el) => { @@ -180,33 +178,50 @@ export default function Bucket({ // // instead of waiting for scrolling to hit the react-waypoint to do the loadMore // loadMore(); // } - + const isRecommended = isRecommendedChallengeType(bucket, filterState); + const isHighestPaying = isRecommended && _.sumBy(filteredChallenges, 'jaccard_index') === 0; + const sectionTile = isHighestPaying ? 'HIGHEST PAYING OPEN CHALLENGES' : 'Recommended Open Challenges'; return ( // challenges.length !== 0 // && ( -
- ({ - label: Sort[item].name, - value: item, - })) - } - title={BUCKET_DATA[bucket].name} - value={{ - label: Sort[activeSort].name, - value: activeSort, - }} - /> - {cards} +
{ - !expanding && !expandable && loadMore && !loading && activeBucket === bucket ? ( - - ) : null + isHighestPaying && (!loading || filteredChallenges.length > 0) + && } - {placeholders} - { +
+ { + isRecommended + ? filteredChallenges.length > 0 && ( + + ) + : ( + ({ + label: Sort[item].name, + value: item, + })) + } + title={BUCKET_DATA[bucket].name} + value={{ + label: Sort[activeSort].name, + value: activeSort, + }} + /> + ) + } + {cards} + { + !expanding && !expandable && loadMore && !loading && activeBucket === bucket ? ( + + ) : null + } + {placeholders} + { // (expandable || loadMore) && (expandable || !keepPlaceholders) && !loading && !expanded ? ( (expanding || expandable) && !loading && loadMore && (expandable ? expanded : !expanded) ? ( ) : null - } + } +
// ) ); diff --git a/src/shared/components/challenge-listing/NoChallengeCard/index.jsx b/src/shared/components/challenge-listing/NoChallengeCard/index.jsx deleted file mode 100644 index 36f7130201..0000000000 --- a/src/shared/components/challenge-listing/NoChallengeCard/index.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; - -import './style.scss'; -import ComputerIcon from 'assets/images/icon-computer.svg'; - -function NoChallengeCard() { - return ( -
-
- -
- - There are no challenges open for registration at the moment that match your skills.
- Try exploring other challenges or checking back later. -
-
- ); -} - -export default NoChallengeCard; diff --git a/src/shared/components/challenge-listing/NoChallengeCard/style.scss b/src/shared/components/challenge-listing/NoChallengeCard/style.scss deleted file mode 100644 index 0cf45ef169..0000000000 --- a/src/shared/components/challenge-listing/NoChallengeCard/style.scss +++ /dev/null @@ -1,28 +0,0 @@ -@import '~styles/mixins'; - -.container { - width: 70%; - height: 150px; - background-color: #fff; - border-radius: 4px; - display: flex; - justify-content: center; - flex-direction: column; - margin: 20px 4px 0 4px; -} - -.icon { - text-align: center; - padding-top: 30px; -} - -.text { - @include roboto-regular; - - font-size: 13px; - text-align: center; - padding-bottom: 26px; - padding-top: 10px; - line-height: 22px; - color: $tc-gray-60; -} diff --git a/src/shared/components/challenge-listing/NoRecommenderChallengeCard/index.jsx b/src/shared/components/challenge-listing/NoRecommenderChallengeCard/index.jsx new file mode 100644 index 0000000000..39ef766991 --- /dev/null +++ b/src/shared/components/challenge-listing/NoRecommenderChallengeCard/index.jsx @@ -0,0 +1,26 @@ +import React from 'react'; + +import { Link, config } from 'topcoder-react-utils'; +import './style.scss'; +import NotFoundIcon from 'assets/images/icon-not-found.svg'; + +const base = config.URL.BASE; + +function NoRecommenderChallengeCard() { + return ( +
+
+ +
+ + NO VERIFIED SKILLS ON YOUR PROFILE + + + Your recommended challenges are based on your Verified Skills. + Competing in challenges is a great way to earn them. + +
+ ); +} + +export default NoRecommenderChallengeCard; diff --git a/src/shared/components/challenge-listing/NoRecommenderChallengeCard/style.scss b/src/shared/components/challenge-listing/NoRecommenderChallengeCard/style.scss new file mode 100644 index 0000000000..e1048e8f16 --- /dev/null +++ b/src/shared/components/challenge-listing/NoRecommenderChallengeCard/style.scss @@ -0,0 +1,62 @@ +@import '~styles/mixins'; + +.container { + min-height: 178px; + background-color: #fff; + border-radius: 4px; + display: flex; + justify-content: center; + flex-direction: column; + margin-top: 20px; +} + +.icon { + display: flex; + justify-content: center; + + @include xs-to-sm { + padding-top: 37.61px; + } + + @include sm-to-xl { + padding-top: 46.25px; + } +} + +.text-header { + @include xs-to-lg { + margin: 17.92px 10px 0 10px; + } + + @include lg-to-xl { + margin: 26.68px 10px 0 10px; + } + + @include barlow-semi-bold; + + font-size: 16px; + text-align: center; + line-height: 16px; + color: #2a2a2a; +} + +.text { + @include roboto-regular; + + padding: 8px 10px 24px; + font-size: 16px; + text-align: center; + line-height: 26px; + color: #2a2a2a; +} + +.challenge-link { + color: #2862b9; + text-decoration: underline; + + &:hover, + &:active, + &:visited { + color: #2862b9; + } +} diff --git a/src/shared/components/challenge-listing/index.jsx b/src/shared/components/challenge-listing/index.jsx index c05b8ab9fe..bc3bf94b7f 100644 --- a/src/shared/components/challenge-listing/index.jsx +++ b/src/shared/components/challenge-listing/index.jsx @@ -15,7 +15,6 @@ import Sidebar from 'containers/challenge-listing/Sidebar'; // import { config } from 'topcoder-react-utils'; import { useMediaQuery } from 'react-responsive'; -import NoChallengeCard from './NoChallengeCard'; import Listing from './Listing'; // import ChallengeCardPlaceholder from './placeholders/ChallengeCard'; import Banner from './Banner'; @@ -51,7 +50,6 @@ export default function ChallengeListing(props) { // isBucketSwitching, isLoggedIn, setSearchText, - loadingOpenForRegistrationChallenges, } = props; // const { challenges } = props; @@ -151,10 +149,6 @@ export default function ChallengeListing(props) { ); const desktop = useMediaQuery({ minWidth: 1024 }); - const isRecommendedOn = filterState.recommended - && !loadingOpenForRegistrationChallenges - && activeBucket === 'openForRegistration' - && !openForRegistrationChallenges.length; return (
@@ -186,11 +180,7 @@ export default function ChallengeListing(props) { />
- { - isRecommendedOn - ? - : challengeCardContainer - } + { challengeCardContainer }
diff --git a/src/shared/utils/challenge-listing/buckets.js b/src/shared/utils/challenge-listing/buckets.js index d1cf709f58..55883e82a0 100644 --- a/src/shared/utils/challenge-listing/buckets.js +++ b/src/shared/utils/challenge-listing/buckets.js @@ -58,7 +58,7 @@ export const BUCKET_DATA = { // hideCount: false, name: 'Open for registration', sorts: [ - SORTS.BEST_MATCH, + // SORTS.BEST_MATCH, SORTS.MOST_RECENT_START_DATE, // SORTS.TIME_TO_REGISTER, // SORTS.TIME_TO_SUBMIT,