Skip to content

Commit

Permalink
Merge pull request #44277 from tienifr/feature/tooltip-for-gbr
Browse files Browse the repository at this point in the history
Feature: Tooltip for GBR
  • Loading branch information
grgia authored Sep 10, 2024
2 parents e96b038 + 8883a82 commit fe4d19e
Show file tree
Hide file tree
Showing 14 changed files with 297 additions and 189 deletions.
4 changes: 4 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ const ONYXKEYS = {
/** The NVP containing all information related to educational tooltip in workspace chat */
NVP_WORKSPACE_TOOLTIP: 'workspaceTooltip',

/** Whether to hide gbr tooltip */
NVP_SHOULD_HIDE_GBR_TOOLTIP: 'nvp_should_hide_gbr_tooltip',

/** Does this user have push notifications enabled for this device? */
PUSH_NOTIFICATIONS_ENABLED: 'pushNotificationsEnabled',

Expand Down Expand Up @@ -949,6 +952,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED]: number;
[ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END]: number;
[ONYXKEYS.NVP_WORKSPACE_TOOLTIP]: OnyxTypes.WorkspaceTooltip;
[ONYXKEYS.NVP_SHOULD_HIDE_GBR_TOOLTIP]: boolean;
[ONYXKEYS.NVP_PRIVATE_CANCELLATION_DETAILS]: OnyxTypes.CancellationDetails[];
[ONYXKEYS.APPROVAL_WORKFLOW]: OnyxTypes.ApprovalWorkflowOnyx;
[ONYXKEYS.IMPORTED_SPREADSHEET]: OnyxTypes.ImportedSpreadsheet;
Expand Down
2 changes: 2 additions & 0 deletions src/components/LHNOptionsList/LHNOptionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {PersonalDetails} from '@src/types/onyx';
import OptionRowLHNData from './OptionRowLHNData';
import OptionRowRendererComponent from './OptionRowRendererComponent';
import type {LHNOptionsListProps, RenderItemProps} from './types';

const keyExtractor = (item: string) => `report_${item}`;
Expand Down Expand Up @@ -267,6 +268,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
ref={flashListRef}
indicatorStyle="white"
keyboardShouldPersistTaps="always"
CellRendererComponent={OptionRowRendererComponent}
contentContainerStyle={StyleSheet.flatten(contentContainerStyles)}
data={data}
testID="lhn-options-list"
Expand Down
388 changes: 222 additions & 166 deletions src/components/LHNOptionsList/OptionRowLHN.tsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {CellContainer} from '@shopify/flash-list';
import type {CellContainerProps} from '@shopify/flash-list/dist/native/cell-container/CellContainer';

function OptionRowRendererComponent(props: CellContainerProps) {
return (
<CellContainer
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
style={[props.style, {zIndex: -props.index}]}
/>
);
}

OptionRowRendererComponent.displayName = 'OptionRowRendererComponent';

export default OptionRowRendererComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const OptionRowRendererComponent = undefined;

export default OptionRowRendererComponent;
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import React, {memo, useEffect, useRef} from 'react';
import {InteractionManager} from 'react-native';
import React, {memo, useEffect, useRef, useState} from 'react';
import type {LayoutRectangle, NativeSyntheticEvent} from 'react-native';
import GenericTooltip from '@components/Tooltip/GenericTooltip';
import type {EducationalTooltipProps} from '@components/Tooltip/types';
import CONST from '@src/CONST';
import measureTooltipCoordinate from './measureTooltipCoordinate';

type LayoutChangeEventWithTarget = NativeSyntheticEvent<{layout: LayoutRectangle; target: HTMLElement}>;

