diff --git a/.circleci/config.yml b/.circleci/config.yml index f374780470..7d69ac3ab7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -363,7 +363,7 @@ workflows: filters: branches: only: - - free + - reskin-profile-settings # This is beta env for production soft releases - "build-prod-beta": context : org-global diff --git a/src/shared/components/ProfilePage/Stats/ChartTooltip/index.jsx b/src/shared/components/ProfilePage/Stats/ChartTooltip/index.jsx index de48b50123..3f9df59449 100644 --- a/src/shared/components/ProfilePage/Stats/ChartTooltip/index.jsx +++ b/src/shared/components/ProfilePage/Stats/ChartTooltip/index.jsx @@ -5,15 +5,18 @@ import React from 'react'; import PT from 'prop-types'; import './styles.scss'; +import cn from 'classnames'; const ChartTooltip = ({ show, left, top, challengeName, - challengeData, rating, ratingColor, href, + challengeData, rating, rotated, ratingColor, href, + id, }) => ( totalH - padding.bottom - yScale(d.number)) .attr('fill', d => getRatingColor(d.start)); + const updateTooltipPosition = () => { + const e = d3.mouse(document.getElementById('distribution-graph-container')); + const profileModalContainerEl = document.querySelector('.ProfileModalContainer'); + const profileModalContainerRect = profileModalContainerEl + ? profileModalContainerEl.getBoundingClientRect() : null; + const graphEl = document.getElementById('distribution-graph-container'); + const graphRect = graphEl ? graphEl.getBoundingClientRect() : null; + const tooltipElement = document.getElementById('chart-tooltip-distribution-graph'); + + let cx = e[0]; + let cy = e[1]; + const defaultWidth = 320; + const defaultHeight = 115; + if (tooltipElement) { + const { clientWidth, clientHeight } = tooltipElement; + cx -= ((clientWidth || defaultWidth) / 2); + cy += 15; + + if (graphRect && profileModalContainerRect) { + const minLeft = profileModalContainerRect.x - graphRect.x; + const minTop = profileModalContainerRect.y - graphRect.y; + const maxRight = profileModalContainerRect.width + minLeft; + const maxBottom = profileModalContainerRect.height + minTop; + const minXTooltipPosition = minLeft; + const maxXTooltipPosition = maxRight - (clientWidth || defaultWidth); + const minYTooltipPosition = minTop; + const maxYTooltipPosition = maxBottom - (clientHeight || defaultHeight); + if (cx < minXTooltipPosition) { + cx = minXTooltipPosition; + } + if (cx > maxXTooltipPosition) { + cx = maxXTooltipPosition; + } + if (cy < minYTooltipPosition) { + cy = minYTooltipPosition; + } + if (cy > maxYTooltipPosition) { + cy = maxYTooltipPosition; + } + } + } + + $scope.setState({ + show: true, + left: cx, + top: cy, + }); + }; + svg.selectAll('rect.hover') .data(ranges) .enter() @@ -194,24 +243,16 @@ export default class DistributionGraph extends React.Component { .attr('width', xScale.rangeBand()) .attr('height', d => totalH - padding.bottom - yScale(d.number)) .on('mouseover', (d) => { - const e = d3.event; $scope.setState({ - show: true, - left: e.pageX, - top: e.pageY, challengeName: `${d.number} Coders`, challengeData: `Rating Range: ${d.start} - ${d.start + 99}`, rating: d.number, ratingColor: getRatingColor(d.start), }); + updateTooltipPosition(); }) .on('mousemove', () => { - const e = d3.event; - $scope.setState({ - show: true, - left: e.pageX, - top: e.pageY, - }); + updateTooltipPosition(); }) .on('mouseout', () => { $scope.setState({ @@ -253,8 +294,8 @@ export default class DistributionGraph extends React.Component { render() { return ( -
- +
+
); } diff --git a/src/shared/components/ProfilePage/Stats/DistributionGraph/index.scss b/src/shared/components/ProfilePage/Stats/DistributionGraph/index.scss index 47a06bba8f..89a036571a 100644 --- a/src/shared/components/ProfilePage/Stats/DistributionGraph/index.scss +++ b/src/shared/components/ProfilePage/Stats/DistributionGraph/index.scss @@ -4,6 +4,7 @@ display: flex; flex-direction: row; justify-content: center; + position: relative; .axis path, .axis line { diff --git a/src/shared/components/ProfilePage/Stats/HistoryGraph/index.jsx b/src/shared/components/ProfilePage/Stats/HistoryGraph/index.jsx index 9094e27bf2..8d398caf48 100644 --- a/src/shared/components/ProfilePage/Stats/HistoryGraph/index.jsx +++ b/src/shared/components/ProfilePage/Stats/HistoryGraph/index.jsx @@ -34,7 +34,12 @@ export default class HistoryGraph extends React.Component { } }; window.addEventListener('resize', this.resizeHandle); - this.bodyClickHandle = () => this.setState({ show: false }); + this.bodyClickHandle = (event) => { + if (event.target && event.target.tagName === 'circle') { + return; + } + this.setState({ show: false }); + }; document.body.addEventListener('click', this.bodyClickHandle); } @@ -240,6 +245,58 @@ export default class HistoryGraph extends React.Component { .attr('stroke-width', 3); */ + const updateTooltipPosition = () => { + const e = d3.mouse(document.getElementById('history-graph-container')); + const profileModalContainerEl = document.querySelector('.ProfileModalContainer'); + const profileModalContainerRect = profileModalContainerEl + ? profileModalContainerEl.getBoundingClientRect() : null; + const graphEl = document.getElementById('history-graph-container'); + const graphRect = graphEl ? graphEl.getBoundingClientRect() : null; + const tooltipElement = document.getElementById('chart-tooltip-history-graph'); + + let cx = e[0]; + let cy = e[1]; + let rotated = false; + const defaultWidth = 320; + const defaultHeight = 115; + if (tooltipElement) { + const { clientWidth, clientHeight } = tooltipElement; + cx -= ((clientWidth || defaultWidth) / 2); + cy += 15; + + if (graphRect && profileModalContainerRect) { + const minLeft = profileModalContainerRect.x - graphRect.x; + const minTop = profileModalContainerRect.y - graphRect.y; + const maxRight = profileModalContainerRect.width + minLeft; + const maxBottom = profileModalContainerRect.height + minTop; + const minXTooltipPosition = minLeft; + const maxXTooltipPosition = maxRight - (clientWidth || defaultWidth); + const minYTooltipPosition = minTop; + const maxYTooltipPosition = maxBottom - (clientHeight || defaultHeight); + if (cx < minXTooltipPosition) { + cx = minXTooltipPosition; + } + if (cx > maxXTooltipPosition) { + cx = maxXTooltipPosition; + } + if (cy < minYTooltipPosition) { + cy = minYTooltipPosition; + } + if (cy > maxYTooltipPosition) { + cy -= clientHeight + 25; + rotated = true; + } + } + } + + $scope.setState({ + rotated, + show: true, + left: cx, + top: cy, + }); + }; + svg.selectAll('circle') .data(history) .enter() @@ -249,24 +306,25 @@ export default class HistoryGraph extends React.Component { .attr('r', 5.5) .attr('fill', d => getRatingColor(d.newRating)) .on('mouseover', (d) => { - const e = d3.event; $scope.setState({ - show: true, - left: e.pageX, - top: e.pageY, challengeName: d.challengeName, challengeData: moment(d.ratingDate).format('MMM DD, YYYY'), rating: d.newRating, ratingColor: getRatingColor(d.newRating), href: getChallengeLink(d.challengeId), }); + + updateTooltipPosition(); + }) + .on('mousemove', () => { + updateTooltipPosition(); }); } render() { return ( -
- +
+
); } diff --git a/src/shared/components/ProfilePage/Stats/HistoryGraph/index.scss b/src/shared/components/ProfilePage/Stats/HistoryGraph/index.scss index d2b0b5b1c5..1f49115b93 100644 --- a/src/shared/components/ProfilePage/Stats/HistoryGraph/index.scss +++ b/src/shared/components/ProfilePage/Stats/HistoryGraph/index.scss @@ -4,6 +4,7 @@ display: flex; flex-direction: row; justify-content: center; + position: relative; .axis path, .axis line { diff --git a/src/shared/components/ProfilePage/index.jsx b/src/shared/components/ProfilePage/index.jsx index 81e1432252..e8e01730d2 100644 --- a/src/shared/components/ProfilePage/index.jsx +++ b/src/shared/components/ProfilePage/index.jsx @@ -8,6 +8,8 @@ import _ from 'lodash'; import React from 'react'; import PT from 'prop-types'; import { isomorphy } from 'topcoder-react-utils'; +import { Modal } from 'topcoder-react-ui-kit'; +import IconClose from 'assets/images/icon-close-green.svg'; import shortId from 'shortid'; import { actions } from 'topcoder-react-lib'; import { connect } from 'react-redux'; @@ -17,12 +19,12 @@ import { dataMap } from './ExternalLink'; import Header from './Header'; import MemberTracks from './MemberTracks'; -import './styles.scss'; +import styles from './styles.scss'; import Skills from './Skills'; import MemberInfo from './MemberInfo'; import Activity from './Activity'; import TcaCertificates from './TcaCertificates'; -import ProfileModal from './ProfileModal'; +// import ProfileModal from './ProfileModal'; // import Awards from './Awards'; /** @@ -249,26 +251,38 @@ class ProfilePage extends React.Component { }} /> { showDetails && ( - - { - this.setState({ tab }); - }} - isAlreadyLoadChallenge={this.isAlreadyLoadChallenge} - /> - + +
+

+ { + subTrack === 'SRM' ? 'Single round match' + : subTrack.replace('FIRST_2_FINISH', 'FIRST2FINISH').replace(/_/g, ' ') + } +

+
+ +
+
+ { + this.setState({ tab }); + }} + isAlreadyLoadChallenge={this.isAlreadyLoadChallenge} + /> +
+ )}
); diff --git a/src/shared/components/ProfilePage/styles.scss b/src/shared/components/ProfilePage/styles.scss index 1418126f3d..c31eb78e7f 100644 --- a/src/shared/components/ProfilePage/styles.scss +++ b/src/shared/components/ProfilePage/styles.scss @@ -56,3 +56,52 @@ padding-top: 32px; } } + +.modal-overlay { + background: #000; +} + +.modal-container-copilot { + min-height: 220px; +} + +.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; + } + } +}