forked from Expensify/App
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request Expensify#34549 from vadymbokatov/31976-report-rea…
…ction-list-migration [TS migration] Migrate 'ReportReactionList' component to TypeScript
- Loading branch information
Showing
13 changed files
with
461 additions
and
506 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import {useEffect, useRef, useState} from 'react'; | ||
import type {SyntheticEvent} from 'react'; | ||
import {Dimensions} from 'react-native'; | ||
import * as EmojiUtils from '@libs/EmojiUtils'; | ||
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; | ||
import type {BasePopoverReactionListHookProps, ReactionListAnchor, ShowReactionList} from './types'; | ||
|
||
export default function useBasePopoverReactionList({emojiName, emojiReactions, accountID, reportActionID, preferredLocale}: BasePopoverReactionListHookProps) { | ||
const [isPopoverVisible, setIsPopoverVisible] = useState(false); | ||
const [cursorRelativePosition, setCursorRelativePosition] = useState({horizontal: 0, vertical: 0}); | ||
const [popoverAnchorPosition, setPopoverAnchorPosition] = useState({horizontal: 0, vertical: 0}); | ||
const reactionListRef = useRef<ReactionListAnchor>(null); | ||
|
||
function getReactionInformation() { | ||
const selectedReaction = emojiReactions?.[emojiName]; | ||
|
||
if (!selectedReaction) { | ||
// If there is no reaction, we return default values | ||
return { | ||
emojiName: '', | ||
reactionCount: 0, | ||
emojiCodes: [], | ||
hasUserReacted: false, | ||
users: [], | ||
}; | ||
} | ||
|
||
const {emojiCodes, reactionCount, hasUserReacted, userAccountIDs} = EmojiUtils.getEmojiReactionDetails(emojiName, selectedReaction, accountID); | ||
|
||
const users = PersonalDetailsUtils.getPersonalDetailsByIDs(userAccountIDs, accountID, true); | ||
return { | ||
emojiName, | ||
emojiCodes, | ||
reactionCount, | ||
hasUserReacted, | ||
users, | ||
}; | ||
} | ||
|
||
/** | ||
* Get the BasePopoverReactionList anchor position | ||
* We calculate the achor coordinates from measureInWindow async method | ||
*/ | ||
function getReactionListMeasuredLocation(): Promise<{x: number; y: number}> { | ||
return new Promise((resolve) => { | ||
const reactionListAnchor = reactionListRef.current; | ||
if (reactionListAnchor && 'measureInWindow' in reactionListAnchor) { | ||
reactionListAnchor.measureInWindow((x, y) => resolve({x, y})); | ||
} else { | ||
resolve({x: 0, y: 0}); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Show the ReactionList modal popover. | ||
* | ||
* @param event - Object - A press event. | ||
* @param reactionListAnchor - Element - reactionListAnchor | ||
*/ | ||
const showReactionList: ShowReactionList = (event, reactionListAnchor) => { | ||
// We get the cursor coordinates and the reactionListAnchor coordinates to calculate the popover position | ||
const nativeEvent = (event as SyntheticEvent<ReactionListAnchor, MouseEvent>)?.nativeEvent || {}; | ||
reactionListRef.current = reactionListAnchor; | ||
getReactionListMeasuredLocation().then(({x, y}) => { | ||
setCursorRelativePosition({horizontal: nativeEvent.pageX - x, vertical: nativeEvent.pageY - y}); | ||
setPopoverAnchorPosition({ | ||
horizontal: nativeEvent.pageX, | ||
vertical: nativeEvent.pageY, | ||
}); | ||
setIsPopoverVisible(true); | ||
}); | ||
}; | ||
|
||
/** | ||
* Hide the ReactionList modal popover. | ||
*/ | ||
function hideReactionList() { | ||
setIsPopoverVisible(false); | ||
} | ||
|
||
useEffect(() => { | ||
const dimensionsEventListener = Dimensions.addEventListener('change', () => { | ||
if (!isPopoverVisible) { | ||
// If the popover is not visible, we don't need to update the component | ||
return; | ||
} | ||
getReactionListMeasuredLocation().then(({x, y}) => { | ||
if (!x || !y) { | ||
return; | ||
} | ||
setPopoverAnchorPosition({ | ||
horizontal: cursorRelativePosition.horizontal + x, | ||
vertical: cursorRelativePosition.vertical + y, | ||
}); | ||
}); | ||
}); | ||
|
||
return () => { | ||
dimensionsEventListener.remove(); | ||
}; | ||
}, [ | ||
isPopoverVisible, | ||
reportActionID, | ||
preferredLocale, | ||
cursorRelativePosition.horizontal, | ||
cursorRelativePosition.vertical, | ||
popoverAnchorPosition.horizontal, | ||
popoverAnchorPosition.vertical, | ||
]); | ||
|
||
useEffect(() => { | ||
if (!isPopoverVisible) { | ||
// If the popover is not visible, we don't need to update the component | ||
return; | ||
} | ||
|
||
// Hide the list when all reactions are removed | ||
const users = emojiReactions?.[emojiName]?.users; | ||
|
||
if (!users || Object.keys(users).length > 0) { | ||
return; | ||
} | ||
|
||
hideReactionList(); | ||
}, [emojiReactions, emojiName, isPopoverVisible, reportActionID, preferredLocale]); | ||
|
||
return {isPopoverVisible, cursorRelativePosition, popoverAnchorPosition, getReactionInformation, hideReactionList, reactionListRef, showReactionList}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import type {OnyxEntry} from 'react-native-onyx'; | ||
import type {LocaleContextProps} from '@components/LocaleContextProvider'; | ||
import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; | ||
import type {ReactionListAnchor, ReactionListEvent} from '@pages/home/ReportScreenContext'; | ||
import type {AnchorPosition} from '@src/styles'; | ||
import type {ReportActionReactions} from '@src/types/onyx'; | ||
|
||
type BasePopoverReactionListOnyxProps = { | ||
/** The reactions for the report action */ | ||
emojiReactions: OnyxEntry<ReportActionReactions>; | ||
}; | ||
|
||
type BasePopoverReactionListProps = { | ||
/** The ID of the report action */ | ||
reportActionID: string; | ||
|
||
/** The emoji name */ | ||
emojiName: string; | ||
}; | ||
|
||
type BasePopoverReactionListHookProps = BasePopoverReactionListProps & { | ||
/** The reactions for the report action */ | ||
emojiReactions: OnyxEntry<ReportActionReactions>; | ||
|
||
/** The current user's account ID */ | ||
accountID: WithCurrentUserPersonalDetailsProps['currentUserPersonalDetails']['accountID']; | ||
|
||
preferredLocale: LocaleContextProps['preferredLocale']; | ||
}; | ||
|
||
type BasePopoverReactionListPropsWithLocalWithOnyx = WithCurrentUserPersonalDetailsProps & BasePopoverReactionListOnyxProps & BasePopoverReactionListProps; | ||
type BasePopoverReactionListState = { | ||
/** Whether the popover is visible */ | ||
isPopoverVisible: boolean; | ||
|
||
/** The horizontal and vertical position (relative to the screen) where the popover will display. */ | ||
popoverAnchorPosition: AnchorPosition; | ||
|
||
/** The horizontal and vertical position (relative to the screen) where the cursor is. */ | ||
cursorRelativePosition: AnchorPosition; | ||
}; | ||
|
||
type ShowReactionList = (event: ReactionListEvent | undefined, reactionListAnchor: ReactionListAnchor) => void; | ||
|
||
type InnerReactionListRef = { | ||
showReactionList: ShowReactionList; | ||
hideReactionList: () => void; | ||
isActiveReportAction: (actionID: number | string) => boolean; | ||
}; | ||
|
||
export type { | ||
BasePopoverReactionListProps, | ||
BasePopoverReactionListHookProps, | ||
BasePopoverReactionListPropsWithLocalWithOnyx, | ||
BasePopoverReactionListState, | ||
BasePopoverReactionListOnyxProps, | ||
ShowReactionList, | ||
ReactionListAnchor, | ||
InnerReactionListRef, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.