diff --git a/web/modals/chat/toggle-pin-modal.css b/web/modals/chat/toggle-pin-modal.css --- a/web/modals/chat/toggle-pin-modal.css +++ b/web/modals/chat/toggle-pin-modal.css @@ -0,0 +1,54 @@ +.confirmationText { + color: var(--pin-message-information-text-color); + padding: 16px 32px 0 32px; + font-size: small; +} + +.messageContainer { + overflow-y: scroll; + border: 1px solid var(--pin-message-modal-border-color); + border-radius: 7px; + max-height: 400px; + margin: 16px 32px 16px 32px; +} + +.messageDate { + color: var(--chat-timestamp-color); + font-size: var(--xs-font-12); + padding: 6px 0; + line-height: var(--line-height-text); + text-align: center; +} + +.creator { + font-size: small; + color: #777777; + font-size: 14px; + padding: 4px 24px; + text-align: left; +} + +.messageContent { + padding: 0 0 6px 0; +} + +.buttonContainer { + width: 87%; + display: flex; + flex-direction: column; + align-self: center; + align-items: stretch; + margin-bottom: 16px; +} + +.cancelButton { + color: white; + display: flex; + justify-content: center; + margin-top: 16px; +} + +.cancelButton:hover { + cursor: pointer; + text-decoration: underline; +} diff --git a/web/modals/chat/toggle-pin-modal.react.js b/web/modals/chat/toggle-pin-modal.react.js --- a/web/modals/chat/toggle-pin-modal.react.js +++ b/web/modals/chat/toggle-pin-modal.react.js @@ -1,18 +1,157 @@ // @flow +import invariant from 'invariant'; import * as React from 'react'; import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js'; import type { ThreadInfo } from 'lib/types/thread-types.js'; +import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { useStringForUser } from 'lib/hooks/ens-cache.js'; +import { longAbsoluteDate } from 'lib/utils/date-utils.js'; +import type { RelativeUserInfo } from 'lib/types/user-types.js'; +import { + useServerCall, + useDispatchActionPromise, +} from 'lib/utils/action-utils.js'; +import { + toggleMessagePin, + toggleMessagePinActionTypes, +} from 'lib/actions/thread-actions.js'; + +import Button, { buttonThemes } from '../../components/button.react.js'; +import css from './toggle-pin-modal.css'; +import Modal from '../modal.react.js'; +import { useTextMessageRulesFunc } from '../../markdown/rules.react.js'; +import Message from '../../chat/message.react.js'; +import { MessageListContext } from '../../chat/message-list-types.js'; type TogglePinModalProps = { +item: ChatMessageInfoItem, +threadInfo: ThreadInfo, }; -// eslint-disable-next-line no-unused-vars function TogglePinModal(props: TogglePinModalProps): React.Node { - return <>; + const { item, threadInfo } = props; + const { messageInfo, isPinned } = item; + const { creator } = messageInfo; + const { popModal } = useModalContext(); + + const callToggleMessagePin = useServerCall(toggleMessagePin); + const dispatchActionPromise = useDispatchActionPromise(); + + const modalName = isPinned ? 'Remove Pinned Message' : 'Pin Message'; + const action = isPinned ? 'unpin' : 'pin'; + const confirmationText = isPinned + ? `Are you sure you want to remove this pinned message?` + : `You may pin this message to the channel you are currently viewing. + To unpin a message, select the pinned messages icon in the channel. `; + const buttonText = isPinned ? 'Remove Pinned Message' : 'Pin Message'; + const buttonColor = isPinned ? buttonThemes.danger : buttonThemes.standard; + + const getTextMessageMarkdownRules = useTextMessageRulesFunc(threadInfo); + const messageListContext = React.useMemo(() => { + if (!getTextMessageMarkdownRules) { + return undefined; + } + return { getTextMessageMarkdownRules }; + }, [getTextMessageMarkdownRules]); + + const creatorWithViewerFalse: RelativeUserInfo = React.useMemo(() => { + return { + ...creator, + isViewer: false, + }; + }, [creator]); + const shouldShowUsername = !item.startsConversation && !item.startsCluster; + const username = useStringForUser( + shouldShowUsername ? creatorWithViewerFalse : null, + ); + + const shouldShowDate = !item.startsConversation; + const messageDate = shouldShowDate ? ( +
+ {longAbsoluteDate(item.messageInfo.time)} +
+ ) : null; + + // ChatMessageInfoItem is a union type, and both types have different + // properties, so creating a new item by just using the ... operator + // results in Flow errors. Here, we check if the item is composable + // (the only item types that can be pinned), and if so we modify the + // creator to be 'creatorWithViewerFalse', which is the same creator except + // with the isViewer property to be false. This is so the message is + // rendered left-aligned and the creator's name is shown (per the designs). + // If the item is not composable, we just return the item as is. We + // also set the threadCreatedFromMessage property to undefined and + // the reactions property to an empty array, to remove the inline + // engagement bar from the message within the modal. + const modifiedItem = React.useMemo(() => { + if (item.messageInfoType === 'composable') { + return { + ...item, + threadCreatedFromMessage: undefined, + reactions: {}, + messageInfo: { + ...item.messageInfo, + creator: creatorWithViewerFalse, + }, + }; + } else { + return item; + } + }, [item, creatorWithViewerFalse]); + + const onClick = React.useCallback(() => { + const toggleMessagePinPromise = (async () => { + invariant(messageInfo.id, 'messageInfo.id should be defined'); + const result = await callToggleMessagePin({ + messageID: messageInfo.id, + action, + }); + return { + newMessageInfos: result.newMessageInfos, + threadID: result.threadID, + }; + })(); + + dispatchActionPromise(toggleMessagePinActionTypes, toggleMessagePinPromise); + popModal(); + }, [ + action, + callToggleMessagePin, + dispatchActionPromise, + messageInfo.id, + popModal, + ]); + + return ( + +
{confirmationText}
+
+
+ {messageDate} +
{username}
+
+ + + +
+
+
+
+ +
+ Cancel +
+
+
+ ); } export default TogglePinModal; diff --git a/web/theme.css b/web/theme.css --- a/web/theme.css +++ b/web/theme.css @@ -212,4 +212,6 @@ --topbar-button-fg: var(--shades-white-60); --message-label-color: var(--shades-black-60); --topbar-lines: rgba(255, 255, 255, 0.08); + --pin-message-information-text-color: var(--shades-white-60); + --pin-message-modal-border-color: var(--shades-black-80); } diff --git a/web/utils/tooltip-utils.js b/web/utils/tooltip-utils.js --- a/web/utils/tooltip-utils.js +++ b/web/utils/tooltip-utils.js @@ -495,6 +495,8 @@ isComposableMessageType(messageInfo.type) && threadHasPermission(threadInfo, threadPermissions.MANAGE_PINS); + const inputState = React.useContext(InputStateContext); + return React.useMemo(() => { if (!canTogglePin) { return null; @@ -505,7 +507,11 @@ const buttonContent = ; const onClickTogglePin = () => { - pushModal(); + pushModal( + + + , + ); }; return { @@ -513,7 +519,7 @@ onClick: onClickTogglePin, label: isPinned ? 'Unpin' : 'Pin', }; - }, [canTogglePin, isPinned, pushModal, item, threadInfo]); + }, [canTogglePin, inputState, isPinned, pushModal, item, threadInfo]); } function useMessageTooltipActions(