Skip to content

Commit d4b270a

Browse files
authored
Merge pull request #781 from topcoder-platform/profiles-app
MP-25 & MP-128 member locaton -> dev
2 parents c7e3700 + 9014d8e commit d4b270a

File tree

8 files changed

+221
-15
lines changed

8 files changed

+221
-15
lines changed

src/apps/accounts/src/settings/tabs/account/address/MemberAddress.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ const MemberAddress: FC<MemberAddressProps> = (props: MemberAddressProps) => {
6868
props.profile.handle,
6969
{
7070
addresses: [{
71-
city: formValues.city,
72-
stateCode: formValues.stateCode,
73-
streetAddr1: formValues.streetAddr1,
74-
streetAddr2: formValues.streetAddr2,
75-
zip: formValues.zip,
71+
city: trim(formValues.city),
72+
stateCode: trim(formValues.stateCode),
73+
streetAddr1: trim(formValues.streetAddr1),
74+
streetAddr2: trim(formValues.streetAddr2),
75+
zip: trim(formValues.zip),
7676
}],
7777
competitionCountryCode: formValues.country,
7878
homeCountryCode: formValues.country,

src/apps/profiles/src/member-profile/local-info/MemberLocalInfo.module.scss

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@
99
align-items: center;
1010
margin-bottom: $sp-2;
1111

12-
svg {
12+
> svg {
1313
margin-right: $sp-2;
1414
width: 24px;
1515
height: 24px;
1616
}
17+
18+
> button {
19+
margin-left: auto;
20+
}
1721
}
1822
}

src/apps/profiles/src/member-profile/local-info/MemberLocalInfo.tsx

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
import { FC, useMemo } from 'react'
1+
import { Dispatch, FC, SetStateAction, useMemo, useState } from 'react'
22
import cityTimezones from 'city-timezones'
33
import moment from 'moment-timezone'
44

55
import { useCountryName, UserProfile } from '~/libs/core'
66
import { IconSolid } from '~/libs/ui'
77

8+
import { EditMemberPropertyBtn } from '../../components'
9+
10+
import { ModifyLocationModal } from './ModifyLocationModal'
811
import styles from './MemberLocalInfo.module.scss'
912

1013
interface MemberLocalInfoProps {
11-
profile: UserProfile | undefined
14+
profile: UserProfile
15+
authProfile: UserProfile | undefined
16+
refreshProfile: (handle: string) => void
1217
}
1318

1419
const MemberLocalInfo: FC<MemberLocalInfoProps> = (props: MemberLocalInfoProps) => {
@@ -35,11 +40,38 @@ const MemberLocalInfo: FC<MemberLocalInfoProps> = (props: MemberLocalInfoProps)
3540
return moment.tz.zone(memberTimezone) ? memberTimezone : undefined
3641
}, [city, memberCountry])
3742

