mirror of
https://github.com/urbit/shrub.git
synced 2024-12-29 07:03:37 +03:00
contacts: adding yourself to group works
This commit is contained in:
parent
8de18e4d4c
commit
aac3bd9678
@ -105,20 +105,37 @@
|
||||
++ poke-contact-action
|
||||
|= act=contact-action
|
||||
^- (quip card _state)
|
||||
?> ?=(%edit -.act)
|
||||
:: local
|
||||
:_ state
|
||||
?: (team:title our.bol src.bol)
|
||||
=/ ship (~(got by synced) path.act)
|
||||
=/ appl ?:(=(ship our.bol) %contact-store %contact-hook)
|
||||
[%pass / %agent [ship appl] %poke %contact-action !>(act)]~
|
||||
:: foreign
|
||||
=/ ship (~(got by synced) path.act)
|
||||
?. |(=(ship our.bol) =(src.bol ship.act)) ~
|
||||
:: scry group to check if ship is a member
|
||||
=/ =group (need (group-scry path.act))
|
||||
?. (~(has in group) ship) ~
|
||||
[%pass / %agent [our.bol %contact-store] %poke %contact-action !>(act)]~
|
||||
~& src+src.bol
|
||||
~& act+act
|
||||
|^
|
||||
?+ -.act !!
|
||||
%edit (process-action path.act ship.act act)
|
||||
%add (process-action path.act ship.act act)
|
||||
==
|
||||
::
|
||||
++ process-action
|
||||
|= [=path =ship act=contact-action]
|
||||
^- (quip card _state)
|
||||
:: local
|
||||
:_ state
|
||||
?: (team:title our.bol src.bol)
|
||||
~& 'local'
|
||||
=/ shp (~(got by synced) path)
|
||||
=/ appl ?:(=(shp our.bol) %contact-store %contact-hook)
|
||||
~& shp+shp
|
||||
~& appl+appl
|
||||
[%pass / %agent [shp appl] %poke %contact-action !>(act)]~
|
||||
~& 'foreign'
|
||||
:: foreign
|
||||
=/ shp (~(got by synced) path)
|
||||
~& shp+shp
|
||||
?. |(=(shp our.bol) =(src.bol ship)) ~
|
||||
:: scry group to check if ship is a member
|
||||
=/ =group (need (group-scry path))
|
||||
~& group+group
|
||||
?. (~(has in group) shp) ~
|
||||
[%pass / %agent [our.bol %contact-store] %poke %contact-action !>(act)]~
|
||||
--
|
||||
::
|
||||
++ poke-hook-action
|
||||
|= act=contact-hook-action
|
||||
@ -214,7 +231,9 @@
|
||||
^- (quip card _state)
|
||||
|^
|
||||
?: (team:title our.bol src.bol)
|
||||
~& update-local+fact
|
||||
(local fact)
|
||||
~& update-foreign+fact
|
||||
(foreign fact)
|
||||
::
|
||||
++ local
|
||||
@ -222,21 +241,22 @@
|
||||
^- (quip card _state)
|
||||
?+ -.fact [~ state]
|
||||
%add
|
||||
[(give-fact [%add path.fact ship.fact contact.fact]) state]
|
||||
[(give-fact path.fact [%add path.fact ship.fact contact.fact]) state]
|
||||
::
|
||||
%remove
|
||||
:_ state
|
||||
:- [%give %kick `[%contacts path.fact] `ship.fact]
|
||||
(give-fact [%remove path.fact ship.fact])
|
||||
(give-fact path.fact [%remove path.fact ship.fact])
|
||||
::
|
||||
%edit
|
||||
[(give-fact [%edit path.fact ship.fact edit-field.fact]) state]
|
||||
[(give-fact path.fact [%edit path.fact ship.fact edit-field.fact]) state]
|
||||
==
|
||||
::
|
||||
++ give-fact
|
||||
|= update=contact-update
|
||||
|= [=path update=contact-update]
|
||||
^- (list card)
|
||||
[%give %fact ~ %contact-update !>(update)]~
|
||||
~& 'give-fact'
|
||||
[%give %fact `[%contacts path] %contact-update !>(update)]~
|
||||
::
|
||||
++ foreign
|
||||
|= fact=contact-update
|
||||
@ -256,17 +276,17 @@
|
||||
::
|
||||
%add
|
||||
=/ owner (~(got by synced) path.fact)
|
||||
?> =(owner src.bol)
|
||||
?> |(=(owner src.bol) =(src.bol ship.fact))
|
||||
[~[(contact-poke [%add path.fact ship.fact contact.fact])] state]
|
||||
::
|
||||
%remove
|
||||
=/ owner (~(got by synced) path.fact)
|
||||
?> =(owner src.bol)
|
||||
?> |(=(owner src.bol) =(src.bol ship.fact))
|
||||
[~[(contact-poke [%remove path.fact ship.fact])] state]
|
||||
::
|
||||
%edit
|
||||
=/ owner (~(got by synced) path.fact)
|
||||
?> =(owner src.bol)
|
||||
?> |(=(owner src.bol) =(src.bol ship.fact))
|
||||
[~[(contact-poke [%edit path.fact ship.fact edit-field.fact])] state]
|
||||
==
|
||||
--
|
||||
@ -330,7 +350,6 @@
|
||||
++ contact-poke
|
||||
|= act=contact-action
|
||||
^- card
|
||||
~& contact+act
|
||||
[%pass / %agent [our.bol %contact-store] %poke %contact-action !>(act)]
|
||||
::
|
||||
++ contacts-scry
|
||||
|
@ -36,6 +36,7 @@
|
||||
|= [=mark =vase]
|
||||
^- (quip card _this)
|
||||
?> (team:title our.bowl src.bowl)
|
||||
~& %store-poke
|
||||
=^ cards state
|
||||
?+ mark (on-poke:def mark vase)
|
||||
::%json (poke-json:cc !<(json vase))
|
||||
@ -106,6 +107,7 @@
|
||||
|= action=contact-action
|
||||
^- (quip card _state)
|
||||
?> (team:title our.bol src.bol)
|
||||
~& store+action
|
||||
?- -.action
|
||||
%create (handle-create +.action)
|
||||
%delete (handle-delete +.action)
|
||||
|
@ -149,6 +149,12 @@
|
||||
:~ (group-poke [%remove [ship.act ~ ~] path.act])
|
||||
(contact-poke [%remove path.act ship.act])
|
||||
==
|
||||
::
|
||||
%share
|
||||
:: determine whether to send to our contact-hook or foreign
|
||||
:: send contact-action to contact-hook with %add action
|
||||
~& share+act
|
||||
[(share-poke recipient.act [%add path.act ship.act contact.act])]~
|
||||
==
|
||||
++ poke-handle-http-request
|
||||
|= =inbound-request:eyre
|
||||
@ -181,6 +187,11 @@
|
||||
^- card
|
||||
[%pass / %agent [our.bol %contact-hook] %poke %contact-hook-action !>(act)]
|
||||
::
|
||||
++ share-poke
|
||||
|= [=ship act=contact-action]
|
||||
^- card
|
||||
[%pass / %agent [ship %contact-hook] %poke %contact-action !>(act)]
|
||||
::
|
||||
++ launch-poke
|
||||
|= act=[@tas path @t]
|
||||
^- card
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -103,6 +103,7 @@
|
||||
[%delete delete]
|
||||
[%add add]
|
||||
[%remove remove]
|
||||
[%share share]
|
||||
==
|
||||
::
|
||||
++ create
|
||||
@ -124,6 +125,14 @@
|
||||
:~ [%path pa]
|
||||
[%ship (su ;~(pfix sig fed:ag))]
|
||||
==
|
||||
::
|
||||
++ share
|
||||
%- ot
|
||||
:~ [%recipient (su ;~(pfix sig fed:ag))]
|
||||
[%path pa]
|
||||
[%ship (su ;~(pfix sig fed:ag))]
|
||||
[%contact cont]
|
||||
==
|
||||
--
|
||||
::
|
||||
++ json-to-action
|
||||
|
@ -1,17 +1,20 @@
|
||||
/- *contact-store
|
||||
|%
|
||||
+$ contact-view-action
|
||||
$% :: create in both groups and contacts
|
||||
$% :: %create: create in both groups and contacts
|
||||
::
|
||||
[%create =path ships=(set ship)]
|
||||
:: add to both groups and contacts
|
||||
:: %add: add to groups and send invites
|
||||
::
|
||||
[%add =path ships=(set ship)]
|
||||
:: remove from both groups and contacts
|
||||
:: %remove: remove from both groups and contacts
|
||||
::
|
||||
[%remove =path =ship]
|
||||
:: delete in both groups and contacts
|
||||
:: %delete: delete in both groups and contacts
|
||||
::
|
||||
[%delete =path]
|
||||
[%delete =path]
|
||||
:: %share: send %add contact-action to to recipient's contact-hook
|
||||
::
|
||||
[%share recipient=ship =path =ship =contact]
|
||||
==
|
||||
--
|
||||
|
@ -18,7 +18,8 @@ class UrbitApi {
|
||||
create: this.contactCreate.bind(this),
|
||||
delete: this.contactDelete.bind(this),
|
||||
add: this.contactAdd.bind(this),
|
||||
remove: this.contactRemove.bind(this)
|
||||
remove: this.contactRemove.bind(this),
|
||||
share: this.contactShare.bind(this)
|
||||
};
|
||||
|
||||
this.invite = {
|
||||
@ -76,6 +77,15 @@ class UrbitApi {
|
||||
this.contactViewAction({ add: { path, ships }});
|
||||
}
|
||||
|
||||
contactShare(recipient, path, ship, contact) {
|
||||
console.log(recipient, path, ship, contact);
|
||||
this.contactViewAction({
|
||||
share: {
|
||||
recipient, path, ship, contact
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
contactDelete(path) {
|
||||
this.contactViewAction({ delete: { path }});
|
||||
}
|
||||
|
@ -1,22 +1,23 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Sigil } from './icons/sigil';
|
||||
import { uxToHex } from '/lib/util';
|
||||
|
||||
import { api } from '/api';
|
||||
import { Route, Link } from 'react-router-dom';
|
||||
import { EditElement } from '/components/lib/edit-element';
|
||||
import { uxToHex } from '/lib/util';
|
||||
|
||||
export class ContactCard extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
edit: props.share,
|
||||
colorToSet: "",
|
||||
nickNameToSet: "",
|
||||
emailToSet: "",
|
||||
phoneToSet: "",
|
||||
websiteToSet: "",
|
||||
notesToSet: ""
|
||||
}
|
||||
colorToSet: null,
|
||||
nickNameToSet: null,
|
||||
emailToSet: null,
|
||||
phoneToSet: null,
|
||||
websiteToSet: null,
|
||||
notesToSet: null
|
||||
};
|
||||
this.editToggle = this.editToggle.bind(this);
|
||||
this.sigilColorSet = this.sigilColorSet.bind(this);
|
||||
this.nickNameToSet = this.nickNameToSet.bind(this);
|
||||
@ -25,51 +26,52 @@ export class ContactCard extends Component {
|
||||
this.websiteToSet = this.websiteToSet.bind(this);
|
||||
this.notesToSet = this.notesToSet.bind(this);
|
||||
this.setField = this.setField.bind(this);
|
||||
this.shareWithGroup = this.shareWithGroup.bind(this);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const { props } = this;
|
||||
// sigil color updates are done by keystroke parsing on update
|
||||
// other field edits are exclusively handled by setField()
|
||||
let currentColor = (props.contact.color) ? props.contact.color : "0x0";
|
||||
let currentHex = uxToHex(currentColor);
|
||||
let hexExp = /#?([0-9A-Fa-f]{6})/
|
||||
let currentColor = (props.contact.color) ? props.contact.color : "000000";
|
||||
currentColor = uxToHex(currentColor);
|
||||
let hexExp = /([0-9A-Fa-f]{6})/
|
||||
let hexTest = hexExp.exec(this.state.colorToSet);
|
||||
|
||||
if ((hexTest) && (hexTest[1] !== currentHex)) {
|
||||
let ship = "~" + props.ship;
|
||||
api.contactEdit(props.path, ship, {color: hexTest[1]});
|
||||
if (hexTest && (hexTest[1] !== currentColor) && !props.share) {
|
||||
api.contactEdit(props.path, `~${props.ship}`, {color: hexTest[1]});
|
||||
}
|
||||
}
|
||||
|
||||
editToggle() {
|
||||
const { props } = this;
|
||||
let editSwitch = this.state.edit;
|
||||
editSwitch = !editSwitch;
|
||||
this.setState({edit: editSwitch});
|
||||
}
|
||||
|
||||
emailToSet(event) {
|
||||
this.setState({ emailToSet: event.target.value });
|
||||
emailToSet(value) {
|
||||
this.setState({ emailToSet: value });
|
||||
}
|
||||
|
||||
nickNameToSet(event) {
|
||||
this.setState({ nickNameToSet: event.target.value });
|
||||
nickNameToSet(value) {
|
||||
this.setState({ nickNameToSet: value });
|
||||
}
|
||||
|
||||
notesToSet(event) {
|
||||
this.setState({ notesToSet: event.target.value });
|
||||
notesToSet(value) {
|
||||
this.setState({ notesToSet: value });
|
||||
}
|
||||
|
||||
phoneToSet(event) {
|
||||
this.setState({ phoneToSet: event.target.value });
|
||||
phoneToSet(value) {
|
||||
this.setState({ phoneToSet: value });
|
||||
}
|
||||
|
||||
sigilColorSet(event) {
|
||||
this.setState({ colorToSet: event.target.value });
|
||||
sigilColorSet(value) {
|
||||
this.setState({ colorToSet: value });
|
||||
}
|
||||
|
||||
websiteToSet(event) {
|
||||
this.setState({ websiteToSet: event.target.value });
|
||||
websiteToSet(value) {
|
||||
this.setState({ websiteToSet: value });
|
||||
}
|
||||
|
||||
shipParser(ship) {
|
||||
@ -197,8 +199,49 @@ export class ContactCard extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
pickFunction(val, def) {
|
||||
if (val !== null) {
|
||||
return val;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
shareWithGroup() {
|
||||
const { props, state } = this;
|
||||
let defaultVal = props.share ? {
|
||||
nickname: props.rootIdentity.nickname,
|
||||
email: props.rootIdentity.email,
|
||||
phone: props.rootIdentity.phone,
|
||||
website: props.rootIdentity.website,
|
||||
notes: props.rootIdentity.notes,
|
||||
color: props.rootIdentity.color
|
||||
} : {
|
||||
nickname: props.contact.nickname,
|
||||
email: props.contact.email,
|
||||
phone: props.contact.phone,
|
||||
website: props.contact.website,
|
||||
notes: props.contact.notes,
|
||||
color: props.contact.color
|
||||
};
|
||||
|
||||
let contact = {
|
||||
nickname: this.pickFunction(state.nickNameToSet, defaultVal.nickname),
|
||||
email: this.pickFunction(state.emailToSet, defaultVal.email),
|
||||
phone: this.pickFunction(state.phoneToSet, defaultVal.phone),
|
||||
website: this.pickFunction(state.websiteToSet, defaultVal.website),
|
||||
notes: this.pickFunction(state.notesToSet, defaultVal.notes),
|
||||
color: this.pickFunction(state.colorToSet, defaultVal.color),
|
||||
avatar: null
|
||||
};
|
||||
|
||||
api.contactView.share(
|
||||
`~${props.ship}`, props.path, `~${window.ship}`, contact
|
||||
);
|
||||
this.editToggle();
|
||||
}
|
||||
|
||||
renderEditCard() {
|
||||
const { props } = this;
|
||||
const { props, state } = this;
|
||||
// if this is our first edit in a new group, propagate from root identity
|
||||
let defaultValue = props.share ? {
|
||||
nickname: props.rootIdentity.nickname,
|
||||
@ -218,49 +261,52 @@ export class ContactCard extends Component {
|
||||
|
||||
let shipType = this.shipParser(props.ship);
|
||||
|
||||
let currentColor = !!defaultValue.color ? defaultValue.color : "0x0";
|
||||
let hexColor = uxToHex(currentColor);
|
||||
let defaultColor = !!defaultValue.color ? defaultValue.color : "000000";
|
||||
defaultColor = uxToHex(defaultColor);
|
||||
let currentColor = !!state.colorToSet ? state.colorToSet : defaultColor;
|
||||
currentColor = uxToHex(currentColor);
|
||||
|
||||
let sigilColor = "";
|
||||
let hasAvatar =
|
||||
'avatar' in props.contact && props.contact.avatar !== "TODO";
|
||||
|
||||
|
||||
if (!hasAvatar) {
|
||||
sigilColor = (
|
||||
<div className="tl mt4 mb4 w-auto ml-auto mr-auto"
|
||||
style={{ width: "fit-content" }}>
|
||||
<p className="f9 gray2 lh-copy">Sigil Color</p>
|
||||
style={{ width: "fit-content" }}>
|
||||
<p className="f9 gray2 lh-copy">Sigil Color</p>
|
||||
<textarea
|
||||
className="b--gray4 black f7 ba db pl2"
|
||||
onChange={this.sigilColorSet}
|
||||
defaultValue={"#" + hexColor}
|
||||
key={hexColor}
|
||||
style={{
|
||||
resize: "none",
|
||||
height: 40,
|
||||
paddingTop: 10,
|
||||
className="b--gray4 black f7 ba db pl2"
|
||||
onChange={this.sigilColorSet}
|
||||
defaultValue={defaultColor}
|
||||
key={"default" + defaultColor}
|
||||
style={{
|
||||
resize: "none",
|
||||
height: 40,
|
||||
paddingTop: 10,
|
||||
width: 114
|
||||
}}></textarea>
|
||||
}}>
|
||||
</textarea>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
let removeImage = "";
|
||||
let avatar = (hasAvatar)
|
||||
? <img className="dib h-auto" width={128} src={props.contact.avatar} />
|
||||
: <Sigil ship={props.ship} size={128} color={"#" + hexColor} />;
|
||||
|
||||
if (hasAvatar) {
|
||||
removeImage = (
|
||||
let removeImage = hasAvatar ? (
|
||||
<div>
|
||||
<button className="f9 black pointer db"
|
||||
onClick={() => this.setField("removeAvatar")}>
|
||||
Remove photo
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
) : "";
|
||||
|
||||
let avatar = (hasAvatar)
|
||||
? <img className="dib h-auto" width={128} src={props.contact.avatar} />
|
||||
: <Sigil
|
||||
ship={props.ship}
|
||||
size={128}
|
||||
color={currentColor}
|
||||
key={"avatar" + currentColor} />;
|
||||
|
||||
return (
|
||||
<div className="w-100 mt8 flex justify-center pa4 pt8 pt0-l pa0-xl pt4-xl">
|
||||
@ -275,144 +321,45 @@ export class ContactCard extends Component {
|
||||
<p className="f9 gray2 mt3">Ship Type</p>
|
||||
<p className="f8">{shipType}</p>
|
||||
<hr className="mv8 gray4 b--gray4 bb-0 b--solid" />
|
||||
<p className="f9 gray2">Nickname</p>
|
||||
<div className="w-100 flex">
|
||||
<textarea
|
||||
ref="nickname"
|
||||
className="w-100 ba pl3 b--gray4"
|
||||
style={{ resize: "none",
|
||||
height: 40,
|
||||
paddingTop: 10 }}
|
||||
onChange={this.nickNameToSet}
|
||||
defaultValue={defaultValue.nickname}/>
|
||||
<button
|
||||
className={"f9 pointer ml3 ba pa2 pl3 pr3 b--red2 red2 " +
|
||||
((props.contact.nickname === "") ? "dn" : "dib")
|
||||
}
|
||||
onClick={() => this.setField("removeNickname")}>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
className={"pointer db mv2 f9 ba pa2 pl3 pr3 " +
|
||||
((
|
||||
(props.contact.nickname === this.state.nickNameToSet)
|
||||
|| (this.state.nickNameToSet === "")
|
||||
) ? "b--gray4 gray4" : "b--black")
|
||||
}
|
||||
onClick={() => this.setField("nickname")}>
|
||||
Save
|
||||
</button>
|
||||
<p className="f9 gray2">Email</p>
|
||||
<div className="w-100 flex">
|
||||
<textarea
|
||||
ref="email"
|
||||
className="w-100 ba pl3 b--gray4"
|
||||
style={{
|
||||
resize: "none",
|
||||
height: 40,
|
||||
paddingTop: 10
|
||||
}}
|
||||
onChange={this.emailToSet}
|
||||
defaultValue={defaultValue.email} />
|
||||
<button className={"f9 pointer ml3 ba pa2 pl3 pr3 b--red2 red2 " +
|
||||
((props.contact.email === "") ? "dn" : "dib")}
|
||||
onClick={() => this.setField("removeEmail")}>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<button className={"pointer db mv2 f9 ba pa2 pl3 pr3 " +
|
||||
(((props.contact.email === this.state.emailToSet)
|
||||
|| (this.state.emailToSet === ""))
|
||||
? "b--gray4 gray4"
|
||||
: "b--black")}
|
||||
onClick={() => this.setField("email")}>
|
||||
Save
|
||||
</button>
|
||||
<p className="f9 gray2">Phone</p>
|
||||
<div className="w-100 flex">
|
||||
<textarea
|
||||
ref="phone"
|
||||
className="w-100 ba pl3 b--gray4"
|
||||
style={{
|
||||
resize: "none",
|
||||
height: 40,
|
||||
paddingTop: 10
|
||||
}}
|
||||
onChange={this.phoneToSet}
|
||||
defaultValue={defaultValue.phone} />
|
||||
<button className={"f9 pointer ml3 ba pa2 pl3 pr3 b--red2 red2 " +
|
||||
((props.contact.phone === "") ? "dn" : "dib")}
|
||||
onClick={() => this.setField("removePhone")}>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<button className={"pointer db mv2 f9 ba pa2 pl3 pr3 " +
|
||||
(((props.contact.phone === this.state.phoneToSet)
|
||||
|| (this.state.phoneToSet === ""))
|
||||
? "b--gray4 gray4"
|
||||
: "b--black")}
|
||||
onClick={() => this.setField("phone")}>
|
||||
Save
|
||||
</button>
|
||||
<p className="f9 gray2">Website</p>
|
||||
<div className="w-100 flex">
|
||||
<textarea
|
||||
ref="website"
|
||||
className="w-100 ba pl3 b--gray4"
|
||||
style={{
|
||||
resize: "none",
|
||||
height: 40,
|
||||
paddingTop: 10
|
||||
}}
|
||||
onChange={this.websiteToSet}
|
||||
defaultValue={defaultValue.website} />
|
||||
<button className={"f9 pointer ml3 ba pa2 pl3 pr3 b--red2 red2 " +
|
||||
((props.contact.website === "") ? "dn" : "dib")}
|
||||
onClick={() => this.setField("removeWebsite")}>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<button className={"pointer db mv2 f9 ba pa2 pl3 pr3 " +
|
||||
(((props.contact.website === this.state.websiteToSet)
|
||||
|| (this.state.websitetoSet === ""))
|
||||
? "b--gray4 gray4"
|
||||
: "b--black")}
|
||||
onClick={() => this.setField("website")}>
|
||||
Save
|
||||
</button>
|
||||
|
||||
<p className="f9 gray2">Notes</p>
|
||||
<div className="w-100 flex">
|
||||
<textarea
|
||||
ref="notes"
|
||||
className="w-100 ba pl3 b--gray4"
|
||||
style={{
|
||||
resize: "none",
|
||||
height: 40,
|
||||
paddingTop: 10
|
||||
}}
|
||||
onChange={this.notesToSet}
|
||||
defaultValue={defaultValue.notes} />
|
||||
<button className={"f9 pointer ml3 ba pa2 pl3 pr3 b--red2 red2 " +
|
||||
((props.contact.notes === "") ? "dn" : "dib")}
|
||||
onClick={() => this.setField("removeNotes")}>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<button className={"pointer db mv2 f9 ba pa2 pl3 pr3 " +
|
||||
(((props.contact.notes === this.state.notesToSet)
|
||||
|| (this.state.notesToSet === ""))
|
||||
? "b--gray4 gray4"
|
||||
: "b--black")}
|
||||
onClick={() => this.setField("notes")}>
|
||||
Save
|
||||
</button>
|
||||
|
||||
<EditElement
|
||||
title="Nickname"
|
||||
defaultValue={defaultValue.nickname}
|
||||
onChange={this.nickNameToSet}
|
||||
onDeleteClick={() => this.setField("removeNickname")}
|
||||
onSaveClick={() => this.setField("nickname")}
|
||||
showButtons={!props.share} />
|
||||
<EditElement
|
||||
title="Email"
|
||||
defaultValue={defaultValue.email}
|
||||
onChange={this.emailToSet}
|
||||
onDeleteClick={() => this.setField("removeEmail")}
|
||||
onSaveClick={() => this.setField("email")}
|
||||
showButtons={!props.share} />
|
||||
<EditElement
|
||||
title="Phone"
|
||||
defaultValue={defaultValue.phone}
|
||||
onChange={this.phoneToSet}
|
||||
onDeleteClick={() => this.setField("removePhone")}
|
||||
onSaveClick={() => this.setField("phone")}
|
||||
showButtons={!props.share} />
|
||||
<EditElement
|
||||
title="Website"
|
||||
defaultValue={defaultValue.website}
|
||||
onChange={this.websiteToSet}
|
||||
onDeleteClick={() => this.setField("removeWebsite")}
|
||||
onSaveClick={() => this.setField("website")}
|
||||
showButtons={!props.share} />
|
||||
<EditElement
|
||||
title="Notes"
|
||||
defaultValue={defaultValue.notes}
|
||||
onChange={this.notesToSet}
|
||||
onDeleteClick={() => this.setField("removeNotes")}
|
||||
onSaveClick={() => this.setField("notes")}
|
||||
showButtons={!props.share} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
renderCard() {
|
||||
@ -424,7 +371,11 @@ export class ContactCard extends Component {
|
||||
let avatar =
|
||||
('avatar' in props.contact && props.contact.avatar !== "TODO") ?
|
||||
<img className="dib h-auto" width={128} src={props.contact.avatar} /> :
|
||||
<Sigil ship={props.ship} size={128} color={"#" + hexColor} />;
|
||||
<Sigil
|
||||
ship={props.ship}
|
||||
size={128}
|
||||
color={hexColor}
|
||||
key={hexColor} />;
|
||||
|
||||
let websiteHref =
|
||||
(props.contact.website && props.contact.website.includes("://")) ?
|
||||
@ -514,7 +465,13 @@ export class ContactCard extends Component {
|
||||
<Link to="/~contacts/">{"⟵"}</Link>
|
||||
</div>
|
||||
<button
|
||||
onClick={this.editToggle}
|
||||
onClick={() => {
|
||||
if (props.share) {
|
||||
this.shareWithGroup();
|
||||
} else {
|
||||
this.editToggle();
|
||||
}
|
||||
}}
|
||||
className={`ml3 mt2 mb2 f9 pa1 ba br2 pointer b--black ` + ourOpt}>
|
||||
{editInfoText}
|
||||
</button>
|
||||
|
@ -13,8 +13,9 @@ export class ContactItem extends Component {
|
||||
let name = (props.nickname) ? props.nickname : "~" + props.ship;
|
||||
|
||||
let prefix = props.share ? 'share' : 'view';
|
||||
let suffix = !props.share ? `/${props.ship}` : '';
|
||||
return (
|
||||
<Link to={`/~contacts/${prefix}` + props.path}>
|
||||
<Link to={`/~contacts/${prefix}` + props.path + suffix}>
|
||||
<div className=
|
||||
{"pl4 pt1 pb1 f9 flex justify-start content-center " + selectedClass}
|
||||
>
|
||||
|
@ -41,7 +41,7 @@ export class ContactSidebar extends Component {
|
||||
color={obj.color}
|
||||
path={props.path}
|
||||
selected={path === props.selectedContact}
|
||||
share={true}
|
||||
share={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
70
pkg/interface/contacts/src/js/components/lib/edit-element.js
Normal file
70
pkg/interface/contacts/src/js/components/lib/edit-element.js
Normal file
@ -0,0 +1,70 @@
|
||||
import React, { Component } from 'react'
|
||||
import { Route, Link } from 'react-router-dom';
|
||||
|
||||
export class EditElement extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
currentValue: ''
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
// TODO: make ref clear function and make it work
|
||||
let showDelete = props.defaultValue === "";
|
||||
let allowSave = (
|
||||
props.defaultValue !== state.currentValue &&
|
||||
state.currentValue !== ""
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p className="f9 gray2">{props.title}</p>
|
||||
<div className="w-100 flex">
|
||||
<textarea
|
||||
ref={props.title}
|
||||
className="w-100 ba pl3 b--gray4"
|
||||
style={{ resize: "none", height: 40, paddingTop: 10 }}
|
||||
onChange={(e) => {
|
||||
let val = e.target.value;
|
||||
this.setState({
|
||||
currentValue: val
|
||||
}, () => {
|
||||
props.onChange(val);
|
||||
});
|
||||
}}
|
||||
defaultValue={props.defaultValue} />
|
||||
{!!props.showButtons ? (
|
||||
<button
|
||||
className={
|
||||
"f9 pointer ml3 ba pa2 pl3 pr3 b--red2 red2 " +
|
||||
(showDelete ? "dn" : "dib")
|
||||
}
|
||||
onClick={() => {
|
||||
this.refs[props.title].value = "";
|
||||
props.onDeleteClick();
|
||||
}}>
|
||||
Delete
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
{!!props.showButtons ? (
|
||||
<button
|
||||
className={
|
||||
"pointer db mv2 f9 ba pa2 pl3 pr3 " +
|
||||
(allowSave ? "b--black" : "b--gray4 gray4")
|
||||
}
|
||||
onClick={() => {
|
||||
if (!allowSave) { return; }
|
||||
props.onSaveClick();
|
||||
}}>
|
||||
Save
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ export class Sigil extends Component {
|
||||
render() {
|
||||
const { props } = this;
|
||||
|
||||
let color = "#" + props.color;
|
||||
if (props.ship.length > 14) {
|
||||
return (
|
||||
<div className="bg-black" style={{width: props.size, height: props.size}}>
|
||||
@ -13,12 +14,12 @@ export class Sigil extends Component {
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="dib" style={{ flexBasis: 32, backgroundColor: props.color }}>
|
||||
<div className="dib" style={{ flexBasis: 32, backgroundColor: color }}>
|
||||
{sigil({
|
||||
patp: props.ship,
|
||||
renderer: reactRenderer,
|
||||
size: props.size,
|
||||
colors: [props.color, "white"]
|
||||
colors: [color, "white"]
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
@ -63,6 +63,11 @@ export function deSig(ship) {
|
||||
}
|
||||
|
||||
export function uxToHex(ux) {
|
||||
let value = ux.substr(2).replace('.', '').padStart(6, '0');
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user