remove MainHeader class no longer used
parent
71c47ba87a
commit
2335dbab93
@ -1,419 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { debounce } from 'lodash';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
// Use this to trigger whisper events
|
|
||||||
import { trigger } from '../shims/events';
|
|
||||||
|
|
||||||
// Use this to check for password
|
|
||||||
import { hasPassword } from '../shims/Signal';
|
|
||||||
|
|
||||||
import { Avatar } from './Avatar';
|
|
||||||
import { ContactName } from './conversation/ContactName';
|
|
||||||
|
|
||||||
import { cleanSearchTerm } from '../util/cleanSearchTerm';
|
|
||||||
import { LocalizerType } from '../types/Util';
|
|
||||||
import { SearchOptions } from '../types/Search';
|
|
||||||
import { clipboard } from 'electron';
|
|
||||||
|
|
||||||
import { validateNumber } from '../types/PhoneNumber';
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
lokiFeatureFlags: any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MenuItem {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
onClick?: () => void;
|
|
||||||
}
|
|
||||||
export interface Props {
|
|
||||||
searchTerm: string;
|
|
||||||
|
|
||||||
// To be used as an ID
|
|
||||||
ourNumber: string;
|
|
||||||
regionCode: string;
|
|
||||||
|
|
||||||
// For display
|
|
||||||
phoneNumber: string;
|
|
||||||
isMe: boolean;
|
|
||||||
name?: string;
|
|
||||||
color: string;
|
|
||||||
verified: boolean;
|
|
||||||
profileName?: string;
|
|
||||||
avatarPath?: string;
|
|
||||||
isSecondaryDevice: boolean;
|
|
||||||
|
|
||||||
i18n: LocalizerType;
|
|
||||||
updateSearchTerm: (searchTerm: string) => void;
|
|
||||||
search: (query: string, options: SearchOptions) => void;
|
|
||||||
clearSearch: () => void;
|
|
||||||
|
|
||||||
onClick?: () => void;
|
|
||||||
onCopyPublicKey?: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MainHeader extends React.Component<Props, any> {
|
|
||||||
private readonly updateSearchBound: (
|
|
||||||
event: React.FormEvent<HTMLInputElement>
|
|
||||||
) => void;
|
|
||||||
private readonly clearSearchBound: () => void;
|
|
||||||
private readonly copyFromClipboardBound: () => void;
|
|
||||||
private readonly handleKeyUpBound: (
|
|
||||||
event: React.KeyboardEvent<HTMLInputElement>
|
|
||||||
) => void;
|
|
||||||
private readonly setFocusBound: () => void;
|
|
||||||
private readonly inputRef: React.RefObject<HTMLInputElement>;
|
|
||||||
private readonly debouncedSearch: (searchTerm: string) => void;
|
|
||||||
private readonly timerId: any;
|
|
||||||
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
expanded: false,
|
|
||||||
hasPass: null,
|
|
||||||
clipboardText: '',
|
|
||||||
menuItems: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
this.updateSearchBound = this.updateSearch.bind(this);
|
|
||||||
this.clearSearchBound = this.clearSearch.bind(this);
|
|
||||||
this.copyFromClipboardBound = this.copyFromClipboard.bind(this);
|
|
||||||
this.handleKeyUpBound = this.handleKeyUp.bind(this);
|
|
||||||
this.setFocusBound = this.setFocus.bind(this);
|
|
||||||
this.inputRef = React.createRef();
|
|
||||||
|
|
||||||
this.debouncedSearch = debounce(this.search.bind(this), 20);
|
|
||||||
|
|
||||||
this.timerId = setInterval(() => {
|
|
||||||
const clipboardText = clipboard.readText();
|
|
||||||
if (this.state.clipboardText !== clipboardText) {
|
|
||||||
this.setState({ clipboardText });
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillMount() {
|
|
||||||
// tslint:disable-next-line
|
|
||||||
this.updateHasPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillUnmount() {
|
|
||||||
// tslint:disable-next-line
|
|
||||||
clearInterval(this.timerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidUpdate(_prevProps: Props, prevState: any) {
|
|
||||||
if (
|
|
||||||
prevState.hasPass !== this.state.hasPass ||
|
|
||||||
_prevProps.isSecondaryDevice !== this.props.isSecondaryDevice
|
|
||||||
) {
|
|
||||||
this.updateMenuItems();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public search() {
|
|
||||||
const {
|
|
||||||
searchTerm,
|
|
||||||
search,
|
|
||||||
i18n,
|
|
||||||
ourNumber,
|
|
||||||
regionCode,
|
|
||||||
isSecondaryDevice,
|
|
||||||
} = this.props;
|
|
||||||
if (search) {
|
|
||||||
search(searchTerm, {
|
|
||||||
noteToSelf: i18n('noteToSelf').toLowerCase(),
|
|
||||||
ourNumber,
|
|
||||||
regionCode,
|
|
||||||
isSecondaryDevice,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateSearch(event: React.FormEvent<HTMLInputElement>) {
|
|
||||||
const { updateSearchTerm, clearSearch } = this.props;
|
|
||||||
const searchTerm = event.currentTarget.value;
|
|
||||||
|
|
||||||
if (!searchTerm) {
|
|
||||||
clearSearch();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateSearchTerm) {
|
|
||||||
updateSearchTerm(searchTerm);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchTerm.length < 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cleanedTerm = cleanSearchTerm(searchTerm);
|
|
||||||
if (!cleanedTerm) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.debouncedSearch(cleanedTerm);
|
|
||||||
}
|
|
||||||
|
|
||||||
public clearSearch() {
|
|
||||||
const { clearSearch } = this.props;
|
|
||||||
|
|
||||||
clearSearch();
|
|
||||||
this.setFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public copyFromClipboard() {
|
|
||||||
const { clipboardText } = this.state;
|
|
||||||
|
|
||||||
this.props.updateSearchTerm(clipboardText);
|
|
||||||
this.debouncedSearch(clipboardText);
|
|
||||||
}
|
|
||||||
|
|
||||||
public handleKeyUp(event: React.KeyboardEvent<HTMLInputElement>) {
|
|
||||||
const { clearSearch } = this.props;
|
|
||||||
|
|
||||||
if (event.key === 'Escape') {
|
|
||||||
clearSearch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public setFocus() {
|
|
||||||
if (this.inputRef.current) {
|
|
||||||
// @ts-ignore
|
|
||||||
this.inputRef.current.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { onClick } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div role="button" className="module-main-header" onClick={onClick}>
|
|
||||||
<div className="module-main-header__container">
|
|
||||||
{this.renderName()}
|
|
||||||
{this.renderMenu()}
|
|
||||||
</div>
|
|
||||||
{this.renderSearch()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderName() {
|
|
||||||
const {
|
|
||||||
avatarPath,
|
|
||||||
i18n,
|
|
||||||
color,
|
|
||||||
name,
|
|
||||||
phoneNumber,
|
|
||||||
profileName,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const { expanded } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
role="button"
|
|
||||||
className="module-main-header__title"
|
|
||||||
onClick={() => {
|
|
||||||
this.setState({ expanded: !expanded });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Avatar
|
|
||||||
avatarPath={avatarPath}
|
|
||||||
color={color}
|
|
||||||
conversationType="direct"
|
|
||||||
i18n={i18n}
|
|
||||||
name={name}
|
|
||||||
phoneNumber={phoneNumber}
|
|
||||||
profileName={profileName}
|
|
||||||
size={28}
|
|
||||||
/>
|
|
||||||
<div className="module-main-header__contact-name">
|
|
||||||
<ContactName
|
|
||||||
phoneNumber={phoneNumber}
|
|
||||||
profileName={profileName}
|
|
||||||
i18n={i18n}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
'module-main-header-content-toggle',
|
|
||||||
expanded && 'module-main-header-content-toggle-visible'
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderMenu() {
|
|
||||||
const { expanded, menuItems } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="module-main-header__menu">
|
|
||||||
<div className={classNames('accordian', expanded && 'expanded')}>
|
|
||||||
{menuItems.map((item: MenuItem) => (
|
|
||||||
<div
|
|
||||||
role="button"
|
|
||||||
className="menu-item"
|
|
||||||
key={item.id}
|
|
||||||
onClick={item.onClick}
|
|
||||||
>
|
|
||||||
{item.name}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private shouldShowPaste() {
|
|
||||||
const { searchTerm, i18n } = this.props;
|
|
||||||
const { clipboardText } = this.state;
|
|
||||||
|
|
||||||
const error = validateNumber(clipboardText, i18n);
|
|
||||||
|
|
||||||
return !searchTerm && !error;
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderSearch() {
|
|
||||||
const { searchTerm, i18n } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="module-main-header__search">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
ref={this.inputRef}
|
|
||||||
className="module-main-header__search__input"
|
|
||||||
placeholder={i18n('search')}
|
|
||||||
dir="auto"
|
|
||||||
onKeyUp={this.handleKeyUpBound}
|
|
||||||
value={searchTerm}
|
|
||||||
onChange={this.updateSearchBound}
|
|
||||||
/>
|
|
||||||
{this.shouldShowPaste() ? (
|
|
||||||
<span
|
|
||||||
role="button"
|
|
||||||
className="module-main-header__search__copy-from-clipboard"
|
|
||||||
onClick={this.copyFromClipboardBound}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
<span
|
|
||||||
role="button"
|
|
||||||
className="module-main-header__search__icon"
|
|
||||||
onClick={this.setFocusBound}
|
|
||||||
/>
|
|
||||||
{searchTerm ? (
|
|
||||||
<span
|
|
||||||
role="button"
|
|
||||||
className="module-main-header__search__cancel-icon"
|
|
||||||
onClick={this.clearSearchBound}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async updateHasPass() {
|
|
||||||
const hasPass = await hasPassword();
|
|
||||||
this.setState({ hasPass });
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateMenuItems() {
|
|
||||||
const { i18n, onCopyPublicKey, isSecondaryDevice } = this.props;
|
|
||||||
const { hasPass } = this.state;
|
|
||||||
|
|
||||||
const menuItems = [
|
|
||||||
{
|
|
||||||
id: 'copyPublicKey',
|
|
||||||
name: i18n('copyPublicKey'),
|
|
||||||
onClick: onCopyPublicKey,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'showSeed',
|
|
||||||
name: i18n('showSeed'),
|
|
||||||
onClick: () => {
|
|
||||||
trigger('showSeedDialog');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'showQRCode',
|
|
||||||
name: i18n('showQRCode'),
|
|
||||||
onClick: () => {
|
|
||||||
trigger('showQRDialog');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'showAddServer',
|
|
||||||
name: i18n('showAddServer'),
|
|
||||||
onClick: () => {
|
|
||||||
trigger('showAddServerDialog');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
if (window.lokiFeatureFlags.privateGroupChats) {
|
|
||||||
menuItems.push({
|
|
||||||
id: 'createPrivateGroup',
|
|
||||||
name: i18n('createPrivateGroup'),
|
|
||||||
onClick: () => {
|
|
||||||
trigger('createNewGroup');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const passItem = (type: string) => ({
|
|
||||||
id: `${type}Password`,
|
|
||||||
name: i18n(`${type}Password`),
|
|
||||||
onClick: () => {
|
|
||||||
trigger('showPasswordDialog', {
|
|
||||||
type,
|
|
||||||
resolve: () => {
|
|
||||||
trigger('showToast', {
|
|
||||||
message: i18n(`${type}PasswordSuccess`),
|
|
||||||
});
|
|
||||||
setTimeout(async () => this.updateHasPass(), 100);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hasPass) {
|
|
||||||
menuItems.push(passItem('change'), passItem('remove'));
|
|
||||||
} else {
|
|
||||||
menuItems.push(passItem('set'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSecondaryDevice) {
|
|
||||||
// insert as second element
|
|
||||||
menuItems.splice(1, 0, {
|
|
||||||
id: 'editProfile',
|
|
||||||
name: i18n('editProfile'),
|
|
||||||
onClick: () => {
|
|
||||||
trigger('onEditProfile');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
menuItems.push({
|
|
||||||
id: 'pairNewDevice',
|
|
||||||
name: 'Device Pairing',
|
|
||||||
onClick: () => {
|
|
||||||
trigger('showDevicePairingDialog');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
menuItems.push({
|
|
||||||
id: 'showPairingWords',
|
|
||||||
name: 'Show Pairing Words',
|
|
||||||
onClick: () => {
|
|
||||||
trigger('showDevicePairingWordsDialog');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ menuItems });
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import { mapDispatchToProps } from '../actions';
|
|
||||||
|
|
||||||
import { MainHeader } from '../../components/MainHeader';
|
|
||||||
import { StateType } from '../reducer';
|
|
||||||
|
|
||||||
import { getQuery } from '../selectors/search';
|
|
||||||
import {
|
|
||||||
getIntl,
|
|
||||||
getIsSecondaryDevice,
|
|
||||||
getRegionCode,
|
|
||||||
getUserNumber,
|
|
||||||
} from '../selectors/user';
|
|
||||||
import { getMe } from '../selectors/conversations';
|
|
||||||
|
|
||||||
const mapStateToProps = (state: StateType) => {
|
|
||||||
return {
|
|
||||||
searchTerm: getQuery(state),
|
|
||||||
regionCode: getRegionCode(state),
|
|
||||||
ourNumber: getUserNumber(state),
|
|
||||||
isSecondaryDevice: getIsSecondaryDevice(state),
|
|
||||||
...getMe(state),
|
|
||||||
i18n: getIntl(state),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const smart = connect(mapStateToProps, mapDispatchToProps);
|
|
||||||
|
|
||||||
export const SmartMainHeader = smart(MainHeader);
|
|
Loading…
Reference in New Issue