diff --git a/src/apps/profiles/src/member-profile/page-layout/ProfilePageLayout.module.scss b/src/apps/profiles/src/member-profile/page-layout/ProfilePageLayout.module.scss index 18583fd06..6df186d91 100644 --- a/src/apps/profiles/src/member-profile/page-layout/ProfilePageLayout.module.scss +++ b/src/apps/profiles/src/member-profile/page-layout/ProfilePageLayout.module.scss @@ -32,17 +32,17 @@ } .profileHeaderBottom { - height: 90px; + height: 30px; background-color: $tc-white; - - @include ltelg { - height: 30px; - } } } .profileOuter { - margin-top: 130px; + margin-top: 185px; + + @include ltelg { + margin-top: 155px; + } .profileInner { width: 100%; diff --git a/src/apps/profiles/src/member-profile/profile-header/ModifyMemberNameModal/ModifyMemberNameModal.module.scss b/src/apps/profiles/src/member-profile/profile-header/ModifyMemberNameModal/ModifyMemberNameModal.module.scss index e31ea7ff7..57d1011be 100644 --- a/src/apps/profiles/src/member-profile/profile-header/ModifyMemberNameModal/ModifyMemberNameModal.module.scss +++ b/src/apps/profiles/src/member-profile/profile-header/ModifyMemberNameModal/ModifyMemberNameModal.module.scss @@ -6,8 +6,30 @@ width: 100%; } -.nameToggle { - display: flex; - align-items: center; - justify-content: space-between; -} +.modalContent { + :global(.input-el) { + @include ltelg { + margin-bottom: $sp-4; + } + } + + .radioButtons { + display: flex; + align-items: center; + justify-content: flex-start; + margin-top: $sp-4; + + @include ltelg { + flex-direction: column; + align-items: flex-start; + } + + >div:not(:last-child) { + margin-right: $sp-8; + + @include ltelg { + margin-bottom: $sp-2; + } + } + } +} \ No newline at end of file diff --git a/src/apps/profiles/src/member-profile/profile-header/ModifyMemberNameModal/ModifyMemberNameModal.tsx b/src/apps/profiles/src/member-profile/profile-header/ModifyMemberNameModal/ModifyMemberNameModal.tsx index 2d310f705..ab3a1c435 100644 --- a/src/apps/profiles/src/member-profile/profile-header/ModifyMemberNameModal/ModifyMemberNameModal.tsx +++ b/src/apps/profiles/src/member-profile/profile-header/ModifyMemberNameModal/ModifyMemberNameModal.tsx @@ -1,4 +1,4 @@ -import { Dispatch, FC, SetStateAction, useState } from 'react' +import { Dispatch, FC, FocusEvent, SetStateAction, useState } from 'react' import { reject, trim } from 'lodash' import { toast } from 'react-toastify' @@ -11,7 +11,9 @@ import { UserTraitCategoryNames, UserTraitIds, } from '~/libs/core' -import { BaseModal, Button, FormToggleSwitch, InputText } from '~/libs/ui' +import { BaseModal, Button, InputRadio, InputText } from '~/libs/ui' + +import { NamesAndHandleAppearance } from '../ProfileHeader' import styles from './ModifyMemberNameModal.module.scss' @@ -20,7 +22,7 @@ interface ModifyMemberNameModalProps { onClose: () => void onSave: () => void memberPersonalizationTraitsData: UserTrait[] | undefined - hideMyNameInProfile: boolean + namesAndHandleAppearance: NamesAndHandleAppearance | undefined } const methodsMap: { [key: string]: any } = { @@ -47,8 +49,10 @@ const ModifyMemberNameModal: FC = (props: ModifyMemb const [currentLastName, setCurrentLastName]: [string, Dispatch>] = useState(props.profile.lastName) - const [hideMyNameInProfile, setHideMyNameInProfile]: [boolean, Dispatch>] - = useState(props.hideMyNameInProfile) + const [namesAndHandleAppearance, setNamesAndHandleAppearance]: [ + NamesAndHandleAppearance | undefined, Dispatch> + ] + = useState(props.namesAndHandleAppearance) function handleFirstNameChange(e: React.ChangeEvent): void { setCurrentFirstName(e.target.value) @@ -60,8 +64,8 @@ const ModifyMemberNameModal: FC = (props: ModifyMemb setIsFormChanged(true) } - function handleShowMyNameInProfileToggle(): void { - setHideMyNameInProfile(!hideMyNameInProfile) + function handleShowMyNameInProfileToggle(event: FocusEvent): void { + setNamesAndHandleAppearance(event.target.value as NamesAndHandleAppearance) setIsFormChanged(true) } @@ -99,9 +103,9 @@ const ModifyMemberNameModal: FC = (props: ModifyMemb data: [ ...reject( props.memberPersonalizationTraitsData, - (trait: any) => trait.hideNamesOnProfile, + (trait: any) => trait.namesAndHandleAppearance, ), - { hideNamesOnProfile: hideMyNameInProfile }, + { namesAndHandleAppearance }, ], }, }]), @@ -121,6 +125,7 @@ const ModifyMemberNameModal: FC = (props: ModifyMemb onClose={props.onClose} open title='My Name' + size='lg' buttons={(
) diff --git a/src/apps/profiles/src/member-profile/profile-header/ProfileHeader.module.scss b/src/apps/profiles/src/member-profile/profile-header/ProfileHeader.module.scss index 06539f8aa..b6ece0b27 100644 --- a/src/apps/profiles/src/member-profile/profile-header/ProfileHeader.module.scss +++ b/src/apps/profiles/src/member-profile/profile-header/ProfileHeader.module.scss @@ -19,7 +19,7 @@ @include ltelg { margin: auto; position: absolute; - bottom: -125px; + bottom: -150px; left: calc(50% - 125px); } @@ -28,7 +28,16 @@ height: 300px; border: 12px solid $tc-white; border-radius: 50%; - background-color: $tc-white; + background: linear-gradient(90deg, #075F96, #038664); + display: flex; + justify-content: center; + align-items: center; + + > span { + font-size: 100px; + line-height: 100px; + font-family: $font-barlow; + } @include ltelg { width: 250px; diff --git a/src/apps/profiles/src/member-profile/profile-header/ProfileHeader.tsx b/src/apps/profiles/src/member-profile/profile-header/ProfileHeader.tsx index 69427c4e3..30bf3e287 100644 --- a/src/apps/profiles/src/member-profile/profile-header/ProfileHeader.tsx +++ b/src/apps/profiles/src/member-profile/profile-header/ProfileHeader.tsx @@ -27,13 +27,12 @@ interface ProfileHeaderProps { refreshProfile: (handle: string) => void } -const DEFAULT_MEMBER_AVATAR: string - = 'https://d1aahxkjiobka8.cloudfront.net/static-assets/images/ab4a084a9815ebb1cf8f7b451ce4c88f.svg' +export type NamesAndHandleAppearance = 'namesOnly' | 'handleOnly' | 'namesAndHandle' const ProfileHeader: FC = (props: ProfileHeaderProps) => { const isMobile: boolean = useCheckIsMobile() - const photoURL: string = props.profile.photoURL || DEFAULT_MEMBER_AVATAR + const photoURL: string | undefined = props.profile.photoURL const hasProfilePicture = !!props.profile.photoURL const canEdit: boolean = props.authProfile?.handle === props.profile.handle @@ -59,9 +58,9 @@ const ProfileHeader: FC = (props: ProfileHeaderProps) => { (trait: UserTrait) => trait.availableForGigs, ), [memberPersonalizationTraits]) - const hideNamesOnProfile: UserTrait | undefined + const namesAndHandleAppearanceData: UserTrait | undefined = useMemo(() => memberPersonalizationTraits?.[0]?.traits?.data?.find( - (trait: UserTrait) => trait.hideNamesOnProfile, + (trait: UserTrait) => trait.namesAndHandleAppearance, ), [memberPersonalizationTraits]) useEffect(() => { @@ -135,7 +134,18 @@ const ProfileHeader: FC = (props: ProfileHeaderProps) => { function renderMemberPhotoWrap(): JSX.Element { return (
- Topcoder - Member Profile Avatar + { + photoURL ? ( + Topcoder - Member Profile Avatar + ) : ( +
+ + {props.profile.firstName[0]} + {props.profile.lastName[0]} + +
+ ) + } {canEdit && hasProfilePicture && ( = (props: ProfileHeaderProps) => {

{ - hideNamesOnProfile + namesAndHandleAppearanceData?.namesAndHandleAppearance === 'handleOnly' ? props.profile.handle : `${props.profile.firstName} ${props.profile.lastName}` } @@ -180,7 +190,7 @@ const ProfileHeader: FC = (props: ProfileHeaderProps) => {

{ - !hideNamesOnProfile ? ( + namesAndHandleAppearanceData?.namesAndHandleAppearance === 'namesAndHandle' ? ( <> {props.profile.handle} {' '} @@ -212,7 +222,7 @@ const ProfileHeader: FC = (props: ProfileHeaderProps) => { onSave={handleModifyNameModalSave} profile={props.profile} memberPersonalizationTraitsData={memberPersonalizationTraits?.[0]?.traits?.data} - hideMyNameInProfile={hideNamesOnProfile?.hideNamesOnProfile || false} + namesAndHandleAppearance={namesAndHandleAppearanceData?.namesAndHandleAppearance} /> ) } diff --git a/src/libs/ui/lib/components/form/form-groups/form-input/index.ts b/src/libs/ui/lib/components/form/form-groups/form-input/index.ts index bb617f0c3..27f9e2e7e 100644 --- a/src/libs/ui/lib/components/form/form-groups/form-input/index.ts +++ b/src/libs/ui/lib/components/form/form-groups/form-input/index.ts @@ -8,3 +8,4 @@ export * from './input-text' export * from './input-textarea' export { inputOptional, InputWrapper } from './input-wrapper' export * from './input-date-picker' +export * from './input-radio' diff --git a/src/libs/ui/lib/components/form/form-groups/form-input/input-radio/InputRadio.module.scss b/src/libs/ui/lib/components/form/form-groups/form-input/input-radio/InputRadio.module.scss new file mode 100644 index 000000000..759b160b7 --- /dev/null +++ b/src/libs/ui/lib/components/form/form-groups/form-input/input-radio/InputRadio.module.scss @@ -0,0 +1,57 @@ +@import '../../../../../styles/includes'; + +.container { + display: flex; + align-items: center; + + input[type="radio"] { + -webkit-appearance: none; + appearance: none; + /* For iOS < 15 to remove gradient background */ + background-color: #fff; + /* Not removed via appearance */ + margin: 0; + font: inherit; + color: $black-60; + width: 20px; + height: 20px; + border: 1.5px solid $black-60; + border-radius: 50%; + transform: translateY(-0.075em); + display: grid; + place-content: center; + } + + input[type="radio"]::before { + content: ""; + width: 0.65em; + height: 0.65em; + border-radius: 50%; + transform: scale(0); + transition: 120ms transform ease-in-out; + box-shadow: inset 1em 1em $turq-160; + } + + input[type="radio"]:checked::before { + transform: scale(1); + } + + &:has(input[disabled]) { + input[type="radio"] { + border-color: $black-20; + + &::before { + box-shadow: inset 1em 1em $black-20; + } + } + + label { + color: $black-60; + } + } + + label { + color: $black-100; + margin-left: $sp-2; + } +} \ No newline at end of file diff --git a/src/libs/ui/lib/components/form/form-groups/form-input/input-radio/InputRadio.tsx b/src/libs/ui/lib/components/form/form-groups/form-input/input-radio/InputRadio.tsx new file mode 100644 index 000000000..588c6eacc --- /dev/null +++ b/src/libs/ui/lib/components/form/form-groups/form-input/input-radio/InputRadio.tsx @@ -0,0 +1,34 @@ +import { FC, FocusEvent } from 'react' + +import styles from './InputRadio.module.scss' + +interface InputRadioProps { + readonly checked?: boolean + readonly disabled?: boolean + readonly name: string + readonly onChange: (event: FocusEvent) => void + readonly value: string + readonly id: string + readonly label?: string +} + +const InputRadio: FC = (props: InputRadioProps) => ( +

+ + { + props.label && ( + + ) + } +
+) + +export default InputRadio diff --git a/src/libs/ui/lib/components/form/form-groups/form-input/input-radio/index.ts b/src/libs/ui/lib/components/form/form-groups/form-input/input-radio/index.ts new file mode 100644 index 000000000..3aeaef691 --- /dev/null +++ b/src/libs/ui/lib/components/form/form-groups/form-input/input-radio/index.ts @@ -0,0 +1 @@ +export { default as InputRadio } from './InputRadio'