Changeset View
Changeset View
Standalone View
Standalone View
web/chat/message-tooltip.react.js
// @flow | // @flow | ||||
import data from '@emoji-mart/data'; | import data from '@emoji-mart/data'; | ||||
import Picker from '@emoji-mart/react'; | import Picker from '@emoji-mart/react'; | ||||
import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors'; | import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors'; | ||||
import { localIDPrefix } from 'lib/shared/message-utils'; | import { localIDPrefix } from 'lib/shared/message-utils'; | ||||
import type { ThreadInfo } from 'lib/types/thread-types'; | import type { ThreadInfo } from 'lib/types/thread-types'; | ||||
import { useSelector } from '../redux/redux-utils'; | import { useSelector } from '../redux/redux-utils'; | ||||
import { type MessageTooltipAction } from '../utils/tooltip-utils'; | import { type MessageTooltipAction } from '../utils/tooltip-utils'; | ||||
import type { TooltipSize, TooltipPositionStyle } from '../utils/tooltip-utils'; | |||||
import { | import { | ||||
tooltipButtonStyle, | tooltipButtonStyle, | ||||
tooltipLabelStyle, | tooltipLabelStyle, | ||||
tooltipStyle, | tooltipStyle, | ||||
} from './chat-constants'; | } from './chat-constants'; | ||||
import css from './message-tooltip.css'; | import css from './message-tooltip.css'; | ||||
import { useSendReaction } from './reaction-message-utils'; | import { | ||||
useSendReaction, | |||||
getEmojiKeyboardPosition, | |||||
} from './reaction-message-utils'; | |||||
import { useTooltipContext } from './tooltip-provider'; | import { useTooltipContext } from './tooltip-provider'; | ||||
type MessageTooltipProps = { | type MessageTooltipProps = { | ||||
+actions: $ReadOnlyArray<MessageTooltipAction>, | +actions: $ReadOnlyArray<MessageTooltipAction>, | ||||
+messageTimestamp: string, | +messageTimestamp: string, | ||||
+alignment?: 'left' | 'center' | 'right', | tooltipPositionStyle: TooltipPositionStyle, | ||||
+tooltipSize: TooltipSize, | |||||
+item: ChatMessageInfoItem, | +item: ChatMessageInfoItem, | ||||
+threadInfo: ThreadInfo, | +threadInfo: ThreadInfo, | ||||
}; | }; | ||||
function MessageTooltip(props: MessageTooltipProps): React.Node { | function MessageTooltip(props: MessageTooltipProps): React.Node { | ||||
const { | const { | ||||
actions, | actions, | ||||
messageTimestamp, | messageTimestamp, | ||||
alignment = 'left', | tooltipPositionStyle, | ||||
tooltipSize, | |||||
item, | item, | ||||
threadInfo, | threadInfo, | ||||
} = props; | } = props; | ||||
const { messageInfo, reactions } = item; | const { messageInfo, reactions } = item; | ||||
const { alignment = 'left' } = tooltipPositionStyle; | |||||
const [activeTooltipLabel, setActiveTooltipLabel] = React.useState<?string>(); | const [activeTooltipLabel, setActiveTooltipLabel] = React.useState<?string>(); | ||||
const { renderEmojiKeyboard } = useTooltipContext(); | const { renderEmojiKeyboard } = useTooltipContext(); | ||||
const messageActionButtonsContainerClassName = classNames( | const messageActionButtonsContainerClassName = classNames( | ||||
css.messageActionContainer, | css.messageActionContainer, | ||||
css.messageActionButtons, | css.messageActionButtons, | ||||
); | ); | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | const tooltipTimestamp = React.useMemo(() => { | ||||
} | } | ||||
return ( | return ( | ||||
<div className={css.messageTooltipLabel} style={messageTooltipLabelStyle}> | <div className={css.messageTooltipLabel} style={messageTooltipLabelStyle}> | ||||
{messageTimestamp} | {messageTimestamp} | ||||
</div> | </div> | ||||
); | ); | ||||
}, [messageTimestamp, messageTooltipLabelStyle]); | }, [messageTimestamp, messageTooltipLabelStyle]); | ||||
const emojiKeyboardPosition = React.useMemo( | |||||
() => getEmojiKeyboardPosition(tooltipPositionStyle, tooltipSize), | |||||
[tooltipPositionStyle, tooltipSize], | |||||
); | |||||
const emojiKeyboardPositionStyle = React.useMemo( | |||||
() => ({ | |||||
bottom: emojiKeyboardPosition.bottom, | |||||
left: emojiKeyboardPosition.left, | |||||
}), | |||||
[emojiKeyboardPosition], | |||||
tomek: Usually it's a good idea to include only the necessary values in dependency array. In this case… | |||||
); | |||||
const nextLocalID = useSelector(state => state.nextLocalID); | const nextLocalID = useSelector(state => state.nextLocalID); | ||||
const localID = `${localIDPrefix}${nextLocalID}`; | const localID = `${localIDPrefix}${nextLocalID}`; | ||||
const sendReaction = useSendReaction(messageInfo.id, localID, threadInfo.id); | const sendReaction = useSendReaction(messageInfo.id, localID, threadInfo.id); | ||||
const onEmojiSelect = React.useCallback( | const onEmojiSelect = React.useCallback( | ||||
emoji => { | emoji => { | ||||
const reactionInput = emoji.native; | const reactionInput = emoji.native; | ||||
const viewerReacted = !!reactions.get(reactionInput)?.viewerReacted; | const viewerReacted = !!reactions.get(reactionInput)?.viewerReacted; | ||||
const action = viewerReacted ? 'remove_reaction' : 'add_reaction'; | const action = viewerReacted ? 'remove_reaction' : 'add_reaction'; | ||||
sendReaction(reactionInput, action); | sendReaction(reactionInput, action); | ||||
}, | }, | ||||
[sendReaction, reactions], | [sendReaction, reactions], | ||||
); | ); | ||||
const emojiKeyboard = React.useMemo(() => { | const emojiKeyboard = React.useMemo(() => { | ||||
if (!renderEmojiKeyboard) { | if (!renderEmojiKeyboard) { | ||||
return null; | return null; | ||||
} | } | ||||
return <Picker data={data} onEmojiSelect={onEmojiSelect} />; | |||||
}, [onEmojiSelect, renderEmojiKeyboard]); | |||||
const messageTooltipContainerStyle = React.useMemo(() => tooltipStyle, []); | return ( | ||||
<div style={emojiKeyboardPositionStyle} className={css.emojiKeyboard}> | |||||
<Picker data={data} onEmojiSelect={onEmojiSelect} /> | |||||
</div> | |||||
); | |||||
}, [emojiKeyboardPositionStyle, onEmojiSelect, renderEmojiKeyboard]); | |||||
const containerClassName = classNames({ | const messageTooltipContainerStyle = React.useMemo(() => tooltipStyle, []); | ||||
tomekUnsubmitted Not Done Inline ActionsWhat's the point of this? tomek: What's the point of this? | |||||
ginsuAuthorUnsubmitted Done Inline ActionsJust thought messageTooltipContainerStyle was a better variable name, but I will switch it back ginsu: Just thought `messageTooltipContainerStyle` was a better variable name, but I will switch it… | |||||
[css.container]: true, | |||||
[css.containerLeftAlign]: alignment === 'left', | |||||
[css.containerCenterAlign]: alignment === 'center', | |||||
}); | |||||
const messageTooltipContainerClassNames = classNames({ | const messageTooltipContainerClassNames = classNames({ | ||||
[css.messageTooltipContainer]: true, | [css.messageTooltipContainer]: true, | ||||
[css.leftTooltipAlign]: alignment === 'left', | [css.leftTooltipAlign]: alignment === 'left', | ||||
[css.centerTooltipAlign]: alignment === 'center', | [css.centerTooltipAlign]: alignment === 'center', | ||||
[css.rightTooltipAlign]: alignment === 'right', | [css.rightTooltipAlign]: alignment === 'right', | ||||
}); | }); | ||||
return ( | return ( | ||||
<div className={containerClassName}> | <div> | ||||
{emojiKeyboard} | {emojiKeyboard} | ||||
<div | <div | ||||
className={messageTooltipContainerClassNames} | className={messageTooltipContainerClassNames} | ||||
style={messageTooltipContainerStyle} | style={messageTooltipContainerStyle} | ||||
> | > | ||||
<div style={messageTooltipTopLabelStyle}>{tooltipLabel}</div> | <div style={messageTooltipTopLabelStyle}>{tooltipLabel}</div> | ||||
{tooltipButtons} | {tooltipButtons} | ||||
{tooltipTimestamp} | {tooltipTimestamp} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
); | ); | ||||
} | } | ||||
export default MessageTooltip; | export default MessageTooltip; |
Usually it's a good idea to include only the necessary values in dependency array. In this case, we don't have to depend on the whole emojiKeyboardPosition value.