mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-14 04:19:22 +03:00
interface: move group pokes to airlock
This commit is contained in:
parent
73f43a2829
commit
2f70a433bd
@ -32,6 +32,8 @@ import ModalButton from './components/ModalButton';
|
||||
import Tiles from './components/tiles';
|
||||
import Tile from './components/tiles/tile';
|
||||
import './css/custom.css';
|
||||
import airlock from '~/logic/api';
|
||||
import { join } from '@urbit/api/groups';
|
||||
|
||||
const ScrollbarLessBox = styled(Box)`
|
||||
scrollbar-width: none !important;
|
||||
@ -107,7 +109,7 @@ export const LaunchApp = (props: LaunchAppProps): ReactElement | null => {
|
||||
const onContinue = async (e) => {
|
||||
e.stopPropagation();
|
||||
if (!hasTutorialGroup({ associations })) {
|
||||
await props.api.groups.join(TUTORIAL_HOST, TUTORIAL_GROUP);
|
||||
await airlock.poke(join(TUTORIAL_HOST, TUTORIAL_GROUP));
|
||||
await props.api.settings.putEntry('tutorial', 'joined', Date.now());
|
||||
await waiter(hasTutorialGroup);
|
||||
await Promise.all(
|
||||
|
@ -1,12 +1,9 @@
|
||||
import { Box, Row, SegmentedProgressBar, Text } from '@tlon/indigo-react';
|
||||
import {
|
||||
joinError, joinProgress,
|
||||
|
||||
JoinRequest
|
||||
} from '@urbit/api';
|
||||
import { joinError, joinProgress, JoinRequest, hideGroup } from '@urbit/api';
|
||||
import React, { useCallback } from 'react';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
interface JoiningStatusProps {
|
||||
status: JoinRequest;
|
||||
@ -23,13 +20,17 @@ const description: string[] = [
|
||||
];
|
||||
|
||||
export function JoiningStatus(props: JoiningStatusProps) {
|
||||
const { status, resource, api } = props;
|
||||
const { status, resource } = props;
|
||||
|
||||
const current = joinProgress.indexOf(status.progress);
|
||||
const desc = description?.[current] || '';
|
||||
const isError = joinError.indexOf(status.progress as any) !== -1;
|
||||
const onHide = useCallback(() => api.groups.hide(resource)
|
||||
, [resource, api]);
|
||||
const onHide = useCallback(
|
||||
async () => {
|
||||
await airlock.poke(hideGroup(resource));
|
||||
},
|
||||
[resource]
|
||||
);
|
||||
return (
|
||||
<Row
|
||||
display={['flex-column', 'flex']}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { Box, Text } from '@tlon/indigo-react';
|
||||
import { Association, Group } from '@urbit/api';
|
||||
import { addTag, Association, Group } from '@urbit/api';
|
||||
import { Form, Formik } from 'formik';
|
||||
import React, { ReactElement } from 'react';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { resourceFromPath } from '~/logic/lib/group';
|
||||
import { AsyncButton } from '~/views/components/AsyncButton';
|
||||
import { ShipSearch } from '~/views/components/ShipSearch';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
interface WritersProps {
|
||||
api: GlobalApi;
|
||||
@ -14,18 +15,18 @@ interface WritersProps {
|
||||
}
|
||||
|
||||
export const Writers = (props: WritersProps): ReactElement => {
|
||||
const { association, groups, api } = props;
|
||||
const { association, groups } = props;
|
||||
|
||||
const resource = resourceFromPath(association?.group);
|
||||
|
||||
const onSubmit = async (values, actions) => {
|
||||
try {
|
||||
const ships = values.ships.map(e => `~${e}`);
|
||||
await api.groups.addTag(
|
||||
await airlock.poke(addTag(
|
||||
resource,
|
||||
{ app: 'graph', resource: association.resource, tag: 'writers' },
|
||||
ships
|
||||
);
|
||||
));
|
||||
actions.resetForm();
|
||||
actions.setStatus({ success: null });
|
||||
} catch (e) {
|
||||
|
@ -5,7 +5,8 @@ import {
|
||||
LoadingSpinner, Row, Text
|
||||
} from '@tlon/indigo-react';
|
||||
import {
|
||||
Invite, joinProgress,
|
||||
hideGroup,
|
||||
Invite, join, joinProgress,
|
||||
JoinRequest,
|
||||
Metadata, MetadataUpdatePreview,
|
||||
resourceFromPath
|
||||
@ -27,6 +28,7 @@ import { Header } from '~/views/apps/notifications/header';
|
||||
import { NotificationWrapper } from '~/views/apps/notifications/notification';
|
||||
import { MetadataIcon } from '~/views/landscape/components/MetadataIcon';
|
||||
import { StatelessAsyncButton } from '../StatelessAsyncButton';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
interface GroupInviteProps {
|
||||
preview?: MetadataUpdatePreview;
|
||||
@ -164,7 +166,7 @@ export function useInviteAccept(
|
||||
return false;
|
||||
}
|
||||
|
||||
await api.groups.join(ship, name);
|
||||
await airlock.poke(join(ship, name));
|
||||
await api.invite.accept(app, uid);
|
||||
await waiter((p) => {
|
||||
return (
|
||||
@ -216,15 +218,15 @@ function InviteActions(props: {
|
||||
|
||||
const hideJoin = useCallback(async (e) => {
|
||||
if(status?.progress === 'done') {
|
||||
set(s => {
|
||||
set((s) => {
|
||||
// @ts-ignore investigate zustand types
|
||||
delete s.pendingJoin[resource]
|
||||
delete s.pendingJoin[resource];
|
||||
});
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
await api.groups.hide(resource);
|
||||
}, [api, resource, status]);
|
||||
await airlock.poke(hideGroup(resource));
|
||||
}, [resource, status]);
|
||||
|
||||
if (status) {
|
||||
return (
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
|
||||
Text
|
||||
} from '@tlon/indigo-react';
|
||||
import { Association, Group, metadataUpdate, PermVariation } from '@urbit/api';
|
||||
import { addTag, Association, Group, metadataUpdate, PermVariation, removeTag } from '@urbit/api';
|
||||
import { Form, Formik } from 'formik';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
@ -72,7 +72,7 @@ const formSchema = (members: string[]) => {
|
||||
};
|
||||
|
||||
export function GraphPermissions(props: GraphPermissionsProps) {
|
||||
const { api, group, association } = props;
|
||||
const { group, association } = props;
|
||||
|
||||
const writers = _.get(
|
||||
group?.tags,
|
||||
@ -119,7 +119,7 @@ export function GraphPermissions(props: GraphPermissionsProps) {
|
||||
actions.setStatus({ success: null });
|
||||
return;
|
||||
}
|
||||
await api.groups.removeTag(resource, tag, allWriters);
|
||||
await airlock.poke(removeTag(tag, resource, allWriters));
|
||||
} else if (values.writePerms === 'self') {
|
||||
if (writePerms === 'self') {
|
||||
actions.setStatus({ success: null });
|
||||
@ -127,8 +127,8 @@ export function GraphPermissions(props: GraphPermissionsProps) {
|
||||
}
|
||||
const promises: Promise<any>[] = [];
|
||||
allWriters.length > 0 &&
|
||||
promises.push(api.groups.removeTag(resource, tag, allWriters));
|
||||
promises.push(api.groups.addTag(resource, tag, [`~${hostShip}`]));
|
||||
promises.push(airlock.poke(removeTag(tag, resource, allWriters)));
|
||||
promises.push(airlock.poke(addTag(resource, tag, [`~${hostShip}`])));
|
||||
await Promise.all(promises);
|
||||
actions.setStatus({ success: null });
|
||||
} else if (values.writePerms === 'subset') {
|
||||
@ -141,9 +141,9 @@ export function GraphPermissions(props: GraphPermissionsProps) {
|
||||
|
||||
const promises: Promise<any>[] = [];
|
||||
toRemove.length > 0 &&
|
||||
promises.push(api.groups.removeTag(resource, tag, toRemove));
|
||||
promises.push(airlock.poke(removeTag(tag, resource, toRemove)));
|
||||
toAdd.length > 0 &&
|
||||
promises.push(api.groups.addTag(resource, tag, toAdd));
|
||||
promises.push(airlock.poke(addTag(resource, tag, toAdd)));
|
||||
await Promise.all(promises);
|
||||
|
||||
actions.setStatus({ success: null });
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { Button, Col, Icon, Label, Row, Text } from '@tlon/indigo-react';
|
||||
import { Association } from '@urbit/api';
|
||||
import { Association, leaveGroup } from '@urbit/api';
|
||||
import { deleteGroup } from '@urbit/api/dist';
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { resourceFromPath } from '~/logic/lib/group';
|
||||
import { useModal } from '~/logic/lib/useModal';
|
||||
import { StatelessAsyncButton } from '~/views/components/StatelessAsyncButton';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
export function DeleteGroup(props: {
|
||||
owner: boolean;
|
||||
@ -22,9 +24,9 @@ export function DeleteGroup(props: {
|
||||
return;
|
||||
}
|
||||
if(props.owner) {
|
||||
props.api.groups.deleteGroup(ship, name);
|
||||
airlock.thread(deleteGroup(ship, name));
|
||||
} else {
|
||||
props.api.groups.leaveGroup(ship, name);
|
||||
airlock.thread(leaveGroup(ship, name));
|
||||
}
|
||||
history.push('/');
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
ManagedToggleSwitchField as Checkbox,
|
||||
Text
|
||||
} from '@tlon/indigo-react';
|
||||
import { Enc, metadataUpdate } from '@urbit/api';
|
||||
import { changePolicy, Enc, metadataUpdate } from '@urbit/api';
|
||||
import { Group, GroupPolicy } from '@urbit/api/groups';
|
||||
import { Association } from '@urbit/api/metadata';
|
||||
import { Form, Formik, FormikHelpers } from 'formik';
|
||||
@ -76,7 +76,7 @@ export function GroupAdminSettings(props: GroupAdminSettingsProps) {
|
||||
? { invite: { pending: [] } }
|
||||
: { open: { banRanks: [], banned: [] } };
|
||||
const diff = { replace: newPolicy };
|
||||
await props.api.groups.changePolicy(resource, diff);
|
||||
await airlock.poke(changePolicy(resource, diff));
|
||||
}
|
||||
|
||||
actions.setStatus({ success: null });
|
||||
|
@ -24,14 +24,14 @@ export function GroupChannelSettings(props: GroupChannelSettingsProps) {
|
||||
|
||||
const onChange = useCallback(
|
||||
async (resource: string, preview: boolean) => {
|
||||
return airlock.poke(metadataUpdate(associations.graph[resource], { preview }));
|
||||
await airlock.poke(metadataUpdate(associations.graph[resource], { preview }));
|
||||
},
|
||||
[associations.graph]
|
||||
);
|
||||
|
||||
const onRemove = useCallback(
|
||||
async (resource: string) => {
|
||||
return airlock.poke(metadataRemove('graph', resource, association.group));
|
||||
await airlock.poke(metadataRemove('graph', resource, association.group));
|
||||
},
|
||||
[association]
|
||||
);
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
|
||||
Row, Text
|
||||
} from '@tlon/indigo-react';
|
||||
import { invite } from '@urbit/api/groups';
|
||||
import { Association } from '@urbit/api/metadata';
|
||||
import { Form, Formik } from 'formik';
|
||||
import _ from 'lodash';
|
||||
@ -19,6 +20,7 @@ import { Workspace } from '~/types/workspace';
|
||||
import { AsyncButton } from '~/views/components/AsyncButton';
|
||||
import { FormError } from '~/views/components/FormError';
|
||||
import { ShipSearch } from '~/views/components/ShipSearch';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
interface InvitePopoverProps {
|
||||
baseUrl: string;
|
||||
@ -39,7 +41,7 @@ const formSchema = Yup.object({
|
||||
});
|
||||
|
||||
export function InvitePopover(props: InvitePopoverProps) {
|
||||
const { baseUrl, api, association } = props;
|
||||
const { baseUrl, association } = props;
|
||||
|
||||
const relativePath = (p: string) => baseUrl + p;
|
||||
const { title } = association?.metadata || { title: '' };
|
||||
@ -55,11 +57,11 @@ export function InvitePopover(props: InvitePopoverProps) {
|
||||
// TODO: how to invite via email?
|
||||
try {
|
||||
const { ship, name } = resourceFromPath(association.group);
|
||||
await api.groups.invite(
|
||||
await airlock.thread(invite(
|
||||
ship, name,
|
||||
_.compact(ships).map(s => `~${deSig(s)}`),
|
||||
description
|
||||
);
|
||||
));
|
||||
|
||||
actions.setStatus({ success: null });
|
||||
onOutsideClick();
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
ManagedTextInputField as Input, Row,
|
||||
Text
|
||||
} from '@tlon/indigo-react';
|
||||
import { MetadataUpdatePreview } from '@urbit/api';
|
||||
import { join, MetadataUpdatePreview } from '@urbit/api';
|
||||
import { Form, Formik, FormikHelpers, useFormikContext } from 'formik';
|
||||
import _ from 'lodash';
|
||||
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
|
||||
@ -22,6 +22,7 @@ import { AsyncButton } from '~/views/components/AsyncButton';
|
||||
import { FormError } from '~/views/components/FormError';
|
||||
import { StatelessAsyncButton } from '~/views/components/StatelessAsyncButton';
|
||||
import { GroupSummary } from './GroupSummary';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
const formSchema = Yup.object({
|
||||
group: Yup.string()
|
||||
@ -80,7 +81,7 @@ export function JoinGroup(props: JoinGroupProps): ReactElement {
|
||||
if (group in groups) {
|
||||
return history.push(`/~landscape${group}`);
|
||||
}
|
||||
await api.groups.join(ship, name);
|
||||
await airlock.poke(join(ship, name));
|
||||
try {
|
||||
await waiter((p) => {
|
||||
return group in p.groups &&
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Box, Col, Text } from '@tlon/indigo-react';
|
||||
import { invite } from '@urbit/api/groups';
|
||||
import { Form, Formik } from 'formik';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
@ -7,6 +8,7 @@ import { resourceFromPath } from '~/logic/lib/group';
|
||||
import { deSig } from '~/logic/lib/util';
|
||||
import { AsyncButton } from '~/views/components/AsyncButton';
|
||||
import { ShipSearch } from '~/views/components/ShipSearch';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
interface FormSchema {
|
||||
ships: string[];
|
||||
@ -17,17 +19,17 @@ const formSchema = Yup.object<FormSchema>({
|
||||
});
|
||||
|
||||
export const MessageInvite = (props) => {
|
||||
const { association, api } = props;
|
||||
const { association } = props;
|
||||
const initialValues: FormSchema = { ships: [] };
|
||||
const onSubmit = async ({ ships }: FormSchema, actions) => {
|
||||
try {
|
||||
const { ship, name } = resourceFromPath(association.group);
|
||||
await api.groups.invite(
|
||||
await airlock.thread(invite(
|
||||
ship,
|
||||
name,
|
||||
_.compact(ships).map(s => `~${deSig(s)}`),
|
||||
`Inviting you to a DM with ~${ship}`
|
||||
);
|
||||
));
|
||||
actions.setStatus({ success: null });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
ManagedTextInputField as Input,
|
||||
Text
|
||||
} from '@tlon/indigo-react';
|
||||
import { addTag } from '@urbit/api/dist';
|
||||
import { Form, Formik } from 'formik';
|
||||
import _ from 'lodash';
|
||||
import React, { ReactElement } from 'react';
|
||||
@ -21,6 +22,7 @@ import { FormError } from '~/views/components/FormError';
|
||||
import { IconRadio } from '~/views/components/IconRadio';
|
||||
import { ShipSearch, shipSearchSchema, shipSearchSchemaInGroup } from '~/views/components/ShipSearch';
|
||||
import { ChannelWriteFieldSchema, ChannelWritePerms } from './ChannelWritePerms';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
type FormSchema = {
|
||||
name: string;
|
||||
@ -98,10 +100,10 @@ export function NewChannel(props: NewChannelProps): ReactElement {
|
||||
writers = _.compact(writers).map(s => `~${s}`);
|
||||
const us = `~${window.ship}`;
|
||||
if (values.writePerms === 'self') {
|
||||
await api.groups.addTag(resource, tag, [us]);
|
||||
await airlock.poke(addTag(resource, tag, [us]));
|
||||
} else if (values.writePerms === 'subset') {
|
||||
writers.push(us);
|
||||
await api.groups.addTag(resource, tag, writers);
|
||||
await airlock.poke(addTag(resource, tag, writers));
|
||||
}
|
||||
} else {
|
||||
await api.graph.createUnmanagedGraph(
|
||||
|
@ -3,10 +3,10 @@ import {
|
||||
|
||||
ManagedCheckboxField as Checkbox, ManagedTextInputField as Input, Text
|
||||
} from '@tlon/indigo-react';
|
||||
import { Enc, GroupPolicy } from '@urbit/api';
|
||||
import { createGroup, Enc, GroupPolicy } from '@urbit/api';
|
||||
import { Form, Formik, FormikHelpers } from 'formik';
|
||||
import React, { ReactElement, useCallback } from 'react';
|
||||
import { RouteComponentProps, useHistory } from 'react-router-dom';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import * as Yup from 'yup';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { useWaitForProps } from '~/logic/lib/useWaitForProps';
|
||||
@ -14,6 +14,7 @@ import { stringToSymbol } from '~/logic/lib/util';
|
||||
import useGroupState from '~/logic/state/group';
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
import { AsyncButton } from '~/views/components/AsyncButton';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
const formSchema = Yup.object({
|
||||
title: Yup.string().required('Group must have a name'),
|
||||
@ -32,7 +33,6 @@ interface NewGroupProps {
|
||||
}
|
||||
|
||||
export function NewGroup(props: NewGroupProps): ReactElement {
|
||||
const { api } = props;
|
||||
const history = useHistory();
|
||||
const initialValues: FormSchema = {
|
||||
title: '',
|
||||
@ -61,7 +61,7 @@ export function NewGroup(props: NewGroupProps): ReactElement {
|
||||
banned: []
|
||||
}
|
||||
};
|
||||
await api.groups.create(name, policy, title, description);
|
||||
await airlock.thread(createGroup(name, policy, title, description));
|
||||
const path = `/ship/~${window.ship}/${name}`;
|
||||
await waiter((p) => {
|
||||
return path in p.groups && path in p.associations.groups;
|
||||
@ -74,7 +74,7 @@ export function NewGroup(props: NewGroupProps): ReactElement {
|
||||
actions.setStatus({ error: e.message });
|
||||
}
|
||||
},
|
||||
[api, waiter, history]
|
||||
[waiter, history]
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
StatelessTextInput as Input, Text
|
||||
} from '@tlon/indigo-react';
|
||||
import { Contact, Contacts } from '@urbit/api/contacts';
|
||||
import { Group, RoleTags } from '@urbit/api/groups';
|
||||
import { addTag, removeMembers, changePolicy, Group, removeTag, RoleTags } from '@urbit/api/groups';
|
||||
import { Association } from '@urbit/api/metadata';
|
||||
import _ from 'lodash';
|
||||
import f from 'lodash/fp';
|
||||
@ -26,6 +26,7 @@ import useContactState from '~/logic/state/contact';
|
||||
import useSettingsState, { selectCalmState } from '~/logic/state/settings';
|
||||
import { Dropdown } from '~/views/components/Dropdown';
|
||||
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
const TruncText = styled(Text)`
|
||||
white-space: nowrap;
|
||||
@ -47,6 +48,19 @@ const searchParticipant = (search: string) => (p: Participant) => {
|
||||
return p.patp.includes(s) || p.nickname.toLowerCase().includes(s);
|
||||
};
|
||||
|
||||
const emptyContact = (patp: string, pending: boolean): Participant => ({
|
||||
nickname: '',
|
||||
bio: '',
|
||||
status: '',
|
||||
color: '0x0',
|
||||
avatar: null,
|
||||
cover: null,
|
||||
groups: [],
|
||||
patp,
|
||||
'last-updated': 0,
|
||||
pending
|
||||
});
|
||||
|
||||
function getParticipants(cs: Contacts, group: Group) {
|
||||
const contacts: Participant[] = _.flow(
|
||||
f.omitBy<Contacts>((_c, patp) => !group.members.has(patp.slice(1))),
|
||||
@ -77,19 +91,6 @@ function getParticipants(cs: Contacts, group: Group) {
|
||||
] as const;
|
||||
}
|
||||
|
||||
const emptyContact = (patp: string, pending: boolean): Participant => ({
|
||||
nickname: '',
|
||||
bio: '',
|
||||
status: '',
|
||||
color: '0x0',
|
||||
avatar: null,
|
||||
cover: null,
|
||||
groups: [],
|
||||
patp,
|
||||
'last-updated': 0,
|
||||
pending
|
||||
});
|
||||
|
||||
const Tab = ({ selected, id, label, setSelected }) => (
|
||||
<Box
|
||||
py={2}
|
||||
@ -249,7 +250,7 @@ function Participant(props: {
|
||||
role?: RoleTags;
|
||||
api: GlobalApi;
|
||||
}) {
|
||||
const { contact, association, group, api } = props;
|
||||
const { contact, association, group } = props;
|
||||
const { title } = association.metadata;
|
||||
const { hideAvatars, hideNicknames } = useSettingsState(selectCalmState);
|
||||
|
||||
@ -266,34 +267,32 @@ function Participant(props: {
|
||||
|
||||
const onPromote = useCallback(async () => {
|
||||
const resource = resourceFromPath(association.group);
|
||||
await api.groups.addTag(resource, { tag: 'admin' }, [`~${contact.patp}`]);
|
||||
}, [api, association]);
|
||||
await airlock.poke(addTag(resource, { tag: 'admin' }, [`~${contact.patp}`]));
|
||||
}, [contact.patp, association]);
|
||||
|
||||
const onDemote = useCallback(async () => {
|
||||
const resource = resourceFromPath(association.group);
|
||||
await api.groups.removeTag(resource, { tag: 'admin' }, [
|
||||
`~${contact.patp}`
|
||||
]);
|
||||
}, [api, association]);
|
||||
await airlock.poke(removeTag({ tag: 'admin' }, resource, [`~${contact.patp}`]));
|
||||
}, [association, contact.patp]);
|
||||
|
||||
const onBan = useCallback(async () => {
|
||||
const resource = resourceFromPath(association.group);
|
||||
await api.groups.changePolicy(resource, {
|
||||
await airlock.poke(changePolicy(resource, {
|
||||
open: { banShips: [`~${contact.patp}`] }
|
||||
});
|
||||
}, [api, association]);
|
||||
}));
|
||||
}, [association, contact.patp]);
|
||||
|
||||
const onKick = useCallback(async () => {
|
||||
const resource = resourceFromPath(association.group);
|
||||
if(contact.pending) {
|
||||
await api.groups.changePolicy(
|
||||
await airlock.poke(changePolicy(
|
||||
resource,
|
||||
{ invite: { removeInvites: [`~${contact.patp}`] } }
|
||||
);
|
||||
));
|
||||
} else {
|
||||
await api.groups.remove(resource, [`~${contact.patp}`]);
|
||||
await airlock.poke(removeMembers(resource, [`~${contact.patp}`]));
|
||||
}
|
||||
}, [api, contact, association]);
|
||||
}, [contact, association]);
|
||||
|
||||
const avatar =
|
||||
contact?.avatar && !hideAvatars ? (
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Box, Button, Col, Icon, Row, Text } from '@tlon/indigo-react';
|
||||
import { leaveGroup } from '@urbit/api';
|
||||
import _ from 'lodash';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
@ -15,6 +16,7 @@ import { ModalOverlay } from '~/views/components/ModalOverlay';
|
||||
import { Portal } from '~/views/components/Portal';
|
||||
import { StatelessAsyncButton } from '~/views/components/StatelessAsyncButton';
|
||||
import { Triangle } from '~/views/components/Triangle';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
const localSelector = selectLocalState([
|
||||
'tutorialProgress',
|
||||
@ -31,8 +33,7 @@ export function TutorialModal(props: { api: GlobalApi }) {
|
||||
tutorialRef,
|
||||
nextTutStep,
|
||||
prevTutStep,
|
||||
hideTutorial,
|
||||
set: setLocalState
|
||||
hideTutorial
|
||||
} = useLocalState(localSelector);
|
||||
const {
|
||||
title,
|
||||
@ -105,10 +106,10 @@ export function TutorialModal(props: { api: GlobalApi }) {
|
||||
setPaused(true);
|
||||
}, []);
|
||||
|
||||
const leaveGroup = useCallback(async () => {
|
||||
await props.api.groups.leaveGroup(TUTORIAL_HOST, TUTORIAL_GROUP);
|
||||
const doLeaveGroup = useCallback(async () => {
|
||||
await airlock.thread(leaveGroup(TUTORIAL_HOST, TUTORIAL_GROUP));
|
||||
await dismiss();
|
||||
}, [props.api, dismiss]);
|
||||
}, [dismiss]);
|
||||
|
||||
const progressIdx = progress.findIndex(p => p === tutorialProgress);
|
||||
|
||||
@ -149,7 +150,7 @@ export function TutorialModal(props: { api: GlobalApi }) {
|
||||
<Button backgroundColor="washedGray" onClick={dismiss}>
|
||||
Later
|
||||
</Button>
|
||||
<StatelessAsyncButton primary destructive onClick={leaveGroup}>
|
||||
<StatelessAsyncButton primary destructive onClick={doLeaveGroup}>
|
||||
Leave Group
|
||||
</StatelessAsyncButton>
|
||||
</Row>
|
||||
@ -173,7 +174,7 @@ export function TutorialModal(props: { api: GlobalApi }) {
|
||||
</Text>
|
||||
</Col>
|
||||
<Text lineHeight="tall">
|
||||
You can always restart the tutorial by typing "tutorial" in Leap.
|
||||
You can always restart the tutorial by typing "tutorial" in Leap.
|
||||
</Text>
|
||||
<Row mt={3} gapX={2} justifyContent="flex-end">
|
||||
<Button backgroundColor="washedGray" onClick={bailExit}>
|
||||
|
Loading…
Reference in New Issue
Block a user