do not show search input if we only got a single conversation

pull/1884/head
audric 4 years ago
parent 714024fb1f
commit 985a5d92bc

@ -131,7 +131,7 @@
"deleteForEveryone": "Delete for Everyone", "deleteForEveryone": "Delete for Everyone",
"deleteConversationConfirmation": "Permanently delete the messages in this conversation?", "deleteConversationConfirmation": "Permanently delete the messages in this conversation?",
"clearAllData": "Clear All Data", "clearAllData": "Clear All Data",
"deleteAccountWarning": "This will permanently delete your messages, sessions, and contacts.", "deleteAccountWarning": "This will permanently delete your messages and contacts.",
"deleteContactConfirmation": "Are you sure you want to delete this conversation?", "deleteContactConfirmation": "Are you sure you want to delete this conversation?",
"quoteThumbnailAlt": "Thumbnail of image from quoted message", "quoteThumbnailAlt": "Thumbnail of image from quoted message",
"imageAttachmentAlt": "Image attached to message", "imageAttachmentAlt": "Image attached to message",
@ -337,6 +337,8 @@
"onlyAdminCanRemoveMembersDesc": "Only the creator of the group can remove users", "onlyAdminCanRemoveMembersDesc": "Only the creator of the group can remove users",
"createAccount": "Create account", "createAccount": "Create account",
"signIn": "Sign In", "signIn": "Sign In",
"startInTrayTitle": "Start in Tray",
"startInTrayDescription": "Start Session as a minified app ",
"yourUniqueSessionID": "Say hello to your Session ID", "yourUniqueSessionID": "Say hello to your Session ID",
"allUsersAreRandomly...": "Your Session ID is the unique address people can use to contact you on Session. With no connection to your real identity, your Session ID is totally anonymous and private by design.", "allUsersAreRandomly...": "Your Session ID is the unique address people can use to contact you on Session. With no connection to your real identity, your Session ID is totally anonymous and private by design.",
"getStarted": "Get started", "getStarted": "Get started",
@ -419,5 +421,15 @@
"latestUnreadIsAbove": "First unread message is above", "latestUnreadIsAbove": "First unread message is above",
"sendRecoveryPhraseTitle": "Sending Recovery Phrase", "sendRecoveryPhraseTitle": "Sending Recovery Phrase",
"sendRecoveryPhraseMessage": "You are attempting to send your recovery phrase which can be used to access your account. Are you sure you want to send this message?", "sendRecoveryPhraseMessage": "You are attempting to send your recovery phrase which can be used to access your account. Are you sure you want to send this message?",
"dialogClearAllDataDeletionFailedTitle": "Data not deleted",
"dialogClearAllDataDeletionFailedDesc": "Data not deleted with an unknown error. Do you want to delete data from just this device?",
"dialogClearAllDataDeletionFailedTitleQuestion": "Do you want to delete data from just this device?",
"dialogClearAllDataDeletionFailedMultiple": "Data not deleted by those Service Nodes: $snodes$",
"dialogClearAllDataDeletionQuestion": "Would you like to clear only this device, or delete your entire account?",
"deviceOnly": "Device Only",
"entireAccount": "Entire Account",
"recoveryPhraseSecureTitle": "You're almost finished!",
"recoveryPhraseRevealMessage": "Secure your account by saving your recovery phrase. Reveal your recovery phrase then store it safely to secure it.",
"recoveryPhraseRevealButtonText": "Reveal Recovery Phrase",
"notificationSubtitle": "Notifications - $setting$" "notificationSubtitle": "Notifications - $setting$"
} }

