Skip to content

Commit 1ced5fd

Browse files
committed
Merge branch 'dev' of github.com:topcoder-platform/platform-ui into TSJR-314_skill-manager_landing-page
2 parents 471acf8 + ec43301 commit 1ced5fd

File tree

10 files changed

+108
-29
lines changed

10 files changed

+108
-29
lines changed

src/apps/profiles/src/components/tc-achievements/MemberStatsBlock/MemberStatsBlock.tsx

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { getRatingColor, MemberStats, UserProfile } from '~/libs/core'
66
import { IconOutline } from '~/libs/ui'
77

88
import { useFetchActiveTracks } from '../../../hooks'
9-
import { WinnerIcon } from '../../../lib'
9+
import { formatPlural, WinnerIcon } from '../../../lib'
1010
import { MemberProfileContextValue, useMemberProfileContext } from '../../../member-profile/MemberProfile.context'
1111

1212
import styles from './MemberStatsBlock.module.scss'
@@ -45,30 +45,25 @@ const MemberStatsBlock: FC<MemberStatsBlockProps> = props => {
4545
<div className={styles.trackDetails}>
4646
{!track.isDSTrack && ((track.submissions || track.wins) > 0) && (
4747
<>
48-
<WinnerIcon className='icon-xxxl' />
48+
{track.wins > 0 && (
49+
<WinnerIcon className='icon-xxxl' />
50+
)}
4951
<span className={styles.trackStats}>
5052
<span className={styles.count}>
5153
{track.wins || track.submissions}
5254
</span>
5355
<span className={styles.label}>
54-
{track.wins > 0 ? 'Wins' : 'Submissions'}
56+
{formatPlural(
57+
track.wins || track.submissions || 0,
58+
track.wins > 0 ? 'Win' : 'Submission',
59+
)}
5560
</span>
5661
</span>
5762
</>
5863
)}
5964
{/* competitive programming only */}
6065
{track.isDSTrack && (
61-
(track.percentile as number) >= 50 ? (
62-
<span className={styles.trackStats}>
63-
<span className={styles.count}>
64-
{track.percentile}
65-
%
66-
</span>
67-
<span className={styles.label}>
68-
Percentile
69-
</span>
70-
</span>
71-
) : (
66+
(track.isCPTrack || (track.percentile as number) < 50) ? (
7267
<>
7368
<span
7469
className={styles.icon}
@@ -83,6 +78,16 @@ const MemberStatsBlock: FC<MemberStatsBlockProps> = props => {
8378
</span>
8479
</span>
8580
</>
81+
) : (
82+
<span className={styles.trackStats}>
83+
<span className={styles.count}>
84+
{track.percentile}
85+
%
86+
</span>
87+
<span className={styles.label}>
88+
Percentile
89+
</span>
90+
</span>
8691
)
8792
)}
8893
<IconOutline.ChevronRightIcon

src/apps/profiles/src/components/tc-achievements/StatsSummaryBlock/StatsSummaryBlock.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { find, get } from 'lodash'
44

55
import { getRatingColor } from '~/libs/core'
66

7-
import { numberToFixed } from '../../../lib'
7+
import { formatPlural, numberToFixed } from '../../../lib'
88
import { TracksSummaryStats } from '../../../config'
99

1010
import styles from './StatsSummaryBlock.module.scss'
@@ -49,7 +49,10 @@ const StatsSummaryBlock: FC<StatsSummaryBlockProps> = props => {
4949
</span>
5050
<span className={styles.summaryItemLabel}>
5151
<span className='body-small'>
52-
{props.trackTitle === 'Single Round Match' ? 'Competitions' : 'Challenges'}
52+
{formatPlural(
53+
props.challenges || 0,
54+
props.trackTitle === 'Single Round Match' ? 'Competition' : 'Challenge',
55+
)}
5356
</span>
5457
</span>
5558
</div>
@@ -61,7 +64,7 @@ const StatsSummaryBlock: FC<StatsSummaryBlockProps> = props => {
6164
</span>
6265
<span className={styles.summaryItemLabel}>
6366
<span className='body-small'>
64-
Wins
67+
{formatPlural(props.wins || 0, 'Win')}
6568
</span>
6669
</span>
6770
</div>
@@ -73,7 +76,7 @@ const StatsSummaryBlock: FC<StatsSummaryBlockProps> = props => {
7376
</span>
7477
<span className={styles.summaryItemLabel}>
7578
<span className='body-small'>
76-
Submissions
79+
{formatPlural(props.submissions || 0, 'Submission')}
7780
</span>
7881
</span>
7982
</div>

src/apps/profiles/src/components/tc-achievements/SubTrackSummaryCard/SubTrackSummaryCard.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import classNames from 'classnames'
33

44
import { IconSolid } from '~/libs/ui'
55

6-
import { subTrackLabelToHumanName, WinnerIcon } from '../../../lib'
6+
import { formatPlural, subTrackLabelToHumanName, WinnerIcon } from '../../../lib'
77

88
import styles from './SubTrackSummaryCard.module.scss'
99

@@ -29,7 +29,9 @@ const SubTrackSummaryCard: FC<SubTrackSummaryCardProps> = props => (
2929
{props.wins}
3030
</span>
3131
<span className={styles.statsItemLabel}>
32-
<span className='label'>wins</span>
32+
<span className='label'>
33+
{formatPlural(props.wins || 0, 'Win')}
34+
</span>
3335
</span>
3436
</div>
3537
)}
@@ -38,7 +40,9 @@ const SubTrackSummaryCard: FC<SubTrackSummaryCardProps> = props => (
3840
{props.submissions}
3941
</span>
4042
<span className={styles.statsItemLabel}>
41-
<span className='label'>submissions</span>
43+
<span className='label'>
44+
{formatPlural(props.submissions || 0, 'Submission')}
45+
</span>
4246
</span>
4347
</div>
4448
</div>

src/apps/profiles/src/hooks/useFetchActiveTracks.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface MemberStatsTrack {
2121
wins: number,
2222
order?: number
2323
isDSTrack?: boolean
24+
isCPTrack?: boolean
2425
}
2526

2627
/**
@@ -206,6 +207,7 @@ export const useFetchActiveTracks = (userHandle: string): MemberStatsTrack[] =>
206207
return {
207208
challenges: dataScienceSubTracks.SRM?.challenges ?? 0,
208209
isActive: (dataScienceSubTracks.SRM?.challenges ?? 0) > 0,
210+
isCPTrack: true,
209211
isDSTrack: true,
210212
name: 'Competitive Programming',
211213
order: -2,

src/apps/profiles/src/lib/helpers.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,15 @@ export function isValidURL(urlToValidate: string): boolean {
113113

114114
return true
115115
}
116+
117+
/**
118+
* Creates the string with the number of items and the word describing the item
119+
* possibly in plural form.
120+
*
121+
* @param {number} count - The number of entities
122+
* @param {string} baseWord - The base word that describes the entity
123+
* @returns {string}
124+
*/
125+
export function formatPlural(count: number, baseWord: string): string {
126+
return `${baseWord}${count === 1 ? '' : 's'}`
127+
}

src/apps/profiles/src/member-profile/education-and-certifications/ModifyEducationModal/ModifyEducationModal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import classNames from 'classnames'
66

77
import { BaseModal, Button, IconOutline, InputSelect, InputText } from '~/libs/ui'
88
import {
9-
updateOrCreateMemberTraitsAsync,
9+
updateDeleteOrCreateMemberTraitAsync,
1010
UserProfile,
1111
UserTrait,
1212
UserTraitCategoryNames,
@@ -72,13 +72,13 @@ const ModifyEducationModal: FC<ModifyEducationModalProps> = (props: ModifyEducat
7272

7373
setIsSaving(true)
7474

75-
updateOrCreateMemberTraitsAsync(props.profile.handle, [{
75+
updateDeleteOrCreateMemberTraitAsync(props.profile.handle, {
7676
categoryName: UserTraitCategoryNames.education,
7777
traitId: UserTraitIds.education,
7878
traits: {
7979
data: memberEducation || [],
8080
},
81-
}])
81+
}, props.education)
8282
.then(() => {
8383
toast.success('Education updated successfully.', { position: toast.POSITION.BOTTOM_RIGHT })
8484
props.onSave()

src/apps/profiles/src/member-profile/work-expirence/ModifyWorkExpirenceModal/ModifyWorkExpirenceModal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import classNames from 'classnames'
66

77
import { BaseModal, Button, IconOutline, InputDatePicker, InputSelect, InputText } from '~/libs/ui'
88
import {
9-
updateOrCreateMemberTraitsAsync,
9+
updateDeleteOrCreateMemberTraitAsync,
1010
UserProfile, UserTrait,
1111
UserTraitCategoryNames,
1212
UserTraitIds,
@@ -71,13 +71,13 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
7171

7272
setIsSaving(true)
7373

74-
updateOrCreateMemberTraitsAsync(props.profile.handle, [{
74+
updateDeleteOrCreateMemberTraitAsync(props.profile.handle, {
7575
categoryName: UserTraitCategoryNames.work,
7676
traitId: UserTraitIds.work,
7777
traits: {
7878
data: workExpirence || [],
7979
},
80-
}])
80+
}, props.workExpirence)
8181
.then(() => {
8282
toast.success('Work Experience updated successfully.', { position: toast.POSITION.BOTTOM_RIGHT })
8383
props.onSave()

src/libs/core/lib/profile/profile-functions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export {
1616
updateMemberProfileAsync,
1717
updateMemberPhotoAsync,
1818
updateOrCreateMemberTraitsAsync,
19+
updateDeleteOrCreateMemberTraitAsync,
1920
} from './profile.functions'
2021
export * from './profile-store'
2122
export * from './rating.functions'

src/libs/core/lib/profile/profile-functions/profile-store/profile-xhr.store.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { xhrGetAsync, xhrPatchAsync, xhrPostAsync, xhrPutAsync } from '../../../xhr'
1+
import { xhrDeleteAsync, xhrGetAsync, xhrPatchAsync, xhrPostAsync, xhrPutAsync } from '../../../xhr'
22
import { CountryLookup } from '../../country-lookup.model'
33
import { EditNameRequest } from '../../edit-name-request.model'
44
import { ModifyTracksRequest } from '../../modify-tracks.request'
@@ -95,6 +95,14 @@ export async function createMemberTraits(
9595
return xhrPostAsync<UserTraits[], UserTraits[]>(`${profileUrl(handle)}/traits`, traits)
9696
}
9797

98+
export async function deleteMemberTrait(
99+
handle: string,
100+
traitIds: string,
101+
): Promise<UserTraits[]> {
102+
await xhrDeleteAsync<UserTraits[]>(`${profileUrl(handle)}/traits?traitIds=${traitIds}`)
103+
return []
104+
}
105+
98106
export async function modifyTracks(handle: string, request: ModifyTracksRequest): Promise<UserProfile> {
99107
return xhrPutAsync<ModifyTracksRequest, UserProfile>(profileUrl(handle), request)
100108
}

src/libs/core/lib/profile/profile-functions/profile.functions.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ import { ModifyUserPropertyResponse } from '../modify-user-role.model'
99
import { UserEmailPreferences } from '../user-email-preference.model'
1010
import { UserProfile } from '../user-profile.model'
1111
import { UserStats } from '../user-stats.model'
12-
import { UserTraits } from '../user-traits.model'
12+
import { UserTrait, UserTraits } from '../user-traits.model'
1313
import { UserVerify } from '../user-verify.model'
1414

1515
import { profileFactoryCreate } from './profile-factory'
1616
import { getMemberStats, getVerification, profileStoreGet, profileStorePatchName } from './profile-store'
1717
import {
1818
createMemberTraits,
19+
deleteMemberTrait,
1920
getCountryLookup,
2021
modifyTracks,
2122
updateMemberEmailPreferences,
@@ -135,6 +136,13 @@ export async function createMemberTraitsAsync(
135136
return createMemberTraits(handle, traits)
136137
}
137138

139+
export async function deleteMemberTraitAsync(
140+
handle: string,
141+
traitIds: string,
142+
): Promise<UserTraits[]> {
143+
return deleteMemberTrait(handle, traitIds)
144+
}
145+
138146
export async function modifyTracksAsync(handle: string, tracks: ModifyTracksRequest): Promise<UserProfile> {
139147
return modifyTracks(handle, tracks)
140148
}
@@ -159,3 +167,39 @@ export async function updateOrCreateMemberTraitsAsync(
159167
return createdTraitsRsp
160168
}
161169
}
170+
171+
export async function updateDeleteOrCreateMemberTraitAsync(
172+
handle: string,
173+
trait: UserTraits,
174+
previousTraitsData: Array<UserTrait> | undefined,
175+
): Promise<UserTraits[]> {
176+
if (!trait.traits.data.length) {
177+
if (!previousTraitsData) {
178+
return [] // no need to delete trait if trait data is null
179+
}
180+
181+
try {
182+
await deleteMemberTraitAsync(handle, trait.traitId)
183+
return []
184+
} catch (error) {
185+
}
186+
}
187+
188+
if (!previousTraitsData) {
189+
try {
190+
// call request to create trait data if trait data is null
191+
const createdTraitsRsp = await createMemberTraitsAsync(handle, [trait])
192+
return createdTraitsRsp
193+
} catch (error) {
194+
}
195+
}
196+
197+
try {
198+
// call request to update trait data if trait data is not null
199+
const updatedTraitsRsp = await updateMemberTraitsAsync(handle, [trait])
200+
return updatedTraitsRsp
201+
} catch (error) {
202+
const createdTraitsRsp = await createMemberTraitsAsync(handle, [trait])
203+
return createdTraitsRsp
204+
}
205+
}

0 commit comments

Comments
 (0)