Skip to content

Commit 599e1cb

Browse files
authored
Merge branch 'dev' into PM-5787-2
2 parents 86ba781 + 258fa37 commit 599e1cb

39 files changed

Lines changed: 2075 additions & 163 deletions

src/apps/customer-portal/src/lib/services/statistics.service.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,6 @@ function normalizeCountryRows(
157157
return
158158
}
159159

160-
if (row['country.country_name'] === 'Taiwan') {
161-
console.log('here', row)
162-
163-
}
164-
165160
const code = toAlpha2CountryCode(lookup.countryCode)
166161
const current = countries.get(code)
167162
const topWinners = (row.topWinners || [])

src/apps/customer-portal/src/pages/statistics/StatisticsPage/StatisticsPage.module.scss

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,12 @@
296296
}
297297
}
298298

299+
:global(.highcharts-tooltip) {
300+
position: fixed !important;
301+
transform: none !important;
302+
z-index: 20;
303+
}
304+
299305
&:fullscreen {
300306
height: 100vh;
301307
min-height: 100vh;
@@ -306,6 +312,12 @@
306312
height: 100vh !important;
307313
}
308314
}
315+
316+
@include ltesm {
317+
:global(.highcharts-legend-item text) {
318+
font-size: 10px !important;
319+
}
320+
}
309321
}
310322

311323
.mapFullscreenButton {
@@ -367,6 +379,9 @@
367379
top: 100%;
368380
transform: translateX(-50%);
369381
width: 0;
382+
@include ltemd {
383+
display: none;
384+
}
370385
}
371386
}
372387