@ -8,6 +8,8 @@ import { disableRecoveryPhrasePrompt } from '../../state/ducks/userConfig';
import { getShowRecoveryPhrasePrompt } from '../../state/selectors/userConfig'; import { getShowRecoveryPhrasePrompt } from '../../state/selectors/userConfig';
import { recoveryPhraseModal } from '../../state/ducks/modalDialog'; import { recoveryPhraseModal } from '../../state/ducks/modalDialog';
import { Flex } from '../basic/Flex'; import { Flex } from '../basic/Flex';
import { getFocusedSection } from '../../state/selectors/section';
import { SectionType } from '../../state/ducks/section';
const Tab = ({ const Tab = ({
isSelected, isSelected,
@ -71,6 +73,8 @@ export const LeftPaneSectionHeader = (props: Props) => {
export const LeftPaneBanner = () => { export const LeftPaneBanner = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const section = useSelector(getFocusedSection);
const showRecoveryPhraseModal = () => { const showRecoveryPhraseModal = () => {
dispatch( dispatch(
recoveryPhraseModal({ recoveryPhraseModal({
@ -81,6 +85,10 @@ export const LeftPaneBanner = () => {
); );
}; };
if (section !== SectionType.Message) {
return null;
}
const BannerInner = () => { const BannerInner = () => {
return ( return (
<StyledBannerInner> <StyledBannerInner>

@ -2,7 +2,6 @@ import React from 'react';
import { SessionIconButton, SessionIconSize, SessionIconType } from './icon'; import { SessionIconButton, SessionIconSize, SessionIconType } from './icon';
import { SessionIdEditable } from './SessionIdEditable'; import { SessionIdEditable } from './SessionIdEditable';
import { UserSearchDropdown } from './UserSearchDropdown';
import { ContactType, SessionMemberListItem } from './SessionMemberListItem'; import { ContactType, SessionMemberListItem } from './SessionMemberListItem';
import { ReduxConversationType } from '../../state/ducks/conversations'; import { ReduxConversationType } from '../../state/ducks/conversations';
import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton'; import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton';
@ -100,16 +99,7 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
// tslint:disable-next-line max-func-body-length cyclomatic-complexity */ // tslint:disable-next-line max-func-body-length cyclomatic-complexity */
public render(): JSX.Element { public render(): JSX.Element {
const { const { overlayMode, onCloseClick, onChangeSessionID, showSpinner, onButtonClick } = this.props;
overlayMode,
onCloseClick,
onChangeSessionID,
showSpinner,
searchTerm,
updateSearch,
searchResults,
onButtonClick,
} = this.props;
const { groupName, selectedMembers } = this.state; const { groupName, selectedMembers } = this.state;
@ -218,16 +208,7 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
{descriptionLong && <div className="session-description-long">{descriptionLong}</div>} {descriptionLong && <div className="session-description-long">{descriptionLong}</div>}
{isMessageView && false && <h4>{window.i18n('or')}</h4>} {isMessageView && false && <h4>{window.i18n('or')}</h4>}
{/* FIXME enable back those two items when they are working */}
{isOpenGroupView && <SessionJoinableRooms onRoomClicked={this.props.onCloseClick} />} {isOpenGroupView && <SessionJoinableRooms onRoomClicked={this.props.onCloseClick} />}
{isMessageView && false && (
<UserSearchDropdown
searchTerm={searchTerm || ''}
updateSearch={updateSearch}
placeholder={window.i18n('searchFor...')}
searchResults={searchResults}
/>
)}
<SessionButton <SessionButton
buttonColor={SessionButtonColor.Green} buttonColor={SessionButtonColor.Green}

@ -1,65 +1,32 @@
import React from 'react'; import React from 'react';
import { animation, contextMenu, Item, Menu } from 'react-contexify'; import { useSelector } from 'react-redux';
import { getConversationsCount } from '../../state/selectors/conversations';
import { SessionIconButton, SessionIconSize, SessionIconType } from './icon'; import { SessionIconButton, SessionIconSize, SessionIconType } from './icon';
interface Props { interface Props {
searchString: string; searchString: string;
onChange: any; onChange: any;
handleNavigation?: any;
placeholder: string; placeholder: string;
} }
export class SessionSearchInput extends React.Component<Props> { export const SessionSearchInput = (props: Props) => {
public constructor(props: Props) { const { searchString, onChange, placeholder } = props;
super(props);
this.handleKeyDown = this.handleKeyDown.bind(this); const convoCount = useSelector(getConversationsCount);
}
public render() { // just after onboard we only have a conversation with ourself
const { searchString } = this.props; if (convoCount <= 1) {
const triggerId = 'session-search-input-context'; return null;
}
return ( return (
<> <div className="session-search-input">
<div
className="session-search-input"
onContextMenu={(e: any) => {
contextMenu.show({
id: triggerId,
event: e,
});
}}
>
<SessionIconButton iconSize={SessionIconSize.Medium} iconType={SessionIconType.Search} /> <SessionIconButton iconSize={SessionIconSize.Medium} iconType={SessionIconType.Search} />
<input <input
value={searchString} value={searchString}
onChange={e => this.props.onChange(e.target.value)} onChange={e => onChange(e.target.value)}
onKeyDown={this.handleKeyDown} placeholder={placeholder}
placeholder={this.props.placeholder}
/> />
</div> </div>
<Menu id={triggerId} animation={animation.fade}>
<Item onClick={() => document.execCommand('undo')}>{window.i18n('editMenuUndo')}</Item>
<Item onClick={() => document.execCommand('redo')}>{window.i18n('editMenuRedo')}</Item>
<hr />
<Item onClick={() => document.execCommand('cut')}>{window.i18n('editMenuCut')}</Item>
<Item onClick={() => document.execCommand('copy')}>{window.i18n('editMenuCopy')}</Item>
<Item onClick={() => document.execCommand('paste')}>{window.i18n('editMenuPaste')}</Item>
<Item onClick={() => document.execCommand('selectAll')}>
{window.i18n('editMenuSelectAll')}
</Item>
</Menu>
</>
); );
} };
public handleKeyDown(e: any) {
if (e.keyCode === 38 || e.keyCode === 40 || e.key === 'Enter') {
// Up or Bottom arrow pressed
if (this.props.handleNavigation) {
e.stopPropagation();
this.props.handleNavigation(e);
}
}
}
}

@ -1,86 +0,0 @@
import React from 'react';
import { UserSearchResults } from '../UserSearchResults';
import { SessionSearchInput } from './SessionSearchInput';
import { SearchResultsProps } from '../SearchResults';
import autoBind from 'auto-bind';
export interface Props {
searchTerm: string;
placeholder: string;
searchResults?: SearchResultsProps;
updateSearch: (searchTerm: string) => void;
}
interface State {
selectedContact: number;
}
export class UserSearchDropdown extends React.Component<Props, State> {
public constructor(props: Props) {
super(props);
autoBind(this);
this.state = {
selectedContact: -1,
};
}
public handleNavigation(e: any) {
const { selectedContact } = this.state;
const { searchResults } = this.props;
// arrow up/down button should select next/previous list element
if (
e.keyCode === 38 &&
selectedContact > 0 &&
searchResults &&
searchResults.contacts.length > 0
) {
this.setState(prevState => ({
selectedContact: +prevState.selectedContact - 1,
}));
} else if (
e.keyCode === 40 &&
searchResults &&
selectedContact < searchResults.contacts.length - 1
) {
this.setState(prevState => ({
selectedContact: +prevState.selectedContact + 1,
}));
} else if (e.key === 'Enter' && searchResults && searchResults.contacts.length > 0) {
this.handleContactSelected(searchResults.contacts[selectedContact].phoneNumber);
}
}
public render() {
const { searchResults, placeholder } = this.props;
const { selectedContact } = this.state;
return (
<div className="user-search-dropdown">
<SessionSearchInput
searchString={this.props.searchTerm}
onChange={this.updateSearch}
placeholder={placeholder}
handleNavigation={this.handleNavigation}
/>
{searchResults && (
<UserSearchResults
{...searchResults}
selectedContact={selectedContact}
onContactSelected={this.handleContactSelected}
/>
)}
</div>
);
}
public updateSearch(data: string) {
this.setState({ selectedContact: -1 });
this.props.updateSearch(data);
}
public handleContactSelected(key: string) {
this.updateSearch(key);
}
}

@ -33,12 +33,16 @@ export const persistConfig = {
const persistedReducer = persistReducer(persistConfig, rootReducer); const persistedReducer = persistReducer(persistConfig, rootReducer);
// Exclude logger if we're in production mode // Exclude logger if we're in production mode
const disableLogging = env === 'production' || true; // ALWAYS TURNED OFF const disableLogging = true; //; env === 'production' || true; // ALWAYS TURNED OFF
const middlewareList = disableLogging ? [promise] : [promise, logger]; const middlewareList = disableLogging ? [] : [logger];
export const createStore = (initialState: any) => export const createStore = (initialState: any) =>
configureStore({ configureStore({
reducer: persistedReducer, reducer: persistedReducer,
preloadedState: initialState, preloadedState: initialState,
middleware: (getDefaultMiddleware: any) => getDefaultMiddleware().concat(middlewareList), middleware: (getDefaultMiddleware: any) =>
getDefaultMiddleware({
serializableCheck: false,
immutableCheck: false,
}).concat(middlewareList),
}); });

@ -46,6 +46,10 @@ export const getConversationLookup = createSelector(
} }
); );
export const getConversationsCount = createSelector(getConversationLookup, (state): number => {
return Object.values(state).length;
});
export const getSelectedConversationKey = createSelector( export const getSelectedConversationKey = createSelector(
getConversations, getConversations,
(state: ConversationsStateType): string | undefined => { (state: ConversationsStateType): string | undefined => {

Loading…
Cancel
Save