interface: fix misc bugs

This commit is contained in:
Liam Fitzgerald 2021-09-20 14:34:55 +10:00
parent a49399269b
commit d593561b0f
9 changed files with 43 additions and 115 deletions

View File

@ -18,11 +18,11 @@
"display": "standalone", "display": "standalone",
"background_color": "%23FFFFFF", "background_color": "%23FFFFFF",
"theme_color": "%23000000"}' /> "theme_color": "%23000000"}' />
<script src="/apps/landscape/desk.js"></script>
<script src="/session.js"></script>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
<div id="portal-root"></div> <div id="portal-root"></div>
<script src="/apps/landscape/desk.js"></script>
<script src="/session.js"></script>
</body> </body>
</html> </html>

View File

@ -107,7 +107,7 @@ function updateNotificationStats(state: HarkState, place: HarkPlace, f: (s: Hark
} }
function seenIndex(json: any, state: HarkState): HarkState { function seenIndex(json: any, state: HarkState): HarkState {
const data = _.get(json, 'seen-index'); const data = _.get(json, 'saw-place');
if(data) { if(data) {
updateNotificationStats(state, data, s => ({ last: Date.now() })); updateNotificationStats(state, data, s => ({ last: Date.now() }));
} }
@ -154,6 +154,7 @@ function unreadEach(json: any, state: HarkState): HarkState {
function allStats(json: any, state: HarkState): HarkState { function allStats(json: any, state: HarkState): HarkState {
if('all-stats' in json) { if('all-stats' in json) {
const data = json['all-stats']; const data = json['all-stats'];
console.log(data);
data.forEach(({ place, stats }) => { data.forEach(({ place, stats }) => {
state.unreads[place.path] = stats; state.unreads[place.path] = stats;
}); });

View File

@ -4,7 +4,6 @@ import {
markCountAsRead, markCountAsRead,
Notification, Notification,
NotificationGraphConfig, NotificationGraphConfig,
readNote,
Unreads Unreads
} from '@urbit/api'; } from '@urbit/api';
import { Poke } from '@urbit/http-api'; import { Poke } from '@urbit/http-api';
@ -132,9 +131,8 @@ export function useHarkDm(ship: string) {
return useHarkState( return useHarkState(
useCallback( useCallback(
(s) => { (s) => {
return s.unreads[`/graph/~${window.ship}/dm-inbox`]?.[ const key = `/graph/~${window.ship}/dm-inbox/${patp2dec(ship)}`;
`/${patp2dec(ship)}` return s.unreads[key] || emptyStats();
] || emptyStats();
}, },
[ship] [ship]
) )

View File

@ -1,19 +1,18 @@
import React, { useState, useEffect, useCallback } from "react"; import React, { useState, useEffect, useCallback } from 'react';
import { useHistory, useParams } from "react-router-dom"; import { useHistory, useParams } from 'react-router-dom';
import { import {
Box, Box,
Col, Col,
Row, Row,
Text, Text,
Button,
Action, Action,
LoadingSpinner, LoadingSpinner
} from "@tlon/indigo-react"; } from '@tlon/indigo-react';
import * as Dialog from "@radix-ui/react-dialog"; import * as Dialog from '@radix-ui/react-dialog';
import { PropFunc } from "~/types"; import { PropFunc } from '~/types';
import { useRunIO } from "~/logic/lib/useRunIO"; import { useRunIO } from '~/logic/lib/useRunIO';
import useMetadataState from "~/logic/state/metadata"; import useMetadataState from '~/logic/state/metadata';
import { GroupSummary } from "~/views/landscape/components/GroupSummary"; import { GroupSummary } from '~/views/landscape/components/GroupSummary';
import { import {
accept, accept,
decline, decline,
@ -22,13 +21,13 @@ import {
join, join,
Metadata, Metadata,
MetadataUpdatePreview, MetadataUpdatePreview,
resourceFromPath, resourceFromPath
} from "@urbit/api"; } from '@urbit/api';
import useInviteState from "~/logic/state/invite"; import useInviteState from '~/logic/state/invite';
import useGroupState from "~/logic/state/group"; import useGroupState from '~/logic/state/group';
import useGraphState from "~/logic/state/graph"; import useGraphState from '~/logic/state/graph';
import { useWaitForProps } from "~/logic/lib/useWaitForProps"; import { useWaitForProps } from '~/logic/lib/useWaitForProps';
import airlock from "~/logic/api"; import airlock from '~/logic/api';
function InviteDialog({ children, ...rest }: PropFunc<typeof Col>) { function InviteDialog({ children, ...rest }: PropFunc<typeof Col>) {
return ( return (
@ -84,7 +83,7 @@ function inviteUrl(
return `/~landscape${resource}`; return `/~landscape${resource}`;
} }
if (metadata.config?.graph === "chat") { if (metadata.config?.graph === 'chat') {
return `/~landscape/messages/resource/${metadata.config.graph}${resource}`; return `/~landscape/messages/resource/${metadata.config.graph}${resource}`;
} else { } else {
return `/~landscape/home/resource/${metadata.config?.graph}${resource}`; return `/~landscape/home/resource/${metadata.config?.graph}${resource}`;
@ -94,9 +93,9 @@ function inviteUrl(
function useInviteAccept(resource: string, app?: string, uid?: string) { function useInviteAccept(resource: string, app?: string, uid?: string) {
const { ship, name } = resourceFromPath(resource); const { ship, name } = resourceFromPath(resource);
const history = useHistory(); const history = useHistory();
const associations = useMetadataState((s) => s.associations); const associations = useMetadataState(s => s.associations);
const groups = useGroupState((s) => s.groups); const groups = useGroupState(s => s.groups);
const graphKeys = useGraphState((s) => s.graphKeys); const graphKeys = useGraphState(s => s.graphKeys);
const waiter = useWaitForProps({ associations, graphKeys, groups }); const waiter = useWaitForProps({ associations, graphKeys, groups });
return useRunIO<void, boolean>( return useRunIO<void, boolean>(
@ -110,7 +109,6 @@ function useInviteAccept(resource: string, app?: string, uid?: string) {
} }
await airlock.poke(join(ship, name)); await airlock.poke(join(ship, name));
await airlock.poke(accept(app, uid));
await waiter((p) => { await waiter((p) => {
return ( return (
(resource in p.groups && (resource in p.groups &&
@ -119,10 +117,12 @@ function useInviteAccept(resource: string, app?: string, uid?: string) {
resource in (p.associations?.groups ?? {}) resource in (p.associations?.groups ?? {})
); );
}); });
airlock.poke(accept(app, uid));
return true; return true;
}, },
(success: boolean) => { (success: boolean) => {
if (!success) { if (!success) {
history.push('/');
return; return;
} }
const redir = inviteUrl( const redir = inviteUrl(
@ -147,11 +147,11 @@ export function Invite() {
uid: string; uid: string;
}>(); }>();
const invite = useInviteState((s) => s.invites?.[app]?.[uid]); const invite = useInviteState(s => s.invites?.[app]?.[uid]);
return ( return (
<InviteDialog> <InviteDialog>
{!!invite ? ( {invite ? (
<> <>
{renderInviteContent(app, uid, invite)} {renderInviteContent(app, uid, invite)}
<InviteActions app={app} uid={uid} invite={invite} /> <InviteActions app={app} uid={uid} invite={invite} />
@ -166,7 +166,7 @@ export function Invite() {
function InviteActions({ function InviteActions({
app, app,
uid, uid,
invite, invite
}: { }: {
app: string; app: string;
uid: string; uid: string;
@ -201,9 +201,9 @@ function InviteActions({
function GroupInvite({ uid, invite }: { uid: string; invite: IInvite }) { function GroupInvite({ uid, invite }: { uid: string; invite: IInvite }) {
const { const {
resource: { ship, name }, resource: { ship, name }
} = invite; } = invite;
const { associations, getPreview } = useMetadataState(); const { getPreview } = useMetadataState();
const [preview, setPreview] = useState<MetadataUpdatePreview | null>(null); const [preview, setPreview] = useState<MetadataUpdatePreview | null>(null);
useEffect(() => { useEffect(() => {
(async () => { (async () => {
@ -218,8 +218,8 @@ function GroupInvite({ uid, invite }: { uid: string; invite: IInvite }) {
return preview ? ( return preview ? (
<GroupSummary <GroupSummary
metadata={preview.metadata} metadata={preview.metadata}
channelCount={preview["channel-count"]} channelCount={preview['channel-count']}
memberCount={preview["members"]} memberCount={preview['members']}
/> />
) : ( ) : (
<LoadingSpinner /> <LoadingSpinner />
@ -232,9 +232,9 @@ function GraphInvite({ uid, invite }: { uid: string; invite: IInvite }) {
function renderInviteContent(app: string, uid: string, invite: IInvite) { function renderInviteContent(app: string, uid: string, invite: IInvite) {
switch (app) { switch (app) {
case "groups": case 'groups':
return <GroupInvite uid={uid} invite={invite} />; return <GroupInvite uid={uid} invite={invite} />;
case "graph": case 'graph':
return <GraphInvite uid={uid} invite={invite} />; return <GraphInvite uid={uid} invite={invite} />;
default: default:
return null; return null;

View File

@ -8,13 +8,10 @@ import {
Text Text
} from '@tlon/indigo-react'; } from '@tlon/indigo-react';
import React, { useRef } from 'react'; import React, { useRef } from 'react';
import { Link, useHistory } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Sigil } from '~/logic/lib/sigil'; import { Sigil } from '~/logic/lib/sigil';
import { uxToHex } from '~/logic/lib/util'; import { uxToHex } from '~/logic/lib/util';
import useContactState from '~/logic/state/contact'; import useContactState from '~/logic/state/contact';
import useHarkState from '~/logic/state/hark';
import useLaunchState from '~/logic/state/launch';
import useInviteState from '~/logic/state/invite';
import useLocalState, { selectLocalState } from '~/logic/state/local'; import useLocalState, { selectLocalState } from '~/logic/state/local';
import useSettingsState, { selectCalmState } from '~/logic/state/settings'; import useSettingsState, { selectCalmState } from '~/logic/state/settings';
import { Dropdown } from './Dropdown'; import { Dropdown } from './Dropdown';
@ -22,21 +19,13 @@ import { ProfileStatus } from './ProfileStatus';
import ReconnectButton from './ReconnectButton'; import ReconnectButton from './ReconnectButton';
import { StatusBarItem } from './StatusBarItem'; import { StatusBarItem } from './StatusBarItem';
import { useTutorialModal } from './useTutorialModal'; import { useTutorialModal } from './useTutorialModal';
import {StatusBarJoins} from './StatusBarJoins'; import { StatusBarJoins } from './StatusBarJoins';
const localSel = selectLocalState(['toggleOmnibox']); const localSel = selectLocalState(['toggleOmnibox']);
const StatusBar = (props) => { const StatusBar = (props) => {
const { ship } = props; const { ship } = props;
const history = useHistory();
const runtimeLag = useLaunchState(state => state.runtimeLag);
const ourContact = useContactState(state => state.contacts[`~${ship}`]); const ourContact = useContactState(state => state.contacts[`~${ship}`]);
const notificationsCount = useHarkState(state => state.notificationsCount);
const doNotDisturb = useHarkState(state => state.doNotDisturb);
const inviteState = useInviteState(state => state.invites);
const invites = [].concat(
...Object.values(inviteState).map(obj => Object.values(obj))
);
const metaKey = window.navigator.platform.includes('Mac') ? '⌘' : 'Ctrl+'; const metaKey = window.navigator.platform.includes('Mac') ? '⌘' : 'Ctrl+';
const { toggleOmnibox } = useLocalState(localSel); const { toggleOmnibox } = useLocalState(localSel);
const { hideAvatars } = useSettingsState(selectCalmState); const { hideAvatars } = useSettingsState(selectCalmState);
@ -87,16 +76,6 @@ const StatusBar = (props) => {
<Icon icon='Dashboard' color='black' /> <Icon icon='Dashboard' color='black' />
</Button> </Button>
<StatusBarItem float={floatLeap} mr={2} onClick={() => toggleOmnibox()}> <StatusBarItem float={floatLeap} mr={2} onClick={() => toggleOmnibox()}>
{!doNotDisturb && runtimeLag && (
<Box display='block' right='-8px' top='-8px' position='absolute'>
<Icon color='yellow' icon='Bullet' />
</Box>
)}
{!doNotDisturb && (notificationsCount > 0 || invites.length > 0) && (
<Box display='block' right='-8px' top='-8px' position='absolute'>
<Icon color='blue' icon='Bullet' />
</Box>
)}
<Icon icon='LeapArrow' /> <Icon icon='LeapArrow' />
<Text ref={anchorRef} ml={2} color='black'> <Text ref={anchorRef} ml={2} color='black'>
Leap Leap

View File

@ -119,7 +119,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
if (category === 'other') { if (category === 'other') {
return [ return [
'other', 'other',
index.get('other').filter(({ app }) => app !== 'tutorial') index.get('other').filter(({ app }) => app !== 'tutorial' && app !== 'inbox')
]; ];
} }
return [category, []]; return [category, []];

View File

@ -7,8 +7,6 @@ import { cite, uxToHex } from '~/logic/lib/util';
import { IconRef } from '~/types/util'; import { IconRef } from '~/types/util';
import withState from '~/logic/lib/withState'; import withState from '~/logic/lib/withState';
import useContactState from '~/logic/state/contact'; import useContactState from '~/logic/state/contact';
import useHarkState from '~/logic/state/hark';
import useLaunchState from '~/logic/state/launch';
import useInviteState from '~/logic/state/invite'; import useInviteState from '~/logic/state/invite';
function OmniboxResultChord(props: { function OmniboxResultChord(props: {
@ -34,8 +32,6 @@ interface OmniboxResultProps {
invites: Invites; invites: Invites;
link: string; link: string;
navigate: () => void; navigate: () => void;
notificationsCount: number;
runtimeLag: any;
selected: string; selected: string;
setSelection: () => void; setSelection: () => void;
subtext: string; subtext: string;
@ -80,21 +76,11 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
icon: string, icon: string,
selected: string, selected: string,
link: string, link: string,
invites: Invites,
lag: any,
notificationsCount: number,
text: string, text: string,
color: string color: string
): (any) { ): (any) {
const iconFill = const iconFill =
(this.state.hovered || selected === link) ? 'white' : 'black'; (this.state.hovered || selected === link) ? 'white' : 'black';
const bulletFill =
(this.state.hovered || selected === link) ? 'white' : 'blue';
const lagFill =
this.state.hovered || selected === link ? 'white' : 'yellow';
const inviteCount = [].concat(
...Object.values(invites).map(obj => Object.values(obj))
);
let graphic: ReactElement = <div />; let graphic: ReactElement = <div />;
if ( if (
@ -120,35 +106,6 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
color={iconFill} color={iconFill}
/> />
); );
} else if (icon === 'inbox') {
graphic = (
<Box display='flex' verticalAlign='middle' position='relative'>
<Icon
display='inline-block'
verticalAlign='middle'
icon='Notifications'
mr={2}
size='18px'
color={iconFill}
/>
{lag && (
<Icon
display='inline-block'
icon='Bullet'
style={{ position: 'absolute', top: -5, left: 5 }}
color={lagFill}
/>
)}
{(notificationsCount > 0 || inviteCount.length > 0) && (
<Icon
display='inline-block'
icon='Bullet'
style={{ position: 'absolute', top: -5, left: 5 }}
color={bulletFill}
/>
)}
</Box>
);
} else if (icon === 'logout') { } else if (icon === 'logout') {
graphic = ( graphic = (
<Icon <Icon
@ -245,9 +202,6 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
cursor, cursor,
navigate, navigate,
selected, selected,
invites,
notificationsCount,
runtimeLag,
contacts, contacts,
setSelection, setSelection,
shiftDescription, shiftDescription,
@ -262,9 +216,6 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
icon, icon,
selected, selected,
link, link,
invites,
runtimeLag,
notificationsCount,
text, text,
color color
); );
@ -334,8 +285,6 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
} }
export default withState(OmniboxResult, [ export default withState(OmniboxResult, [
[useLaunchState, ['runtimeLag']],
[useInviteState], [useInviteState],
[useHarkState, ['notificationsCount']],
[useContactState] [useContactState]
]); ]);

View File

@ -108,7 +108,7 @@ export const Content = (props) => {
if(Object.keys(associations).length > 0 && query.has('grid-note')) { if(Object.keys(associations).length > 0 && query.has('grid-note')) {
history.push(getNotificationRedirect(query.get('grid-note'))); history.push(getNotificationRedirect(query.get('grid-note')));
} }
}, [location.search]); }, [location.search, associations]);
useShortcut('navForward', useCallback((e) => { useShortcut('navForward', useCallback((e) => {
e.preventDefault(); e.preventDefault();

View File

@ -128,7 +128,8 @@ export const SidebarDmItem = React.memo((props: {
!hideNicknames && contact?.nickname !hideNicknames && contact?.nickname
? contact?.nickname ? contact?.nickname
: cite(ship) ?? ship; : cite(ship) ?? ship;
const { unreads } = useHarkDm(ship) || { unreads: 0 }; const { count, each } = useHarkDm(ship);
const unreads = count + each.length;
const img = const img =
contact?.avatar && !hideAvatars ? ( contact?.avatar && !hideAvatars ? (
<BaseImage <BaseImage