mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-02 15:13:25 +03:00
Invites, JoinStatus: refactor for smoothness
This commit is contained in:
parent
b4e5430bfc
commit
afb0424efd
@ -1,8 +1,9 @@
|
||||
import React, { useCallback, useState } from "react";
|
||||
import _ from 'lodash';
|
||||
import { Box, Row, Col } from "@tlon/indigo-react";
|
||||
import GlobalApi from "~/logic/api/global";
|
||||
import { Invites as IInvites, Associations, Invite, JoinRequests, Groups } from "~/types";
|
||||
import { resourceAsPath } from "~/logic/lib/util";
|
||||
import { Invites as IInvites, Associations, Invite, JoinRequests, Groups, Contacts, AppInvites, JoinProgress } from "~/types";
|
||||
import { resourceAsPath, alphabeticalOrder } from "~/logic/lib/util";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { useWaitForProps } from "~/logic/lib/useWaitForProps";
|
||||
import InviteItem from "~/views/components/Invite";
|
||||
@ -14,10 +15,17 @@ interface InvitesProps {
|
||||
api: GlobalApi;
|
||||
invites: IInvites;
|
||||
groups: Groups;
|
||||
contacts: Contacts;
|
||||
associations: Associations;
|
||||
pendingJoin: JoinRequests;
|
||||
}
|
||||
|
||||
interface InviteRef {
|
||||
uid: string;
|
||||
app: string
|
||||
invite: Invite;
|
||||
}
|
||||
|
||||
export function Invites(props: InvitesProps) {
|
||||
const { api, invites, pendingJoin } = props;
|
||||
const [selected, setSelected] = useState<[string, string, Invite] | undefined>()
|
||||
@ -48,7 +56,18 @@ export function Invites(props: InvitesProps) {
|
||||
inviteUid={uid}
|
||||
inviteApp={app}
|
||||
/>
|
||||
)}});
|
||||
)}});
|
||||
|
||||
const inviteArr: InviteRef[] = _.reduce(invites, (acc: InviteRef[], val: AppInvites, app: string) => {
|
||||
const appInvites = _.reduce(val, (invs: InviteRef[], invite: Invite, uid: string) => {
|
||||
return [...invs, { invite, uid, app }];
|
||||
|
||||
}, []);
|
||||
return [...acc, ...appInvites];
|
||||
}, []);
|
||||
|
||||
const invitesAndStatus: { [rid: string]: JoinProgress | InviteRef } =
|
||||
{..._.keyBy(inviteArr, ({ invite }) => resourceAsPath(invite.resource)), ...props.pendingJoin };
|
||||
|
||||
|
||||
|
||||
@ -61,33 +80,42 @@ export function Invites(props: InvitesProps) {
|
||||
position="sticky"
|
||||
flexShrink={0}
|
||||
>
|
||||
{modal}
|
||||
{ Object
|
||||
.keys(props.pendingJoin)
|
||||
.map(resource => (
|
||||
<JoiningStatus
|
||||
key={resource}
|
||||
resource={resource}
|
||||
status={pendingJoin[resource]}
|
||||
api={api} />
|
||||
))
|
||||
}
|
||||
.keys(invitesAndStatus)
|
||||
.sort(alphabeticalOrder)
|
||||
.map(resource => {
|
||||
const inviteOrStatus = invitesAndStatus[resource];
|
||||
if(typeof inviteOrStatus === 'string') {
|
||||
return (
|
||||
<InviteItem
|
||||
key={resource}
|
||||
contacts={props.contacts}
|
||||
groups={props.groups}
|
||||
associations={props.associations}
|
||||
resource={resource}
|
||||
pendingJoin={pendingJoin}
|
||||
api={api} />
|
||||
)
|
||||
|
||||
{Object.keys(invites).reduce((items, appKey) => {
|
||||
const app = invites[appKey];
|
||||
let appItems = Object.keys(app).map((uid) => {
|
||||
const invite = app[uid];
|
||||
} else {
|
||||
const { app, uid, invite } = inviteOrStatus;
|
||||
console.log(inviteOrStatus);
|
||||
return (
|
||||
<InviteItem
|
||||
key={uid}
|
||||
key={resource}
|
||||
api={api}
|
||||
invite={invite}
|
||||
onAccept={acceptInvite(appKey, uid, invite)}
|
||||
onDecline={declineInvite(appKey, uid)}
|
||||
app={app}
|
||||
uid={uid}
|
||||
pendingJoin={pendingJoin}
|
||||
resource={resource}
|
||||
contacts={props.contacts}
|
||||
groups={props.groups}
|
||||
associations={props.associations}
|
||||
/>
|
||||
);
|
||||
});
|
||||
return [...items, ...appItems];
|
||||
}, [] as JSX.Element[])}
|
||||
)
|
||||
}
|
||||
})}
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
|
@ -1,49 +1,45 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Col, Text, SegmentedProgressBar } from "@tlon/indigo-react";
|
||||
import { Col, Row, Text, SegmentedProgressBar, Box } from "@tlon/indigo-react";
|
||||
import GlobalApi from "~/logic/api/global";
|
||||
import { JoinProgress, joinProgress, MetadataUpdatePreview, joinError } from "~/types";
|
||||
import {
|
||||
JoinProgress,
|
||||
joinProgress,
|
||||
MetadataUpdatePreview,
|
||||
joinError,
|
||||
} from "~/types";
|
||||
import { clamp } from "~/logic/lib/util";
|
||||
|
||||
interface JoiningStatusProps {
|
||||
resource: string;
|
||||
api: GlobalApi;
|
||||
status: JoinProgress;
|
||||
}
|
||||
|
||||
const description: string[] =
|
||||
["Attempting to contact group host",
|
||||
"Retrieving group data",
|
||||
"Finished join",
|
||||
"Unable to join group, you do not have the correct permissions",
|
||||
"Internal error, please file an issue"
|
||||
];
|
||||
|
||||
|
||||
const description: string[] = [
|
||||
"Attempting to contact host",
|
||||
"Retrieving data",
|
||||
"Finished join",
|
||||
"Unable to join, you do not have the correct permissions",
|
||||
"Internal error, please file an issue",
|
||||
];
|
||||
|
||||
export function JoiningStatus(props: JoiningStatusProps) {
|
||||
const { resource, status, api } = props;
|
||||
|
||||
const [preview, setPreview] = useState<MetadataUpdatePreview | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const prev = await api.metadata.preview(resource);
|
||||
setPreview(prev)
|
||||
})();
|
||||
return () => {
|
||||
setPreview(null);
|
||||
}
|
||||
}, [resource])
|
||||
const { status } = props;
|
||||
|
||||
const current = joinProgress.indexOf(status);
|
||||
const desc = description?.[current] || "";
|
||||
const title = preview?.metadata?.title ?? resource;
|
||||
const isError = joinError.indexOf(status as any) !== -1;
|
||||
return (
|
||||
<Col py="3" mx="5" gapY="2">
|
||||
<Text fontSize="1">{isError ? "Failed to join " : "Joining "} {title}</Text>
|
||||
<Text color={isError ? "red" : "gray"}>{desc}</Text>
|
||||
<SegmentedProgressBar current={current + 1} segments={3} />
|
||||
</Col>
|
||||
<Row
|
||||
display={["flex-column", "flex"]}
|
||||
alignItems="center"
|
||||
px="4"
|
||||
gapX="4"
|
||||
>
|
||||
<Box flexGrow={1} maxWidth="400px">
|
||||
<SegmentedProgressBar current={current + 1} segments={3} />
|
||||
</Box>
|
||||
<Text display="block" flexShrink={0} color={isError ? "red" : "gray"}>
|
||||
{desc}
|
||||
</Text>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
@ -1,52 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Invite } from '~/types/invite-update';
|
||||
import { Text, Box, Button, Row, Rule } from '@tlon/indigo-react';
|
||||
import { StatelessAsyncAction } from "~/views/components/StatelessAsyncAction";
|
||||
import { cite } from '~/logic/lib/util';
|
||||
|
||||
export class InviteItem extends Component<{invite: Invite, onAccept: (i: any) => Promise<any>, onDecline: (i: any) => Promise<any>}, {}> {
|
||||
render() {
|
||||
const { props } = this;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box width='100%' p='4'>
|
||||
<Box width='100%' verticalAlign='middle'>
|
||||
<Text display='block' pb='2' gray>
|
||||
<Text mono>{cite(props.invite.resource.ship)}</Text>
|
||||
{" "}invited you to{" "}
|
||||
<Text fontWeight='500'>{props.invite.resource.name}</Text></Text>
|
||||
</Box>
|
||||
{props.invite.text && (
|
||||
<Box pb="2">
|
||||
<Text gray>{props.invite.text}</Text>
|
||||
</Box>
|
||||
)}
|
||||
<Row>
|
||||
<StatelessAsyncAction
|
||||
name="accept"
|
||||
bg="transparent"
|
||||
onClick={() => props.onAccept(props.invite)}
|
||||
color='blue'
|
||||
mr='2'
|
||||
>
|
||||
Accept
|
||||
</StatelessAsyncAction>
|
||||
<StatelessAsyncAction
|
||||
name="decline"
|
||||
bg="transparent"
|
||||
color='red'
|
||||
onClick={() => props.onDecline(props.invite)}
|
||||
>
|
||||
Reject
|
||||
</StatelessAsyncAction>
|
||||
|
||||
</Row>
|
||||
</Box>
|
||||
<Rule />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default InviteItem;
|
76
pkg/interface/src/views/components/Invite/Group.tsx
Normal file
76
pkg/interface/src/views/components/Invite/Group.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
import React, { ReactNode } from "react";
|
||||
import { Text, Box, Button, Icon, Row, Rule, Col } from "@tlon/indigo-react";
|
||||
|
||||
import { cite } from "~/logic/lib/util";
|
||||
import { MetadataUpdatePreview, JoinProgress, Invite } from "~/types";
|
||||
import { GroupSummary } from "~/views/landscape/components/GroupSummary";
|
||||
import { InviteSkeleton } from "./InviteSkeleton";
|
||||
import { JoinSkeleton } from "./JoinSkeleton";
|
||||
|
||||
interface GroupInviteProps {
|
||||
preview: MetadataUpdatePreview;
|
||||
status?: JoinProgress;
|
||||
invite?: Invite;
|
||||
onAccept: () => Promise<any>;
|
||||
onDecline: () => Promise<any>;
|
||||
}
|
||||
|
||||
export function GroupInvite(props: GroupInviteProps) {
|
||||
const { preview, invite, status, onAccept, onDecline } = props;
|
||||
const { metadata, members } = props.preview;
|
||||
|
||||
let inner: ReactNode = null;
|
||||
let Outer: (p: { children: ReactNode }) => JSX.Element = (p) => (
|
||||
<>{p.children}</>
|
||||
);
|
||||
|
||||
if (status) {
|
||||
inner = (
|
||||
<Text mr="1">
|
||||
You are joining <Text fontWeight="medium">{metadata.title}</Text>
|
||||
</Text>
|
||||
);
|
||||
Outer = ({ children }) => (
|
||||
<JoinSkeleton gapY="3" status={status}>
|
||||
{children}
|
||||
</JoinSkeleton>
|
||||
);
|
||||
} else if (invite) {
|
||||
Outer = ({ children }) => (
|
||||
<InviteSkeleton
|
||||
onDecline={onDecline}
|
||||
onAccept={onAccept}
|
||||
acceptDesc="Join Group"
|
||||
declineDesc="Decline Invitation"
|
||||
gapY="3"
|
||||
>
|
||||
{children}
|
||||
</InviteSkeleton>
|
||||
);
|
||||
inner = (
|
||||
<>
|
||||
<Text mr="1" mono>
|
||||
{cite(`~${invite!.ship}`)}
|
||||
</Text>
|
||||
<Text mr="1">invited you to </Text>
|
||||
<Text fontWeight="medium">{metadata.title}</Text>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Outer>
|
||||
<Row py="1" alignItems="center">
|
||||
<Icon display="block" mr={2} icon="Bullet" color="blue" />
|
||||
{inner}
|
||||
</Row>
|
||||
<Box px="4">
|
||||
<GroupSummary
|
||||
gray
|
||||
metadata={metadata}
|
||||
memberCount={members}
|
||||
channelCount={preview?.["channel-count"]}
|
||||
/>
|
||||
</Box>
|
||||
</Outer>
|
||||
);
|
||||
}
|
53
pkg/interface/src/views/components/Invite/InviteSkeleton.tsx
Normal file
53
pkg/interface/src/views/components/Invite/InviteSkeleton.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import React, { ReactNode } from "react";
|
||||
import { Text, Box, Button, Icon, Row, Rule, Col } from "@tlon/indigo-react";
|
||||
|
||||
import { StatelessAsyncAction } from "~/views/components/StatelessAsyncAction";
|
||||
import { PropFunc } from "~/types";
|
||||
|
||||
export interface InviteSkeletonProps {
|
||||
onAccept: () => Promise<any>;
|
||||
onDecline: () => Promise<any>;
|
||||
acceptDesc: string;
|
||||
declineDesc: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function InviteSkeleton(
|
||||
props: InviteSkeletonProps & PropFunc<typeof Col>
|
||||
) {
|
||||
const {
|
||||
children,
|
||||
acceptDesc,
|
||||
declineDesc,
|
||||
onAccept,
|
||||
onDecline,
|
||||
...rest
|
||||
} = props;
|
||||
return (
|
||||
<>
|
||||
<Col width="100%" p="1" {...rest}>
|
||||
{children}
|
||||
<Row px="4" gapX="4">
|
||||
<StatelessAsyncAction
|
||||
name="accept"
|
||||
bg="transparent"
|
||||
onClick={onAccept}
|
||||
color="blue"
|
||||
mr="2"
|
||||
>
|
||||
{acceptDesc}
|
||||
</StatelessAsyncAction>
|
||||
<StatelessAsyncAction
|
||||
name="decline"
|
||||
bg="transparent"
|
||||
color="red"
|
||||
onClick={onDecline}
|
||||
>
|
||||
{declineDesc}
|
||||
</StatelessAsyncAction>
|
||||
</Row>
|
||||
</Col>
|
||||
<Rule />
|
||||
</>
|
||||
);
|
||||
}
|
22
pkg/interface/src/views/components/Invite/JoinSkeleton.tsx
Normal file
22
pkg/interface/src/views/components/Invite/JoinSkeleton.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import React, { ReactNode } from "react";
|
||||
import { Col, Row, SegmentedProgressBar, Text, Rule } from "@tlon/indigo-react";
|
||||
import { JoiningStatus } from "~/views/apps/notifications/joining";
|
||||
import { JoinProgress, PropFunc } from "~/types";
|
||||
|
||||
type JoinSkeletonProps = {
|
||||
children: ReactNode;
|
||||
status: JoinProgress;
|
||||
} & PropFunc<typeof Col>;
|
||||
|
||||
export function JoinSkeleton(props: JoinSkeletonProps) {
|
||||
const { children, status, ...rest } = props;
|
||||
return (
|
||||
<>
|
||||
<Col p="1" {...rest}>
|
||||
{children}
|
||||
<JoiningStatus status={status} />
|
||||
</Col>
|
||||
<Rule />
|
||||
</>
|
||||
);
|
||||
}
|
172
pkg/interface/src/views/components/Invite/index.tsx
Normal file
172
pkg/interface/src/views/components/Invite/index.tsx
Normal file
@ -0,0 +1,172 @@
|
||||
import React, { Component, useState, useEffect, useCallback, useMemo } from "react";
|
||||
import { Invite } from "~/types/invite-update";
|
||||
import { Text, Box, Button, Icon, Row, Rule, Col } from "@tlon/indigo-react";
|
||||
import { StatelessAsyncAction } from "~/views/components/StatelessAsyncAction";
|
||||
import { cite } from "~/logic/lib/util";
|
||||
import {
|
||||
MetadataUpdatePreview,
|
||||
Contacts,
|
||||
JoinRequests,
|
||||
JoinProgress,
|
||||
Groups,
|
||||
Associations,
|
||||
} from "~/types";
|
||||
import GlobalApi from "~/logic/api/global";
|
||||
import { GroupSummary } from "~/views/landscape/components/GroupSummary";
|
||||
import { JoiningStatus } from "~/views/apps/notifications/joining";
|
||||
import { resourceFromPath } from "~/logic/lib/group";
|
||||
import { GroupInvite } from "./Group";
|
||||
import { InviteSkeleton } from "./InviteSkeleton";
|
||||
import { JoinSkeleton } from "./JoinSkeleton";
|
||||
import { useWaitForProps } from "~/logic/lib/useWaitForProps";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
interface InviteItemProps {
|
||||
invite?: Invite;
|
||||
resource: string;
|
||||
groups: Groups;
|
||||
associations: Associations;
|
||||
|
||||
pendingJoin: JoinRequests;
|
||||
app?: string;
|
||||
uid?: string;
|
||||
api: GlobalApi;
|
||||
contacts: Contacts;
|
||||
}
|
||||
|
||||
export function InviteItem(props: InviteItemProps) {
|
||||
const [preview, setPreview] = useState<MetadataUpdatePreview | null>(null);
|
||||
const { associations, pendingJoin, invite, resource, uid, app, api } = props;
|
||||
const { ship, name } = resourceFromPath(resource);
|
||||
const waiter = useWaitForProps(props, 50000);
|
||||
const status = pendingJoin[resource];
|
||||
|
||||
const history = useHistory();
|
||||
const inviteAccept = useCallback(async () => {
|
||||
if (!(app && invite && uid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
api.groups.join(ship, name);
|
||||
await waiter(p => resource in p.pendingJoin);
|
||||
|
||||
api.invite.accept(app, uid);
|
||||
await waiter((p) => {
|
||||
return (
|
||||
resource in p.groups &&
|
||||
(resource in (p.associations?.graph ?? {}) ||
|
||||
resource in (p.associations?.groups ?? {}))
|
||||
);
|
||||
});
|
||||
|
||||
if (props.groups?.[resource]?.hidden) {
|
||||
const { metadata } = associations.graph[resource];
|
||||
if (name.startsWith("dm--")) {
|
||||
history.push(`/~landscape/messages/resource/${metadata.module}${resource}`);
|
||||
} else {
|
||||
history.push(`/~landscape/home/resource/${metadata.module}${resource}`);
|
||||
}
|
||||
} else {
|
||||
history.push(`/~landscape${resource}`);
|
||||
}
|
||||
}, [app, invite, uid, resource, props.groups, associations]);
|
||||
|
||||
const inviteDecline = useCallback(async () => {
|
||||
if(!(app && uid)) {
|
||||
return;
|
||||
}
|
||||
await api.invite.decline(app, uid);
|
||||
}, [app, uid]);
|
||||
|
||||
const handlers = { onAccept: inviteAccept, onDecline: inviteDecline }
|
||||
|
||||
useEffect(() => {
|
||||
if (!app || app === "groups") {
|
||||
(async () => {
|
||||
setPreview(await api.metadata.preview(resource));
|
||||
})();
|
||||
return () => {
|
||||
setPreview(null);
|
||||
};
|
||||
} else {
|
||||
return () => {};
|
||||
}
|
||||
}, [invite]);
|
||||
|
||||
if (preview) {
|
||||
return (
|
||||
<GroupInvite
|
||||
preview={preview}
|
||||
invite={invite}
|
||||
status={status}
|
||||
{...handlers}
|
||||
/>
|
||||
);
|
||||
} else if (invite && name.startsWith("dm--")) {
|
||||
return (
|
||||
<InviteSkeleton
|
||||
gapY="3"
|
||||
{...handlers}
|
||||
acceptDesc="Join DM"
|
||||
declineDesc="Decline DM"
|
||||
>
|
||||
<Row py="1" alignItems="center">
|
||||
<Icon display="block" color="blue" icon="Bullet" mr="2" />
|
||||
<Text mr="1" mono>
|
||||
{cite(`~${invite!.ship}`)}
|
||||
</Text>
|
||||
<Text mr="1">invited you to a DM</Text>
|
||||
</Row>
|
||||
</InviteSkeleton>
|
||||
);
|
||||
} else if (status && name.startsWith("dm--")) {
|
||||
return (
|
||||
<JoinSkeleton status={status} gapY="3">
|
||||
<Row py="1" alignItems="center">
|
||||
<Icon display="block" color="blue" icon="Bullet" mr="2" />
|
||||
<Text mr="1">You are joining a DM with</Text>
|
||||
<Text mr="1" mono>
|
||||
{cite("~hastuc-dibtux")}
|
||||
</Text>
|
||||
</Row>
|
||||
</JoinSkeleton>
|
||||
);
|
||||
} else if (invite) {
|
||||
return (
|
||||
<InviteSkeleton
|
||||
acceptDesc="Accept Invite"
|
||||
declineDesc="Decline Invite"
|
||||
{...handlers}
|
||||
gapY="3"
|
||||
>
|
||||
<Row py="1" alignItems="center">
|
||||
<Icon display="block" color="blue" icon="Bullet" mr="2" />
|
||||
<Text mr="1" mono>
|
||||
{cite(`~${invite!.ship}`)}
|
||||
</Text>
|
||||
<Text mr="1">
|
||||
invited you to ~{invite.resource.ship}/{invite.resource.name}
|
||||
</Text>
|
||||
</Row>
|
||||
</InviteSkeleton>
|
||||
);
|
||||
} else if (status) {
|
||||
const [, , ship, name] = resource.split("/");
|
||||
return (
|
||||
<JoinSkeleton status={status}>
|
||||
<Row py="1" alignItems="center">
|
||||
<Icon display="block" color="blue" icon="Bullet" mr="2" />
|
||||
<Text mr="1">
|
||||
You are joining
|
||||
</Text>
|
||||
<Text mono>
|
||||
{cite(ship)}/{name}
|
||||
</Text>
|
||||
</Row>
|
||||
</JoinSkeleton>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default InviteItem;
|
@ -1,5 +1,5 @@
|
||||
import React, { ReactNode, useRef } from "react";
|
||||
import { Metadata } from "~/types";
|
||||
import { Metadata, PropFunc } from "~/types";
|
||||
import { Col, Row, Text } from "@tlon/indigo-react";
|
||||
import { MetadataIcon } from "./MetadataIcon";
|
||||
import { useTutorialModal } from "~/views/components/useTutorialModal";
|
||||
@ -11,10 +11,11 @@ interface GroupSummaryProps {
|
||||
channelCount: number;
|
||||
resource?: string;
|
||||
children?: ReactNode;
|
||||
gray?: boolean;
|
||||
}
|
||||
|
||||
export function GroupSummary(props: GroupSummaryProps) {
|
||||
const { channelCount, memberCount, metadata, resource, children } = props;
|
||||
export function GroupSummary(props: GroupSummaryProps & PropFunc<typeof Col>) {
|
||||
const { channelCount, memberCount, metadata, resource, children, ...rest } = props;
|
||||
const anchorRef = useRef<HTMLElement | null>(null);
|
||||
useTutorialModal(
|
||||
"group-desc",
|
||||
@ -22,7 +23,7 @@ export function GroupSummary(props: GroupSummaryProps) {
|
||||
anchorRef.current
|
||||
);
|
||||
return (
|
||||
<Col ref={anchorRef} maxWidth="300px" gapY="4">
|
||||
<Col {...rest} ref={anchorRef} gapY="4">
|
||||
<Row gapX="2" width="100%">
|
||||
<MetadataIcon
|
||||
borderRadius="1"
|
||||
@ -39,7 +40,7 @@ export function GroupSummary(props: GroupSummaryProps) {
|
||||
textOverflow="ellipsis"
|
||||
whiteSpace="nowrap"
|
||||
overflow="hidden">{metadata.title}</Text>
|
||||
<Row gapX="2" justifyContent="space-between">
|
||||
<Row gapX="4" >
|
||||
<Text fontSize="1" gray>
|
||||
{memberCount} participants
|
||||
</Text>
|
||||
@ -51,7 +52,8 @@ export function GroupSummary(props: GroupSummaryProps) {
|
||||
</Row>
|
||||
<Row width="100%">
|
||||
{metadata.description &&
|
||||
<Text
|
||||
<Text
|
||||
gray
|
||||
width="100%"
|
||||
fontSize="1"
|
||||
textOverflow="ellipsis"
|
||||
|
@ -45,9 +45,6 @@ interface JoinGroupProps {
|
||||
groups: Groups;
|
||||
associations: Associations;
|
||||
api: GlobalApi;
|
||||
autojoin?: string;
|
||||
inviteUid?: string;
|
||||
inviteApp?: string;
|
||||
}
|
||||
|
||||
function Autojoin(props: { autojoin: string | null }) {
|
||||
@ -78,9 +75,6 @@ export function JoinGroup(props: JoinGroupProps) {
|
||||
const onConfirm = useCallback(async (group: string) => {
|
||||
const [,,ship,name] = group.split('/');
|
||||
await api.groups.join(ship, name);
|
||||
if (props.inviteUid && props.inviteApp) {
|
||||
api.invite.accept(props.inviteApp, props.inviteUid);
|
||||
}
|
||||
try {
|
||||
await waiter((p: JoinGroupProps) => {
|
||||
return group in p.groups &&
|
||||
@ -99,17 +93,13 @@ export function JoinGroup(props: JoinGroupProps) {
|
||||
// drop them into inbox to show join request still pending
|
||||
history.push('/~notifications');
|
||||
}
|
||||
}, [api, props.inviteApp, props.inviteUid, waiter, history, associations, groups]);
|
||||
}, [api, waiter, history, associations, groups]);
|
||||
|
||||
const onSubmit = useCallback(
|
||||
async (values: FormSchema, actions: FormikHelpers<FormSchema>) => {
|
||||
const [ship, name] = values.group.split("/");
|
||||
const path = `/ship/${ship}/${name}`;
|
||||
// skip if it's unmanaged
|
||||
if(!!autojoin && props.inviteApp !== 'groups') {
|
||||
await onConfirm(path);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const prev = await api.metadata.preview(path);
|
||||
actions.setStatus({ success: null });
|
||||
@ -127,7 +117,7 @@ export function JoinGroup(props: JoinGroupProps) {
|
||||
}
|
||||
}
|
||||
},
|
||||
[api, waiter, history, onConfirm, props.inviteApp]
|
||||
[api, waiter, history, onConfirm]
|
||||
);
|
||||
|
||||
return (
|
||||
@ -152,7 +142,7 @@ export function JoinGroup(props: JoinGroupProps) {
|
||||
<GroupSummary
|
||||
metadata={preview.metadata}
|
||||
memberCount={preview?.members}
|
||||
channelCount={preview?.channels?.length}
|
||||
channelCount={preview?.['channel-count']}
|
||||
>
|
||||
{ Object.keys(preview.channels).length > 0 && (
|
||||
<Col
|
||||
|
Loading…
Reference in New Issue
Block a user