mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-03 02:35:52 +03:00
chat-js: added contacts metadata to chat
This commit is contained in:
parent
a9434743a0
commit
61709260a8
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -117,6 +117,7 @@ class UrbitApi {
|
||||
};
|
||||
|
||||
this.action("chat-hook", "json", data);
|
||||
data.message.envelope.author = data.message.envelope.author.substr(1);
|
||||
this.addPendingMessage(data.message);
|
||||
}
|
||||
|
||||
|
@ -207,6 +207,7 @@ export class ChatScreen extends Component {
|
||||
<Message
|
||||
key={msg.uid}
|
||||
msg={msg}
|
||||
contacts={props.contacts}
|
||||
renderSigil={renderSigil}
|
||||
paddingTop={paddingTop}
|
||||
paddingBot={paddingBot}
|
||||
@ -218,7 +219,9 @@ export class ChatScreen extends Component {
|
||||
let group = Array.from(props.group.values());
|
||||
|
||||
let isinPopout = this.props.popout ? "popout/" : "";
|
||||
|
||||
|
||||
let ownerContact = (window.ship in props.contacts)
|
||||
? props.contacts[window.ship] : false;
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -268,6 +271,7 @@ export class ChatScreen extends Component {
|
||||
numMsgs={lastMsgNum}
|
||||
station={state.station}
|
||||
owner={deSig(props.match.params.ship)}
|
||||
ownerContact={ownerContact}
|
||||
permissions={props.permissions}
|
||||
placeholder="Message..."
|
||||
/>
|
||||
|
@ -6,7 +6,7 @@ import classnames from 'classnames';
|
||||
|
||||
import { Sigil } from '/components/lib/icons/sigil';
|
||||
|
||||
import { uuid } from '/lib/util';
|
||||
import { uuid, uxToHex } from '/lib/util';
|
||||
|
||||
|
||||
export class ChatInput extends Component {
|
||||
@ -153,6 +153,10 @@ export class ChatInput extends Component {
|
||||
}
|
||||
|
||||
readOnlyRender() {
|
||||
const { props } = this;
|
||||
let color = !!props.ownerContact
|
||||
? uxToHex(props.ownerContact.color) : '#000000';
|
||||
|
||||
return (
|
||||
<div className="pa3 cf flex black bt b--gray4 o-50">
|
||||
<div className="fl" style={{
|
||||
@ -160,7 +164,7 @@ export class ChatInput extends Component {
|
||||
flexBasis: 24,
|
||||
height: 24
|
||||
}}>
|
||||
<Sigil ship={window.ship} size={24} color="#4330FC" />
|
||||
<Sigil ship={window.ship} size={24} color={`#${color}`} />
|
||||
</div>
|
||||
<div className="fr h-100 flex" style={{ flexGrow: 1, height: 28, paddingTop: 6, resize: "none" }}>
|
||||
<p className="pl3">This chat is read only and you cannot post.</p>
|
||||
@ -172,6 +176,8 @@ export class ChatInput extends Component {
|
||||
writeAccessRender() {
|
||||
const { props, state } = this;
|
||||
|
||||
let color = !!props.ownerContact
|
||||
? uxToHex(props.ownerContact.color) : '#000000';
|
||||
this.bindShortcuts();
|
||||
|
||||
return (
|
||||
@ -183,7 +189,7 @@ export class ChatInput extends Component {
|
||||
flexBasis: 24,
|
||||
height: 24
|
||||
}}>
|
||||
<Sigil ship={window.ship} size={24} color="#4330FC" />
|
||||
<Sigil ship={window.ship} size={24} color={`#${color}`} />
|
||||
</div>
|
||||
<div className="fr h-100 flex bg-gray0-d" style={{ flexGrow: 1 }}>
|
||||
<textarea
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { Sigil } from '/components/lib/icons/sigil';
|
||||
import { uxToHex } from '/lib/util';
|
||||
|
||||
|
||||
export class MemberElement extends Component {
|
||||
@ -33,15 +34,16 @@ export class MemberElement extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
let name = !!props.contact
|
||||
? `${props.contact.nickname} (~${props.ship})` : `~${props.ship}`;
|
||||
let color = !!props.contact ? uxToHex(props.contact.color) : '000000';
|
||||
|
||||
return (
|
||||
<div className="flex mb2">
|
||||
<Sigil ship={props.ship} size={32} />
|
||||
<p
|
||||
className={
|
||||
<Sigil ship={props.ship} size={32} color={`#${color}`} />
|
||||
<p className={
|
||||
"w-70 mono list-ship dib v-mid black white-d ml2 nowrap f8"
|
||||
}>
|
||||
~{props.ship}
|
||||
</p>
|
||||
}>{name}</p>
|
||||
{actionElem}
|
||||
</div>
|
||||
);
|
||||
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
||||
import { Sigil } from '/components/lib/icons/sigil';
|
||||
import classnames from 'classnames';
|
||||
import { Route, Link } from 'react-router-dom'
|
||||
import { uxToHex } from '/lib/util';
|
||||
import urbitOb from 'urbit-ob';
|
||||
import moment from 'moment';
|
||||
import _ from 'lodash';
|
||||
@ -160,6 +161,15 @@ export class Message extends Component {
|
||||
if (props.renderSigil) {
|
||||
let timestamp = moment.unix(props.msg.when / 1000).format('hh:mm a');
|
||||
|
||||
let contact = !!(props.msg.author in props.contacts)
|
||||
? props.contacts[props.msg.author] : false;
|
||||
let name = props.msg.author;
|
||||
let color = "#000000";
|
||||
if (contact) {
|
||||
name = contact.nickname;
|
||||
color = `#${uxToHex(contact.color)}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
@ -172,19 +182,13 @@ export class Message extends Component {
|
||||
<Sigil
|
||||
ship={props.msg.author}
|
||||
size={24}
|
||||
color={((props.msg.author === window.ship)
|
||||
|| (props.msg.author.substr(1) === window.ship))
|
||||
? "#4330FC" : "#000000"}
|
||||
/>
|
||||
color={color} />
|
||||
</div>
|
||||
<div
|
||||
className="fr clamp-message white-d"
|
||||
style={{ flexGrow: 1, marginTop: -8 }}>
|
||||
<div className="hide-child" style={paddingTop}>
|
||||
<p className="v-mid mono f9 gray2 dib mr3">
|
||||
{props.msg.author.slice(0, 1) === "~" ? "" : "~"}
|
||||
{props.msg.author}
|
||||
</p>
|
||||
<p className="v-mid mono f9 gray2 dib mr3">{name}</p>
|
||||
<p className="v-mid mono f9 gray2 dib">{timestamp}</p>
|
||||
<p className="v-mid mono f9 ml2 gray2 dib child dn-s">{datestamp}</p>
|
||||
</div>
|
||||
|
@ -50,10 +50,14 @@ export class MemberScreen extends Component {
|
||||
}
|
||||
|
||||
let writeListMembers = writeGroup.map((mem) => {
|
||||
let contact = (mem in props.contacts)
|
||||
? props.contacts[mem] : false;
|
||||
|
||||
return (
|
||||
<MemberElement
|
||||
key={mem}
|
||||
owner={deSig(props.match.params.ship)}
|
||||
contact={contact}
|
||||
ship={mem}
|
||||
path={`/chat${state.station}/write`}
|
||||
kind={props.write.kind}
|
||||
@ -62,10 +66,14 @@ export class MemberScreen extends Component {
|
||||
});
|
||||
|
||||
let readListMembers = readGroup.map((mem) => {
|
||||
let contact = (mem in props.contacts)
|
||||
? props.contacts[mem] : false;
|
||||
|
||||
return (
|
||||
<MemberElement
|
||||
key={mem}
|
||||
owner={deSig(props.match.params.ship)}
|
||||
contact={contact}
|
||||
ship={mem}
|
||||
path={`/chat${state.station}/read`}
|
||||
kind={props.read.kind}
|
||||
@ -73,7 +81,7 @@ export class MemberScreen extends Component {
|
||||
);
|
||||
});
|
||||
|
||||
let isinPopout = this.props.popout ? "popout/" : "";
|
||||
let isinPopout = this.props.popout ? "popout/" : "";
|
||||
|
||||
return (
|
||||
<div className="h-100 w-100 overflow-x-hidden flex flex-column white-d">
|
||||
|
@ -51,6 +51,8 @@ export class Root extends Component {
|
||||
let invites = '/chat' in state.invites ?
|
||||
state.invites['/chat'] : {};
|
||||
|
||||
let contacts = !!state.contacts ? state.contacts : {};
|
||||
|
||||
const renderChannelSidebar = (props) => (
|
||||
<Sidebar
|
||||
inbox={state.inbox}
|
||||
@ -139,6 +141,11 @@ export class Root extends Component {
|
||||
envelopes: []
|
||||
};
|
||||
|
||||
/*let defaultContacts = ('/~/default' in contacts)
|
||||
? contacts['/~/default'] : {};*/
|
||||
let roomContacts = (station in contacts)
|
||||
? contacts[station] : {};
|
||||
|
||||
let write = state.groups[`/chat${station}/write`] || new Set([]);
|
||||
|
||||
let popout = props.match.url.includes("/popout/");
|
||||
@ -158,6 +165,7 @@ export class Root extends Component {
|
||||
envelopes={mailbox.envelopes}
|
||||
inbox={state.inbox}
|
||||
group={write}
|
||||
contacts={roomContacts}
|
||||
permissions={state.permissions}
|
||||
pendingMessages={state.pendingMessages}
|
||||
popout={popout}
|
||||
@ -183,6 +191,9 @@ export class Root extends Component {
|
||||
};
|
||||
let popout = props.match.url.includes("/popout/");
|
||||
|
||||
let roomContacts = (station in contacts)
|
||||
? contacts[station] : {};
|
||||
|
||||
return (
|
||||
<Skeleton
|
||||
sidebarHideOnMobile={true}
|
||||
@ -195,6 +206,7 @@ export class Root extends Component {
|
||||
api={api}
|
||||
read={read}
|
||||
write={write}
|
||||
contacts={roomContacts}
|
||||
permissions={state.permissions}
|
||||
popout={popout}
|
||||
sidebarShown={state.sidebarShown}
|
||||
|
@ -61,3 +61,13 @@ export function dateToDa(d, mil) {
|
||||
export function deSig(ship) {
|
||||
return ship.replace('~', '');
|
||||
}
|
||||
|
||||
export function uxToHex(ux) {
|
||||
if (ux.length > 2 && ux.substr(0,2) === '0x') {
|
||||
let value = ux.substr(2).replace('.', '').padStart(6, '0');
|
||||
return value;
|
||||
}
|
||||
|
||||
let value = ux.replace('.', '').padStart(6, '0');
|
||||
return value;
|
||||
}
|
||||
|
68
pkg/interface/chat/src/js/reducers/contact-update.js
Normal file
68
pkg/interface/chat/src/js/reducers/contact-update.js
Normal file
@ -0,0 +1,68 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class ContactUpdateReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'contact-update', false);
|
||||
if (data) {
|
||||
this.create(data, state);
|
||||
this.delete(data, state);
|
||||
this.add(data, state);
|
||||
this.remove(data, state);
|
||||
this.edit(data, state);
|
||||
}
|
||||
}
|
||||
|
||||
create(json, state) {
|
||||
let data = _.get(json, 'create', false);
|
||||
if (data) {
|
||||
state.contacts[data.path] = {};
|
||||
}
|
||||
}
|
||||
|
||||
delete(json, state) {
|
||||
let data = _.get(json, 'delete', false);
|
||||
if (data) {
|
||||
delete state.contacts[data.path];
|
||||
}
|
||||
}
|
||||
|
||||
add(json, state) {
|
||||
let data = _.get(json, 'add', false);
|
||||
if (
|
||||
data &&
|
||||
(data.path in state.contacts)
|
||||
) {
|
||||
state.contacts[data.path][data.ship] = data.contact;
|
||||
}
|
||||
}
|
||||
|
||||
remove(json, state) {
|
||||
let data = _.get(json, 'remove', false);
|
||||
if (
|
||||
data &&
|
||||
(data.path in state.contacts) &&
|
||||
(data.ship in state.contacts[data.path])
|
||||
) {
|
||||
delete state.contacts[data.path][data.ship];
|
||||
}
|
||||
}
|
||||
|
||||
edit(json, state) {
|
||||
let data = _.get(json, 'edit', false);
|
||||
if (
|
||||
data &&
|
||||
(data.path in state.contacts) &&
|
||||
(data.ship in state.contacts[data.path])
|
||||
) {
|
||||
let edit = Object.keys(data['edit-field']);
|
||||
if (edit.length !== 1) {
|
||||
return;
|
||||
}
|
||||
state.contacts[data.path][data.ship][edit[0]] =
|
||||
data['edit-field'][edit[0]];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,6 +29,11 @@ export class InitialReducer {
|
||||
if (data) {
|
||||
state.invites = data;
|
||||
}
|
||||
|
||||
data = _.get(json, 'contact-initial', false);
|
||||
if (data) {
|
||||
state.contacts = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { InitialReducer } from '/reducers/initial';
|
||||
import { GroupUpdateReducer } from '/reducers/group-update';
|
||||
import { ContactUpdateReducer } from '/reducers/contact-update';
|
||||
import { ChatUpdateReducer } from '/reducers/chat-update';
|
||||
import { InviteUpdateReducer } from '/reducers/invite-update';
|
||||
import { PermissionUpdateReducer } from '/reducers/permission-update';
|
||||
@ -11,6 +12,7 @@ class Store {
|
||||
this.state = {
|
||||
inbox: {},
|
||||
groups: {},
|
||||
contacts: {},
|
||||
permissions: {},
|
||||
invites: {},
|
||||
spinner: false,
|
||||
@ -21,6 +23,7 @@ class Store {
|
||||
this.initialReducer = new InitialReducer();
|
||||
this.groupUpdateReducer = new GroupUpdateReducer();
|
||||
this.permissionUpdateReducer = new PermissionUpdateReducer();
|
||||
this.contactUpdateReducer = new ContactUpdateReducer();
|
||||
this.chatUpdateReducer = new ChatUpdateReducer();
|
||||
this.inviteUpdateReducer = new InviteUpdateReducer();
|
||||
this.localReducer = new LocalReducer();
|
||||
@ -38,6 +41,7 @@ class Store {
|
||||
this.initialReducer.reduce(json, this.state);
|
||||
this.groupUpdateReducer.reduce(json, this.state);
|
||||
this.permissionUpdateReducer.reduce(json, this.state);
|
||||
this.contactUpdateReducer.reduce(json, this.state);
|
||||
this.chatUpdateReducer.reduce(json, this.state);
|
||||
this.inviteUpdateReducer.reduce(json, this.state);
|
||||
this.localReducer.reduce(json, this.state);
|
||||
|
@ -30,6 +30,10 @@ export class Subscription {
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this),
|
||||
this.handleQuitAndResubscribe.bind(this));
|
||||
api.bind('/primary', 'PUT', api.authTokens.ship, 'contact-view',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this),
|
||||
this.handleQuitAndResubscribe.bind(this));
|
||||
}
|
||||
|
||||
handleEvent(diff) {
|
||||
|
Loading…
Reference in New Issue
Block a user