diff --git a/.circleci/config.yml b/.circleci/config.yml index 82a9a2c2f3..2b82baa568 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -349,7 +349,7 @@ workflows: filters: branches: only: - - free + - tca-certifications-on-profile-page # This is alternate dev env for parallel testing - "build-test": context : org-global diff --git a/__tests__/shared/components/ProfilePage/__snapshots__/index.jsx.snap b/__tests__/shared/components/ProfilePage/__snapshots__/index.jsx.snap index bcc4226d58..a0cd40abdc 100644 --- a/__tests__/shared/components/ProfilePage/__snapshots__/index.jsx.snap +++ b/__tests__/shared/components/ProfilePage/__snapshots__/index.jsx.snap @@ -713,6 +713,7 @@ exports[`renders a full Profile correctly 1`] = ` "unsubscribe": null, } } + tcAcademyCertifications={Array []} /> `; @@ -862,5 +863,6 @@ exports[`renders an empty Profile correctly 1`] = ` "unsubscribe": null, } } + tcAcademyCertifications={Array []} /> `; diff --git a/config/default.js b/config/default.js index e5325e57eb..8f3d90b2d8 100644 --- a/config/default.js +++ b/config/default.js @@ -444,6 +444,7 @@ module.exports = { GIGS_PAGES_PATH: '/gigs', GIGS_LISTING_CACHE_TIME: 300, // in seconds START_PAGE_PATH: '/start', + TC_ACADEMY_BASE_PATH: '/learn', GUIKIT: { DEBOUNCE_ON_CHANGE_TIME: 150, }, @@ -452,4 +453,5 @@ module.exports = { SDK_KEY: '7V4CJhurXT3Y3bnzv1hv1', }, PLATFORM_SITE_URL: 'https://platform.topcoder-dev.com', + PLATFORMUI_SITE_URL: 'https://platform-ui.topcoder-dev.com', }; diff --git a/config/development.js b/config/development.js index 7991e1a4c9..5088a55f80 100644 --- a/config/development.js +++ b/config/development.js @@ -5,4 +5,5 @@ module.exports = { USER_SETTINGS: '', /* No dev server is available for saved searches */ }, PLATFORM_SITE_URL: 'https://platform.topcoder-dev.com', + PLATFORMUI_SITE_URL: 'https://platform-ui.topcoder-dev.com', }; diff --git a/config/production.js b/config/production.js index b71f7c9800..a97b9b3cb3 100644 --- a/config/production.js +++ b/config/production.js @@ -226,4 +226,5 @@ module.exports = { TC_EDU_SEARCH_BAR_MAX_RESULTS_EACH_GROUP: 3, ENABLE_RECOMMENDER: true, PLATFORM_SITE_URL: 'https://platform.topcoder.com', + PLATFORMUI_SITE_URL: 'https://platform-ui.topcoder.com', }; diff --git a/package.json b/package.json index ac73c3642a..7ad7f93100 100644 --- a/package.json +++ b/package.json @@ -153,7 +153,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.7", + "topcoder-react-lib": "1000.29.7", "topcoder-react-ui-kit": "2.0.1", "topcoder-react-utils": "0.7.8", "turndown": "^4.0.2", diff --git a/src/assets/images/profile/tca-certificates/datascience-badge.png b/src/assets/images/profile/tca-certificates/datascience-badge.png new file mode 100644 index 0000000000..06c3242152 Binary files /dev/null and b/src/assets/images/profile/tca-certificates/datascience-badge.png differ diff --git a/src/assets/images/profile/tca-certificates/design-badge.png b/src/assets/images/profile/tca-certificates/design-badge.png new file mode 100644 index 0000000000..5bdb8bfb25 Binary files /dev/null and b/src/assets/images/profile/tca-certificates/design-badge.png differ diff --git a/src/assets/images/profile/tca-certificates/develop-badge.png b/src/assets/images/profile/tca-certificates/develop-badge.png new file mode 100644 index 0000000000..e24e581c73 Binary files /dev/null and b/src/assets/images/profile/tca-certificates/develop-badge.png differ diff --git a/src/assets/images/profile/tca-certificates/qa-badge.png b/src/assets/images/profile/tca-certificates/qa-badge.png new file mode 100644 index 0000000000..a5e73770b8 Binary files /dev/null and b/src/assets/images/profile/tca-certificates/qa-badge.png differ diff --git a/src/assets/images/profile/tca-certificates/tca-logo.svg b/src/assets/images/profile/tca-certificates/tca-logo.svg new file mode 100644 index 0000000000..95fc94d254 --- /dev/null +++ b/src/assets/images/profile/tca-certificates/tca-logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/shared/components/ProfilePage/ProfileModal/index.jsx b/src/shared/components/ProfilePage/ProfileModal/index.jsx new file mode 100644 index 0000000000..41a4f1bbfa --- /dev/null +++ b/src/shared/components/ProfilePage/ProfileModal/index.jsx @@ -0,0 +1,50 @@ +import React from 'react'; +import PT from 'prop-types'; +import { noop } from 'lodash/noop'; +import { Modal } from 'topcoder-react-ui-kit'; +import cn from 'classnames'; + +import IconClose from 'assets/images/icon-close-green.svg'; +import styles from './styles.scss'; + +const ProfileModal = ({ + children, + title, + onCancel, + containerClassName, +}) => ( + + +
+

