diff --git a/src/App.tsx b/src/App.tsx index 07a03df..2562edc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -81,6 +81,12 @@ export const routeResolver = new RouteResolver({ members: { }, }, + invitations: { + incoming: { + }, + outgoing: { + }, + }, new: "new", import: "import", }, diff --git a/src/Collections/CollectionList.tsx b/src/Collections/CollectionList.tsx index 775fa60..fbcfc36 100644 --- a/src/Collections/CollectionList.tsx +++ b/src/Collections/CollectionList.tsx @@ -7,6 +7,7 @@ import { Link, useHistory } from "react-router-dom"; import IconButton from "@material-ui/core/IconButton"; import IconAdd from "@material-ui/icons/Add"; +import IconInvitation from "@material-ui/icons/MailOutline"; import ContactsIcon from "@material-ui/icons/Contacts"; import CalendarTodayIcon from "@material-ui/icons/CalendarToday"; import FormatListBulletedIcon from "@material-ui/icons/FormatListBulleted"; @@ -56,6 +57,13 @@ export default function CollectionList(props: PropsType) { return ( + + + + + + + + + + + ); +} + +function InvitationsIncoming() { + const [invitations, setInvitations] = React.useState(); + const [chosenInvitation, setChosenInvitation] = React.useState(); + const etebase = useCredentials()!; + + React.useEffect(() => { + loadInvitations(etebase).then(setInvitations); + }, [etebase]); + + function removeInvitation(invite: Etebase.SignedInvitation) { + setInvitations(invitations?.filter((x) => x.uid !== invite.uid)); + } + + async function reject(invite: Etebase.SignedInvitation) { + const invitationManager = etebase.getInvitationManager(); + await invitationManager.reject(invite); + removeInvitation(invite); + } + + async function accept(invite: Etebase.SignedInvitation) { + const invitationManager = etebase.getInvitationManager(); + await invitationManager.accept(invite); + setChosenInvitation(undefined); + removeInvitation(invite); + } + + return ( + <> + + + {invitations ? + + {(invitations.length > 0 ? + invitations.map((invite, idx) => ( + + reject(invite)}> + + + setChosenInvitation(invite)}> + + + + )} + > + Invitation {idx + 1} + + )) + : + + No invitations + + )} + + : + + } + + {chosenInvitation && ( + accept(chosenInvitation)} + onCancel={() => setChosenInvitation(undefined)} + > + Please verify the inviter's security fingerprint to ensure the invitation is secure: +
+ +
+
+ )} + + ); +} diff --git a/src/Collections/Main.tsx b/src/Collections/Main.tsx index f2a773b..9ff2abb 100644 --- a/src/Collections/Main.tsx +++ b/src/Collections/Main.tsx @@ -20,6 +20,7 @@ import CollectionMembers from "./CollectionMembers"; import Collection from "./Collection"; import { useAsyncDispatch } from "../store"; import { collectionUpload } from "../store/actions"; +import Invitations from "./Invitations"; const decryptCollections = getDecryptCollectionsFunction(); @@ -96,6 +97,11 @@ export default function CollectionsMain() { onCancel={onCancel} /> + + + {