Skip to content

Commit 200a5ed

Browse files
committed
fix: show composition & call button disabled when blocked
also offer to unblock on composition box clicks
1 parent f530ac4 commit 200a5ed

File tree

8 files changed

+81
-19
lines changed

8 files changed

+81
-19
lines changed

stylesheets/_session_conversation.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
}
9393

9494
.composition-container {
95+
position: relative;
9596
display: flex;
9697
justify-content: center;
9798
align-items: center;

ts/components/conversation/composition/CompositionBox.tsx

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import {
2323
getIsSelectedBlocked,
2424
getSelectedCanWrite,
2525
getSelectedConversationKey,
26+
useSelectedConversationKey,
27+
useSelectedIsBlocked,
2628
} from '../../../state/selectors/selectedConversation';
2729
import { AttachmentType } from '../../../types/Attachment';
2830
import { processNewAttachment } from '../../../types/MessageAttachment';
@@ -53,6 +55,7 @@ import { CompositionTextArea } from './CompositionTextArea';
5355
import { cleanMentions, mentionsRegex } from './UserMentions';
5456
import { HTMLDirection } from '../../../util/i18n/rtlSupport';
5557
import type { FixedBaseEmoji } from '../../../types/Reaction';
58+
import { useShowBlockUnblock } from '../../menuAndSettingsHooks/useShowBlockUnblock';
5659

5760
export interface ReplyingToMessageProps {
5861
convoId: string;
@@ -299,6 +302,7 @@ class CompositionBoxInner extends Component<Props, State> {
299302
{this.renderAttachmentsStaged()}
300303
<div className="composition-container">
301304
{showRecordingView ? this.renderRecordingView() : this.renderCompositionView()}
305+
<BlockedOverlayOnCompositionBox />
302306
</div>
303307
</Flex>
304308
);
@@ -397,7 +401,8 @@ class CompositionBoxInner extends Component<Props, State> {
397401

398402
// we completely hide the composition box when typing is not enabled now.
399403
// Actually not anymore. We want the above, except when we can't write because that user is blocked.
400-
// When that user is blocked, **and only then**, we want to show the composition box, disabled with the placeholder "unblock to send".
404+
// When that user is blocked, **and only then**, we want to show the composition box, disabled with the placeholder "unblock to send", and the buttons disabled.
405+
// A click on the composition box should bring the "unblock user" dialog.
401406
if (!typingEnabled && !isBlocked) {
402407
return null;
403408
}
@@ -410,7 +415,9 @@ class CompositionBoxInner extends Component<Props, State> {
410415
$alignItems={'center'}
411416
width={'100%'}
412417
>
413-
{typingEnabled && <AddStagedAttachmentButton onClick={this.onChooseAttachment} />}
418+
{typingEnabled || isBlocked ? (
419+
<AddStagedAttachmentButton onClick={this.onChooseAttachment} />
420+
) : null}
414421
<input
415422
className="hidden"
416423
placeholder="Attachment"
@@ -419,7 +426,9 @@ class CompositionBoxInner extends Component<Props, State> {
419426
type="file"
420427
onChange={this.onChoseAttachment}
421428
/>
422-
{typingEnabled && <StartRecordingButton onClick={this.onLoadVoiceNoteView} />}
429+
{typingEnabled || isBlocked ? (
430+
<StartRecordingButton onClick={this.onLoadVoiceNoteView} />
431+
) : null}
423432
<StyledSendMessageInput
424433
role="main"
425434
dir={this.props.htmlDirection}
@@ -948,3 +957,36 @@ const mapStateToProps = (state: StateType) => {
948957
const smart = connect(mapStateToProps);
949958

950959
export const CompositionBox = smart(CompositionBoxInner);
960+
961+
const StyledBlockedOverlayOnCompositionBox = styled.div`
962+
position: absolute;
963+
top: 0;
964+
left: 0;
965+
right: 0;
966+
bottom: 0;
967+
z-index: 2;
968+
background-color: transparent;
969+
cursor: pointer;
970+
`;
971+
972+
/**
973+
* Note: This component is to be removed once we get the updated composition box PR merged.
974+
* It is only used to hijack the clicks on the composition box and display the "unblock user dialog",
975+
* when that user is currently blocked.
976+
* The reason it was easier to do it this way is because the buttons of the composition box do not react
977+
* to click events when they are disabled.
978+
*
979+
* Note2: Actually having this component offer the unblock user dialog on click right away is convenient as a UX.
980+
* Maybe we should keep it?
981+
*/
982+
function BlockedOverlayOnCompositionBox() {
983+
const selectedConvoKey = useSelectedConversationKey();
984+
const isBlocked = useSelectedIsBlocked();
985+
const blockUnblockCb = useShowBlockUnblock(selectedConvoKey);
986+
987+
if (!isBlocked) {
988+
return null;
989+
}
990+
991+
return <StyledBlockedOverlayOnCompositionBox onClick={blockUnblockCb?.cb} />;
992+
}

ts/components/conversation/composition/CompositionButtons.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { forwardRef } from 'react';
22
import styled from 'styled-components';
33
import { useIsOutgoingRequest } from '../../../hooks/useParamSelector';
4-
import { useSelectedConversationKey } from '../../../state/selectors/selectedConversation';
4+
import {
5+
useSelectedConversationKey,
6+
useSelectedIsBlocked,
7+
} from '../../../state/selectors/selectedConversation';
58
import { SessionIconButton } from '../../icon';
69

710
const StyledChatButtonContainer = styled.div<{ disabled?: boolean }>`
@@ -22,8 +25,11 @@ export const AddStagedAttachmentButton = (props: { onClick: () => void }) => {
2225
const selectedConvoKey = useSelectedConversationKey();
2326
const isOutgoingRequest = useIsOutgoingRequest(selectedConvoKey);
2427

28+
const isBlocked = useSelectedIsBlocked();
29+
const disabled = isOutgoingRequest || isBlocked;
30+
2531
return (
26-
<StyledChatButtonContainer disabled={isOutgoingRequest}>
32+
<StyledChatButtonContainer disabled={disabled}>
2733
<SessionIconButton
2834
iconType="plusThin"
2935
backgroundColor={'var(--chat-buttons-background-color)'}
@@ -33,7 +39,7 @@ export const AddStagedAttachmentButton = (props: { onClick: () => void }) => {
3339
iconPadding="8px"
3440
onClick={props.onClick}
3541
dataTestId="attachments-button"
36-
disabled={isOutgoingRequest}
42+
disabled={disabled}
3743
/>
3844
</StyledChatButtonContainer>
3945
);
@@ -42,9 +48,11 @@ export const AddStagedAttachmentButton = (props: { onClick: () => void }) => {
4248
export const StartRecordingButton = (props: { onClick: () => void }) => {
4349
const selectedConvoKey = useSelectedConversationKey();
4450
const isOutgoingRequest = useIsOutgoingRequest(selectedConvoKey);
51+
const isBlocked = useSelectedIsBlocked();
52+
const disabled = isOutgoingRequest || isBlocked;
4553

4654
return (
47-
<StyledChatButtonContainer disabled={isOutgoingRequest}>
55+
<StyledChatButtonContainer disabled={disabled}>
4856
<SessionIconButton
4957
iconType="microphone"
5058
iconSize={'huge2'}
@@ -53,7 +61,7 @@ export const StartRecordingButton = (props: { onClick: () => void }) => {
5361
borderRadius="300px"
5462
iconPadding="6px"
5563
onClick={props.onClick}
56-
disabled={isOutgoingRequest}
64+
disabled={disabled}
5765
dataTestId="microphone-button"
5866
/>
5967
</StyledChatButtonContainer>

ts/components/conversation/header/ConversationHeader.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import {
1313
useIsMessageSelectionMode,
1414
useSelectedConversationKey,
15+
useSelectedIsBlocked,
1516
useSelectedIsLegacyGroup,
1617
useSelectedWeAreAdmin,
1718
} from '../../../state/selectors/selectedConversation';
@@ -33,6 +34,7 @@ export const ConversationHeaderWithDetails = () => {
3334
const isSelectionMode = useIsMessageSelectionMode();
3435
const selectedConvoKey = useSelectedConversationKey();
3536
const isOutgoingRequest = useIsOutgoingRequest(selectedConvoKey);
37+
const isBlocked = useSelectedIsBlocked();
3638

3739
const showConvoSettingsCb = useShowConversationSettingsFor(selectedConvoKey);
3840

@@ -49,7 +51,7 @@ export const ConversationHeaderWithDetails = () => {
4951
width="100%"
5052
$flexGrow={1}
5153
>
52-
<ConversationHeaderTitle showSubtitle={!isOutgoingRequest} />
54+
<ConversationHeaderTitle showSubtitle={!isOutgoingRequest && !isBlocked} />
5355

5456
{!isOutgoingRequest && !isSelectionMode && (
5557
<Flex

ts/components/conversation/header/ConversationHeaderItems.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ export const CallButton = () => {
6969
!isPrivate ||
7070
isMe ||
7171
!selectedConvoKey ||
72-
isBlocked ||
7372
!isActive ||
7473
!isPrivateAndFriend // call requires us to be friends
7574
) {
@@ -87,6 +86,7 @@ export const CallButton = () => {
8786
void callRecipient(selectedConvoKey, canCall);
8887
}}
8988
dataTestId="call-button"
89+
disabled={isBlocked || !canCall}
9090
/>
9191
);
9292
};

ts/components/conversation/header/ConversationHeaderTitle.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { closeRightPanel } from '../../../state/ducks/conversations';
66
import {
77
useSelectedConversationDisappearingMode,
88
useSelectedConversationKey,
9+
useSelectedIsBlocked,
910
useSelectedIsGroupOrCommunity,
1011
useSelectedIsKickedFromGroup,
1112
useSelectedIsLegacyGroup,
@@ -32,10 +33,6 @@ export type SubtitleStringsType = keyof Pick<
3233
'notifications' | 'members' | 'disappearingMessages'
3334
>;
3435

35-
type ConversationHeaderTitleProps = {
36-
showSubtitle: boolean;
37-
};
38-
3936
function useSubtitleArray(convoId?: string) {
4037
const subscriberCount = useSelectedSubscriberCount();
4138

@@ -91,11 +88,10 @@ function useSubtitleArray(convoId?: string) {
9188
return subtitleArray;
9289
}
9390

94-
export const ConversationHeaderTitle = ({ showSubtitle }: ConversationHeaderTitleProps) => {
91+
export const ConversationHeaderTitle = ({ showSubtitle }: { showSubtitle: boolean }) => {
9592
const dispatch = useDispatch();
9693
const convoId = useSelectedConversationKey();
9794
const convoName = useSelectedNicknameOrProfileNameOrShortenedPubkey();
98-
9995
const isRightPanelOn = useIsRightPanelShowing();
10096
const isMe = useSelectedIsNoteToSelf();
10197

@@ -113,6 +109,7 @@ export const ConversationHeaderTitle = ({ showSubtitle }: ConversationHeaderTitl
113109
const showConvoSettingsCb = useShowConversationSettingsFor(convoId);
114110

115111
const subtitles = useSubtitleArray(convoId);
112+
const isBlocked = useSelectedIsBlocked();
116113

117114
const onHeaderClick = () => {
118115
if (isLegacyGroup || !convoId) {
@@ -126,6 +123,12 @@ export const ConversationHeaderTitle = ({ showSubtitle }: ConversationHeaderTitl
126123
return;
127124
}
128125

126+
// when the conversation is blocked, only show the default page of the modal (the other pages are not available)
127+
if (isBlocked) {
128+
showConvoSettingsCb({ settingsModalPage: 'default' });
129+
return;
130+
}
131+
129132
// NOTE If disappearing messages is defined we must show it first
130133
if (subtitles?.[subtitleIndex]?.type === 'disappearingMessages') {
131134
showConvoSettingsCb({

ts/components/menuAndSettingsHooks/useShowBlockUnblock.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import { PubKey } from '../../session/types';
99
import { updateBlockOrUnblockModal } from '../../state/ducks/modalDialog';
1010
import { LUCIDE_ICONS_UNICODE } from '../icon/lucide';
1111

12-
export function useShowBlockUnblock(convoId: string) {
12+
export function useShowBlockUnblock(convoId?: string) {
1313
const isMe = useIsMe(convoId);
1414
const isBlocked = useIsBlocked(convoId);
1515
const isPrivate = useIsPrivate(convoId);
1616
const isIncomingRequest = useIsIncomingRequest(convoId);
1717
const dispatch = useDispatch();
1818

19-
const showBlockUnblock = !isMe && isPrivate && !isIncomingRequest && !PubKey.isBlinded(convoId);
19+
const showBlockUnblock = convoId && !isMe && isPrivate && !isIncomingRequest && !PubKey.isBlinded(convoId);
2020

2121
if (!showBlockUnblock) {
2222
return null;

ts/session/messages/outgoing/controlMessage/DataExtractionNotificationMessage.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,13 @@ export const sendDataExtractionNotification = async (
5353
referencedAttachmentTimestamp: number
5454
) => {
5555
const convo = ConvoHub.use().get(conversationId);
56-
if (!convo || !convo.isPrivate() || convo.isMe() || UserUtils.isUsFromCache(attachmentSender)) {
56+
if (
57+
!convo ||
58+
!convo.isPrivate() ||
59+
convo.isMe() ||
60+
UserUtils.isUsFromCache(attachmentSender) ||
61+
convo.isBlocked()
62+
) {
5763
window.log.warn('Not sending saving attachment notification for', attachmentSender);
5864
return;
5965
}

0 commit comments

Comments
 (0)