src/apps/customer-portal/src/pages/statistics/StatisticsPage/StatisticsPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ const StatisticsPage: FC = () => {
237237
</span>
238238
</td>
239239
<td>
240-
<div>
240+
<div title={country.name}>
241241
{country.code && (
242242
<span
243243
aria-hidden='true'

src/apps/customer-portal/src/pages/statistics/StatisticsPage/WorldMap.tsx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,30 @@ function renderCountryTooltip(point: StatisticsMapPoint): string {
311311
`
312312
}
313313

314+
function getFixedTooltipPosition(
315+
labelWidth: number,
316+
labelHeight: number,
317+
point: Highcharts.Point,
318+
chart: Highcharts.Chart,
319+
): Highcharts.PositionObject {
320+
const chartRenderTo = (chart as unknown as { renderTo: HTMLElement }).renderTo
321+
const chartRect = chartRenderTo.getBoundingClientRect()
322+
const plotX = (point.plotX ?? 0) + chart.plotLeft
323+
const plotY = (point.plotY ?? 0) + chart.plotTop
324+
const pointX = chartRect.left + plotX
325+
const pointY = chartRect.top + plotY
326+
const minOffset = 12
327+
const offsetAbove = 14
328+
329+
return {
330+
x: Math.min(
331+
Math.max(pointX - Math.round(labelWidth / 2), minOffset),
332+
window.innerWidth - labelWidth - minOffset,
333+
),
334+
y: Math.max(pointY - labelHeight - offsetAbove, minOffset),
335+
}
336+
}
337+
314338
function createTooltipFormatter(
315339
props: Pick<WorldMapProps, 'showWinnerDetails'>,
316340
): Highcharts.TooltipFormatterCallbackFunction {
@@ -481,14 +505,14 @@ const WorldMap: FC<WorldMapProps> = props => {
481505
margin: [0, 0, 80, 0],
482506
},
483507
legend: {
484-
itemDistance: 24,
508+
itemDistance: 16,
485509
itemMarginBottom: 4,
486510
itemStyle: {
487-
fontSize: '12px',
511+
fontSize: '9px',
488512
},
489513
symbolHeight: 12,
490514
symbolWidth: 12,
491-
width: 340,
515+
width: 360,
492516
},
493517
},
494518
condition: {
@@ -515,7 +539,28 @@ const WorldMap: FC<WorldMapProps> = props => {
515539
showWinnerDetails: props.showWinnerDetails,
516540
}),
517541
padding: 0,
542+
positioner: (
543+
labelWidth: number,
544+
labelHeight: number,
545+
point: Highcharts.Point,
546+
): Highcharts.PositionObject => {
547+
const chart = chartRef.current?.chart as Highcharts.Chart | undefined
548+
549+
if (!chart) {
550+
return { x: 0, y: 0 }
551+
}
552+
553+
return getFixedTooltipPosition(
554+
labelWidth,
555+
labelHeight,
556+
point,
557+
chart,
558+
)
559+
},
518560
shadow: false,
561+
style: {
562+
position: 'fixed',
563+
},
519564
useHTML: true,
520565
},
521566
}),
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
@import "@libs/ui/styles/includes";
2+
3+
.container {
4+
min-height: 60vh;
5+
display: flex;
6+
align-items: center;
7+
justify-content: center;
8+
}
9+
10+
.content {
11+
display: flex;
12+
flex-direction: column;
13+
align-items: center;
14+
justify-content: center;
15+
text-align: center;
16+
gap: $sp-6;
17+
padding: $sp-15 $sp-8;
18+
color: $black-100;
19+
20+
svg {
21+
color: $black-60;
22+
}
23+
}
24+
25+
.title {
26+
@include font-barlow;
27+
font-weight: 600;
28+
font-size: 28px;
29+
line-height: 34px;
30+
margin: 0;
31+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { FC, useCallback } from 'react'
2+
import { useNavigate } from 'react-router-dom'
3+
4+
import { Button, ContentLayout, IconOutline, IconSolid, PageTitle } from '~/libs/ui'
5+
6+
import styles from './MemberNotFound.module.scss'
7+
8+
interface MemberNotFoundProps {
9+
memberHandle?: string
10+
}
11+
12+
const MemberNotFound: FC<MemberNotFoundProps> = (props: MemberNotFoundProps) => {
13+
const navigate = useNavigate()
14+
15+
const handleBack = useCallback(() => {
16+
navigate(-1)
17+
}, [navigate])
18+
19+
return (
20+
<ContentLayout outerClass={styles.container}>
21+
<PageTitle>Profile Not Found | Topcoder</PageTitle>
22+
23+
<div className={styles.content} role='alert'>
24+
<IconOutline.ExclamationCircleIcon className='icon-xxxl' />
25+
<h2 className={styles.title}>We were unable to locate that profile</h2>
26+
{props.memberHandle && (
27+
<p className='body-main'>
28+
No member was found with the handle
29+
{' '}
30+
<strong>{props.memberHandle}</strong>
31+
.
32+
</p>
33+
)}
34+
<Button
35+
link
36+
size='lg'
37+
iconToLeft
38+
icon={IconSolid.ArrowLeftIcon}
39+
onClick={handleBack}
40+
>
41+
Go back
42+
</Button>
43+
</div>
44+
</ContentLayout>
45+
)
46+
}
47+
48+
export default MemberNotFound
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as MemberNotFound } from './MemberNotFound'

src/apps/profiles/src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export * from './tc-achievements/SRMView/ChallengesGrid'
44
export * from './EditMemberPropertyBtn'
55
export * from './AddButton'
66
export * from './EmptySection'
7+
export * from './MemberNotFound'

src/apps/profiles/src/member-badges/MemberBadgesPage.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react'
22
import { Params, useNavigate, useParams } from 'react-router-dom'
3+
import { AxiosError } from 'axios'
34
import { bind } from 'lodash'
45

56
import { profileGetPublicAsync, useMemberBadges, UserBadge, UserBadgesResponse, UserProfile } from '~/libs/core'
67
import { Button, ContentLayout, IconSolid, LoadingSpinner } from '~/libs/ui'
78

8-
import { MemberBadgeModal } from '../components'
9+
import { MemberBadgeModal, MemberNotFound } from '../components'
910

1011
import styles from './MemberBadgesPage.module.scss'
1112

@@ -19,6 +20,7 @@ const MemberBadgesPage: FC<{}> = () => {
1920
] = useState()
2021

2122
const [profileReady, setProfileReady]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false)
23+
const [notFound, setNotFound]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false)
2224

2325
const memberBadges: UserBadgesResponse | undefined = useMemberBadges(profile?.userId as number, { limit: 100 })
2426

@@ -39,12 +41,21 @@ const MemberBadgesPage: FC<{}> = () => {
3941

4042
useEffect(() => {
4143
if (routeParams.memberHandle) {
44+
setProfileReady(false)
45+
setNotFound(false)
46+
setProfile(undefined)
47+
4248
profileGetPublicAsync(routeParams.memberHandle)
4349
.then(userProfile => {
4450
setProfile(userProfile)
4551
setProfileReady(true)
4652
})
47-
// TODO: NOT FOUND PAGE redirect/dispaly via catch
53+
.catch((e: AxiosError) => {
54+
if (e.code === AxiosError.ERR_BAD_REQUEST && e.response?.status === 404) {
55+
setNotFound(true)
56+
setProfileReady(true)
57+
}
58+
})
4859
}
4960
}, [routeParams.memberHandle])
5061

@@ -54,9 +65,13 @@ const MemberBadgesPage: FC<{}> = () => {
5465

5566
return (
5667
<>
57-
<LoadingSpinner hide={profileReady && !!memberBadges} />
68+
<LoadingSpinner hide={profileReady && (notFound || !!memberBadges)} />
69+
70+
{profileReady && notFound && (
71+
<MemberNotFound memberHandle={routeParams.memberHandle} />
72+
)}
5873

59-
{profileReady && profile && !!memberBadges && (
74+
{profileReady && profile && !notFound && !!memberBadges && (
6075
<ContentLayout
6176
outerClass={styles.container}
6277
>

src/apps/profiles/src/member-profile/MemberProfilePage.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { AxiosError } from 'axios'
55
import { profileContext, ProfileContextData, profileGetPublicAsync, UserProfile } from '~/libs/core'
66
import { LoadingSpinner } from '~/libs/ui'
77

8-
import { rootRoute } from '../profiles.routes'
8+
import { MemberNotFound } from '../components'
99
import { notifyUniNavi } from '../lib'
1010

1111
import { ProfilePageLayout } from './page-layout'
@@ -21,6 +21,7 @@ const MemberProfilePage: FC<{}> = () => {
2121
] = useState()
2222

2323
const [profileReady, setProfileReady]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false)
24+
const [notFound, setNotFound]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false)
2425
const { isTalentSearch }: MemberProfileContextValue = useMemberProfileContext()
2526

2627
const { profile: authProfile }: ProfileContextData = useContext(profileContext)
@@ -31,14 +32,19 @@ const MemberProfilePage: FC<{}> = () => {
3132

3233
useEffect(() => {
3334
if (routeParams.memberHandle) {
35+
setProfileReady(false)
36+
setNotFound(false)
37+
setProfile(undefined)
38+
3439
profileGetPublicAsync(routeParams.memberHandle)
3540
.then(userProfile => {
3641
setProfile({ ...userProfile } as UserProfile)
3742
setProfileReady(true)
3843
})
3944
.catch((e: AxiosError) => {
4045
if (e.code === AxiosError.ERR_BAD_REQUEST && e.response?.status === 404) {
41-
navigate(rootRoute)
46+
setNotFound(true)
47+
setProfileReady(true)
4248
}
4349
})
4450
}
@@ -58,7 +64,11 @@ const MemberProfilePage: FC<{}> = () => {
5864
<>
5965
<LoadingSpinner hide={profileReady} />
6066

61-
{profileReady && profile && (
67+
{profileReady && notFound && (
68+
<MemberNotFound memberHandle={routeParams.memberHandle} />
69+
)}
70+
71+
{profileReady && profile && !notFound && (
6272
<ProfilePageLayout
6373
handleBackBtn={handleBackBtn}
6474
isTalentSearch={isTalentSearch}

0 commit comments

Comments
 (0)