mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-03 02:35:52 +03:00
Merge pull request #4362 from urbit/la/share-interface
contacts: fully integrated share interface wip
This commit is contained in:
commit
1c24043e6c
@ -3,7 +3,7 @@
|
||||
:: data store that holds individual contact data
|
||||
::
|
||||
/- store=contact-store, *resource
|
||||
/+ default-agent, dbug, *migrate
|
||||
/+ default-agent, dbug, *migrate, contact
|
||||
|%
|
||||
+$ card card:agent:gall
|
||||
+$ state-4
|
||||
@ -29,6 +29,7 @@
|
||||
|_ =bowl:gall
|
||||
+* this .
|
||||
def ~(. (default-agent this %|) bowl)
|
||||
con ~(. contact bowl)
|
||||
::
|
||||
++ on-init
|
||||
=. rolodex (~(put by rolodex) our.bowl *contact:store)
|
||||
@ -216,6 +217,16 @@
|
||||
::
|
||||
[%x %allowed-groups ~]
|
||||
``noun+!>(allowed-groups)
|
||||
|
||||
::
|
||||
[%x %is-allowed @ @ @ @ ~]
|
||||
=/ is-personal =(i.t.t.t.t.t.path 'true')
|
||||
=/ =resource
|
||||
?: is-personal
|
||||
[our.bowl %'']
|
||||
[(slav %p i.t.t.path) i.t.t.t.path]
|
||||
=/ =ship (slav %p i.t.t.t.t.path)
|
||||
``json+!>(`json`b+(is-allowed:con resource ship))
|
||||
==
|
||||
::
|
||||
++ on-leave on-leave:def
|
||||
|
@ -175,6 +175,10 @@
|
||||
%share-co
|
||||
?> ?=(%poke-ack -.sign)
|
||||
(ack +.sign)
|
||||
::
|
||||
%push-co
|
||||
?> ?=(%poke-ack -.sign)
|
||||
(ack +.sign)
|
||||
::
|
||||
%md
|
||||
?+ -.sign !!
|
||||
@ -200,6 +204,7 @@
|
||||
%- zing
|
||||
:~ [(poke-our:(jn-pass-io /pull-md) %metadata-pull-hook cag)]~
|
||||
[(poke-our:(jn-pass-io /pull-co) %contact-pull-hook cag)]~
|
||||
::
|
||||
?. scry-is-public:con ~
|
||||
:_ ~
|
||||
%+ poke:(jn-pass-io /share-co)
|
||||
|
@ -173,4 +173,10 @@
|
||||
==
|
||||
--
|
||||
--
|
||||
::
|
||||
++ share-dejs
|
||||
=, dejs:format
|
||||
|%
|
||||
++ share (ot [%share (su ;~(pfix sig fed:ag))]~)
|
||||
--
|
||||
--
|
||||
|
@ -70,20 +70,30 @@
|
||||
|= [rid=resource =ship]
|
||||
^- ?
|
||||
=/ grp ~(. group bowl)
|
||||
=/ shp (scry-for ? /allowed-ship/(scot %p ship))
|
||||
?: ?& scry-is-public
|
||||
=(rid [our.bowl %''])
|
||||
==
|
||||
%.y
|
||||
?: shp %.y
|
||||
?: ?& (~(has in scry-sharing) rid)
|
||||
=/ allowed-groups (scry-for (set resource) /allowed-groups)
|
||||
?| :: if they are requesting our personal profile, check if we are
|
||||
:: either public, or if they are on the allowed-ships list.
|
||||
:: this is used for direct messages and leap searches
|
||||
::
|
||||
?& =(rid [our.bowl %''])
|
||||
?| :: if our profile is public, allow
|
||||
::
|
||||
scry-is-public
|
||||
:: if the requester is an allowed-ship, allow
|
||||
::
|
||||
(scry-for ? /allowed-ship/(scot %p ship))
|
||||
:: if the requester of our profile is the host of one of
|
||||
:: our allowed-groups, allow
|
||||
::
|
||||
%+ lien ~(tap in allowed-groups)
|
||||
|= res=resource
|
||||
=(entity.res ship)
|
||||
== ==
|
||||
:: if they are requesting our contact data within a group,
|
||||
:: we make sure that we are sharing that group,
|
||||
:: and that they are a member of the group
|
||||
::
|
||||
?& (~(has in scry-sharing) rid)
|
||||
(~(has in (members:grp rid)) ship)
|
||||
==
|
||||
%.y
|
||||
=/ allowed-groups ~(tap in (scry-for (set resource) /allowed-groups))
|
||||
|-
|
||||
?~ allowed-groups %.n
|
||||
?: (~(has in (members:grp i.allowed-groups)) ship)
|
||||
%.y
|
||||
$(allowed-groups t.allowed-groups)
|
||||
== ==
|
||||
--
|
||||
|
@ -1,3 +1,5 @@
|
||||
/+ *contact-store
|
||||
::
|
||||
|_ share=[%share =ship]
|
||||
++ grad %noun
|
||||
++ grow
|
||||
@ -7,6 +9,7 @@
|
||||
::
|
||||
++ grab
|
||||
|%
|
||||
++ noun share
|
||||
++ noun _share
|
||||
++ json share:share-dejs
|
||||
--
|
||||
--
|
||||
|
@ -57,6 +57,7 @@ export default class BaseApi<S extends object = {}> {
|
||||
}
|
||||
|
||||
scry<T>(app: string, path: Path): Promise<T> {
|
||||
console.log(path);
|
||||
return fetch(`/~/scry/${app}${path}.json`).then(r => r.json() as Promise<T>);
|
||||
}
|
||||
|
||||
|
@ -34,12 +34,35 @@ export default class ContactsApi extends BaseApi<StoreState> {
|
||||
});
|
||||
}
|
||||
|
||||
allow(ship) {
|
||||
return this.storeAction({
|
||||
allow: ship
|
||||
});
|
||||
}
|
||||
|
||||
setPublic(setPublic: any) {
|
||||
return this.storeAction({
|
||||
'set-public': setPublic
|
||||
});
|
||||
}
|
||||
|
||||
share(recipient, us) {
|
||||
return this.action(
|
||||
'contact-push-hook',
|
||||
'contact-share',
|
||||
{ share: us },
|
||||
recipient
|
||||
);
|
||||
}
|
||||
|
||||
fetchIsAllowed(entity, name, ship, personal) {
|
||||
const isPersonal = personal ? 'true' : 'false';
|
||||
return this.scry<any>(
|
||||
'contact-store',
|
||||
`/is-allowed/${entity}/${name}/${ship}/${isPersonal}`
|
||||
);
|
||||
}
|
||||
|
||||
private storeAction(action: any): Promise<any> {
|
||||
return this.action('contact-store', 'contact-update', action)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useRef, useCallback, useEffect } from 'react';
|
||||
import React, { useRef, useCallback, useEffect, useState } from 'react';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { Col } from '@tlon/indigo-react';
|
||||
import _ from 'lodash';
|
||||
@ -35,6 +35,7 @@ export function ChatResource(props: ChatResourceProps) {
|
||||
|
||||
const [,, owner, name] = station.split('/');
|
||||
const ourContact = contacts?.[`~${window.ship}`];
|
||||
console.log(contacts);
|
||||
|
||||
const chatInput = useRef<ChatInput>();
|
||||
|
||||
@ -86,7 +87,15 @@ export function ChatResource(props: ChatResourceProps) {
|
||||
|
||||
return (
|
||||
<Col {...bind} height="100%" overflow="hidden" position="relative">
|
||||
<ShareProfile our={ourContact} />
|
||||
<ShareProfile
|
||||
our={ourContact}
|
||||
api={props.api}
|
||||
recipient={owner}
|
||||
group={group}
|
||||
groupPath={groupPath}
|
||||
hideBanner={() => {
|
||||
setProfileAllowed(true);
|
||||
}} />
|
||||
{dragging && <SubmitDragger />}
|
||||
<ChatWindow
|
||||
mailboxSize={5}
|
||||
|
@ -1,16 +1,100 @@
|
||||
import React from 'react';
|
||||
import React, {
|
||||
useState,
|
||||
useEffect
|
||||
} from 'react';
|
||||
import { Box, Row, Text, BaseImage } from '@tlon/indigo-react';
|
||||
import { uxToHex } from '~/logic/lib/util';
|
||||
import { Sigil } from '~/logic/lib/sigil';
|
||||
|
||||
export const ShareProfile = (props) => {
|
||||
const image = (props?.our?.avatar)
|
||||
? <BaseImage src={props.our.avatar} width='24px' height='24px' borderRadius={2} style={{ objectFit: 'cover' }} />
|
||||
: <Row p={1} alignItems="center" borderRadius={2} backgroundColor={`#${uxToHex(props?.our?.color)}` || "#000000"}>
|
||||
<Sigil ship={window.ship} size={16} icon color={`#${uxToHex(props?.our?.color)}` || "#000000"} />
|
||||
</Row>;
|
||||
const pathAsResource = (path) => {
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
const pathArr = path.split('/');
|
||||
if (pathArr.length !== 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
return {
|
||||
entity: pathArr[2],
|
||||
name: pathArr[3]
|
||||
};
|
||||
};
|
||||
|
||||
export const ShareProfile = (props) => {
|
||||
const { api, recipient, hideBanner, group, groupPath } = props;
|
||||
console.log(groupPath);
|
||||
// TODO: use isContactPublic somewhere
|
||||
|
||||
const [showBanner, setShowBanner] = useState(false);
|
||||
const res = pathAsResource(groupPath);
|
||||
|
||||
useEffect(() => {
|
||||
if (!res) { return; }
|
||||
if (!group) { return; }
|
||||
console.log(group);
|
||||
if (group.hidden) {
|
||||
// TODO:
|
||||
// take the union of the pending set and the members set,
|
||||
// subtract ourselves, then if *anyone* has not already been shared with,
|
||||
// show the banner
|
||||
// Promise.all all the members of the set
|
||||
let check =
|
||||
Promise.all()
|
||||
props.api.contacts.fetchIsAllowed(
|
||||
`~${window.ship}`,
|
||||
'personal', // not used
|
||||
recipient,
|
||||
true
|
||||
).then((retVal) => {
|
||||
console.log(retVal);
|
||||
setShowBanner(!retVal);
|
||||
});
|
||||
} else {
|
||||
// TODO:
|
||||
// if the group is not in the allowed-groups set, then show the banner
|
||||
props.api.contacts.fetchIsAllowed(
|
||||
res.entity,
|
||||
res.name,
|
||||
recipient,
|
||||
false
|
||||
).then((retVal) => {
|
||||
console.log(retVal);
|
||||
setShowBanner(!retVal);
|
||||
});
|
||||
}
|
||||
}, [recipient, res, group]);
|
||||
|
||||
const image = (props?.our?.avatar)
|
||||
? (
|
||||
<BaseImage
|
||||
src={props.our.avatar}
|
||||
width='24px'
|
||||
height='24px'
|
||||
borderRadius={2}
|
||||
style={{ objectFit: 'cover' }} />
|
||||
) : (
|
||||
<Row
|
||||
p={1}
|
||||
alignItems="center"
|
||||
borderRadius={2}
|
||||
backgroundColor={!props.our ? `#${uxToHex(props.our.color)}` : "#000000"}>
|
||||
<Sigil
|
||||
ship={window.ship}
|
||||
size={16}
|
||||
color={`#${uxToHex(props?.our?.color)}` || "#000000"}
|
||||
icon />
|
||||
</Row>
|
||||
);
|
||||
|
||||
const onClick = () => {
|
||||
api.contacts.allow(recipient).then(() => {
|
||||
api.contacts.share(recipient, window.ship);
|
||||
});
|
||||
hideBanner();
|
||||
};
|
||||
|
||||
return showBanner ? (
|
||||
<Row
|
||||
height="48px"
|
||||
alignItems="center"
|
||||
@ -22,9 +106,9 @@ export const ShareProfile = (props) => {
|
||||
{image}
|
||||
<Text verticalAlign="middle" pl={2}>Share private profile?</Text>
|
||||
</Row>
|
||||
<Box pr={2}>
|
||||
<Box pr={2} onClick={onClick}>
|
||||
<Text color="blue" bold cursor="pointer">Share</Text>
|
||||
</Box>
|
||||
</Row>
|
||||
);
|
||||
) : null;
|
||||
};
|
||||
|
@ -59,3 +59,4 @@ export function SetStatus(props: any) {
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user