mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-01 11:33:41 +03:00
interface: route new joining flow
This commit is contained in:
parent
16e9381176
commit
fd64a627c3
@ -1,19 +1,23 @@
|
||||
/* eslint-disable max-lines-per-function */
|
||||
import { Box, Icon, Row, Text } from '@tlon/indigo-react';
|
||||
import React, { ReactElement } from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Route } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import useSettingsState, { selectCalmState } from '~/logic/state/settings';
|
||||
import { JoinGroup } from '~/views/landscape/components/JoinGroup';
|
||||
import { NewGroup } from '~/views/landscape/components/NewGroup';
|
||||
import Groups from './components/Groups';
|
||||
import ModalButton from './components/ModalButton';
|
||||
import Tiles from './components/tiles';
|
||||
import Tile from './components/tiles/tile';
|
||||
import { Invite } from './components/Invite';
|
||||
import './css/custom.css';
|
||||
import { Box, Icon, Row, Text, Button } from "@tlon/indigo-react";
|
||||
import React, { ReactElement } from "react";
|
||||
import { Helmet } from "react-helmet";
|
||||
import { Route, useHistory } from "react-router-dom";
|
||||
import styled from "styled-components";
|
||||
import useHarkState from "~/logic/state/hark";
|
||||
import useSettingsState, { selectCalmState } from "~/logic/state/settings";
|
||||
import { JoinGroup } from "~/views/landscape/components/JoinGroup";
|
||||
import { NewGroup } from "~/views/landscape/components/NewGroup";
|
||||
import Groups from "./components/Groups";
|
||||
import ModalButton from "./components/ModalButton";
|
||||
import Tiles from "./components/tiles";
|
||||
import Tile from "./components/tiles/tile";
|
||||
import { Invite } from "./components/Invite";
|
||||
import "./css/custom.css";
|
||||
import { join } from "@urbit/api/groups";
|
||||
import { joinGraph } from "@urbit/api/graph";
|
||||
import airlock from "~/logic/api";
|
||||
import { Join, JoinRoute } from "~/views/landscape/components/Join";
|
||||
|
||||
const ScrollbarLessBox = styled(Box)`
|
||||
scrollbar-width: none !important;
|
||||
@ -28,73 +32,85 @@ interface LaunchAppProps {
|
||||
}
|
||||
|
||||
export const LaunchApp = (props: LaunchAppProps): ReactElement | null => {
|
||||
const notificationsCount = useHarkState(state => state.notificationsCount);
|
||||
const notificationsCount = useHarkState((state) => state.notificationsCount);
|
||||
const calmState = useSettingsState(selectCalmState);
|
||||
const { hideUtilities, hideGroups } = calmState;
|
||||
const history = useHistory();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet defer={false}>
|
||||
<title>{ notificationsCount ? `(${String(notificationsCount) }) `: '' }Groups</title>
|
||||
<title>
|
||||
{notificationsCount ? `(${String(notificationsCount)}) ` : ""}Groups
|
||||
</title>
|
||||
</Helmet>
|
||||
<Route path="/invites/:app/:uid">
|
||||
<Invite />
|
||||
<Route path="/join/:ship/:name">
|
||||
<JoinRoute modal />
|
||||
</Route>
|
||||
<ScrollbarLessBox height='100%' overflowY='scroll' display="flex" flexDirection="column">
|
||||
<ScrollbarLessBox
|
||||
height="100%"
|
||||
overflowY="scroll"
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
>
|
||||
<Box
|
||||
mx={2}
|
||||
display='grid'
|
||||
gridTemplateColumns='repeat(auto-fill, minmax(128px, 1fr))'
|
||||
display="grid"
|
||||
gridTemplateColumns="repeat(auto-fill, minmax(128px, 1fr))"
|
||||
gridGap={3}
|
||||
p={2}
|
||||
pt={0}
|
||||
>
|
||||
{!hideUtilities && <>
|
||||
<Tile
|
||||
bg="white"
|
||||
color="scales.black20"
|
||||
to="/~landscape/home"
|
||||
p={0}
|
||||
>
|
||||
<Box
|
||||
p={2}
|
||||
height='100%'
|
||||
width='100%'
|
||||
bg='scales.black20'
|
||||
border={1}
|
||||
borderColor="lightGray"
|
||||
>
|
||||
<Row alignItems='center'>
|
||||
<Icon
|
||||
color="black"
|
||||
icon="Home"
|
||||
/>
|
||||
<Text ml={2} mt='1px' color="black">My Channels</Text>
|
||||
</Row>
|
||||
</Box>
|
||||
</Tile>
|
||||
<Tiles />
|
||||
<ModalButton
|
||||
icon="Plus"
|
||||
bg="washedGray"
|
||||
color="black"
|
||||
text="New Group"
|
||||
style={{ gridColumnStart: 1 }}
|
||||
>
|
||||
<NewGroup />
|
||||
</ModalButton>
|
||||
<ModalButton
|
||||
icon="BootNode"
|
||||
bg="washedGray"
|
||||
color="black"
|
||||
text="Join Group"
|
||||
>
|
||||
{dismiss => <JoinGroup dismiss={dismiss} />}
|
||||
</ModalButton>
|
||||
</>}
|
||||
{!hideGroups &&
|
||||
(<Groups />)
|
||||
}
|
||||
{!hideUtilities && (
|
||||
<>
|
||||
<Tile
|
||||
bg="white"
|
||||
color="scales.black20"
|
||||
to="/~landscape/home"
|
||||
p={0}
|
||||
>
|
||||
<Box
|
||||
p={2}
|
||||
height="100%"
|
||||
width="100%"
|
||||
bg="scales.black20"
|
||||
border={1}
|
||||
borderColor="lightGray"
|
||||
>
|
||||
<Row alignItems="center">
|
||||
<Icon color="black" icon="Home" />
|
||||
<Text ml={2} mt="1px" color="black">
|
||||
My Channels
|
||||
</Text>
|
||||
</Row>
|
||||
</Box>
|
||||
</Tile>
|
||||
<Tiles />
|
||||
<ModalButton
|
||||
icon="Plus"
|
||||
bg="washedGray"
|
||||
color="black"
|
||||
text="New Group"
|
||||
style={{ gridColumnStart: 1 }}
|
||||
>
|
||||
<NewGroup />
|
||||
</ModalButton>
|
||||
<Button
|
||||
bg="washedGray"
|
||||
color="black"
|
||||
border={0}
|
||||
p={0}
|
||||
borderRadius={2}
|
||||
onClick={() => history.push({ search: "?join-kind=group" })}
|
||||
>
|
||||
<Row gapX="2" p={2} height="100%" width="100%" alignItems="center">
|
||||
<Icon icon="BootNode" />
|
||||
<Text fontWeight="medium" whiteSpace="nowrap">Join Group</Text>
|
||||
</Row>
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{!hideGroups && <Groups />}
|
||||
</Box>
|
||||
</ScrollbarLessBox>
|
||||
</>
|
||||
|
@ -1,16 +1,27 @@
|
||||
import { Box, Col, Text } from '@tlon/indigo-react';
|
||||
import { Association, Associations, Unreads } from '@urbit/api';
|
||||
import f from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import { getNotificationCount } from '~/logic/lib/hark';
|
||||
import { alphabeticalOrder } from '~/logic/lib/util';
|
||||
import useGroupState from '~/logic/state/group';
|
||||
import useHarkState, { selHarkGraph } from '~/logic/state/hark';
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
import { Box, Col, Text } from "@tlon/indigo-react";
|
||||
import {
|
||||
Association,
|
||||
Associations,
|
||||
resourceAsPath,
|
||||
resourceFromPath,
|
||||
Unreads,
|
||||
} from "@urbit/api";
|
||||
import f from "lodash/fp";
|
||||
import _ from "lodash";
|
||||
import React from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { getNotificationCount } from "~/logic/lib/hark";
|
||||
import { alphabeticalOrder } from "~/logic/lib/util";
|
||||
import useGroupState from "~/logic/state/group";
|
||||
import useHarkState, { selHarkGraph } from "~/logic/state/hark";
|
||||
import useInviteState from "~/logic/state/invite";
|
||||
import useMetadataState, { usePreview } from "~/logic/state/metadata";
|
||||
import useSettingsState, {
|
||||
selectCalmState
|
||||
} from '~/logic/state/settings';
|
||||
import Tile from '../components/tiles/tile';
|
||||
selectCalmState,
|
||||
SettingsState,
|
||||
} from "~/logic/state/settings";
|
||||
import Tile from "../components/tiles/tile";
|
||||
import { useQuery } from "~/logic/lib/useQuery";
|
||||
|
||||
const sortGroupsAlph = (a: Association, b: Association) =>
|
||||
alphabeticalOrder(a.metadata.title, b.metadata.title);
|
||||
@ -25,7 +36,7 @@ const getGraphUnreads = (associations: Associations) => {
|
||||
return (path: string) =>
|
||||
f.flow(
|
||||
f.pickBy((a: Association) => a.group === path),
|
||||
f.map('resource'),
|
||||
f.map("resource"),
|
||||
f.map(selUnread),
|
||||
f.reduce(f.add, 0)
|
||||
)(associations.graph);
|
||||
@ -37,18 +48,18 @@ const getGraphNotifications = (
|
||||
) => (path: string) =>
|
||||
f.flow(
|
||||
f.pickBy((a: Association) => a.group === path),
|
||||
f.map('resource'),
|
||||
f.map(rid => getNotificationCount(unreads, rid)),
|
||||
f.map("resource"),
|
||||
f.map((rid) => getNotificationCount(unreads, rid)),
|
||||
f.reduce(f.add, 0)
|
||||
)(associations.graph);
|
||||
|
||||
export default function Groups(props: Parameters<typeof Box>[0]) {
|
||||
const unreads = useHarkState(state => state.unreads);
|
||||
const groupState = useGroupState(state => state.groups);
|
||||
const associations = useMetadataState(state => state.associations);
|
||||
const unreads = useHarkState((state) => state.unreads);
|
||||
const groupState = useGroupState((state) => state.groups);
|
||||
const associations = useMetadataState((state) => state.associations);
|
||||
|
||||
const groups = Object.values(associations?.groups || {})
|
||||
.filter(e => e?.group in groupState)
|
||||
.filter((e) => e?.group in groupState)
|
||||
.sort(sortGroupsAlph);
|
||||
const graphUnreads = getGraphUnreads(associations || ({} as Associations));
|
||||
const graphNotifications = getGraphNotifications(
|
||||
@ -56,6 +67,20 @@ export default function Groups(props: Parameters<typeof Box>[0]) {
|
||||
unreads
|
||||
);
|
||||
|
||||
const joining = useGroupState((s) =>
|
||||
_.omit(
|
||||
_.pickBy(s.pendingJoin || {}, req => req.app === 'groups'),
|
||||
groups.map((g) => g.group)
|
||||
)
|
||||
);
|
||||
const invites = useInviteState(
|
||||
(s) =>
|
||||
Object.values(s.invites?.["groups"] || {}).map((inv) =>
|
||||
resourceAsPath(inv.resource)
|
||||
) || []
|
||||
);
|
||||
const pending = _.union(invites, Object.keys(joining));
|
||||
|
||||
return (
|
||||
<>
|
||||
{groups.map((group, index) => {
|
||||
@ -73,10 +98,60 @@ export default function Groups(props: Parameters<typeof Box>[0]) {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{pending.map((group, idx) => (
|
||||
<PendingGroup
|
||||
key={group}
|
||||
path={group}
|
||||
first={idx === 0 && groups.length === 0}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface PendingGroupProps {
|
||||
path: string;
|
||||
first?: boolean;
|
||||
}
|
||||
|
||||
function PendingGroup(props: PendingGroupProps) {
|
||||
const { path, first } = props;
|
||||
const history = useHistory();
|
||||
const { preview, error } = usePreview(path);
|
||||
const title = preview?.metadata?.title || path;
|
||||
const { toQuery } = useQuery();
|
||||
const onClick = () => {
|
||||
const { ship, name } = resourceFromPath(path);
|
||||
history.push(toQuery({ "join-kind": "groups", "join-path": path }));
|
||||
};
|
||||
|
||||
const joining = useGroupState((s) => s.pendingJoin[path]?.progress);
|
||||
|
||||
return (
|
||||
<Tile gridColumnStart={first ? 1 : undefined}>
|
||||
<Col
|
||||
onClick={onClick}
|
||||
width="100%"
|
||||
height="100%"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Box>
|
||||
<Text gray>{title}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
{!joining ? (
|
||||
<Text color="blue">Invited</Text>
|
||||
) : joining !== "done" ? (
|
||||
<Text gray>Joining...</Text>
|
||||
) : (
|
||||
<Text color="blue">Recently joined</Text>
|
||||
)}
|
||||
</Box>
|
||||
</Col>
|
||||
</Tile>
|
||||
);
|
||||
}
|
||||
|
||||
interface GroupProps {
|
||||
path: string;
|
||||
title: string;
|
||||
@ -87,6 +162,7 @@ interface GroupProps {
|
||||
function Group(props: GroupProps) {
|
||||
const { path, title, unreads, updates, first = false } = props;
|
||||
const { hideUnreads } = useSettingsState(selectCalmState);
|
||||
const request = useGroupState((s) => s.pendingJoin[path]);
|
||||
return (
|
||||
<Tile
|
||||
position="relative"
|
||||
@ -97,9 +173,10 @@ function Group(props: GroupProps) {
|
||||
<Text>{title}</Text>
|
||||
{!hideUnreads && (
|
||||
<Col>
|
||||
{!!request ? <Text color="blue">New group</Text> : null}
|
||||
{updates > 0 && (
|
||||
<Text mt={1} color="blue">
|
||||
{updates} update{updates !== 1 && 's'}{' '}
|
||||
{updates} update{updates !== 1 && "s"}{" "}
|
||||
</Text>
|
||||
)}
|
||||
{unreads > 0 && <Text color="lightGray">{unreads}</Text>}
|
||||
|
@ -15,6 +15,7 @@ import { useShortcut } from '~/logic/state/settings';
|
||||
import Landscape from '~/views/landscape/index';
|
||||
import GraphApp from '../../apps/graph/App';
|
||||
import { getNotificationRedirect } from '~/logic/lib/notificationRedirects';
|
||||
import {JoinRoute} from './Join';
|
||||
|
||||
export const Container = styled(Box)`
|
||||
flex-grow: 1;
|
||||
@ -68,11 +69,11 @@ export const Content = (props) => {
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<JoinRoute />
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path={['/', '/invites/:app/:uid']}
|
||||
render={p => (
|
||||
path="/" render={p => (
|
||||
<LaunchApp
|
||||
location={p.location}
|
||||
match={p.match}
|
||||
|
Loading…
Reference in New Issue
Block a user