/**
* A component used to wrap an element intended for displaying a tooltip.
* This tooltip would show immediately without user's interaction and hide after 5 seconds.
*/
function BaseEducationalTooltip({children, shouldAutoDismiss = false, ...props}: EducationalTooltipProps) {
function BaseEducationalTooltip({children, shouldAutoDismiss = false, shouldRender = true, ...props}: EducationalTooltipProps) {
const hideTooltipRef = useRef<() => void>();

const [shouldMeasure, setShouldMeasure] = useState(false);
const show = useRef<() => void>();

useEffect(
() => () => {
if (!hideTooltipRef.current) {
Expand All @@ -37,6 +39,16 @@ function BaseEducationalTooltip({children, shouldAutoDismiss = false, ...props}:
};
}, [shouldAutoDismiss]);

useEffect(() => {
if (!shouldRender || !shouldMeasure) {
return;
}
// When tooltip is used inside an animated view (e.g. popover), we need to wait for the animation to finish before measuring content.
setTimeout(() => {
show.current?.();
}, 500);
}, [shouldMeasure, shouldRender]);

return (
<GenericTooltip
shouldForceAnimate
Expand All @@ -48,22 +60,12 @@ function BaseEducationalTooltip({children, shouldAutoDismiss = false, ...props}:
hideTooltipRef.current = hideTooltip;
return React.cloneElement(children as React.ReactElement, {
onLayout: (e: LayoutChangeEventWithTarget) => {
if (!shouldMeasure) {
setShouldMeasure(true);
}
// e.target is specific to native, use e.nativeEvent.target on web instead
const target = e.target || e.nativeEvent.target;
// When tooltip is used inside an animated view (e.g. popover), we need to wait for the animation to finish before measuring content.
setTimeout(() => {
InteractionManager.runAfterInteractions(() => {
target?.measure((fx, fy, width, height, px, py) => {
updateTargetBounds({
height,
width,
x: px,
y: py,
});
showTooltip();
});
});
}, CONST.ANIMATED_TRANSITION);
show.current = () => measureTooltipCoordinate(target, updateTargetBounds, showTooltip);
},
});
}}
Expand Down
6 changes: 1 addition & 5 deletions src/components/Tooltip/EducationalTooltip/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import React from 'react';
import type {TooltipExtendedProps} from '@components/Tooltip/types';
import BaseEducationalTooltip from './BaseEducationalTooltip';

function EducationalTooltip({shouldRender = true, children, ...props}: TooltipExtendedProps) {
if (!shouldRender) {
return children;
}

function EducationalTooltip({children, ...props}: TooltipExtendedProps) {
return (
<BaseEducationalTooltip
// eslint-disable-next-line react/jsx-props-no-spreading
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type React from 'react';
import type {LayoutRectangle, NativeMethods} from 'react-native';

export default function measureTooltipCoordinate(target: React.Component & Readonly<NativeMethods>, updateTargetBounds: (rect: LayoutRectangle) => void, showTooltip: () => void) {
return target?.measure((x, y, width, height, px, py) => {
updateTargetBounds({height, width, x: px, y: py});
showTooltip();
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type React from 'react';
import type {LayoutRectangle, NativeMethods} from 'react-native';

export default function measureTooltipCoordinate(target: React.Component & Readonly<NativeMethods>, updateTargetBounds: (rect: LayoutRectangle) => void, showTooltip: () => void) {
return target?.measureInWindow((x, y, width, height) => {
updateTargetBounds({height, width, x, y});
showTooltip();
});
}
3 changes: 3 additions & 0 deletions src/components/Tooltip/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ type EducationalTooltipProps = ChildrenProps &
SharedTooltipProps & {
/** Whether to automatically dismiss the tooltip after 5 seconds */
shouldAutoDismiss?: boolean;

/** Whether the actual Tooltip should be rendered. If false, it's just going to return the children */
shouldRender?: boolean;
};

type TooltipExtendedProps = (EducationalTooltipProps | TooltipProps) & {
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@ export default {
listOfChatMessages: 'List of chat messages',
listOfChats: 'List of chats',
saveTheWorld: 'Save the world',
tooltip: 'Get started here!',
},
allSettingsScreen: {
subscription: 'Subscription',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ export default {
listOfChatMessages: 'Lista de mensajes del chat',
listOfChats: 'lista de chats',
saveTheWorld: 'Salvar el mundo',
tooltip: '¡Comienza aquí!',
},
allSettingsScreen: {
subscription: 'Suscripcion',
Expand Down
5 changes: 5 additions & 0 deletions src/libs/actions/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,10 @@ function dismissWorkspaceTooltip() {
Onyx.merge(ONYXKEYS.NVP_WORKSPACE_TOOLTIP, {shouldShow: false});
}

function dismissGBRTooltip() {
Onyx.merge(ONYXKEYS.NVP_SHOULD_HIDE_GBR_TOOLTIP, true);
}

function requestRefund() {
API.write(WRITE_COMMANDS.REQUEST_REFUND, null);
}
Expand Down Expand Up @@ -1349,4 +1353,5 @@ export {
requestValidateCodeAction,
addPendingContactMethod,
clearValidateCodeActionError,
dismissGBRTooltip,
};
1 change: 1 addition & 0 deletions src/styles/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ export default {

composerTooltipShiftHorizontal: 10,
composerTooltipShiftVertical: -10,
gbrTooltipShiftHorizontal: -20,

h20: 20,
h28: 28,
Expand Down

0 comments on commit fe4d19e

Please sign in to comment.