43+
const canEdit: boolean = props.authProfile?.handle === props.profile.handle
44+
45+
const [isEditMode, setIsEditMode]: [boolean, Dispatch<SetStateAction<boolean>>]
46+
= useState<boolean>(false)
47+
48+
function handleModifyLocationClick(): void {
49+
setIsEditMode(true)
50+
}
51+
52+
function handleModifyLocationModalClose(): void {
53+
setIsEditMode(false)
54+
}
55+
56+
function handleModifyLocationModalSave(): void {
57+
setTimeout(() => {
58+
setIsEditMode(false)
59+
props.refreshProfile(props.profile.handle)
60+
}, 1000)
61+
}
62+
3863
return (
3964
<div className={styles.container}>
4065
<div className={styles.localInfo}>
4166
<IconSolid.LocationMarkerIcon />
4267
{`${!!city ? `${city}, ` : ''}${memberCountry}`}
68+
{
69+
canEdit && (
70+
<EditMemberPropertyBtn
71+
onClick={handleModifyLocationClick}
72+
/>
73+
)
74+
}
4375
</div>
4476
{
4577
!!memberCityTimezone && (
@@ -53,6 +85,16 @@ const MemberLocalInfo: FC<MemberLocalInfoProps> = (props: MemberLocalInfoProps)
5385
</div>
5486
)
5587
}
88+
89+
{
90+
isEditMode && (
91+
<ModifyLocationModal
92+
onClose={handleModifyLocationModalClose}
93+
onSave={handleModifyLocationModalSave}
94+
profile={props.profile}
95+
/>
96+
)
97+
}
5698
</div>
5799
)
58100
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.modalButtons {
4+
display: flex;
5+
justify-content: space-between;
6+
width: 100%;
7+
}
8+
9+
.formError {
10+
color: $red-100;
11+
}
12+
13+
.editForm {
14+
margin-top: $sp-4;
15+
16+
:global(.input-wrapper) {
17+
margin-bottom: $sp-4;
18+
}
19+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import { Dispatch, FC, SetStateAction, useState } from 'react'
2+
import { bind, trim } from 'lodash'
3+
import { toast } from 'react-toastify'
4+
5+
import { BaseModal, Button, InputSelect, InputText } from '~/libs/ui'
6+
import {
7+
CountryLookup,
8+
updateMemberProfileAsync,
9+
useCountryLookup,
10+
UserProfile,
11+
} from '~/libs/core'
12+
13+
import styles from './ModifyLocationModal.module.scss'
14+
15+
interface ModifyLocationModalProps {
16+
onClose: () => void
17+
onSave: () => void
18+
profile: UserProfile
19+
}
20+
21+
const ModifyLocationModal: FC<ModifyLocationModalProps> = (props: ModifyLocationModalProps) => {
22+
const countryLookup: CountryLookup[] | undefined
23+
= useCountryLookup()
24+
25+
const [formValues, setFormValues]: [any, Dispatch<any>] = useState({
26+
country: props.profile.homeCountryCode || props.profile.competitionCountryCode,
27+
...props.profile.addresses ? props.profile.addresses[0] : {},
28+
})
29+
30+
const [formSaveError, setFormSaveError]: [
31+
string | undefined,
32+
Dispatch<SetStateAction<string | undefined>>
33+
] = useState<string | undefined>()
34+
35+
const [isSaving, setIsSaving]: [boolean, Dispatch<SetStateAction<boolean>>]
36+
= useState<boolean>(false)
37+
38+
const [isFormChanged, setIsFormChanged]: [boolean, Dispatch<SetStateAction<boolean>>]
39+
= useState<boolean>(false)
40+
41+
function handleFormValueChange(key: string, event: React.ChangeEvent<HTMLInputElement>): void {
42+
const oldFormValues = { ...formValues }
43+
44+
setFormValues({
45+
...oldFormValues,
46+
[key]: event.target.value,
47+
})
48+
setIsFormChanged(true)
49+
}
50+
51+
function handleLocationSave(): void {
52+
updateMemberProfileAsync(
53+
props.profile.handle,
54+
{
55+
addresses: [{
56+
...props.profile.addresses ? props.profile.addresses[0] : {},
57+
city: trim(formValues.city),
58+
}],
59+
competitionCountryCode: formValues.country,
60+
homeCountryCode: formValues.country,
61+
},
62+
)
63+
.then(() => {
64+
toast.success('Your location has been updated.', { position: toast.POSITION.BOTTOM_RIGHT })
65+
props.onSave()
66+
})
67+
.catch((error: any) => {
68+
toast.error('Something went wrong. Please try again.', { position: toast.POSITION.BOTTOM_RIGHT })
69+
setFormSaveError(error.message || error)
70+
})
71+
.finally(() => {
72+
setIsFormChanged(false)
73+
setIsSaving(false)
74+
})
75+
}
76+
77+
return (
78+
<BaseModal
79+
onClose={props.onClose}
80+
open
81+
size='lg'
82+
title='Location'
83+
buttons={(
84+
<div className={styles.modalButtons}>
85+
<Button
86+
label='Cancel'
87+
onClick={props.onClose}
88+
secondary
89+
/>
90+
<Button
91+
label='Save'
92+
onClick={handleLocationSave}
93+
primary
94+
disabled={isSaving || !isFormChanged}
95+
/>
96+
</div>
97+
)}
98+
>
99+
<p>Provide details on your location.</p>
100+
<form className={styles.editForm}>
101+
<InputText
102+
label='City'
103+
name='city'
104+
onChange={bind(handleFormValueChange, this, 'city')}
105+
value={formValues.city}
106+
tabIndex={0}
107+
type='text'
108+
placeholder='Select your city name'
109+
/>
110+
<InputSelect
111+
options={(countryLookup || []).map((cl: CountryLookup) => ({
112+
label: cl.country,
113+
value: cl.countryCode,
114+
}))}
115+
value={formValues.country}
116+
onChange={bind(handleFormValueChange, this, 'country')}
117+
name='country'
118+
label='Country *'
119+
placeholder='Select a Country'
120+
/>
121+
</form>
122+
123+
{
124+
formSaveError && (
125+
<div className={styles.formError}>
126+
{formSaveError}
127+
</div>
128+
)
129+
}
130+
131+
</BaseModal>
132+
)
133+
}
134+
135+
export default ModifyLocationModal
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as ModifyLocationModal } from './ModifyLocationModal'

src/apps/profiles/src/member-profile/page-layout/ProfilePageLayout.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ const ProfilePageLayout: FC<ProfilePageLayoutProps> = (props: ProfilePageLayoutP
6565

6666
<MemberLinks profile={props.profile} authProfile={props.authProfile} />
6767

68-
<MemberLocalInfo profile={props.profile} />
68+
<MemberLocalInfo
69+
profile={props.profile}
70+
authProfile={props.authProfile}
71+
refreshProfile={props.refreshProfile}
72+
/>
6973
</div>
7074
<div className={styles.profileInfoRight}>
7175
{

src/apps/profiles/src/member-profile/profile-header/ProfileHeader.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
UserTraitIds,
1212
UserTraits,
1313
} from '~/libs/core'
14-
import { Button } from '~/libs/ui'
1514

1615
import { EditMemberPropertyBtn } from '../../components'
1716
import { EDIT_MODE_QUERY_PARAM, profileEditModes } from '../../config'
@@ -72,9 +71,10 @@ const ProfileHeader: FC<ProfileHeaderProps> = (props: ProfileHeaderProps) => {
7271
// eslint-disable-next-line react-hooks/exhaustive-deps
7372
}, [props.authProfile])
7473

75-
function handleHireMeClick(): void {
76-
console.log('Hire Me button clicked')
77-
}
74+
// Enable this with talent search app
75+
// function handleHireMeClick(): void {
76+
// console.log('Hire Me button clicked')
77+
// }
7878

7979
function handleModifyNameClick(): void {
8080
setIsNameEditMode(true)
@@ -165,15 +165,16 @@ const ProfileHeader: FC<ProfileHeaderProps> = (props: ProfileHeaderProps) => {
165165
{canEdit ? 'I am' : `${props.profile.firstName} is`}
166166
</span>
167167
<OpenForGigs canEdit={canEdit} authProfile={props.authProfile} profile={props.profile} />
168-
{
168+
{/* Enable this with talent search app */}
169+
{/* {
169170
!canEdit && (
170171
<Button
171172
label={`Hire ${props.profile.firstName}`}
172173
primary
173174
onClick={handleHireMeClick}
174175
/>
175176
)
176-
}
177+
} */}
177178
</div>
178179
) : undefined
179180
}

0 commit comments

Comments
 (0)