Page MenuHomePhabricator

D7309.diff
No OneTemporary

D7309.diff

diff --git a/web/components/message-result.css b/web/components/message-result.css
new file mode 100644
--- /dev/null
+++ b/web/components/message-result.css
@@ -0,0 +1,28 @@
+.messageContainer {
+ overflow-y: scroll;
+ border: 1px solid var(--pin-message-modal-border-color);
+ border-radius: 7px;
+ max-height: 400px;
+ margin: 16px 32px;
+}
+
+.messageDate {
+ color: var(--chat-timestamp-color);
+ font-size: var(--xs-font-12);
+ padding: 0px 0px 6px 0px;
+ line-height: var(--line-height-text);
+ text-align: left;
+ margin-left: 16px;
+}
+
+.creator {
+ font-size: small;
+ color: var(--shades-white-60);
+ font-size: var(--s-font-14);
+ padding: 4px 24px;
+ text-align: left;
+}
+
+.messageContent {
+ margin-bottom: 1px;
+}
diff --git a/web/components/message-result.react.js b/web/components/message-result.react.js
new file mode 100644
--- /dev/null
+++ b/web/components/message-result.react.js
@@ -0,0 +1,57 @@
+// @flow
+
+import * as React from 'react';
+
+import { useStringForUser } from 'lib/hooks/ens-cache.js';
+import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
+import { longAbsoluteDate } from 'lib/utils/date-utils.js';
+
+import css from './message-result.css';
+import { MessageListContext } from '../chat/message-list-types.js';
+import Message from '../chat/message.react.js';
+import { useTextMessageRulesFunc } from '../markdown/rules.react.js';
+
+type MessageResultProps = {
+ +item: ChatMessageInfoItem,
+ +threadInfo: ThreadInfo,
+};
+
+function MessageResult(props: MessageResultProps): React.Node {
+ const { item, threadInfo } = props;
+
+ const getTextMessageMarkdownRules = useTextMessageRulesFunc(threadInfo);
+ const messageListContext = React.useMemo(() => {
+ if (!getTextMessageMarkdownRules) {
+ return undefined;
+ }
+ return { getTextMessageMarkdownRules };
+ }, [getTextMessageMarkdownRules]);
+
+ const shouldShowUsername = !item.startsConversation && !item.startsCluster;
+ const username = useStringForUser(
+ shouldShowUsername ? item.messageInfo.creator : null,
+ );
+
+ return (
+ <div className={css.messageContainer}>
+ <div>
+ <div className={css.creator}>{username}</div>
+ <div className={css.messageContent}>
+ <MessageListContext.Provider value={messageListContext}>
+ <Message
+ item={item}
+ threadInfo={threadInfo}
+ key={item.messageInfo.id}
+ />
+ </MessageListContext.Provider>
+ </div>
+ <div className={css.messageDate}>
+ {longAbsoluteDate(item.messageInfo.time)}
+ </div>
+ </div>
+ </div>
+ );
+}
+
+export default MessageResult;
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,30 @@
+.confirmationText {
+ color: var(--pin-message-information-text-color);
+ padding: 16px 32px 0 32px;
+ font-size: small;
+}
+
+.buttonContainer {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ align-self: center;
+ align-items: stretch;
+ margin-bottom: 16px;
+}
+
+.togglePinButton {
+ margin: 0 32px 0 32px;
+}
+
+.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,129 @@
// @flow
+import invariant from 'invariant';
import * as React from 'react';
+import {
+ toggleMessagePin,
+ toggleMessagePinActionTypes,
+} from 'lib/actions/thread-actions.js';
+import { useModalContext } from 'lib/components/modal-provider.react.js';
import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js';
import type { ThreadInfo } from 'lib/types/thread-types.js';
+import {
+ useServerCall,
+ useDispatchActionPromise,
+} from 'lib/utils/action-utils.js';
+
+import css from './toggle-pin-modal.css';
+import Button, { buttonThemes } from '../../components/button.react.js';
+import MessageResult from '../../components/message-result.react.js';
+import Modal from '../modal.react.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 { popModal } = useModalContext();
+
+ const callToggleMessagePin = useServerCall(toggleMessagePin);
+ const dispatchActionPromise = useDispatchActionPromise();
+
+ const modalInfo = React.useMemo(() => {
+ if (isPinned) {
+ return {
+ name: 'Remove Pinned Message',
+ action: 'unpin',
+ confirmationText:
+ 'Are you sure you want to remove this pinned message?',
+ buttonText: 'Remove Pinned Message',
+ buttonColor: buttonThemes.danger,
+ };
+ }
+
+ return {
+ name: 'Pin Message',
+ action: 'pin',
+ confirmationText: `You may pin this message to the channel
+ you are currently viewing. To unpin a message, select the pinned
+ messages icon in the channel.`,
+ buttonText: 'Pin Message',
+ buttonColor: buttonThemes.standard,
+ };
+ }, [isPinned]);
+
+ // We want to remove inline engagement (threadCreatedFromMessage / reactions)
+ // and the message header (startsConversation). We also want to set isViewer
+ // to false so that the message is left-aligned and uncolored.
+ const modifiedItem = React.useMemo(() => {
+ if (item.messageInfoType !== 'composable') {
+ return item;
+ }
+
+ return {
+ ...item,
+ threadCreatedFromMessage: undefined,
+ reactions: {},
+ startsConversation: false,
+ messageInfo: {
+ ...item.messageInfo,
+ creator: {
+ ...item.messageInfo.creator,
+ isViewer: false,
+ },
+ },
+ };
+ }, [item]);
+
+ const onClick = React.useCallback(() => {
+ const createToggleMessagePinPromise = async () => {
+ invariant(messageInfo.id, 'messageInfo.id should be defined');
+ const result = await callToggleMessagePin({
+ messageID: messageInfo.id,
+ action: modalInfo.action,
+ });
+ return {
+ newMessageInfos: result.newMessageInfos,
+ threadID: result.threadID,
+ };
+ };
+
+ dispatchActionPromise(
+ toggleMessagePinActionTypes,
+ createToggleMessagePinPromise(),
+ );
+ popModal();
+ }, [
+ modalInfo,
+ callToggleMessagePin,
+ dispatchActionPromise,
+ messageInfo.id,
+ popModal,
+ ]);
+
+ return (
+ <Modal name={modalInfo.name} onClose={popModal} size="large">
+ <div className={css.confirmationText}>{modalInfo.confirmationText}</div>
+ <MessageResult item={modifiedItem} threadInfo={threadInfo} />
+ <div className={css.buttonContainer}>
+ <Button
+ variant="filled"
+ className={css.togglePinButton}
+ buttonColor={modalInfo.buttonColor}
+ onClick={onClick}
+ >
+ {modalInfo.buttonText}
+ </Button>
+ <div className={css.cancelButton} onClick={popModal}>
+ Cancel
+ </div>
+ </div>
+ </Modal>
+ );
}
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-action-utils.js b/web/utils/tooltip-action-utils.js
--- a/web/utils/tooltip-action-utils.js
+++ b/web/utils/tooltip-action-utils.js
@@ -192,6 +192,8 @@
isComposableMessageType(messageInfo.type) &&
threadHasPermission(threadInfo, threadPermissions.MANAGE_PINS);
+ const inputState = React.useContext(InputStateContext);
+
return React.useMemo(() => {
if (!canTogglePin) {
return null;
@@ -202,7 +204,11 @@
const buttonContent = <CommIcon icon={iconName} size={18} />;
const onClickTogglePin = () => {
- pushModal(<TogglePinModal item={item} threadInfo={threadInfo} />);
+ pushModal(
+ <InputStateContext.Provider value={inputState}>
+ <TogglePinModal item={item} threadInfo={threadInfo} />
+ </InputStateContext.Provider>,
+ );
};
return {
@@ -210,7 +216,7 @@
onClick: onClickTogglePin,
label: isPinned ? 'Unpin' : 'Pin',
};
- }, [canTogglePin, isPinned, pushModal, item, threadInfo]);
+ }, [canTogglePin, inputState, isPinned, pushModal, item, threadInfo]);
}
function useMessageTooltipActions(

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 25, 2:39 AM (21 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2578057
Default Alt Text
D7309.diff (8 KB)

Event Timeline