From d9479bae64820194d4c147b6f0b0c58355f8c405 Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Mon, 31 Jul 2023 10:30:34 +0300 Subject: [PATCH 01/44] TAL-34 - improve search results cards for talent-search --- .../src/components/match-bar/index.ts | 1 - .../ProfileMatch.module.scss} | 17 +++-- .../ProfileMatch.tsx} | 8 +-- .../src/components/profile-match/index.ts | 1 + .../talent-card/TalentCard.module.scss | 19 +++--- .../src/components/talent-card/TalentCard.tsx | 65 ++++++++----------- 6 files changed, 54 insertions(+), 57 deletions(-) delete mode 100644 src/apps/talent-search/src/components/match-bar/index.ts rename src/apps/talent-search/src/components/{match-bar/MatchBar.module.scss => profile-match/ProfileMatch.module.scss} (69%) rename src/apps/talent-search/src/components/{match-bar/MatchBar.tsx => profile-match/ProfileMatch.tsx} (76%) create mode 100644 src/apps/talent-search/src/components/profile-match/index.ts diff --git a/src/apps/talent-search/src/components/match-bar/index.ts b/src/apps/talent-search/src/components/match-bar/index.ts deleted file mode 100644 index c67f75cbc..000000000 --- a/src/apps/talent-search/src/components/match-bar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as MatchBar } from './MatchBar' diff --git a/src/apps/talent-search/src/components/match-bar/MatchBar.module.scss b/src/apps/talent-search/src/components/profile-match/ProfileMatch.module.scss similarity index 69% rename from src/apps/talent-search/src/components/match-bar/MatchBar.module.scss rename to src/apps/talent-search/src/components/profile-match/ProfileMatch.module.scss index 5842b6775..9bee73d1a 100644 --- a/src/apps/talent-search/src/components/match-bar/MatchBar.module.scss +++ b/src/apps/talent-search/src/components/profile-match/ProfileMatch.module.scss @@ -5,12 +5,13 @@ align-items: center; justify-content: center; color: $tc-white; - font-family: $font-barlow; - - gap: $sp-2; + font-family: $font-roboto; + flex-direction: column; border-radius: 100px; padding-bottom: 2px; + width: 100%; + aspect-ratio: 1 / 1; background: rgb(130,234,207); background: linear-gradient( @@ -26,13 +27,17 @@ background-size: 100% 3000px; background-position: 0 0; + font-size: 16px; + line-height: 26px; + font-weight: $font-weight-bold; + &:global(.dark) { color: $black-100; } strong { - font-size: 26px; - font-weight: $font-weight-medium; - line-height: $sp-8; + font-size: 23px; + line-height: 27px; + font-weight: 900; } } diff --git a/src/apps/talent-search/src/components/match-bar/MatchBar.tsx b/src/apps/talent-search/src/components/profile-match/ProfileMatch.tsx similarity index 76% rename from src/apps/talent-search/src/components/match-bar/MatchBar.tsx rename to src/apps/talent-search/src/components/profile-match/ProfileMatch.tsx index 2de8d66e1..a6a568be6 100644 --- a/src/apps/talent-search/src/components/match-bar/MatchBar.tsx +++ b/src/apps/talent-search/src/components/profile-match/ProfileMatch.tsx @@ -1,14 +1,14 @@ import { FC } from 'react' import classNames from 'classnames' -import styles from './MatchBar.module.scss' +import styles from './ProfileMatch.module.scss' -interface MatchBarProps { +interface ProfileMatchProps { className?: string percent?: number } -const MatchBar: FC = props => { +const ProfileMatch: FC = props => { const value = Math.round((props.percent ?? 0) * 100) return ( @@ -25,4 +25,4 @@ const MatchBar: FC = props => { ) } -export default MatchBar +export default ProfileMatch diff --git a/src/apps/talent-search/src/components/profile-match/index.ts b/src/apps/talent-search/src/components/profile-match/index.ts new file mode 100644 index 000000000..6508c84e9 --- /dev/null +++ b/src/apps/talent-search/src/components/profile-match/index.ts @@ -0,0 +1 @@ +export { default as ProfileMatch } from './ProfileMatch' diff --git a/src/apps/talent-search/src/components/talent-card/TalentCard.module.scss b/src/apps/talent-search/src/components/talent-card/TalentCard.module.scss index 3d9630ef7..f3ae7e033 100644 --- a/src/apps/talent-search/src/components/talent-card/TalentCard.module.scss +++ b/src/apps/talent-search/src/components/talent-card/TalentCard.module.scss @@ -1,7 +1,7 @@ @import "@libs/ui/styles/includes"; .wrap { - padding: $sp-55 $sp-8; + padding: $sp-6; border-radius: $sp-4; background: $tc-white; @@ -12,20 +12,20 @@ .topWrap { display: flex; - gap: $sp-10; + gap: $sp-6; } .profilePic { - width: 200px; - max-width: 200px; + width: 188px; + max-width: 188px; } .detailsContainer { flex: 1 1 auto; - padding: $sp-5 $sp-45 $sp-45 0; + padding: $sp-5 0 $sp-45; display: flex; - flex-direction: column; + gap: $sp-4; } .talentInfo { @@ -34,6 +34,7 @@ align-items: flex-start; gap: $sp-3; margin-bottom: $sp-45; + flex: 1 1 auto; &Name { font-size: 30px; @@ -55,9 +56,9 @@ } -.matchBar { - max-width: 330px; - margin-top: auto; +.profileMatch { + width: 83px; + flex: 0 0 auto; } .skillsContainer { diff --git a/src/apps/talent-search/src/components/talent-card/TalentCard.tsx b/src/apps/talent-search/src/components/talent-card/TalentCard.tsx index 4e40d6077..5c335022f 100644 --- a/src/apps/talent-search/src/components/talent-card/TalentCard.tsx +++ b/src/apps/talent-search/src/components/talent-card/TalentCard.tsx @@ -7,7 +7,7 @@ import codes from 'country-calling-code' import { IconSolid } from '~/libs/ui' import { isSkillVerified, ProfilePicture, Skill, SkillPill } from '~/libs/shared' -import { MatchBar } from '../match-bar' +import { ProfileMatch } from '../profile-match' import { Member } from '../../lib/models' import { TALENT_SEARCH_PATHS } from '../../talent-search.routes' import { useIsMatchingSkill } from '../../lib/utils' @@ -35,12 +35,12 @@ const TalentCard: FC = props => { const matchedSkills = orderBy( props.member.emsiSkills, - isSkillVerified, - 'desc', + [isSkillVerified, a => a.name], + ['desc', 'asc'], ) .filter(isMatchingSkill) - const limitMatchedSkills = matchedSkills.slice(0, 10) + const limitMatchedSkills = matchedSkills.slice(0, 7) const provenSkills = limitMatchedSkills.filter(isSkillVerified) const selfSkills = limitMatchedSkills.filter(s => !isSkillVerified(s)) @@ -48,7 +48,7 @@ const TalentCard: FC = props => { const restLabel = restSkills > 0 && (
- {`+${restSkills} more skill${restSkills > 1 ? 's' : ''}`} + {`+${restSkills} more matched skill${restSkills > 1 ? 's' : ''}`}
) @@ -85,41 +85,32 @@ const TalentCard: FC = props => { ))} - +
+ +
-
Matched skills
- {provenSkills.length > 0 && ( - <> -
Proven skills
-
- {provenSkills.map(skill => ( - - ))} - {!selfSkills.length && restLabel} -
- - )} - {selfSkills.length > 0 && ( - <> -
Self-selected skills
-
- {selfSkills.map(skill => ( - - ))} - {restLabel} -
- - )} +
+ {`${matchedSkills.length} Matched skills`} +
+
+ {provenSkills.length > 0 && provenSkills.map(skill => ( + + ))} + {selfSkills.length > 0 && selfSkills.map(skill => ( + + ))} + {restLabel} +
) From fcb55761f9dee4a22c7042814fc0d2ebffbb7115 Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Mon, 31 Jul 2023 10:57:02 +0300 Subject: [PATCH 02/44] TAL-37 - move how skills work modal to shared library; show it in talent search results --- .../HowSkillsWorkModal/HowSkillsWorkModal.tsx | 114 ------------------ .../skills/MemberSkillsInfo.tsx | 5 +- .../SearchResultsPage.module.scss | 21 ++++ .../search-results-page/SearchResultsPage.tsx | 32 ++++- .../HowSkillsWorkModal.module.scss | 0 .../HowSkillsWorkModal.tsx | 108 +++++++++++++++++ .../modals/how-skills-work-modal}/index.ts | 0 .../shared/lib/components/modals/index.ts | 1 + 8 files changed, 158 insertions(+), 123 deletions(-) delete mode 100644 src/apps/profiles/src/member-profile/skills/HowSkillsWorkModal/HowSkillsWorkModal.tsx rename src/{apps/profiles/src/member-profile/skills/HowSkillsWorkModal => libs/shared/lib/components/modals/how-skills-work-modal}/HowSkillsWorkModal.module.scss (100%) create mode 100644 src/libs/shared/lib/components/modals/how-skills-work-modal/HowSkillsWorkModal.tsx rename src/{apps/profiles/src/member-profile/skills/HowSkillsWorkModal => libs/shared/lib/components/modals/how-skills-work-modal}/index.ts (100%) diff --git a/src/apps/profiles/src/member-profile/skills/HowSkillsWorkModal/HowSkillsWorkModal.tsx b/src/apps/profiles/src/member-profile/skills/HowSkillsWorkModal/HowSkillsWorkModal.tsx deleted file mode 100644 index 56649d21b..000000000 --- a/src/apps/profiles/src/member-profile/skills/HowSkillsWorkModal/HowSkillsWorkModal.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { FC } from 'react' - -import { BaseModal, IconOutline } from '~/libs/ui' - -import styles from './HowSkillsWorkModal.module.scss' - -interface HowSkillsWorkModalProps { - onClose: () => void - isTalentSearch?: boolean - canEdit?: boolean -} - -const HowSkillsWorkModal: FC = (props: HowSkillsWorkModalProps) => ( - - { - !!props.canEdit && ( -
-

- Topcoder Proven Skills -

-

- Look for the proven - - next to skills. -

-

Here’s how it works:

-
    -
  • You perform specific Topcoder opportunities
  • -
  • Each opportunity has associated skills (ex: javascript, HTML)
  • -
  • - You can prove you are proficient in these skills - by completing opportunities on the platform -
  • -
  • Topcoder tracks and labels these skills, displaying what skills have been proven
  • -
  • The more opportunities you complete the higher you rate for associated skills
  • -
-

- You can also self-proclaim skills that have not yet been proven. - These will display as skills without a checkmark. -

-
- ) - } - - { - !props.canEdit && props.isTalentSearch && ( -
-

- Topcoder Skill Matching -

-

Topcoder identifies experts that will best match the skills you are searching for.

-

- Look for the proven - - next to skills. -

-

Here’s how it works:

-
    -
  • Experts perform specific Topcoder opportunities
  • -
  • Each task has associated skills (ex: javascript, HTML)
  • -
  • - Experts prove they are proficient in these skills - by completing opportunities on the platform -
  • -
  • Topcoder tracks and labels these skills, displaying what skills have been proven
  • -
  • The more opportunities our experts complete the higher they rate for associated skills
  • -
-

- Experts can also self-proclaim skills that have not yet been proven. - These will display as skills without a checkmark. -

-
- ) - } - - { - !props.canEdit && !props.isTalentSearch && ( -
-

- Topcoder Proven Skills -

-

Our experts work hard to prove their skills through Topcoder opportunities.

-

- Look for the proven - - next to skills. -

-

Here’s how it works:

-
    -
  • Experts perform specific Topcoder opportunities
  • -
  • Each opportunity has associated skills (ex: javascript, HTML)
  • -
  • - Experts prove they are proficient in these skills - by completing opportunities on the platform -
  • -
  • Topcoder tracks and labels these skills, displaying what skills have been proven
  • -
  • The more opportunities our experts complete the higher they rate for associated skills
  • -
-

- Experts can also self-proclaim skills that have not yet been proven. - These will display as skills without a checkmark. -

-
- ) - } -
-) - -export default HowSkillsWorkModal diff --git a/src/apps/profiles/src/member-profile/skills/MemberSkillsInfo.tsx b/src/apps/profiles/src/member-profile/skills/MemberSkillsInfo.tsx index a0f90a617..f40f437da 100644 --- a/src/apps/profiles/src/member-profile/skills/MemberSkillsInfo.tsx +++ b/src/apps/profiles/src/member-profile/skills/MemberSkillsInfo.tsx @@ -3,7 +3,7 @@ import { useSearchParams } from 'react-router-dom' import { orderBy } from 'lodash' import { UserEMSISkill, UserProfile } from '~/libs/core' -import { ExpandableList, isSkillVerified, Skill, SkillPill } from '~/libs/shared' +import { ExpandableList, HowSkillsWorkModal, isSkillVerified, Skill, SkillPill } from '~/libs/shared' import { Button } from '~/libs/ui' import { AddButton, EditMemberPropertyBtn, EmptySection } from '../../components' @@ -11,7 +11,6 @@ import { EDIT_MODE_QUERY_PARAM, profileEditModes } from '../../config' import { MemberProfileContextValue, useMemberProfileContext } from '../MemberProfile.context' import { ModifySkillsModal } from './ModifySkillsModal' -import { HowSkillsWorkModal } from './HowSkillsWorkModal' import styles from './MemberSkillsInfo.module.scss' interface MemberSkillsInfoProps { @@ -141,7 +140,7 @@ const MemberSkillsInfo: FC = (props: MemberSkillsInfoProp ) } diff --git a/src/apps/talent-search/src/routes/search-results-page/SearchResultsPage.module.scss b/src/apps/talent-search/src/routes/search-results-page/SearchResultsPage.module.scss index ad203f037..823e89372 100644 --- a/src/apps/talent-search/src/routes/search-results-page/SearchResultsPage.module.scss +++ b/src/apps/talent-search/src/routes/search-results-page/SearchResultsPage.module.scss @@ -21,11 +21,32 @@ margin: $sp-4 0 $sp-5; text-align: center; color: $black-60; + + display: flex; + align-items: center; + justify-content: center; + > span { + display: block; + margin: 0 auto; + flex: 1 1 auto; + } + + :global(.highlighting) { color: $black-100; } } +.skillsPill { + flex: 0 0 auto; + + &:first-child { + opacity: 0; + visibility: hidden; + pointer-events: none; + } +} + .searchInput { margin-top: $sp-10; } diff --git a/src/apps/talent-search/src/routes/search-results-page/SearchResultsPage.tsx b/src/apps/talent-search/src/routes/search-results-page/SearchResultsPage.tsx index 1709928aa..c49916412 100644 --- a/src/apps/talent-search/src/routes/search-results-page/SearchResultsPage.tsx +++ b/src/apps/talent-search/src/routes/search-results-page/SearchResultsPage.tsx @@ -1,8 +1,9 @@ -import { FC, useContext, useEffect, useRef } from 'react' +import { FC, useCallback, useContext, useEffect, useRef, useState } from 'react' import classNames from 'classnames' import { profileContext, ProfileContextData } from '~/libs/core' import { Button, ContentLayout, LoadingCircles } from '~/libs/ui' +import { EmsiSkillSources, HowSkillsWorkModal, SkillPill } from '~/libs/shared' import { TalentCard } from '../../components/talent-card' import { SearchInput } from '../../components/search-input' @@ -17,6 +18,7 @@ import styles from './SearchResultsPage.module.scss' const SearchResultsPage: FC = () => { const sprigFlag = useRef(false) + const [showSkillsModal, setShowSkillsModal] = useState(false) const { profile }: ProfileContextData = useContext(profileContext) const [skills, setSkills] = useUrlQuerySearchParms('q') @@ -28,6 +30,17 @@ const SearchResultsPage: FC = () => { total, }: InfiniteTalentMatchesResposne = useInfiniteTalentMatches(skills) + const toggleSkillsModal = useCallback(() => setShowSkillsModal(s => !s), []) + + const skillsModalTriggerBtn = ( +
+ +
+ ) + useEffect(() => { if (profile?.userId && matches?.length && !sprigFlag.current) { sprigFlag.current = true @@ -61,12 +74,16 @@ const SearchResultsPage: FC = () => { ) : ( <> - We found  - - {total} -  Experts + {skillsModalTriggerBtn} + + We found  + + {total} +  Experts + +  that match your search -  that match your search + {skillsModalTriggerBtn} )} @@ -87,6 +104,9 @@ const SearchResultsPage: FC = () => { )} + {showSkillsModal && ( + + )} ) diff --git a/src/apps/profiles/src/member-profile/skills/HowSkillsWorkModal/HowSkillsWorkModal.module.scss b/src/libs/shared/lib/components/modals/how-skills-work-modal/HowSkillsWorkModal.module.scss similarity index 100% rename from src/apps/profiles/src/member-profile/skills/HowSkillsWorkModal/HowSkillsWorkModal.module.scss rename to src/libs/shared/lib/components/modals/how-skills-work-modal/HowSkillsWorkModal.module.scss diff --git a/src/libs/shared/lib/components/modals/how-skills-work-modal/HowSkillsWorkModal.tsx b/src/libs/shared/lib/components/modals/how-skills-work-modal/HowSkillsWorkModal.tsx new file mode 100644 index 000000000..317fe8820 --- /dev/null +++ b/src/libs/shared/lib/components/modals/how-skills-work-modal/HowSkillsWorkModal.tsx @@ -0,0 +1,108 @@ +import { FC } from 'react' + +import { BaseModal, IconOutline } from '~/libs/ui' + +import styles from './HowSkillsWorkModal.module.scss' + +interface HowSkillsWorkModalProps { + onClose: () => void + isTalentSearch?: boolean + iseSelfView?: boolean +} + +const HowSkillsWorkModal: FC = (props: HowSkillsWorkModalProps) => ( + + {!!props.iseSelfView && ( +
+

+ Topcoder Proven Skills +

+

+ Look for the proven + + next to skills. +

+

Here’s how it works:

+
    +
  • You perform specific Topcoder opportunities
  • +
  • Each opportunity has associated skills (ex: javascript, HTML)
  • +
  • + You can prove you are proficient in these skills + by completing opportunities on the platform +
  • +
  • Topcoder tracks and labels these skills, displaying what skills have been proven
  • +
  • The more opportunities you complete the higher you rate for associated skills
  • +
+

+ You can also self-proclaim skills that have not yet been proven. + These will display as skills without a checkmark. +

+
+ )} + + {!props.iseSelfView && props.isTalentSearch && ( +
+

+ Topcoder Skill Matching +

+

Topcoder identifies experts that will best match the skills you are searching for.

+

+ Look for the proven + + next to skills. +

+

Here’s how it works:

+
    +
  • Experts perform specific Topcoder opportunities
  • +
  • Each task has associated skills (ex: javascript, HTML)
  • +
  • + Experts prove they are proficient in these skills + by completing opportunities on the platform +
  • +
  • Topcoder tracks and labels these skills, displaying what skills have been proven
  • +
  • The more opportunities our experts complete the higher they rate for associated skills
  • +
+

+ Experts can also self-proclaim skills that have not yet been proven. + These will display as skills without a checkmark. +

+
+ )} + + {!props.iseSelfView && !props.isTalentSearch && ( +
+

+ Topcoder Proven Skills +

+

Our experts work hard to prove their skills through Topcoder opportunities.

+

+ Look for the proven + + next to skills. +

+

Here’s how it works:

+
    +
  • Experts perform specific Topcoder opportunities
  • +
  • Each opportunity has associated skills (ex: javascript, HTML)
  • +
  • + Experts prove they are proficient in these skills + by completing opportunities on the platform +
  • +
  • Topcoder tracks and labels these skills, displaying what skills have been proven
  • +
  • The more opportunities our experts complete the higher they rate for associated skills
  • +
+

+ Experts can also self-proclaim skills that have not yet been proven. + These will display as skills without a checkmark. +

+
+ )} +
+) + +export default HowSkillsWorkModal diff --git a/src/apps/profiles/src/member-profile/skills/HowSkillsWorkModal/index.ts b/src/libs/shared/lib/components/modals/how-skills-work-modal/index.ts similarity index 100% rename from src/apps/profiles/src/member-profile/skills/HowSkillsWorkModal/index.ts rename to src/libs/shared/lib/components/modals/how-skills-work-modal/index.ts diff --git a/src/libs/shared/lib/components/modals/index.ts b/src/libs/shared/lib/components/modals/index.ts index 89930fa59..2b65b1e3a 100644 --- a/src/libs/shared/lib/components/modals/index.ts +++ b/src/libs/shared/lib/components/modals/index.ts @@ -2,3 +2,4 @@ export * from './contact-support-modal' export * from './order-contract-modal' export * from './privacy-policy-modal' export * from './terms-modal' +export * from './how-skills-work-modal' From b9363f33e9fa74674d1c003207fdcc84db8d8302 Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Fri, 4 Aug 2023 11:14:47 +0300 Subject: [PATCH 03/44] TAL-14 - remove the admin restriction for the talent search app --- src/apps/talent-search/src/talent-search.routes.tsx | 8 +++++--- src/config/environments/default.env.ts | 2 ++ src/config/environments/global-config.model.ts | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/apps/talent-search/src/talent-search.routes.tsx b/src/apps/talent-search/src/talent-search.routes.tsx index 7b3444e2a..b1d9e60a5 100644 --- a/src/apps/talent-search/src/talent-search.routes.tsx +++ b/src/apps/talent-search/src/talent-search.routes.tsx @@ -26,9 +26,11 @@ export const TALENT_SEARCH_PATHS = { export const toolTitle: string = ToolTitle.talentSearch +const isAdminRestricted = EnvironmentConfig.RESTRICT_TALENT_SEARCH + export const talentSearchRoutes: ReadonlyArray = [ { - authRequired: true, + authRequired: isAdminRestricted, children: [ { element: , @@ -46,9 +48,9 @@ export const talentSearchRoutes: ReadonlyArray = [ domain: AppSubdomain.talentSearch, element: , id: toolTitle, - rolesRequired: [ + rolesRequired: isAdminRestricted ? [ UserRole.administrator, - ], + ] : undefined, route: rootRoute, }, ] diff --git a/src/config/environments/default.env.ts b/src/config/environments/default.env.ts index ba8a64f5a..70c8c0581 100644 --- a/src/config/environments/default.env.ts +++ b/src/config/environments/default.env.ts @@ -69,3 +69,5 @@ export const DICE_VERIFY_URL = get({ prod: 'https://accounts-auth0.topcoder.com', qa: 'https://accounts-auth0.topcoder-qa.com', }, ENV, 'https://accounts-auth0.topcoder.com') + +export const RESTRICT_TALENT_SEARCH = getReactEnv('RESTRICT_TALENT_SEARCH', false) diff --git a/src/config/environments/global-config.model.ts b/src/config/environments/global-config.model.ts index 595d0afd3..32f3aeff4 100644 --- a/src/config/environments/global-config.model.ts +++ b/src/config/environments/global-config.model.ts @@ -40,4 +40,5 @@ export interface GlobalConfig { SUBDOMAIN: string, GAMIFICATION_ORG_ID: string DICE_VERIFY_URL: string + RESTRICT_TALENT_SEARCH: boolean } From 858d5e7e16992848dd45b5b9873d126085bf77b1 Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Fri, 4 Aug 2023 11:35:57 +0300 Subject: [PATCH 04/44] TAL-18 - add notification message for missing profile in talent search app --- .../routes/search-page/SearchPage.module.scss | 15 +++++++ .../src/routes/search-page/SearchPage.tsx | 45 ++++++++++++++----- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/apps/talent-search/src/routes/search-page/SearchPage.module.scss b/src/apps/talent-search/src/routes/search-page/SearchPage.module.scss index 853c38a1a..b1686ac78 100644 --- a/src/apps/talent-search/src/routes/search-page/SearchPage.module.scss +++ b/src/apps/talent-search/src/routes/search-page/SearchPage.module.scss @@ -51,3 +51,18 @@ max-width: 931px; width: 100%; } + +.headerErrorWrap { + display: flex; + justify-content: center; +} + +.headerError { + display: flex; + align-items: center; + gap: $sp-3; + + padding: $sp-4 $sp-8; + border-radius: 10px; + background: $purple-140; +} diff --git a/src/apps/talent-search/src/routes/search-page/SearchPage.tsx b/src/apps/talent-search/src/routes/search-page/SearchPage.tsx index 840213ba0..8c455f3e3 100644 --- a/src/apps/talent-search/src/routes/search-page/SearchPage.tsx +++ b/src/apps/talent-search/src/routes/search-page/SearchPage.tsx @@ -1,7 +1,7 @@ import { FC, useRef, useState } from 'react' -import { useNavigate } from 'react-router-dom' +import { useNavigate, useSearchParams } from 'react-router-dom' -import { ContentLayout } from '~/libs/ui' +import { ContentLayout, IconOutline } from '~/libs/ui' import { Skill } from '~/libs/shared' import { SearchInput } from '../../components/search-input' @@ -12,6 +12,9 @@ import { encodeUrlQuerySearch } from '../../lib/utils/search-query' import styles from './SearchPage.module.scss' export const SearchPage: FC = () => { + const [params] = useSearchParams() + const isMissingProfileRoute = params.get('memberNotFound') !== null + const searchInputRef = useRef() const navigate = useNavigate() const [skillsFilter, setSkillsFilter] = useState([]) @@ -26,20 +29,42 @@ export const SearchPage: FC = () => { searchInputRef.current?.focus() } + function renderHeader(): JSX.Element { + return isMissingProfileRoute ? ( + <> +
+
+ + We were unable to locate that profile +
+
+
+
+ You can also try finding members through our Talent Search: +
+
+ + ) : ( + <> +
+ Looking for a technology expert? +
+
+
+ Search thousands of skills to match with our global experts. +
+
+ + ) + } + return ( -
- Looking for a technology expert? -
-
-
- Search thousands of skills to match with our global experts. -
-
+ {renderHeader()}
Search by skills Date: Fri, 4 Aug 2023 12:58:08 +0300 Subject: [PATCH 05/44] TAL-10 - redirect to talent search from profiles app --- .../profiles/src/member-profile/MemberProfilePage.tsx | 8 +++++++- src/apps/talent-search/src/index.ts | 2 +- src/apps/talent-search/src/talent-search.routes.tsx | 9 ++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/apps/profiles/src/member-profile/MemberProfilePage.tsx b/src/apps/profiles/src/member-profile/MemberProfilePage.tsx index eebf6e893..fbd5273cd 100644 --- a/src/apps/profiles/src/member-profile/MemberProfilePage.tsx +++ b/src/apps/profiles/src/member-profile/MemberProfilePage.tsx @@ -1,7 +1,9 @@ import { Dispatch, FC, SetStateAction, useCallback, useContext, useEffect, useState } from 'react' import { Params, useNavigate, useParams } from 'react-router-dom' +import { AxiosError } from 'axios' import { profileContext, ProfileContextData, profileGetPublicAsync, UserProfile } from '~/libs/core' +import { TALENT_SEARCH_PATHS } from '~/apps/talent-search' import { LoadingSpinner } from '~/libs/ui' import { notifyUniNavi, triggerSprigSurvey } from '../lib' @@ -34,7 +36,11 @@ const MemberProfilePage: FC<{}> = () => { setProfile({ ...userProfile } as UserProfile) setProfileReady(true) }) - // TODO: NOT FOUND PAGE redirect/dispaly + .catch((e: AxiosError) => { + if (e.code === AxiosError.ERR_BAD_REQUEST && e.response?.status === 404) { + window.location.href = `${TALENT_SEARCH_PATHS.absoluteRootUrl}?memberNotFound` + } + }) } }, [routeParams.memberHandle]) diff --git a/src/apps/talent-search/src/index.ts b/src/apps/talent-search/src/index.ts index f826d5422..19db451f9 100644 --- a/src/apps/talent-search/src/index.ts +++ b/src/apps/talent-search/src/index.ts @@ -1 +1 @@ -export { talentSearchRoutes } from './talent-search.routes' +export { talentSearchRoutes, TALENT_SEARCH_PATHS } from './talent-search.routes' diff --git a/src/apps/talent-search/src/talent-search.routes.tsx b/src/apps/talent-search/src/talent-search.routes.tsx index b1d9e60a5..736ad8412 100644 --- a/src/apps/talent-search/src/talent-search.routes.tsx +++ b/src/apps/talent-search/src/talent-search.routes.tsx @@ -14,11 +14,18 @@ const TalentPage: LazyLoadedComponent = lazyLoad( 'TalentPage', ) +const isOnAppSubdomain = EnvironmentConfig.SUBDOMAIN === AppSubdomain.talentSearch export const rootRoute: string = ( - EnvironmentConfig.SUBDOMAIN === AppSubdomain.talentSearch ? '' : `/${AppSubdomain.talentSearch}` + isOnAppSubdomain ? '' : `/${AppSubdomain.talentSearch}` ) +const absoluteRootUrl = (() => { + const subdomain = isOnAppSubdomain ? AppSubdomain.talentSearch : EnvironmentConfig.SUBDOMAIN + return `//${subdomain}.${EnvironmentConfig.TC_DOMAIN}${rootRoute}` +})() + export const TALENT_SEARCH_PATHS = { + absoluteRootUrl, results: `${rootRoute}/results`, root: rootRoute, talent: `${rootRoute}/talent`, From 477f5537325d8a3822fe8b32bcf31ee44109509b Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Fri, 4 Aug 2023 14:04:00 +0300 Subject: [PATCH 06/44] fix absolute url root for talent-search --- src/apps/talent-search/src/talent-search.routes.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/apps/talent-search/src/talent-search.routes.tsx b/src/apps/talent-search/src/talent-search.routes.tsx index 736ad8412..ca9c76d81 100644 --- a/src/apps/talent-search/src/talent-search.routes.tsx +++ b/src/apps/talent-search/src/talent-search.routes.tsx @@ -19,13 +19,8 @@ export const rootRoute: string = ( isOnAppSubdomain ? '' : `/${AppSubdomain.talentSearch}` ) -const absoluteRootUrl = (() => { - const subdomain = isOnAppSubdomain ? AppSubdomain.talentSearch : EnvironmentConfig.SUBDOMAIN - return `//${subdomain}.${EnvironmentConfig.TC_DOMAIN}${rootRoute}` -})() - export const TALENT_SEARCH_PATHS = { - absoluteRootUrl, + absoluteRootUrl: `//${AppSubdomain.talentSearch}.${EnvironmentConfig.TC_DOMAIN}${rootRoute}`, results: `${rootRoute}/results`, root: rootRoute, talent: `${rootRoute}/talent`, From d28b17fd9521bd1bc4e64015a9351594574821f8 Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Fri, 4 Aug 2023 16:25:40 +0300 Subject: [PATCH 07/44] update talent-search redirect --- src/apps/profiles/src/member-profile/MemberProfilePage.tsx | 2 +- src/apps/talent-search/src/talent-search.routes.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/profiles/src/member-profile/MemberProfilePage.tsx b/src/apps/profiles/src/member-profile/MemberProfilePage.tsx index fbd5273cd..206207faf 100644 --- a/src/apps/profiles/src/member-profile/MemberProfilePage.tsx +++ b/src/apps/profiles/src/member-profile/MemberProfilePage.tsx @@ -38,7 +38,7 @@ const MemberProfilePage: FC<{}> = () => { }) .catch((e: AxiosError) => { if (e.code === AxiosError.ERR_BAD_REQUEST && e.response?.status === 404) { - window.location.href = `${TALENT_SEARCH_PATHS.absoluteRootUrl}?memberNotFound` + window.location.href = `${TALENT_SEARCH_PATHS.absoluteUrl}?memberNotFound` } }) } diff --git a/src/apps/talent-search/src/talent-search.routes.tsx b/src/apps/talent-search/src/talent-search.routes.tsx index ca9c76d81..0f4175297 100644 --- a/src/apps/talent-search/src/talent-search.routes.tsx +++ b/src/apps/talent-search/src/talent-search.routes.tsx @@ -20,7 +20,7 @@ export const rootRoute: string = ( ) export const TALENT_SEARCH_PATHS = { - absoluteRootUrl: `//${AppSubdomain.talentSearch}.${EnvironmentConfig.TC_DOMAIN}${rootRoute}`, + absoluteUrl: `//${AppSubdomain.talentSearch}.${EnvironmentConfig.TC_DOMAIN}`, results: `${rootRoute}/results`, root: rootRoute, talent: `${rootRoute}/talent`, From 674621f516cdb024616b2415ad0dd77c5d88a7ab Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Mon, 7 Aug 2023 08:06:55 +0300 Subject: [PATCH 08/44] MP-334 omit audit fields on profile update --- .../ModifyLocationModal/ModifyLocationModal.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/apps/profiles/src/member-profile/local-info/ModifyLocationModal/ModifyLocationModal.tsx b/src/apps/profiles/src/member-profile/local-info/ModifyLocationModal/ModifyLocationModal.tsx index 8ee76d0cd..646181fcd 100644 --- a/src/apps/profiles/src/member-profile/local-info/ModifyLocationModal/ModifyLocationModal.tsx +++ b/src/apps/profiles/src/member-profile/local-info/ModifyLocationModal/ModifyLocationModal.tsx @@ -1,5 +1,5 @@ import { Dispatch, FC, SetStateAction, useMemo, useState } from 'react' -import { bind, trim } from 'lodash' +import { bind, omit, trim } from 'lodash' import { toast } from 'react-toastify' import { BaseModal, Button, InputSelect, InputText } from '~/libs/ui' @@ -18,6 +18,10 @@ interface ModifyLocationModalProps { profile: UserProfile } +const OMIT_ADDRESS_KEYS_ON_UPDATE = [ + 'createdAt', 'createdBy', 'updatedAt', 'updatedBy', +] + const ModifyLocationModal: FC = (props: ModifyLocationModalProps) => { const countryLookup: CountryLookup[] | undefined = useCountryLookup() @@ -59,7 +63,7 @@ const ModifyLocationModal: FC = (props: ModifyLocation props.profile.handle, { addresses: [{ - ...props.profile.addresses ? props.profile.addresses[0] : {}, + ...props.profile.addresses ? omit(props.profile.addresses[0], OMIT_ADDRESS_KEYS_ON_UPDATE) : {}, city: trim(formValues.city), }], competitionCountryCode: formValues.country, From f1096dec00570615dd748187b70aa0feedfe5ad4 Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Mon, 7 Aug 2023 09:10:56 +0300 Subject: [PATCH 09/44] MP-339 support www links --- src/apps/profiles/src/lib/helpers.ts | 14 ++++++++++++- .../LinkForm/LinkForm.tsx | 20 +++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/apps/profiles/src/lib/helpers.ts b/src/apps/profiles/src/lib/helpers.ts index 6f644ffcd..64ebf07b9 100644 --- a/src/apps/profiles/src/lib/helpers.ts +++ b/src/apps/profiles/src/lib/helpers.ts @@ -80,11 +80,23 @@ export function subTrackLabelToHumanName(label: string): string { } export function isValidURL(urlToValidate: string): boolean { + const pattern = new RegExp( + '^(https?:\\/\\/)?' // protocol + + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' // domain name + + '((\\d{1,3}\\.){3}\\d{1,3}))' // OR IP (v4) address + + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' // port and path + + '(\\?[;&a-z\\d%_.~+=-]*)?' // query string + + '(\\#[-a-z\\d_]*)?$', // fragment locator + 'i', + ) + let url: URL try { url = new URL(urlToValidate) } catch (e) { - return false + // try to validate with regex + // as sometimes new URL is wonky with some urls + return pattern.test(urlToValidate) } if (!url.protocol || !url.hostname) { diff --git a/src/apps/profiles/src/member-profile/links/ModifyMemberLinksModal/LinkForm/LinkForm.tsx b/src/apps/profiles/src/member-profile/links/ModifyMemberLinksModal/LinkForm/LinkForm.tsx index 6158c708d..795d24344 100644 --- a/src/apps/profiles/src/member-profile/links/ModifyMemberLinksModal/LinkForm/LinkForm.tsx +++ b/src/apps/profiles/src/member-profile/links/ModifyMemberLinksModal/LinkForm/LinkForm.tsx @@ -52,10 +52,22 @@ const LinkForm: FC = props => { return } - props.onSave({ - name: selectedLinkType, - url: trim(selectedLinkURL) || '', - }) + let absoluteURL = trim(selectedLinkURL) || '' + + if (absoluteURL.indexOf('://') > 0 || absoluteURL.indexOf('//') === 0) { + + props.onSave({ + name: selectedLinkType, + url: absoluteURL, + }) + } else { + absoluteURL = `https://${absoluteURL}` + + props.onSave({ + name: selectedLinkType, + url: absoluteURL, + }) + } } function handleDiscardClick(): void { From de6c372d6eb9f95432651ac78feba1a704441c20 Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Mon, 7 Aug 2023 09:47:39 +0300 Subject: [PATCH 10/44] MP-340 show handle if pref --- .../src/member-profile/about-me/AboutMe.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/apps/profiles/src/member-profile/about-me/AboutMe.tsx b/src/apps/profiles/src/member-profile/about-me/AboutMe.tsx index 8934d50ed..69be73a23 100644 --- a/src/apps/profiles/src/member-profile/about-me/AboutMe.tsx +++ b/src/apps/profiles/src/member-profile/about-me/AboutMe.tsx @@ -3,7 +3,7 @@ import { useSearchParams } from 'react-router-dom' import { KeyedMutator } from 'swr' import classNames from 'classnames' -import { useMemberTraits, UserProfile, UserTraitIds, UserTraits } from '~/libs/core' +import { useMemberTraits, UserProfile, UserTrait, UserTraitIds, UserTraits } from '~/libs/core' import { AddButton, EditMemberPropertyBtn, EmptySection } from '../../components' import { EDIT_MODE_QUERY_PARAM, profileEditModes } from '../../config' @@ -38,6 +38,11 @@ const AboutMe: FC = (props: AboutMeProps) => { props.profile && !props.profile.description ), [props.profile]) + const namesAndHandleAppearanceData: UserTrait | undefined + = useMemo(() => memberPersonalizationTraits?.[0]?.traits?.data?.find( + (trait: UserTrait) => trait.namesAndHandleAppearance, + ), [memberPersonalizationTraits]) + useEffect(() => { if (props.authProfile && editMode === profileEditModes.aboutMe) { setIsEditMode(true) @@ -70,7 +75,11 @@ const AboutMe: FC = (props: AboutMeProps) => { {' '} I'm {' '} - {props.profile?.firstName || props.profile?.handle} + { + namesAndHandleAppearanceData?.namesAndHandleAppearance === 'handleOnly' + ? props.profile?.handle + : props.profile?.firstName + }

From 60d005a78ef9088df28b4e8fbc0b83387c5ad1c0 Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Mon, 7 Aug 2023 10:39:09 +0300 Subject: [PATCH 11/44] TAL-37 - limit shown skill pills to 3 rows --- .../talent-card/TalentCard.module.scss | 6 +++ .../src/components/talent-card/TalentCard.tsx | 47 ++++++++++++++----- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/apps/talent-search/src/components/talent-card/TalentCard.module.scss b/src/apps/talent-search/src/components/talent-card/TalentCard.module.scss index f3ae7e033..285f0afa2 100644 --- a/src/apps/talent-search/src/components/talent-card/TalentCard.module.scss +++ b/src/apps/talent-search/src/components/talent-card/TalentCard.module.scss @@ -98,4 +98,10 @@ align-items: center; gap: $sp-1; flex-wrap: wrap; + position: relative; + + &:global(.init) { + max-height: 116px; + overflow: hidden; + } } diff --git a/src/apps/talent-search/src/components/talent-card/TalentCard.tsx b/src/apps/talent-search/src/components/talent-card/TalentCard.tsx index 5c335022f..52c2a927a 100644 --- a/src/apps/talent-search/src/components/talent-card/TalentCard.tsx +++ b/src/apps/talent-search/src/components/talent-card/TalentCard.tsx @@ -1,4 +1,4 @@ -import { FC, useMemo } from 'react' +import { FC, useEffect, useMemo, useRef } from 'react' import { Link } from 'react-router-dom' import { orderBy } from 'lodash' import classNames from 'classnames' @@ -23,6 +23,12 @@ const getAddrString = (city: string, country: string): string => ( .join(', ') ) +function isOverflow(el: HTMLElement): boolean { + const parentHeight = el.parentElement?.offsetHeight ?? 0 + const bottom = el.offsetTop + el.offsetHeight + return bottom > parentHeight +} + interface TalentCardProps { queriedSkills: Skill[] member: Member @@ -30,6 +36,7 @@ interface TalentCardProps { } const TalentCard: FC = props => { + const skillsWrapRef = useRef(null) const talentRoute = `${TALENT_SEARCH_PATHS.talent}/${props.member.handle}` const isMatchingSkill = useIsMatchingSkill(props.queriedSkills) @@ -40,23 +47,38 @@ const TalentCard: FC = props => { ) .filter(isMatchingSkill) - const limitMatchedSkills = matchedSkills.slice(0, 7) + const limitMatchedSkills = matchedSkills - const provenSkills = limitMatchedSkills.filter(isSkillVerified) - const selfSkills = limitMatchedSkills.filter(s => !isSkillVerified(s)) - const restSkills = matchedSkills.length - limitMatchedSkills.length - - const restLabel = restSkills > 0 && ( -
- {`+${restSkills} more matched skill${restSkills > 1 ? 's' : ''}`} -
- ) + const provenSkills = matchedSkills.filter(isSkillVerified) + const selfSkills = matchedSkills.filter(s => !isSkillVerified(s)) const matchState = useMemo(() => ({ matchValue: props.match, queriedSkills: props.queriedSkills, }), [props.match, props.queriedSkills]) + // after initial render, check and limit to 3 rows of skills + useEffect(() => { + if (!skillsWrapRef.current) { + return + } + + // check if there are more than 3 rows of skills displayed initially, and hide them + const isHidden: HTMLElement[] = [].filter.call(skillsWrapRef.current.childNodes, isOverflow) + isHidden.forEach(c => { c.style.display = 'none' }) + + // remove css height limit from the skillsWrap el + skillsWrapRef.current.classList.toggle('init', false) + + // if there are hidden skill pills, show the "+N more matched skills" pill + if (isHidden.length) { + const restLabel = document.createElement('div') + restLabel.classList.add(styles.unmatchedSkills) + restLabel.innerText = `+${isHidden.length} more matched skill${isHidden.length > 1 ? 's' : ''}` + skillsWrapRef.current.appendChild(restLabel) + } + }, [limitMatchedSkills]) + return (
@@ -94,7 +116,7 @@ const TalentCard: FC = props => {
{`${matchedSkills.length} Matched skills`}
-
+
{provenSkills.length > 0 && provenSkills.map(skill => ( = props => { skill={skill} /> ))} - {restLabel}
From 8f93d4ae5a06f1216a3730106e0087b29766b81f Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Mon, 7 Aug 2023 11:00:35 +0300 Subject: [PATCH 12/44] Fix useFetchTalentMatches: reset page number when updating skills --- .../talent-search/src/lib/services/use-fetch-talent-matches.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/apps/talent-search/src/lib/services/use-fetch-talent-matches.ts b/src/apps/talent-search/src/lib/services/use-fetch-talent-matches.ts index 9b333067a..d0621fa5c 100644 --- a/src/apps/talent-search/src/lib/services/use-fetch-talent-matches.ts +++ b/src/apps/talent-search/src/lib/services/use-fetch-talent-matches.ts @@ -74,6 +74,7 @@ export function useInfiniteTalentMatches( // clear matches when skills array is updated useEffect(() => { setMatches([]) + setPage(1) }, [skills]) // when we have new matches, concatenate the response to the matches array From b8af7c301f9f6ad492e9c1ebc5b5f2066ec9ebb5 Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Mon, 7 Aug 2023 18:47:44 +0300 Subject: [PATCH 13/44] TAL-39 Talent search initial mobile work --- .../popular-skills/PopularSkills.module.scss | 27 +++++---- .../popular-skills/PopularSkills.tsx | 59 +++++++++---------- .../components/search-input/SearchInput.tsx | 12 +++- .../routes/search-page/SearchPage.module.scss | 19 +++++- .../skill-pill/SkillPill.module.scss | 4 ++ 5 files changed, 75 insertions(+), 46 deletions(-) diff --git a/src/apps/talent-search/src/components/popular-skills/PopularSkills.module.scss b/src/apps/talent-search/src/components/popular-skills/PopularSkills.module.scss index 1d7d66578..7079a4aad 100644 --- a/src/apps/talent-search/src/components/popular-skills/PopularSkills.module.scss +++ b/src/apps/talent-search/src/components/popular-skills/PopularSkills.module.scss @@ -9,22 +9,25 @@ :global(.body-medium-bold) { margin-bottom: $sp-4; } + + @include ltemd { + margin-top: $sp-8; + } } -.pillRow{ +.wrapTitle { + font-size: 20px; + line-height: 26px; + font-family: $font-roboto; + font-weight: $font-weight-bold; + margin-bottom: $sp-4; +} + +.pills { display: flex; + flex-wrap: wrap; align-items: center; justify-content: center; gap: $sp-2; - - + .pillRow { - margin-top: $sp-2; - } - - &:nth-child(4) { - opacity: 60%; - } - &:nth-child(n+5) { - opacity: 40%; - } + max-width: 680px; } diff --git a/src/apps/talent-search/src/components/popular-skills/PopularSkills.tsx b/src/apps/talent-search/src/components/popular-skills/PopularSkills.tsx index e5b22ceb0..3f679ce29 100644 --- a/src/apps/talent-search/src/components/popular-skills/PopularSkills.tsx +++ b/src/apps/talent-search/src/components/popular-skills/PopularSkills.tsx @@ -6,23 +6,23 @@ import styles from './PopularSkills.module.scss' // TODO: Make this configurable, or read from a service. We need to discuss // how we want to handle this. -const popularSkills: Skill[][] = [ - [{ emsiId: 'KS441LF7187KS0CV4B6Y', name: 'Typescript' }, - { emsiId: 'KS1244K6176NLVWV02B6', name: 'Front-End Engineering' }, - { emsiId: 'KS1214R5XG4X4PY7LGY6', name: 'Bootstrap (Front-End Framework)' }], - [{ emsiId: 'KS121F45VPV8C9W3QFYH', name: 'Cascading Style Sheets (CSS)' }, - { emsiId: 'KS1200771D9CR9LB4MWW', name: 'JavaScript (Programming Language)' }], - [{ emsiId: 'KS1200578T5QCYT0Z98G', name: 'HyperText Markup Language (HTML)' }, - { emsiId: 'ES86A20379CD2AD061F3', name: 'IOS Development' }, - { emsiId: 'KS127296VDYS7ZFWVC46', name: 'Node.js' }], - [{ emsiId: 'ES50D03AC9CFC1A0BC93', name: '.NET Development' }, - { emsiId: 'KS1219W70LY1GXZDSKW5', name: 'C++ (Programming Language)' }, - { emsiId: 'KS127SZ60YZR8B5CQKV1', name: 'PHP Development' }], - [{ emsiId: 'KS1206V6K46N1SDVJGBD', name: 'Adobe Illustrator' }, - { emsiId: 'ESD07FEE22E7EC094EB8', name: 'Ruby (Programming Language)' }, - { emsiId: 'KS120076FGP5WGWYMP0F', name: 'Java (Programming Language)' }], - [{ emsiId: 'KSPSGF5MXB6568UIQ4BK', name: 'React Native' }, - { emsiId: 'KS441PL6JPXW200W0GRQ', name: 'User Experience (UX)' }], +const popularSkills: Skill[] = [ + { emsiId: 'KS441LF7187KS0CV4B6Y', name: 'Typescript' }, + { emsiId: 'KS1244K6176NLVWV02B6', name: 'Front-End Engineering' }, + { emsiId: 'KS1214R5XG4X4PY7LGY6', name: 'Bootstrap (Front-End Framework)' }, + { emsiId: 'KS121F45VPV8C9W3QFYH', name: 'Cascading Style Sheets (CSS)' }, + { emsiId: 'KS1200771D9CR9LB4MWW', name: 'JavaScript (Programming Language)' }, + { emsiId: 'KS1200578T5QCYT0Z98G', name: 'HyperText Markup Language (HTML)' }, + { emsiId: 'ES86A20379CD2AD061F3', name: 'IOS Development' }, + { emsiId: 'KS127296VDYS7ZFWVC46', name: 'Node.js' }, + { emsiId: 'ES50D03AC9CFC1A0BC93', name: '.NET Development' }, + { emsiId: 'KS1219W70LY1GXZDSKW5', name: 'C++ (Programming Language)' }, + { emsiId: 'KS127SZ60YZR8B5CQKV1', name: 'PHP Development' }, + { emsiId: 'KS1206V6K46N1SDVJGBD', name: 'Adobe Illustrator' }, + { emsiId: 'ESD07FEE22E7EC094EB8', name: 'Ruby (Programming Language)' }, + { emsiId: 'KS120076FGP5WGWYMP0F', name: 'Java (Programming Language)' }, + { emsiId: 'KSPSGF5MXB6568UIQ4BK', name: 'React Native' }, + { emsiId: 'KS441PL6JPXW200W0GRQ', name: 'User Experience (UX)' }, ] interface PopularSkillsProps { @@ -58,21 +58,18 @@ const PopularSkills: FC = props => { return (
-
Popular Skills
+
Popular Skills
- {popularSkills.map((row, i) => ( - // eslint-disable-next-line react/no-array-index-key -
- {row.map(skill => ( - - ))} -
- ))} +
+ {popularSkills.map(skill => ( + + ))} +
) } diff --git a/src/apps/talent-search/src/components/search-input/SearchInput.tsx b/src/apps/talent-search/src/components/search-input/SearchInput.tsx index db15f2cb9..9461fabd6 100644 --- a/src/apps/talent-search/src/components/search-input/SearchInput.tsx +++ b/src/apps/talent-search/src/components/search-input/SearchInput.tsx @@ -1,4 +1,4 @@ -import { FC, Ref, useMemo } from 'react' +import { FC, MouseEvent, Ref, useMemo } from 'react' import classNames from 'classnames' import { IconOutline, InputMultiselectOption } from '~/libs/ui' @@ -30,10 +30,18 @@ const SearchInput: FC = props => { }))) } + function handleSearchClick(ev: MouseEvent): void { + ev.preventDefault() + ev.stopPropagation() + + props.onSearch?.() + } + const searchIcon = useMemo(() => (
diff --git a/src/apps/talent-search/src/routes/search-page/SearchPage.module.scss b/src/apps/talent-search/src/routes/search-page/SearchPage.module.scss index b1686ac78..fe9ce86a7 100644 --- a/src/apps/talent-search/src/routes/search-page/SearchPage.module.scss +++ b/src/apps/talent-search/src/routes/search-page/SearchPage.module.scss @@ -7,8 +7,11 @@ } .contentLayout-inner { - padding: 86px 48px 48px 48px; + padding: 86px $sp-12 $sp-12; color: $tc-white; + @include ltemd { + padding: $sp-9 0 0; + } } .searchHeader{ @@ -42,6 +45,12 @@ font-size: 16px; line-height: 48px; color: $tc-white; + display: block; + + @include ltemd { + line-height: 24px; + margin-bottom: $sp-2; + } } .searchOptions{ @@ -50,6 +59,10 @@ padding: 70px 32px 32px 32px; max-width: 931px; width: 100%; + + @include ltemd { + padding: 49px 0 0; + } } .headerErrorWrap { @@ -65,4 +78,8 @@ padding: $sp-4 $sp-8; border-radius: 10px; background: $purple-140; + + @include ltemd { + padding: $sp-4; + } } diff --git a/src/libs/shared/lib/components/skill-pill/SkillPill.module.scss b/src/libs/shared/lib/components/skill-pill/SkillPill.module.scss index dc0984a18..6e38e1c8c 100644 --- a/src/libs/shared/lib/components/skill-pill/SkillPill.module.scss +++ b/src/libs/shared/lib/components/skill-pill/SkillPill.module.scss @@ -11,6 +11,10 @@ align-items: center; gap: $sp-1; + @include ltemd { + padding: $sp-1 $sp-3; + } + &.interactive { cursor: pointer; From 3f5048f647b223c9dcb11e4b962af590bb90bb0f Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Tue, 8 Aug 2023 10:25:35 +0300 Subject: [PATCH 14/44] TAL-32 start hiting intake form --- .../HiringFormModal/HiringFormModal.tsx | 48 +++++++ .../profile-header/HiringFormModal/index.ts | 1 + .../profile-header/ProfileHeader.module.scss | 76 +++++++---- .../profile-header/ProfileHeader.tsx | 127 +++++++++++------- 4 files changed, 179 insertions(+), 73 deletions(-) create mode 100644 src/apps/profiles/src/member-profile/profile-header/HiringFormModal/HiringFormModal.tsx create mode 100644 src/apps/profiles/src/member-profile/profile-header/HiringFormModal/index.ts diff --git a/src/apps/profiles/src/member-profile/profile-header/HiringFormModal/HiringFormModal.tsx b/src/apps/profiles/src/member-profile/profile-header/HiringFormModal/HiringFormModal.tsx new file mode 100644 index 000000000..eea5d7e30 --- /dev/null +++ b/src/apps/profiles/src/member-profile/profile-header/HiringFormModal/HiringFormModal.tsx @@ -0,0 +1,48 @@ +import { FC } from 'react' + +import { UserProfile } from '~/libs/core' +import { BaseModal } from '~/libs/ui' + +interface HiringFormModalProps { + onClose: () => void + authProfile: UserProfile | undefined + profile: UserProfile + searchedSkills: string[] +} + +function populateIframeForm(profile: UserProfile, authProfile: any | undefined, searchedSkills: string[]): string { + const formUrl = `https://go.topcoder.com/talent-search-intake?handle=${profile.handle}` + + if (authProfile) { + return `${formUrl} +&first_name=${authProfile.firstName} +&last_name=${authProfile.lastName} +&email=${authProfile.email} +&searched_skills=${searchedSkills.join(',')}` + } + + return formUrl +} + +const HiringFormModal: FC = (props: HiringFormModalProps) => ( + + Interested in working with one of our experts? +
+ Start with this form. +

+ )} + size='lg' + > +