From 7d3a7a166bdcc946527d3551fbff93327bb8712a Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 2 Jul 2020 11:12:54 +1000 Subject: [PATCH] chat-js: update frontend for new group-store --- pkg/interface/src/apps/chat/app.tsx | 50 ++++------ .../src/apps/chat/components/chat.tsx | 5 +- .../src/apps/chat/components/join.js | 10 +- .../chat/components/lib/invite-element.js | 2 +- .../src/apps/chat/components/member.js | 93 +++++++------------ .../src/apps/chat/components/new-dm.js | 29 +++--- pkg/interface/src/apps/chat/components/new.js | 59 ++++++++---- .../src/apps/chat/components/settings.js | 4 +- .../src/apps/chat/components/sidebar.js | 26 +++--- 9 files changed, 129 insertions(+), 149 deletions(-) diff --git a/pkg/interface/src/apps/chat/app.tsx b/pkg/interface/src/apps/chat/app.tsx index 371912ef6d..df0d0faa71 100644 --- a/pkg/interface/src/apps/chat/app.tsx +++ b/pkg/interface/src/apps/chat/app.tsx @@ -15,6 +15,7 @@ import { PatpNoSig } from '../../types/noun'; import GlobalApi from '../../api/global'; import { StoreState } from '../../store/type'; import GlobalSubscription from '../../subscription/global'; +import {groupBunts} from '../../types/group-update'; type ChatAppProps = StoreState & { ship: PatpNoSig; @@ -97,11 +98,11 @@ export default class ChatApp extends React.Component { sidebarShown, inbox, contacts, - permissions, chatSynced, api, chatInitialized, - pendingMessages + pendingMessages, + groups } = props; const renderChannelSidebar = (props, station?) => ( @@ -161,7 +162,7 @@ export default class ChatApp extends React.Component { { { /> { let station = `/${props.match.params.ship}/${props.match.params.station}`; const sig = props.match.url.includes('/~/'); - if (sig) { - station = '/~' + station; - } return ( { const association = station in associations['chat'] ? associations.chat[station] : {}; - const permission = - station in permissions - ? permissions[station] - : { - who: new Set([]), - kind: 'white' - }; + const group = groups[association['group-path']] || groupBunts.group(); + const popout = props.match.url.includes('/popout/'); return ( @@ -285,7 +278,7 @@ export default class ChatApp extends React.Component { envelopes={mailbox.envelopes} inbox={inbox} contacts={roomContacts} - permission={permission} + group={group} pendingMessages={pendingMessages} s3={s3} popout={popout} @@ -302,20 +295,14 @@ export default class ChatApp extends React.Component { path="/~chat/(popout)?/members/(~)?/:ship/:station+" render={(props) => { let station = `/${props.match.params.ship}/${props.match.params.station}`; - const sig = props.match.url.includes('/~/'); - if (sig) { - station = '/~' + station; - } - const permission = permissions[station] || { - kind: '', - who: new Set([]) - }; const popout = props.match.url.includes('/popout/'); const association = station in associations['chat'] ? associations.chat[station] : {}; + const groupPath = association['group-path']; + const group = groups[groupPath] || {}; return ( { @@ -352,13 +340,9 @@ export default class ChatApp extends React.Component { const popout = props.match.url.includes('/popout/'); - const permission = permissions[station] || { - kind: '', - who: new Set([]) - }; - const association = station in associations['chat'] ? associations.chat[station] : {}; + const group = groups[association['group-path']] || groupBunts.group(); return ( { {...props} station={station} association={association} - permission={permission} - permissions={permissions || {}} + groups={groups || {}} + group={group} contacts={contacts || {}} associations={associations.contacts} api={api} diff --git a/pkg/interface/src/apps/chat/components/chat.tsx b/pkg/interface/src/apps/chat/components/chat.tsx index cd943f2ef6..dccd4ea7e3 100644 --- a/pkg/interface/src/apps/chat/components/chat.tsx +++ b/pkg/interface/src/apps/chat/components/chat.tsx @@ -19,6 +19,7 @@ import { Contacts } from "../../../types/contact-update"; import { Path, Patp } from "../../../types/noun"; import GlobalApi from "../../../api/global"; import { Association } from "../../../types/metadata-update"; +import {Group} from "../../../types/group-update"; function getNumPending(props: any) { const result = props.pendingMessages.has(props.station) @@ -79,7 +80,7 @@ type ChatScreenProps = RouteComponentProps<{ length: number; inbox: Inbox; contacts: Contacts; - permission: any; + group: Group; pendingMessages: Map; s3: any; popout: boolean; @@ -503,7 +504,7 @@ export class ChatScreen extends Component { const lastMsgNum = messages.length > 0 ? messages.length : 0; - const group = Array.from(props.permission.who.values()); + const group = Array.from(props.group.members); const isinPopout = props.popout ? "popout/" : ""; diff --git a/pkg/interface/src/apps/chat/components/join.js b/pkg/interface/src/apps/chat/components/join.js index 333567dcfb..48db1f4953 100644 --- a/pkg/interface/src/apps/chat/components/join.js +++ b/pkg/interface/src/apps/chat/components/join.js @@ -27,12 +27,10 @@ export class JoinScreen extends Component { props.autoJoin !== '/~/undefined/undefined') && (props.api && (prevProps?.api !== props.api))) { let station = props.autoJoin.split('/'); - const sig = props.autoJoin.includes('/~/'); - const ship = sig ? station[2] : station[1]; + const ship = station[1]; if ( station.length < 2 || - (Boolean(sig) && station.length < 3) || !urbitOb.isValidPatp(ship) ) { this.setState({ @@ -59,12 +57,10 @@ export class JoinScreen extends Component { const { props, state } = this; let station = state.station.split('/'); - const sig = state.station.includes('/~/'); - const ship = sig ? station[2] : station[1]; + const ship = station[1]; if ( station.length < 2 || - (Boolean(sig) && station.length < 3) || !urbitOb.isValidPatp(ship) ) { this.setState({ @@ -84,7 +80,7 @@ export class JoinScreen extends Component { stationChange(event) { this.setState({ - station: `/${event.target.value}` + station: `/${event.target.value.trim()}` }); } diff --git a/pkg/interface/src/apps/chat/components/lib/invite-element.js b/pkg/interface/src/apps/chat/components/lib/invite-element.js index bdc709377f..d3f88e79e6 100644 --- a/pkg/interface/src/apps/chat/components/lib/invite-element.js +++ b/pkg/interface/src/apps/chat/components/lib/invite-element.js @@ -33,7 +33,7 @@ export class InviteElement extends Component { members: [], awaiting: true }, () => { - props.api.groups.add(aud, props.path).then(() => { + props.api.chatView.invite(props.path, aud).then(() => { this.setState({ awaiting: false }); }); }); diff --git a/pkg/interface/src/apps/chat/components/member.js b/pkg/interface/src/apps/chat/components/member.js index 4e073aa6bc..2ffb04461a 100644 --- a/pkg/interface/src/apps/chat/components/member.js +++ b/pkg/interface/src/apps/chat/components/member.js @@ -7,44 +7,23 @@ import { ChatTabBar } from './lib/chat-tabbar'; import { MemberElement } from './lib/member-element'; import { InviteElement } from './lib/invite-element'; import { SidebarSwitcher } from '../../../components/SidebarSwitch'; +import { GroupView } from '../../../components/Group'; +import { PatpNoSig } from '../../../types/noun'; export class MemberScreen extends Component { + constructor(props) { + super(props); + this.inviteShips = this.inviteShips.bind(this); + } + + inviteShips(ships) { + const { props } = this; + return props.api.chat.invite(props.station, ships.map(s => `~${s}`)); + } + render() { const { props } = this; - const perm = Array.from(props.permission.who.values()); - - let memberText = ''; - let modifyText = ''; - - if (props.permission.kind === 'black') { - memberText = 'Everyone banned from accessing this chat.'; - modifyText = 'Ban someone from accessing this chat.'; - } else if (props.permission.kind === 'white') { - memberText = 'Everyone with permission to access this chat.'; - modifyText = 'Invite someone to this chat.'; - } - - const contacts = (props.station in props.contacts) - ? props.contacts[props.station] : {}; - - const members = perm.map((mem) => { - const contact = (mem in contacts) - ? contacts[mem] : false; - - return ( - - ); - }); - const isinPopout = this.props.popout ? 'popout/' : ''; let title = props.station.substr(1); @@ -57,12 +36,12 @@ export class MemberScreen extends Component { } return ( -
+
- {'⟵ All Chats'} + {'⟵ All Chats'}
-

{title} @@ -88,30 +70,23 @@ export class MemberScreen extends Component {

-
-
-

Modify Permissions

-

{modifyText}

- {window.ship === deSig(props.match.params.ship) ? ( - - ) : null} -
-
-

Members

-

{memberText}

- {members} -
+
+ { props.association['group-path'] && ( + )}
); diff --git a/pkg/interface/src/apps/chat/components/new-dm.js b/pkg/interface/src/apps/chat/components/new-dm.js index 72b384e748..5d1bc39dff 100644 --- a/pkg/interface/src/apps/chat/components/new-dm.js +++ b/pkg/interface/src/apps/chat/components/new-dm.js @@ -1,7 +1,7 @@ -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 urbitOb from "urbit-ob"; export class NewDmScreen extends Component { constructor(props) { @@ -43,9 +43,9 @@ export class NewDmScreen extends Component { onClickCreate() { const { props, state } = this; - const station = `/~/~${window.ship}/dm--${state.ship}`; + const station = `/ship/~${window.ship}/dm--${state.ship}`; - const theirStation = `/~/~${state.ship}/dm--${window.ship}`; + const theirStation = `/ship/~${state.ship}/dm--${window.ship}`; if (station in props.inbox) { props.history.push(`/~chat/room${station}`); @@ -57,6 +57,8 @@ export class NewDmScreen extends Component { return; } + const aud = state.ship !== window.ship ? [`~${state.ship}`] : []; + this.setState( { station @@ -65,12 +67,13 @@ export class NewDmScreen extends Component { const groupPath = station; props.api.chat.create( `~${window.ship} <-> ~${state.ship}`, - '', + "", station, groupPath, - 'village', - state.ship !== window.ship ? [`~${state.ship}`] : [], - true + { invite: { pending: aud } }, + aud, + true, + false ); } ); @@ -80,12 +83,12 @@ export class NewDmScreen extends Component { return (
- {'⟵ All Chats'} + {"⟵ All Chats"}

New DM

diff --git a/pkg/interface/src/apps/chat/components/new.js b/pkg/interface/src/apps/chat/components/new.js index d6ba81b842..6c2caae431 100644 --- a/pkg/interface/src/apps/chat/components/new.js +++ b/pkg/interface/src/apps/chat/components/new.js @@ -14,7 +14,7 @@ export class NewScreen extends Component { idName: '', groups: [], ships: [], - security: 'channel', + privacy: 'open', idError: false, inviteError: false, allowHistory: true, @@ -27,6 +27,7 @@ export class NewScreen extends Component { 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) { @@ -65,13 +66,23 @@ export class NewScreen extends Component { createGroupChange(event) { if (event.target.checked) { this.setState({ - createGroup: Boolean(event.target.checked), - security: 'village' + createGroup: Boolean(event.target.checked) }); } else { this.setState({ - createGroup: Boolean(event.target.checked), - security: 'channel' + createGroup: Boolean(event.target.checked) + }); + } + } + + privacyChange(event) { + if (event.target.checked) { + this.setState({ + privacy: 'open' + }); + } else { + this.setState({ + privacy: 'invite' }); } } @@ -111,7 +122,7 @@ export class NewScreen extends Component { } }); - if(state.ships.length === 1 && state.security === 'village' && !state.createGroup) { + if(state.ships.length === 1 && state.privacy === 'invite' && !state.createGroup) { props.history.push(`/~chat/new/dm/${aud[0]}`); } @@ -128,6 +139,8 @@ export class NewScreen extends Component { this.textarea.value = ''; } + const policy = state.privacy === 'invite' ? { invite: { pending: aud } } : { open: { banRanks: [], banned: [] } }; + this.setState({ error: false, success: true, @@ -139,10 +152,10 @@ export class NewScreen extends Component { // 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}`; - } - let groupPath = appPath; + // if (!state.createGroup && state.groups.length === 0) { + // appPath = `/~${appPath}`; + // } + let groupPath = `/ship${appPath}`; if (state.groups.length > 0) { groupPath = state.groups[0]; } @@ -151,9 +164,10 @@ export class NewScreen extends Component { state.description, appPath, groupPath, - state.security, + policy, aud, - state.allowHistory + state.allowHistory, + state.createGroup ); submit.then(() => { this.setState({ awaiting: false }); @@ -164,12 +178,9 @@ export class NewScreen extends Component { render() { const { props, state } = this; - let inviteSwitchClasses = (state.security === 'village') + 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'; - if (state.createGroup) { - inviteSwitchClasses = inviteSwitchClasses + ' o-50'; - } const createGroupClasses = state.createGroup ? 'relative checked bg-green2 br3 h1 toggle v-mid z-0' @@ -211,8 +222,8 @@ export class NewScreen extends Component { } const groups = {}; - Object.keys(props.permissions).forEach((pem) => { - groups[pem] = props.permissions[pem].who; + Object.keys(props.groups).forEach((pem) => { + groups[pem] = props.groups[pem].members; }); return ( @@ -271,6 +282,18 @@ export class NewScreen extends Component { setInvite={this.setInvite} /> {createGroupToggle} +
+ + Private +

+ Users will have to be invited to join +

+