landscape: surface invites in notifications

This commit is contained in:
Matilde Park 2020-11-11 15:42:06 -05:00
parent 2ba78348fb
commit 6782785083
7 changed files with 76 additions and 75 deletions

View File

@ -155,7 +155,8 @@ class App extends React.Component {
associations={state.associations}
apps={state.launch}
api={this.api}
dark={state.dark}
notifications={state.notificationsCount}
invites={state.invites}
groups={state.groups}
show={state.omniboxShown}
/>

View File

@ -2,12 +2,10 @@ import React from 'react';
import Helmet from 'react-helmet';
import styled from 'styled-components';
import { Box, Row, Icon, Text, Center } from '@tlon/indigo-react';
import { uxToHex, adjustHex } from '~/logic/lib/util';
import { Box, Row, Icon, Text } from '@tlon/indigo-react';
import './css/custom.css';
import { Sigil } from '~/logic/lib/sigil';
import Tiles from './components/tiles';
import Tile from './components/tiles/tile';
import Welcome from './components/welcome';
@ -65,7 +63,7 @@ export default class LaunchApp extends React.Component {
weather={props.weather}
/>
<Box display={["none", "block"]} width="100%" gridColumn="1 / -1"></Box>
<Groups groups={props.groups} associations={props.associations} invites={props.invites} api={props.api}/>
<Groups groups={props.groups} associations={props.associations} />
</Box>
</ScrollbarLessBox>
<Box

View File

@ -13,70 +13,14 @@ const sortGroupsAlph = (a: Association, b: Association) =>
alphabeticalOrder(a.metadata.title, b.metadata.title);
export default function Groups(props: GroupsProps & Parameters<typeof Box>[0]) {
const { associations, invites, api, ...boxProps } = props;
const incomingGroups = Object.values(invites?.['contacts'] || {});
const getKeyByValue = (object, value) => {
return Object.keys(object).find(key => object[key] === value);
}
const { associations, ...boxProps } = props;
const groups = Object.values(associations?.contacts || {})
.filter(e => e['group-path'] in props.groups)
.sort(sortGroupsAlph);
const acceptInvite = (invite) => {
const resource = {
ship: `~${invite.resource.ship}`,
name: invite.resource.name
};
return api.contacts.join(resource).then(() => {
api.invite.accept('contacts', getKeyByValue(invites['contacts'], invite));
});
};
return (
<>
{incomingGroups.map((invite) => (
<Box
height='100%'
width='100%'
bg='white'
border='1'
borderRadius='2'
borderColor='lightGray'
p='2'
fontSize='0'>
<Text display='block' pb='2' gray>You have been invited to:</Text>
<Text
display='inline-block'
overflow='hidden'
maxWidth='100%'
style={{ textOverflow: 'ellipsis', whiteSpace: 'pre' }}
title={`~${invite.resource.ship}/${invite.resource.name}`}>
{`~${invite.resource.ship}/${invite.resource.name}`}
</Text>
<Box pt='5'>
<Text
onClick={() => acceptInvite(invite)}
color='blue'
mr='2'
cursor='pointer'>
Accept
</Text>
<Text
color='red'
onClick={() =>
api.invite.decline(
'contacts',
getKeyByValue(invites['contacts'], invite)
)
}
cursor='pointer'>
Reject
</Text>
</Box>
</Box>
))}
{groups.map((group) => (
<Tile to={`/~landscape${group["group-path"]}`}>
<Text>{group.metadata.title}</Text>

View File

@ -9,6 +9,7 @@ import { BigInteger } from "big-integer";
import GlobalApi from "~/logic/api/global";
import { Notification } from "./notification";
import { Associations } from "~/types";
import { cite } from '~/logic/lib/util';
type DatedTimebox = [BigInteger, Timebox];
@ -39,8 +40,9 @@ export default function Inbox(props: {
associations: Associations;
contacts: Rolodex;
filter: string[];
invites: any;
}) {
const { api, associations } = props;
const { api, associations, invites } = props;
useEffect(() => {
let seen = false;
setTimeout(() => {
@ -67,8 +69,54 @@ export default function Inbox(props: {
f.values
)(notifications);
const incomingGroups = Object.values(invites?.['contacts'] || {});
const getKeyByValue = (object, value) => {
return Object.keys(object).find(key => object[key] === value);
};
const acceptInvite = (invite) => {
const resource = {
ship: `~${invite.resource.ship}`,
name: invite.resource.name
};
return api.contacts.join(resource).then(() => {
api.invite.accept('contacts', getKeyByValue(invites['contacts'], invite));
});
};
return (
<Col overflowY="auto" flexGrow="1">
{incomingGroups.map((invite) => (
<Box
height='100%'
width='100%'
bg='white'
p='3'
fontSize='0'>
<Text display='block' pb='2' gray>{cite(invite.resource.ship)} invited you to <Text fontWeight='500'>{invite.resource.name}</Text></Text>
<Box pt='3'>
<Text
onClick={() => acceptInvite(invite)}
color='blue'
mr='2'
cursor='pointer'>
Accept
</Text>
<Text
color='red'
onClick={() =>
api.invite.decline(
'contacts',
getKeyByValue(invites['contacts'], invite)
)
}
cursor='pointer'>
Reject
</Text>
</Box>
</Box>
))}
{newNotifications && (
<DaySection
latest

View File

@ -1,13 +1,12 @@
import React from 'react';
import { useLocation } from 'react-router-dom';
import { Row, Box, Text, Icon, Button } from '@tlon/indigo-react';
import ReconnectButton from './ReconnectButton';
import { StatusBarItem } from './StatusBarItem';
import { Sigil } from '~/logic/lib/sigil';
const StatusBar = (props) => {
const invites = Object.keys(props.invites?.['contacts'] || {});
const metaKey = (window.navigator.platform.includes('Mac')) ? '⌘' : 'Ctrl+';
return (
@ -26,7 +25,7 @@ const StatusBar = (props) => {
</Button>
<StatusBarItem mr={2} onClick={() => props.api.local.setOmnibox()}>
{ !props.doNotDisturb && props.notificationsCount > 0 &&
{ !props.doNotDisturb && (props.notificationsCount > 0 || invites.length > 0) &&
(<Box display="block" right="-5px" top="-5px" position="absolute" >
<Icon color="blue" icon="Bullet" />
</Box>

View File

@ -241,7 +241,9 @@ export class Omnibox extends Component {
link={result.link}
navigate={() => this.navigate(result.app, result.link)}
selected={selected}
dark={props.dark} />
invites={props.invites}
notifications={props.notifications}
/>
))}
</Box>
);

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { Row, Icon, Text } from '@tlon/indigo-react';
import { Box, Row, Icon, Text } from '@tlon/indigo-react';
import defaultApps from '~/logic/lib/default-apps';
import Sigil from '~/logic/lib/sigil';
@ -25,21 +25,30 @@ export class OmniboxResult extends Component {
}
}
getIcon(icon, dark, selected, link) {
getIcon(icon, selected, link, invites, notifications) {
const iconFill = (this.state.hovered || (selected === link)) ? 'white' : 'black';
const sigilFill = (this.state.hovered || (selected === link)) ? '#3a8ff7' : '#ffffff';
const bulletFill = (this.state.hovered || (selected === link)) ? 'white' : 'blue';
const inviteCount = Object.keys(invites?.['contacts'] || {});
let graphic = <div />;
if (defaultApps.includes(icon.toLowerCase()) || icon.toLowerCase() === 'links' || icon === 'inbox') {
icon = (icon === 'inbox') ? 'Inbox' : icon;
if (defaultApps.includes(icon.toLowerCase()) || icon.toLowerCase() === 'links') {
icon = (icon === 'Link') ? 'Links' : icon;
graphic = <Icon display="inline-block" verticalAlign="middle" icon={icon} mr='2' size='16px' color={iconFill} />;
} else if (icon === 'inbox') {
graphic = <Box display='flex' verticalAlign='middle'>
<Icon display='inline-block' verticalAlign='middle' icon='Inbox' mr='2' size='16px' color={iconFill} />
{(notifications > 0 || inviteCount.length > 0) && (
<Icon display='inline-block' icon='Bullet' style={{ position: 'absolute', top: -5, left: 5 }} color={bulletFill} />
)}
</Box>;
} else if (icon === 'logout') {
graphic = <Icon display="inline-block" verticalAlign="middle" icon='ArrowWest' mr='2' size='16px' color={iconFill} />;
graphic = <Icon display="inline-block" verticalAlign="middle" icon='SignOut' mr='2' size='16px' color={iconFill} />;
} else if (icon === 'profile') {
graphic = <Sigil color={sigilFill} classes='dib flex-shrink-0 v-mid mr2' ship={window.ship} size={16} icon padded />;
} else if (icon === 'home') {
graphic = <Icon display='inline-block' verticalAlign='middle' icon='Circle' mr='2' size='16px' color={iconFill} />;
graphic = <Icon display='inline-block' verticalAlign='middle' icon='Boot' mr='2' size='16px' color={iconFill} />;
} else if (icon === 'notifications') {
graphic = <Icon display='inline-block' verticalAlign='middle' icon='Inbox' mr='2' size='16px' color={iconFill} />;
} else {
@ -54,9 +63,9 @@ export class OmniboxResult extends Component {
}
render() {
const { icon, text, subtext, link, navigate, selected, dark } = this.props;
const { icon, text, subtext, link, navigate, selected, invites, notifications } = this.props;
const graphic = this.getIcon(icon, dark, selected, link);
const graphic = this.getIcon(icon, selected, link, invites, notifications);
return (
<Row