+ {title} +

+
+ +
+
+ {children} +
+
+); + +ProfileModal.defaultProps = { + title: null, + onCancel: noop, + containerClassName: '', +}; + +ProfileModal.propTypes = { + children: PT.node.isRequired, + title: PT.node, + onCancel: PT.func, + containerClassName: PT.string, +}; + +export default ProfileModal; diff --git a/src/shared/components/ProfilePage/ProfileModal/styles.scss b/src/shared/components/ProfilePage/ProfileModal/styles.scss new file mode 100644 index 0000000000..a93949450d --- /dev/null +++ b/src/shared/components/ProfilePage/ProfileModal/styles.scss @@ -0,0 +1,47 @@ +@import "~styles/mixins"; + +.modal-overlay { + background: #000; +} + +.modal-container-copilot, +.modal-container { + width: 1232px; + min-height: 700px; + max-width: 1232px; + border-radius: 8px; + padding: 32px 32px 0 32px; + gap: 24px; + + &.modal-container-copilot { + height: auto; + } + + @include xs-to-sm { + width: 100%; + max-width: 100%; + height: 100% !important; + max-height: 100% !important; + padding: 24px 16px 48px 16px; + } + + .header { + display: flex; + justify-content: space-between; + align-items: center; + padding-bottom: 24px; + + .title { + @include barlow-medium; + + font-weight: 600; + font-size: 22px; + line-height: 26px; + text-transform: uppercase; + } + + .icon { + cursor: pointer; + } + } +} diff --git a/src/shared/components/ProfilePage/TcaCertificates/CourseBadge/index.jsx b/src/shared/components/ProfilePage/TcaCertificates/CourseBadge/index.jsx new file mode 100644 index 0000000000..1ab0766e66 --- /dev/null +++ b/src/shared/components/ProfilePage/TcaCertificates/CourseBadge/index.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import PT from 'prop-types'; + +import DataScienceBadgeImg from 'assets/images/profile/tca-certificates/datascience-badge.png'; +import DesignBadgeImg from 'assets/images/profile/tca-certificates/design-badge.png'; +import DevelopBadgeImg from 'assets/images/profile/tca-certificates/develop-badge.png'; +import QaBadgeImg from 'assets/images/profile/tca-certificates/qa-badge.png'; + +import './styles.scss'; + +const badgesMap = { + DATASCIENCE: DataScienceBadgeImg, + DESIGN: DesignBadgeImg, + DEV: DevelopBadgeImg, + QA: QaBadgeImg, +}; + +const CourseBadge = ({ type: badgeType, size }) => { + const badgeImg = badgesMap[badgeType]; + + return ( +
+ {badgeType} +
+ ); +}; + +CourseBadge.defaultProps = { + size: 'md', +}; + +CourseBadge.propTypes = { + size: PT.oneOf(['md']), + type: PT.oneOf(['DATASCIENCE', 'DESIGN', 'DEV', 'QA']).isRequired, +}; + + +export default CourseBadge; diff --git a/src/shared/components/ProfilePage/TcaCertificates/CourseBadge/styles.scss b/src/shared/components/ProfilePage/TcaCertificates/CourseBadge/styles.scss new file mode 100644 index 0000000000..d27584562e --- /dev/null +++ b/src/shared/components/ProfilePage/TcaCertificates/CourseBadge/styles.scss @@ -0,0 +1,13 @@ +.tca-badge-wrap { + &.size-md { + width: 48px; + height: 48px; + } + + img { + display: block; + width: 100%; + height: 100%; + object-fit: contain; + } +} diff --git a/src/shared/components/ProfilePage/TcaCertificates/List/index.jsx b/src/shared/components/ProfilePage/TcaCertificates/List/index.jsx new file mode 100644 index 0000000000..ae77b2203d --- /dev/null +++ b/src/shared/components/ProfilePage/TcaCertificates/List/index.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import PT from 'prop-types'; + +import './styles.scss'; +import CourseBadge from '../CourseBadge'; + +const preventDefault = ev => ev.stopPropagation(); + +const List = ({ + certificates, + onClick, +}) => ( +
+ {certificates.map(certificate => ( +
onClick(certificate)} + onKeyPress={() => onClick(certificate)} + role="button" + tabIndex={-1} + > +
+ +
+
+
+ {certificate.certificationTitle} +
+
+ + by {certificate.provider} + +
+
+
+ ))} +
+); + +List.propTypes = { + certificates: PT.arrayOf(PT.shape()).isRequired, + onClick: PT.func.isRequired, +}; + +export default List; diff --git a/src/shared/components/ProfilePage/TcaCertificates/List/styles.scss b/src/shared/components/ProfilePage/TcaCertificates/List/styles.scss new file mode 100644 index 0000000000..24fecab25f --- /dev/null +++ b/src/shared/components/ProfilePage/TcaCertificates/List/styles.scss @@ -0,0 +1,63 @@ +@import "~styles/mixins"; + +.list { + display: flex; + gap: 16px; + margin-top: 24px; + flex-wrap: wrap; + + @include xs-to-sm { + flex-direction: column; + flex-wrap: nowrap; + margin-top: 16px; + } +} + +.list-item { + background: $listing-white; + border-radius: 8px; + padding: 16px; + display: flex; + align-items: center; + gap: 16px; + width: 316px; + transition: 0.25s ease-in-out; + box-shadow: 0 0 0 rgba(0, 0, 0, 0); + cursor: pointer; + + &:hover { + box-shadow: 0 0 16px rgba(22, 103, 154, 0.5); + } + + @include xs-to-sm { + width: 100%; + } +} + +.list-item_badge { + width: 48px; + height: 48px; + + svg { + display: block; + width: 48px; + height: 48px; + } +} + +.list-item_title { + @include roboto-sans-regular; + + font-size: 16px; + line-height: 24px; + font-weight: bold; +} + +.list-item_sub { + @include roboto-sans-regular; + + font-style: italic; + font-size: 14px; + line-height: 22px; + color: $listing-placeholder-gray; +} diff --git a/src/shared/components/ProfilePage/TcaCertificates/TcaCertificateModal/index.jsx b/src/shared/components/ProfilePage/TcaCertificates/TcaCertificateModal/index.jsx new file mode 100644 index 0000000000..4d9cfb8dd1 --- /dev/null +++ b/src/shared/components/ProfilePage/TcaCertificates/TcaCertificateModal/index.jsx @@ -0,0 +1,45 @@ +import React from 'react'; +import PT from 'prop-types'; +import { noop } from 'lodash/noop'; +import { config } from 'topcoder-react-utils'; + +import ProfileModal from '../../ProfileModal'; +import styles from './styles.scss'; + +const tcAcademyPath = `${config.PLATFORMUI_SITE_URL}${config.TC_ACADEMY_BASE_PATH}`; + +const TcaCertificateModal = ({ + certificate, + onCancel, + memberHandle, +}) => ( + +