-
Notifications
You must be signed in to change notification settings - Fork 20
[PROD RELEASE] - Bug fixes #1484
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d0943c4
f4d99c6
b19e2c8
cbefdb4
0eb6a6e
929c56e
0d80754
da831ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -81,6 +81,13 @@ export const TeamCalendar: FC<TeamCalendarProps> = (props: TeamCalendarProps) => | |
| [isMobile], | ||
| ) | ||
|
|
||
| const handleMoreClick = useCallback((e: React.MouseEvent<HTMLButtonElement>) => { | ||
| if (isMobile) return // hover only matters on desktop | ||
| const dateKey = e.currentTarget.dataset.dateKey | ||
| if (!dateKey) return | ||
| setOpenDateKey(dateKey) | ||
| }, [isMobile]) | ||
|
|
||
| const monthDates = useMemo( | ||
| () => getMonthDates(currentDate.getFullYear(), currentDate.getMonth()), | ||
| [currentDate], | ||
|
|
@@ -132,7 +139,7 @@ export const TeamCalendar: FC<TeamCalendarProps> = (props: TeamCalendarProps) => | |
| const leaveEntry = teamLeaveDates.find(item => item.date === dateKey) | ||
| const users = leaveEntry?.usersOnLeave ?? [] | ||
| const sortedUsers = [...users].sort(compareUsersByName) | ||
| const displayedUsers = sortedUsers.slice(0, 10) | ||
| const displayedUsers = sortedUsers.slice(0, 2) | ||
| const overflowCount = sortedUsers.length - displayedUsers.length | ||
| const weekendClass = isWeekend(date) ? styles.weekend : undefined | ||
|
|
||
|
|
@@ -191,7 +198,16 @@ export const TeamCalendar: FC<TeamCalendarProps> = (props: TeamCalendarProps) => | |
| })} | ||
| {overflowCount > 0 && ( | ||
| <div className={styles.overflowIndicator}> | ||
| {`+${overflowCount} more`} | ||
| <button | ||
| type='button' | ||
| className={styles.moreButton} | ||
| data-date-key={dateKey} | ||
| onClick={handleMoreClick} | ||
| aria-haspopup='dialog' | ||
| aria-label={`Show ${overflowCount} more for ${dateKey}`} | ||
| > | ||
| {`+${overflowCount} more`} | ||
| </button> | ||
| </div> | ||
| )} | ||
| </div> | ||
|
|
@@ -202,7 +218,7 @@ export const TeamCalendar: FC<TeamCalendarProps> = (props: TeamCalendarProps) => | |
| })} | ||
| </div> | ||
|
|
||
| {isMobile && openDateKey && (() => { | ||
| {openDateKey && (() => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| const selectedDate = paddedDates.find(d => d && getDateKey(d) === openDateKey) | ||
| if (!selectedDate) return undefined | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import remarkFrontmatter from 'remark-frontmatter' | |
| import remarkGfm from 'remark-gfm' | ||
|
|
||
| import { Button, IconSolid } from '~/libs/ui' | ||
| import { EnvironmentConfig } from '~/config' | ||
|
|
||
| import type { Engagement, EngagementAssignment } from '../../lib/models' | ||
| import { formatDate, formatLocation, truncateText } from '../../lib/utils' | ||
|
|
@@ -58,6 +59,8 @@ interface AssignmentCardProps { | |
| onRejectOffer?: () => void | ||
| onContactTalentManager: (contactEmail?: string) => void | ||
| canContactTalentManager?: boolean | ||
| profileGateError?: string | ||
| profileHandle?: string | ||
| } | ||
|
|
||
| const DESCRIPTION_MAX_LENGTH = 160 | ||
|
|
@@ -154,6 +157,42 @@ const AssignmentCard: FC<AssignmentCardProps> = (props: AssignmentCardProps) => | |
| const showAssignedActions = assignmentStatus === 'assigned' | ||
| const showOfferActions = assignmentStatus === 'selected' | ||
|
|
||
| const renderOfferActions = ( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| profileGateError?: string, | ||
| onAcceptOffer?: () => void, | ||
| onRejectOffer?: () => void, | ||
| actionButtonClass?: string, | ||
| ): JSX.Element | undefined => { | ||
| if ( | ||
| profileGateError | ||
| || !showOfferActions | ||
| || !onAcceptOffer | ||
| || !onRejectOffer | ||
| ) { | ||
| return undefined | ||
| } | ||
|
|
||
| return ( | ||
| <> | ||
| <Button | ||
| label='Accept Offer' | ||
| onClick={onAcceptOffer} | ||
| primary | ||
| textWrap | ||
| className={actionButtonClass} | ||
| /> | ||
| <Button | ||
| label='Reject Offer' | ||
| onClick={onRejectOffer} | ||
| secondary | ||
| variant='danger' | ||
| textWrap | ||
| className={actionButtonClass} | ||
| /> | ||
| </> | ||
| ) | ||
| } | ||
|
|
||
| return ( | ||
| <div className={styles.card}> | ||
| <div className={styles.header}> | ||
|
|
@@ -205,6 +244,21 @@ const AssignmentCard: FC<AssignmentCardProps> = (props: AssignmentCardProps) => | |
| <span className={styles.moreSkills}>{`+${extraSkillsCount} more`}</span> | ||
| )} | ||
| </div> | ||
| <div> | ||
| { props.profileGateError && ( | ||
| <div className={styles.applyMessage}> | ||
| <span className={styles.termsError}> | ||
| {props.profileGateError} | ||
| </span> | ||
| <a | ||
| className={styles.signInLink} | ||
| href={`${EnvironmentConfig.URLS.USER_PROFILE}/${props.profileHandle}`} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| > | ||
| Please update your profile here. | ||
| </a> | ||
| </div> | ||
| )} | ||
| </div> | ||
| <div className={styles.actions}> | ||
| {showAssignedActions && ( | ||
| <> | ||
|
|
@@ -224,24 +278,11 @@ const AssignmentCard: FC<AssignmentCardProps> = (props: AssignmentCardProps) => | |
| /> | ||
| </> | ||
| )} | ||
| {showOfferActions && props.onAcceptOffer && props.onRejectOffer && ( | ||
| <> | ||
| <Button | ||
| label='Accept Offer' | ||
| onClick={props.onAcceptOffer} | ||
| primary | ||
| textWrap | ||
| className={styles.actionButton} | ||
| /> | ||
| <Button | ||
| label='Reject Offer' | ||
| onClick={props.onRejectOffer} | ||
| secondary | ||
| variant='danger' | ||
| textWrap | ||
| className={styles.actionButton} | ||
| /> | ||
| </> | ||
| {renderOfferActions( | ||
| props.profileGateError, | ||
| props.onAcceptOffer, | ||
| props.onRejectOffer, | ||
| styles.actionButton, | ||
| )} | ||
| <Button | ||
| label='Contact Talent Manager' | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom' | |
| import { toast } from 'react-toastify' | ||
|
|
||
| import { EnvironmentConfig } from '~/config' | ||
| import { useProfileContext } from '~/libs/core' | ||
| import { useProfileCompleteness, useProfileContext } from '~/libs/core' | ||
| import { Button, ContentLayout, IconOutline, LoadingSpinner } from '~/libs/ui' | ||
| import { Pagination } from '~/apps/admin/src/lib/components/common/Pagination' | ||
|
|
||
|
|
@@ -76,6 +76,9 @@ const MyAssignmentsPage: FC = () => { | |
| const profileContext = useProfileContext() | ||
| const isLoggedIn = profileContext.isLoggedIn | ||
| const userId = profileContext.profile?.userId | ||
| const profileHandle = profileContext.profile?.handle | ||
| const profileCompleteness = useProfileCompleteness(profileHandle) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| const [profileGateError, setProfileGateError] = useState<string | undefined>() | ||
|
|
||
| const [assignments, setAssignments] = useState<Engagement[]>([]) | ||
| const [loading, setLoading] = useState<boolean>(false) | ||
|
|
@@ -333,6 +336,23 @@ const MyAssignmentsPage: FC = () => { | |
| } | ||
|
|
||
| const handleAcceptOfferClick = function (): void { | ||
| setProfileGateError(undefined) | ||
|
|
||
| if (profileCompleteness?.isLoading) { | ||
| return | ||
| } | ||
|
|
||
| if ( | ||
| profileCompleteness | ||
| && typeof profileCompleteness.percent === 'number' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| && profileCompleteness.percent < 100 | ||
| ) { | ||
| setProfileGateError( | ||
| 'Your profile must be 100% complete before applying.', | ||
| ) | ||
| return | ||
| } | ||
|
|
||
| handleOpenOfferModal(engagement, 'accept') | ||
| } | ||
|
|
||
|
|
@@ -352,6 +372,8 @@ const MyAssignmentsPage: FC = () => { | |
| onRejectOffer={handleRejectOfferClick} | ||
| onContactTalentManager={handleContactTalentManager} | ||
| canContactTalentManager={Boolean(contactEmail)} | ||
| profileGateError={profileGateError} | ||
| profileHandle={profileHandle} | ||
| /> | ||
| ) | ||
| })} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| import { useNavigate } from 'react-router-dom' | ||
| import { FC, MutableRefObject, useEffect, useRef, useState } from 'react' | ||
| import { Dispatch, FC, MutableRefObject, SetStateAction, useEffect, useRef, useState } from 'react' | ||
| import { connect } from 'react-redux' | ||
| import { toast } from 'react-toastify' | ||
| import classNames from 'classnames' | ||
|
|
@@ -12,7 +12,8 @@ import { updateOrCreateMemberTraitsAsync, | |
| UserTraitIds, | ||
| UserTraits } from '~/libs/core' | ||
| import { OpenToWorkData } from '~/libs/shared/lib/components/modify-open-to-work-modal' | ||
| import OpenToWorkForm from '~/libs/shared/lib/components/modify-open-to-work-modal/ModifyOpenToWorkModal' | ||
| import OpenToWorkForm, | ||
| { validateOpenToWork } from '~/libs/shared/lib/components/modify-open-to-work-modal/ModifyOpenToWorkModal' | ||
|
|
||
| import { ProgressBar } from '../../components/progress-bar' | ||
| import { updateMemberOpenForWork, updatePersonalizations } from '../../redux/actions/member' | ||
|
|
@@ -46,6 +47,14 @@ export const PageOpenToWorkContent: FC<PageOpenToWorkContentProps> = props => { | |
| preferredRoles: [], | ||
| }) | ||
|
|
||
| const [submitAttempted, setSubmitAttempted] = useState(false) | ||
|
|
||
| const [formErrors, setFormErrors]: [ | ||
| { [key: string]: string }, | ||
| Dispatch<SetStateAction<{ [key: string]: string }>> | ||
| ] | ||
| = useState<{ [key: string]: string }>({}) | ||
|
|
||
| useEffect(() => { | ||
| if (!memberPersonalizationTraits) return | ||
|
|
||
|
|
@@ -61,6 +70,14 @@ export const PageOpenToWorkContent: FC<PageOpenToWorkContentProps> = props => { | |
| })) | ||
| }, [memberPersonalizationTraits, props.availableForGigs]) | ||
|
|
||
| function handleFormChange(nextValue: OpenToWorkData): void { | ||
| setFormValue(nextValue) | ||
|
|
||
| if (submitAttempted) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| setFormErrors(validateOpenToWork(nextValue)) | ||
| } | ||
| } | ||
|
|
||
| useEffect(() => { | ||
| if (!loading && !shouldSavingData.current && !!shouldNavigateTo.current) { | ||
| navigate(shouldNavigateTo.current) | ||
|
|
@@ -73,6 +90,16 @@ export const PageOpenToWorkContent: FC<PageOpenToWorkContentProps> = props => { | |
| } | ||
|
|
||
| async function goToNextStep(): Promise<void> { | ||
| setSubmitAttempted(true) | ||
|
|
||
| const errors = validateOpenToWork(formValue) | ||
| setFormErrors(errors) | ||
|
|
||
| if (Object.keys(errors).length > 0) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| // Don't move to next step | ||
| return | ||
| } | ||
|
|
||
| setLoading(true) | ||
|
|
||
| const existing = memberPersonalizationTraits?.[0]?.traits?.data?.[0] || {} | ||
|
|
@@ -118,6 +145,14 @@ export const PageOpenToWorkContent: FC<PageOpenToWorkContentProps> = props => { | |
| } | ||
| } | ||
|
|
||
| // reset error when open to work toggle off | ||
| useEffect(() => { | ||
| if (!formValue.availableForGigs) { | ||
| setFormErrors({}) | ||
| setSubmitAttempted(false) | ||
| } | ||
| }, [formValue.availableForGigs]) | ||
|
|
||
| return ( | ||
| <div className={classNames('d-flex flex-column', styles.container)}> | ||
| <h2> | ||
|
|
@@ -136,8 +171,10 @@ export const PageOpenToWorkContent: FC<PageOpenToWorkContentProps> = props => { | |
| <div className='mt-26'> | ||
| <OpenToWorkForm | ||
| value={formValue} | ||
| onChange={setFormValue} | ||
| onChange={handleFormChange} | ||
| disabled={loading} | ||
| formErrors={formErrors} | ||
| showErrors={submitAttempted} | ||
| /> | ||
| </div> | ||
| </div> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[⚠️
design]Reducing the number of displayed users from 10 to 2 might significantly change the user experience. Ensure that this change is intentional and aligns with the design requirements.