mirror of
https://github.com/ilyakooo0/urbit.git
synced 2025-01-05 13:55:54 +03:00
chat: UX overhaul for new groups
Removes public unmanaged chats, allows group DMs. Renames variables that only made sense during sig-prepended unmanaged paths usage.
This commit is contained in:
parent
3f29e98918
commit
f82a464719
@ -147,7 +147,7 @@ export default class ChatApp extends React.Component<ChatAppProps, {}> {
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/~chat/new/dm/:ship"
|
||||
path="/~chat/new/dm/:ship?"
|
||||
render={(props) => {
|
||||
const ship = props.match.params.ship;
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ChannelItem } from './channel-item';
|
||||
|
||||
export class GroupItem extends Component {
|
||||
@ -14,10 +15,10 @@ export class GroupItem extends Component {
|
||||
}
|
||||
|
||||
const channels = props.channels ? props.channels : [];
|
||||
const first = (props.index === 0) ? 'pt1' : 'pt4';
|
||||
const first = (props.index === 0) ? 'mt1 ' : 'mt4 ';
|
||||
|
||||
const channelItems = channels.sort((a, b) => {
|
||||
if (props.index === '/~/') {
|
||||
if (props.index === 'dm') {
|
||||
const aPreview = props.messagePreviews[a];
|
||||
const bPreview = props.messagePreviews[b];
|
||||
const aWhen = aPreview ? aPreview.when : 0;
|
||||
@ -63,10 +64,23 @@ export class GroupItem extends Component {
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
let dmLink = <div />;
|
||||
|
||||
if (props.index === 'dm') {
|
||||
dmLink = <Link
|
||||
className="absolute right-0 f9 top-0 mr4 green2 bg-gray5 bg-gray1-d b--transparent br1"
|
||||
to="/~chat/new/dm"
|
||||
style={{ padding: '0rem 0.2rem' }}
|
||||
>
|
||||
+ DM
|
||||
</Link>;
|
||||
}
|
||||
return (
|
||||
<div className={first}>
|
||||
<div className={first + 'relative'}>
|
||||
<p className="f9 ph4 fw6 pb2 gray3">{title}</p>
|
||||
{channelItems}
|
||||
{dmLink}
|
||||
{channelItems}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,26 +1,36 @@
|
||||
import React, { Component } from "react";
|
||||
import { Spinner } from "../../../components/Spinner";
|
||||
import { Link } from "react-router-dom";
|
||||
import urbitOb from "urbit-ob";
|
||||
import React, { Component } from 'react';
|
||||
import { Spinner } from '../../../components/Spinner';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { InviteSearch } from '../../../components/InviteSearch';
|
||||
import urbitOb from 'urbit-ob';
|
||||
import { deSig } from '../../../lib/util';
|
||||
|
||||
export class NewDmScreen extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
ship: null,
|
||||
ships: [],
|
||||
station: null,
|
||||
awaiting: false
|
||||
awaiting: false,
|
||||
title: '',
|
||||
idName: '',
|
||||
description: ''
|
||||
};
|
||||
|
||||
this.titleChange = this.titleChange.bind(this);
|
||||
this.descriptionChange = this.descriptionChange.bind(this);
|
||||
this.onClickCreate = this.onClickCreate.bind(this);
|
||||
this.setInvite = this.setInvite.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { props } = this;
|
||||
if (props.autoCreate && urbitOb.isValidPatp(props.autoCreate)) {
|
||||
const addedShip = this.state.ships;
|
||||
addedShip.push(props.autoCreate.slice(1));
|
||||
this.setState(
|
||||
{
|
||||
ship: props.autoCreate.slice(1),
|
||||
ships: addedShip,
|
||||
awaiting: true
|
||||
},
|
||||
this.onClickCreate
|
||||
@ -40,65 +50,188 @@ export class NewDmScreen extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
titleChange(event) {
|
||||
const asciiSafe = event.target.value.toLowerCase()
|
||||
.replace(/[^a-z0-9~_.-]/g, '-');
|
||||
this.setState({
|
||||
idName: asciiSafe,
|
||||
title: event.target.value
|
||||
});
|
||||
}
|
||||
|
||||
descriptionChange(event) {
|
||||
this.setState({
|
||||
description: event.target.value
|
||||
});
|
||||
}
|
||||
|
||||
setInvite(value) {
|
||||
this.setState({
|
||||
ships: value.ships
|
||||
});
|
||||
}
|
||||
|
||||
onClickCreate() {
|
||||
const { props, state } = this;
|
||||
|
||||
const station = `/~${window.ship}/dm--${state.ship}`;
|
||||
if (state.ships.length === 1) {
|
||||
const station = `/~${window.ship}/dm--${state.ships[0]}`;
|
||||
|
||||
const theirStation = `/~${state.ship}/dm--${window.ship}`;
|
||||
const theirStation = `/~${state.ships[0]}/dm--${window.ship}`;
|
||||
|
||||
if (station in props.inbox) {
|
||||
props.history.push(`/~chat/room${station}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (theirStation in props.inbox) {
|
||||
props.history.push(`/~chat/room${theirStation}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const aud = state.ship !== window.ship ? [`~${state.ship}`] : [];
|
||||
|
||||
this.setState(
|
||||
{
|
||||
station
|
||||
},
|
||||
() => {
|
||||
const groupPath = `/ship${station}`;
|
||||
props.api.chat.create(
|
||||
`~${window.ship} <-> ~${state.ship}`,
|
||||
"",
|
||||
station,
|
||||
groupPath,
|
||||
{ invite: { pending: aud } },
|
||||
aud,
|
||||
true,
|
||||
false
|
||||
);
|
||||
if (station in props.inbox) {
|
||||
props.history.push(`/~chat/room${station}`);
|
||||
return;
|
||||
}
|
||||
);
|
||||
|
||||
if (theirStation in props.inbox) {
|
||||
props.history.push(`/~chat/room${theirStation}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const aud = state.ship !== window.ship ? [`~${state.ships[0]}`] : [];
|
||||
|
||||
let title = `~${window.ship} <-> ~${state.ships[0]}`;
|
||||
|
||||
if (state.title !== '') {
|
||||
title = state.title;
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
station, awaiting: true
|
||||
},
|
||||
() => {
|
||||
const groupPath = `/ship/~${window.ship}/dm--${state.ships[0]}`;
|
||||
props.api.chat.create(
|
||||
title,
|
||||
state.description,
|
||||
station,
|
||||
groupPath,
|
||||
{ invite: { pending: aud } },
|
||||
aud,
|
||||
true,
|
||||
false
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (state.ships.length > 1) {
|
||||
const aud = state.ships.map(mem => `~${deSig(mem.trim())}`);
|
||||
|
||||
let title = 'Direct Message';
|
||||
|
||||
if (state.title !== '') {
|
||||
title = state.title;
|
||||
} else {
|
||||
const asciiSafe = title.toLowerCase()
|
||||
.replace(/[^a-z0-9~_.-]/g, '-');
|
||||
this.setState({ idName: asciiSafe });
|
||||
}
|
||||
|
||||
const station = `/~${window.ship}/${state.idName}-${Math.floor(Math.random() * 10000)}`;
|
||||
|
||||
this.setState(
|
||||
{
|
||||
station, awaiting: true
|
||||
},
|
||||
() => {
|
||||
const groupPath = `/ship${station}`;
|
||||
props.api.chat.create(
|
||||
title,
|
||||
state.description,
|
||||
station,
|
||||
groupPath,
|
||||
{ invite: { pending: aud } },
|
||||
aud,
|
||||
true,
|
||||
false
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
|
||||
const createClasses = (state.idName || state.ships.length >= 1)
|
||||
? 'pointer dib f9 green2 bg-gray0-d ba pv3 ph4 b--green2 mt4'
|
||||
: 'pointer dib f9 gray2 ba bg-gray0-d pa2 pv3 ph4 b--gray3 mt4';
|
||||
|
||||
const idClasses =
|
||||
'f7 ba b--gray3 b--gray2-d bg-gray0-d white-d pa3 db w-100 ' +
|
||||
'focus-b--black focus-b--white-d mt1 ';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
"h-100 w-100 mw6 pa3 pt4 overflow-x-hidden " +
|
||||
"bg-gray0-d white-d flex flex-column"
|
||||
'h-100 w-100 mw6 pa3 pt4 overflow-x-hidden ' +
|
||||
'bg-gray0-d white-d flex flex-column'
|
||||
}
|
||||
>
|
||||
<div className="w-100 dn-m dn-l dn-xl inter pt1 pb6 f8">
|
||||
<Link to="/~chat/">{"⟵ All Chats"}</Link>
|
||||
<Link to="/~chat/">{'⟵ All Chats'}</Link>
|
||||
</div>
|
||||
<h2 className="mb3 f8">New DM</h2>
|
||||
<h2 className="mb3 f8">New Direct Message</h2>
|
||||
<div className="w-100">
|
||||
<p className="f8 mt4 db">
|
||||
Name
|
||||
<span className="gray3"> (Optional)</span>
|
||||
</p>
|
||||
<textarea
|
||||
className={idClasses}
|
||||
placeholder="The Passage"
|
||||
rows={1}
|
||||
style={{
|
||||
resize: 'none'
|
||||
}}
|
||||
onChange={this.titleChange}
|
||||
/>
|
||||
<p className="f8 mt4 db">
|
||||
Description
|
||||
<span className="gray3"> (Optional)</span>
|
||||
</p>
|
||||
<textarea
|
||||
className={idClasses}
|
||||
placeholder="The most beautiful direct message"
|
||||
rows={1}
|
||||
style={{
|
||||
resize: 'none'
|
||||
}}
|
||||
onChange={this.descriptionChange}
|
||||
/>
|
||||
<p className="f8 mt4 db">
|
||||
Invite Members
|
||||
</p>
|
||||
<p className="f9 gray2 db mv1">
|
||||
Selected ships will be invited to the direct message
|
||||
</p>
|
||||
<InviteSearch
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
associations={props.associations}
|
||||
groupResults={false}
|
||||
shipResults={true}
|
||||
invites={{
|
||||
groups: [],
|
||||
ships: state.ships
|
||||
}}
|
||||
setInvite={this.setInvite}
|
||||
/>
|
||||
<button
|
||||
onClick={this.onClickCreate.bind(this)}
|
||||
className={createClasses}
|
||||
>
|
||||
Create Direct Message
|
||||
</button>
|
||||
<Spinner
|
||||
awaiting={this.state.awaiting}
|
||||
classes="mt4"
|
||||
text="Creating chat..."
|
||||
text="Creating Direct Message..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import { InviteSearch } from '../../../components/InviteSearch';
|
||||
import { Spinner } from '../../../components/Spinner';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { deSig } from '../../../lib/util';
|
||||
import urbitOb from 'urbit-ob';
|
||||
|
||||
export class NewScreen extends Component {
|
||||
constructor(props) {
|
||||
@ -14,9 +13,8 @@ export class NewScreen extends Component {
|
||||
idName: '',
|
||||
groups: [],
|
||||
ships: [],
|
||||
privacy: 'open',
|
||||
privacy: 'invite',
|
||||
idError: false,
|
||||
inviteError: false,
|
||||
allowHistory: true,
|
||||
createGroup: false,
|
||||
awaiting: false
|
||||
@ -24,10 +22,7 @@ export class NewScreen extends Component {
|
||||
|
||||
this.titleChange = this.titleChange.bind(this);
|
||||
this.descriptionChange = this.descriptionChange.bind(this);
|
||||
this.allowHistoryChange = this.allowHistoryChange.bind(this);
|
||||
this.setInvite = this.setInvite.bind(this);
|
||||
this.createGroupChange = this.createGroupChange.bind(this);
|
||||
this.privacyChange = this.privacyChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
@ -63,42 +58,13 @@ export class NewScreen extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
createGroupChange(event) {
|
||||
if (event.target.checked) {
|
||||
this.setState({
|
||||
createGroup: Boolean(event.target.checked)
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
createGroup: Boolean(event.target.checked)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
privacyChange(event) {
|
||||
if (event.target.checked) {
|
||||
this.setState({
|
||||
privacy: 'open'
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
privacy: 'invite'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
allowHistoryChange(event) {
|
||||
this.setState({ allowHistory: Boolean(event.target.checked) });
|
||||
}
|
||||
|
||||
onClickCreate() {
|
||||
const { props, state } = this;
|
||||
const grouped = (this.state.createGroup || (this.state.groups.length > 0));
|
||||
|
||||
if (!state.title) {
|
||||
this.setState({
|
||||
idError: true,
|
||||
inviteError: false
|
||||
idError: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -107,33 +73,13 @@ export class NewScreen extends Component {
|
||||
|
||||
if (station in props.inbox) {
|
||||
this.setState({
|
||||
inviteError: false,
|
||||
idError: true,
|
||||
success: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let isValid = true;
|
||||
const aud = state.ships.map(mem => `~${deSig(mem.trim())}`);
|
||||
aud.forEach((mem) => {
|
||||
if (!urbitOb.isValidPatp(mem)) {
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
if(state.ships.length === 1 && state.privacy === 'invite' && !state.createGroup) {
|
||||
props.history.push(`/~chat/new/dm/${aud[0]}`);
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
this.setState({
|
||||
inviteError: true,
|
||||
idError: false,
|
||||
success: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.textarea) {
|
||||
this.textarea.value = '';
|
||||
@ -148,13 +94,7 @@ export class NewScreen extends Component {
|
||||
ships: [],
|
||||
awaiting: true
|
||||
}, () => {
|
||||
// if we want a "proper group" that can be managed from the contacts UI,
|
||||
// we make a path of the form /~zod/cool-group
|
||||
// if not, we make a path of the form /~/~zod/free-chat
|
||||
let appPath = `/~${window.ship}${station}`;
|
||||
// if (!state.createGroup && state.groups.length === 0) {
|
||||
// appPath = `/~${appPath}`;
|
||||
// }
|
||||
const appPath = `/~${window.ship}${station}`;
|
||||
let groupPath = `/ship${appPath}`;
|
||||
if (state.groups.length > 0) {
|
||||
groupPath = state.groups[0];
|
||||
@ -178,21 +118,14 @@ export class NewScreen extends Component {
|
||||
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
let privacySwitchClasses = (state.privacy === 'invite')
|
||||
? 'relative checked bg-green2 br3 h1 toggle v-mid z-0'
|
||||
: 'relative bg-gray4 bg-gray1-d br3 h1 toggle v-mid z-0';
|
||||
|
||||
const createGroupClasses = state.createGroup
|
||||
? 'relative checked bg-green2 br3 h1 toggle v-mid z-0'
|
||||
: 'relative bg-gray4 bg-gray1-d br3 h1 toggle v-mid z-0';
|
||||
|
||||
const createClasses = state.idName
|
||||
? 'pointer db f9 green2 bg-gray0-d ba pv3 ph4 b--green2'
|
||||
: 'pointer db f9 gray2 ba bg-gray0-d pa2 pv3 ph4 b--gray3';
|
||||
? 'pointer db f9 green2 bg-gray0-d ba pv3 ph4 b--green2 mt4'
|
||||
: 'pointer db f9 gray2 ba bg-gray0-d pa2 pv3 ph4 b--gray3 mt4';
|
||||
|
||||
const idClasses =
|
||||
'f7 ba b--gray3 b--gray2-d bg-gray0-d white-d pa3 db w-100 ' +
|
||||
'focus-b--black focus-b--white-d ';
|
||||
'focus-b--black focus-b--white-d mt1 ';
|
||||
|
||||
let idErrElem = (<span />);
|
||||
if (state.idError) {
|
||||
@ -203,24 +136,6 @@ export class NewScreen extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
let createGroupToggle = <div />;
|
||||
if (state.groups.length === 0) {
|
||||
createGroupToggle = (
|
||||
<div className="mv7">
|
||||
<input
|
||||
type="checkbox"
|
||||
style={{ WebkitAppearance: 'none', width: 28 }}
|
||||
className={createGroupClasses}
|
||||
onChange={this.createGroupChange}
|
||||
/>
|
||||
<span className="dib f9 white-d inter ml3">Create Group</span>
|
||||
<p className="f9 gray2 pt1" style={{ paddingLeft: 40 }}>
|
||||
Participants will share this group across applications
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
@ -231,9 +146,9 @@ export class NewScreen extends Component {
|
||||
<div className="w-100 dn-m dn-l dn-xl inter pt1 pb6 f8">
|
||||
<Link to="/~chat/">{'⟵ All Chats'}</Link>
|
||||
</div>
|
||||
<h2 className="mb3 f8">New Chat</h2>
|
||||
<h2 className="mb4 f8">New Group Chat</h2>
|
||||
<div className="w-100">
|
||||
<p className="f8 mt3 lh-copy db">Name</p>
|
||||
<p className="f8 mt4 db">Name</p>
|
||||
<textarea
|
||||
className={idClasses}
|
||||
placeholder="Secret Chat"
|
||||
@ -244,7 +159,7 @@ export class NewScreen extends Component {
|
||||
onChange={this.titleChange}
|
||||
/>
|
||||
{idErrElem}
|
||||
<p className="f8 mt3 lh-copy db">
|
||||
<p className="f8 mt4 db">
|
||||
Description
|
||||
<span className="gray3"> (Optional)</span>
|
||||
</p>
|
||||
@ -257,38 +172,27 @@ export class NewScreen extends Component {
|
||||
}}
|
||||
onChange={this.descriptionChange}
|
||||
/>
|
||||
<p className="f8 mt4 lh-copy db">
|
||||
Invite
|
||||
<span className="gray3"> (Optional)</span>
|
||||
<div className="mt4 db relative">
|
||||
<p className="f8">
|
||||
Select Group
|
||||
</p>
|
||||
<p className="f9 gray2 db mb2 pt1">
|
||||
Selected groups or ships will be able to post to chat
|
||||
<Link className="green2 absolute right-0 bottom-0 f9" to="/~groups/new">+New</Link>
|
||||
<p className="f9 gray2 db mv1">
|
||||
Chat will be added to selected group
|
||||
</p>
|
||||
</div>
|
||||
<InviteSearch
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
associations={props.associations}
|
||||
groupResults={true}
|
||||
shipResults={true}
|
||||
shipResults={false}
|
||||
invites={{
|
||||
groups: state.groups,
|
||||
ships: state.ships
|
||||
ships: []
|
||||
}}
|
||||
setInvite={this.setInvite}
|
||||
/>
|
||||
{createGroupToggle}
|
||||
<div className="mv7">
|
||||
<input
|
||||
type="checkbox"
|
||||
style={{ WebkitAppearance: 'none', width: 28 }}
|
||||
className={privacySwitchClasses}
|
||||
onChange={this.privacyChange}
|
||||
/>
|
||||
<span className="dib f9 white-d inter ml3">Private</span>
|
||||
<p className="f9 gray2 pt1" style={{ paddingLeft: 40 }}>
|
||||
Users will have to be invited to join
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={this.onClickCreate.bind(this)}
|
||||
className={createClasses}
|
||||
|
@ -1,40 +1,17 @@
|
||||
import React, { Component } from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Welcome from './lib/welcome';
|
||||
import { alphabetiseAssociations } from '../../../lib/util';
|
||||
import { SidebarInvite } from './lib/sidebar-invite';
|
||||
import { GroupItem } from './lib/group-item';
|
||||
import { ShipSearchInput } from './lib/ship-search';
|
||||
|
||||
export class Sidebar extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
dmOverlay: false
|
||||
};
|
||||
}
|
||||
|
||||
onClickNew() {
|
||||
this.props.history.push('/~chat/new');
|
||||
}
|
||||
|
||||
onClickDm() {
|
||||
this.setState(({ dmOverlay }) => ({ dmOverlay: !dmOverlay }) );
|
||||
}
|
||||
|
||||
onClickJoin() {
|
||||
this.props.history.push('/~chat/join');
|
||||
}
|
||||
|
||||
goDm(ship) {
|
||||
this.setState({ dmOverlay: false }, () => {
|
||||
this.props.history.push(`/~chat/new/dm/~${ship}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
const { props } = this;
|
||||
|
||||
const selectedGroups = props.selectedGroups ? props.selectedGroups : [];
|
||||
|
||||
@ -60,12 +37,12 @@ export class Sidebar extends Component {
|
||||
groupedChannels[path] = [box];
|
||||
}
|
||||
} else {
|
||||
if (groupedChannels['/~/']) {
|
||||
const array = groupedChannels['/~/'];
|
||||
if (groupedChannels['dm']) {
|
||||
const array = groupedChannels['dm'];
|
||||
array.push(box);
|
||||
groupedChannels['/~/'] = array;
|
||||
groupedChannels['dm'] = array;
|
||||
} else {
|
||||
groupedChannels['/~/'] = [box];
|
||||
groupedChannels['dm'] = [box];
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -109,29 +86,21 @@ export class Sidebar extends Component {
|
||||
/>
|
||||
);
|
||||
});
|
||||
if (groupedChannels['/~/'] && groupedChannels['/~/'].length !== 0) {
|
||||
if (groupedChannels['dm'] && groupedChannels['dm'].length !== 0) {
|
||||
groupedItems.push(
|
||||
<GroupItem
|
||||
association={'/~/'}
|
||||
association={'dm'}
|
||||
chatMetadata={chatAssoc}
|
||||
channels={groupedChannels['/~/']}
|
||||
channels={groupedChannels['dm']}
|
||||
inbox={props.inbox}
|
||||
station={props.station}
|
||||
unreads={props.unreads}
|
||||
index={'/~/'}
|
||||
key={'/~/'}
|
||||
index={'dm'}
|
||||
key={'dm'}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const candidates = state.dmOverlay
|
||||
? _.chain(this.props.contacts)
|
||||
.values()
|
||||
.map(_.keys)
|
||||
.flatten()
|
||||
.uniq()
|
||||
.value()
|
||||
: [];
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -143,33 +112,7 @@ export class Sidebar extends Component {
|
||||
className="dib f9 pointer green2 gray4-d mr4"
|
||||
onClick={this.onClickNew.bind(this)}
|
||||
>
|
||||
New Chat
|
||||
</a>
|
||||
|
||||
<div className="dib relative mr4">
|
||||
{ state.dmOverlay && (
|
||||
<ShipSearchInput
|
||||
className="absolute"
|
||||
contacts={{}}
|
||||
candidates={candidates}
|
||||
onSelect={this.goDm.bind(this)}
|
||||
onClear={this.onClickDm.bind(this)}
|
||||
|
||||
/>
|
||||
)}
|
||||
<a
|
||||
className="f9 pointer green2 gray4-d"
|
||||
onClick={this.onClickDm.bind(this)}
|
||||
>
|
||||
DM
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<a
|
||||
className="dib f9 pointer gray4-d"
|
||||
onClick={this.onClickJoin.bind(this)}
|
||||
>
|
||||
Join Chat
|
||||
New Group Chat
|
||||
</a>
|
||||
</div>
|
||||
<div className="overflow-y-auto h-100">
|
||||
|
Loading…
Reference in New Issue
Block a user