Files
session-desktop/ts/components/conversation/header/ConversationHeaderSelectionOverlay.tsx

115 lines
3.7 KiB
TypeScript

import { useRef } from 'react';
import { useSelector } from 'react-redux';
import useKey from 'react-use/lib/useKey';
import { getAppDispatch } from '../../../state/dispatch';
import { deleteMessagesForX } from '../../../interactions/conversations/unsendingInteractions';
import { resetSelectedMessageIds } from '../../../state/ducks/conversations';
import { getSelectedMessageIds } from '../../../state/selectors/conversations';
import {
useSelectedConversationKey,
useSelectedIsPublic,
} from '../../../state/selectors/selectedConversation';
import {
SessionButton,
SessionButtonColor,
SessionButtonShape,
SessionButtonType,
} from '../../basic/SessionButton';
import { SessionFocusTrap } from '../../SessionFocusTrap';
import { tr } from '../../../localization/localeTools';
import { SessionLucideIconButton } from '../../icon/SessionIconButton';
import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide';
export const SelectionOverlay = () => {
const selectedMessageIds = useSelector(getSelectedMessageIds);
const selectedConversationKey = useSelectedConversationKey();
const isPublic = useSelectedIsPublic();
const dispatch = getAppDispatch();
const ref = useRef(null);
function onCloseOverlay() {
dispatch(resetSelectedMessageIds());
}
/**
* This is a duplicate with the onKeyDown of SessionConversation.
* At some point we'll make a global handler to deal with the key presses
* and handle them depending on what is visible, but that's not part of this PR
*/
useKey(
shouldProcess => {
return (
shouldProcess.code === 'Escape' ||
shouldProcess.code === 'Backspace' ||
shouldProcess.code === 'Delete'
);
},
event => {
const selectionMode = !!selectedMessageIds.length;
switch (event.key) {
case 'Escape':
if (selectionMode) {
onCloseOverlay();
}
return true;
case 'Backspace':
case 'Delete':
if (selectionMode && selectedConversationKey) {
void deleteMessagesForX(selectedMessageIds, selectedConversationKey, isPublic);
}
return true;
default:
}
return false;
}
);
// `enforceDeleteServerSide` should check for message statuses too, but when we have multiple selected,
// some might be sent and some in an error state. We default to trying to delete all of them server side first,
// which might fail. If that fails, the user will need to do a delete for all the ones sent already, and a manual delete
// for each ones which is in an error state.
const enforceDeleteServerSide = isPublic;
return (
<SessionFocusTrap
initialFocus={() => ref.current}
containerDivStyle={{
position: 'absolute',
display: 'flex',
left: '0px',
right: '0px',
padding: '0px var(--margins-md)',
alignItems: 'center',
justifyContent: 'space-between',
height: 'var(--main-view-header-height)',
background: 'var(--background-primary-color)',
}}
>
<SessionLucideIconButton
unicode={LUCIDE_ICONS_UNICODE.X}
iconColor="var(--chat-buttons-icon-color)"
iconSize="large"
onClick={onCloseOverlay}
aria-label={tr('close')}
ref={ref}
/>
<SessionButton
buttonColor={SessionButtonColor.Danger}
buttonShape={SessionButtonShape.Square}
buttonType={SessionButtonType.Solid}
text={tr('delete')}
onClick={async () => {
if (selectedConversationKey) {
await deleteMessagesForX(
selectedMessageIds,
selectedConversationKey,
enforceDeleteServerSide
);
}
}}
/>
</SessionFocusTrap>
);
};