-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Fix tooltip for QAB doesn't show for new user #52446
Fix tooltip for QAB doesn't show for new user #52446
Conversation
@rayane-djouah Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
I use a different approach since the previous one fails to close the tooltip automatically. The new solution is similar to actions/Modal.ts Lines 13 to 24 in 7256ad6
There are 2 cases we need to handle for tooltip.
So, TooltipManager holds all the pending and active tooltip. When a modal will show, we cancel them all. |
@@ -86,6 +87,9 @@ function setDisableDismissOnEscape(disableDismissOnEscape: boolean) { | |||
* isPopover indicates that the next open modal is popover or bottom docked | |||
*/ | |||
function willAlertModalBecomeVisible(isVisible: boolean, isPopover = false) { | |||
if (isVisible) { | |||
TooltipManager.cancelPendingAndActiveTooltips(); | |||
} |
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.
We only cancel it in willAlertModalBecomeVisible
and not in setModalVisibility
because setModalVisibility
is called when the modal is shown, not when the modal will show.
App/src/components/Modal/BaseModal.tsx
Lines 102 to 109 in 7256ad6
useEffect(() => { | |
isVisibleRef.current = isVisible; | |
let removeOnCloseListener: () => void; | |
if (isVisible) { | |
Modal.willAlertModalBecomeVisible(true, type === CONST.MODAL.MODAL_TYPE.POPOVER || type === CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED); | |
// To handle closing any modal already visible when this modal is mounted, i.e. PopoverReportActionContextMenu | |
removeOnCloseListener = Modal.setCloseModal(onClose); | |
} |
App/src/components/Modal/BaseModal.tsx
Lines 131 to 136 in 7256ad6
const handleShowModal = () => { | |
if (shouldSetModalVisibility) { | |
Modal.setModalVisibility(true); | |
} | |
onModalShow(); | |
}; |
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.
Could you please add a comment in the code for this?
@@ -202,6 +203,7 @@ const RootStack = createCustomStackNavigator<AuthScreensParamList>(); | |||
|
|||
const modalScreenListeners = { | |||
focus: () => { | |||
TooltipManager.cancelPendingAndActiveTooltips(); | |||
Modal.setModalVisibility(true); | |||
}, |
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.
And because the RHP modal uses setModalVisbility
, we need to manually cancel it here.
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.
Could you please add a comment in the code for this?
Reviewer Checklist
Screenshots/VideosAndroid: NativeScreen.Recording.2024-11-23.at.12.52.34.PM.movAndroid: mWeb ChromeScreen.Recording.2024-11-23.at.12.46.48.PM.moviOS: NativeSimulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2024-11-23.at.12.44.50.mp4iOS: mWeb SafariSimulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2024-11-23.at.12.46.14.mp4MacOS: Chrome / SafariScreen.Recording.2024-11-23.at.12.37.12.PM.movMacOS: DesktopScreen.Recording.2024-11-23.at.12.35.55.PM.mov |
const pendingTooltip: NodeJS.Timeout[] = []; | ||
const tooltipCloseCallback: Array<() => void> = []; |
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.
const pendingTooltip: NodeJS.Timeout[] = []; | |
const tooltipCloseCallback: Array<() => void> = []; | |
const pendingTooltips = new Set<NodeJS.Timeout>(); | |
const activeTooltips = new Set<() => void>(); |
pendingTooltip.push(timeout); | ||
return () => { | ||
const index = pendingTooltip.indexOf(timeout); | ||
pendingTooltip.splice(index, 1); | ||
}; |
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.
pendingTooltip.push(timeout); | |
return () => { | |
const index = pendingTooltip.indexOf(timeout); | |
pendingTooltip.splice(index, 1); | |
}; | |
pendingTooltips.add(timeout); | |
return () => { | |
pendingTooltips.delete(timeout); | |
}; |
tooltipCloseCallback.push(closeCallback); | ||
return () => { | ||
const index = tooltipCloseCallback.indexOf(closeCallback); | ||
tooltipCloseCallback.splice(index, 1); | ||
}; |
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.
tooltipCloseCallback.push(closeCallback); | |
return () => { | |
const index = tooltipCloseCallback.indexOf(closeCallback); | |
tooltipCloseCallback.splice(index, 1); | |
}; | |
activeTooltips.add(closeCallback); | |
return () => { | |
activeTooltips.delete(closeCallback); | |
}; |
while (pendingTooltip.length > 0) { | ||
clearTimeout(pendingTooltip.pop()); | ||
} | ||
while (tooltipCloseCallback.length > 0) { | ||
tooltipCloseCallback.pop()?.(); | ||
} |
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.
while (pendingTooltip.length > 0) { | |
clearTimeout(pendingTooltip.pop()); | |
} | |
while (tooltipCloseCallback.length > 0) { | |
tooltipCloseCallback.pop()?.(); | |
} | |
pendingTooltips.forEach((timeout) => clearTimeout(timeout)); | |
pendingTooltips.clear(); | |
activeTooltips.forEach((closeCallback) => closeCallback()); | |
activeTooltips.clear(); |
}; | ||
}, [shouldRender]); | ||
const removeActiveTooltipRef = useRef(() => {}); | ||
const removePendingToltipRef = useRef(() => {}); |
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.
const removePendingToltipRef = useRef(() => {}); | |
const removePendingTooltipRef = useRef(() => {}); |
const pendingTooltip: NodeJS.Timeout[] = []; | ||
const tooltipCloseCallback: Array<() => void> = []; |
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.
const pendingTooltip: NodeJS.Timeout[] = []; | |
const tooltipCloseCallback: Array<() => void> = []; | |
// We store the timeouts for each pending tooltip here. We're using the timeout because when a tooltip is used inside an animated view (e.g., popover), we need to wait for the animation to finish before measuring content. | |
const pendingTooltipsTimouts: NodeJS.Timeout[] = []; | |
// We store the callback for closing a tooltip here. | |
const closeActiveTooltipCallbacks: Array<() => void> = []; |
Addressed all |
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.
LGTM and tests well 👍
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.
Small suggestion
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by https://github.com/pecanoro in version: 9.0.67-0 🚀
|
🚀 Deployed to production by https://github.com/mountiny in version: 9.0.67-9 🚀
|
Explanation of Change
We previously prevent the tooltip to show in a modal. In this PR, we hide the tooltip when a modal will show.
Fixed Issues
$ #51987
PROPOSAL: #51987 (comment)
Tests
Same as QA Steps
Offline tests
Same as QA Steps
QA Steps
// TODO: These must be filled out, or the issue title must include "[No QA]."
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)src/languages/*
files and using the translation methodSTYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)Design
label and/or tagged@Expensify/design
so the design team can review the changes.ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Android: Native
android.mp4
Android: mWeb Chrome
android.mweb.mp4
iOS: Native
ios.mp4
iOS: mWeb Safari
ios.mweb.mp4
MacOS: Chrome / Safari
web.mp4
MacOS: Desktop
desktop.mp4