Merge pull request #3516 from tylershuster/pub-unsub

publish: allow unsubscribing from notebooks
This commit is contained in:
matildepark 2020-09-18 20:15:43 -04:00 committed by GitHub
commit 9d40a23077
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 126 additions and 107 deletions

View File

@ -4,6 +4,7 @@ import { Spinner } from "~/views/components/Spinner";
import { Notebooks } from "~/types/publish-update"; import { Notebooks } from "~/types/publish-update";
import { useWaitForProps } from "~/logic/lib/useWaitForProps"; import { useWaitForProps } from "~/logic/lib/useWaitForProps";
import { RouteComponentProps } from "react-router-dom"; import { RouteComponentProps } from "react-router-dom";
import { deSig } from "~/logic/lib/util";
interface JoinScreenProps { interface JoinScreenProps {
api: any; // GlobalApi; api: any; // GlobalApi;
@ -21,15 +22,9 @@ export function JoinScreen(props: JoinScreenProps & RouteComponentProps) {
const onJoin = useCallback(async () => { const onJoin = useCallback(async () => {
joining.current = true; joining.current = true;
const action = {
subscribe: {
who: ship.replace("~", ""),
book,
},
};
try { try {
await api.publish.publishAction(action); await api.publish.subscribeNotebook(deSig(ship), book);
await waiter((p) => !!p.notebooks?.[ship]?.[book]); await waiter((p) => !!p.notebooks?.[ship]?.[book]);
props.history.replace(`/~publish/notebook/${ship}/${book}`); props.history.replace(`/~publish/notebook/${ship}/${book}`);
} catch (e) { } catch (e) {

View File

@ -1,8 +1,9 @@
import React from "react"; import React, { PureComponent } from "react";
import { Link, RouteComponentProps, Route, Switch } from "react-router-dom"; import { Link, RouteComponentProps, Route, Switch } from "react-router-dom";
import { NotebookPosts } from "./NotebookPosts"; import { NotebookPosts } from "./NotebookPosts";
import { Subscribers } from "./Subscribers"; import { Subscribers } from "./Subscribers";
import { Settings } from "./Settings"; import { Settings } from "./Settings";
import { Spinner } from '~/views/components/Spinner';
import { roleForShip } from "~/logic/lib/group"; import { roleForShip } from "~/logic/lib/group";
import { import {
Box, Box,
@ -21,6 +22,7 @@ import { Contacts, Rolodex } from "~/types/contact-update";
import GlobalApi from "~/logic/api/global"; import GlobalApi from "~/logic/api/global";
import styled from "styled-components"; import styled from "styled-components";
import {Associations} from "~/types"; import {Associations} from "~/types";
import { deSig } from "~/logic/lib/util";
const TabList = styled(_TabList)` const TabList = styled(_TabList)`
margin-bottom: ${(p) => p.theme.space[4]}px; margin-bottom: ${(p) => p.theme.space[4]}px;
@ -42,105 +44,127 @@ interface NotebookProps {
associations: Associations; associations: Associations;
} }
export function Notebook(props: NotebookProps & RouteComponentProps) { interface NotebookState {
const { api, ship, book, notebook, notebookContacts, groups } = props; isUnsubscribing: boolean;
const contact = notebookContacts[ship];
const group = groups[notebook?.["writers-group-path"]];
const role = group ? roleForShip(group, window.ship) : undefined;
const isOwn = `~${window.ship}` === ship;
const isAdmin = role === "admin" || isOwn;
const isWriter =
isOwn || group.tags?.publish?.[`writers-${book}`]?.has(window.ship);
const notesList = notebook?.["notes-by-date"] || [];
const notes = notebook?.notes || {};
const showNickname = contact?.nickname && !props.hideNicknames;
return (
<Box
pt={4}
mx="auto"
display="grid"
gridAutoRows="min-content"
gridTemplateColumns={["100%", "1fr 1fr"]}
maxWidth="500px"
gridRowGap={[4, 6]}
gridColumnGap={3}
>
<Box display={["block", "none"]} gridColumn={["1/2", "1/3"]}>
<Link to="/~publish">{"<- All Notebooks"}</Link>
</Box>
<Box>
<Text> {notebook?.title}</Text>
<br />
<Text color="lightGray">by </Text>
<Text fontFamily={showNickname ? "sans" : "mono"}>
{showNickname ? contact?.nickname : ship}
</Text>
</Box>
<Row justifyContent={["flex-start", "flex-end"]}>
{isWriter && (
<Link to={`/~publish/notebook/${ship}/${book}/new`}>
<Button primary border>
New Post
</Button>
</Link>
)}
{!isOwn && (
<Button ml={isWriter ? 2 : 0} error border>
Unsubscribe
</Button>
)}
</Row>
<Box gridColumn={["1/2", "1/3"]}>
<Tabs>
<TabList>
<Tab>All Posts</Tab>
<Tab>About</Tab>
{isAdmin && <Tab>Subscribers</Tab>}
{isOwn && <Tab>Settings</Tab>}
</TabList>
<TabPanels>
<TabPanel>
<NotebookPosts
notes={notes}
list={notesList}
host={ship}
book={book}
contacts={notebookContacts}
hideNicknames={props.hideNicknames}
/>
</TabPanel>
<TabPanel>
<Box color="black">{notebook?.about}</Box>
</TabPanel>
<TabPanel>
<Subscribers
host={ship}
book={book}
notebook={notebook}
api={api}
groups={groups}
/>
</TabPanel>
<TabPanel>
<Settings
host={ship}
book={book}
api={api}
notebook={notebook}
contacts={notebookContacts}
associations={props.associations}
groups={groups}
/>
</TabPanel>
</TabPanels>
</Tabs>
</Box>
</Box>
);
} }
export class Notebook extends PureComponent<NotebookProps & RouteComponentProps, NotebookState> {
constructor(props) {
super(props);
this.state = {
isUnsubscribing: false
};
}
render() {
const { api, ship, book, notebook, notebookContacts, groups, history, hideNicknames, associations } = this.props;
const contact = notebookContacts[ship];
const group = groups[notebook?.["writers-group-path"]];
const role = group ? roleForShip(group, window.ship) : undefined;
const isOwn = `~${window.ship}` === ship;
const isAdmin = role === "admin" || isOwn;
const isWriter =
isOwn || group.tags?.publish?.[`writers-${book}`]?.has(window.ship);
const notesList = notebook?.["notes-by-date"] || [];
const notes = notebook?.notes || {};
const showNickname = contact?.nickname && !hideNicknames;
return (
<Box
pt={4}
mx="auto"
display="grid"
gridAutoRows="min-content"
gridTemplateColumns={["100%", "1fr 1fr"]}
maxWidth="500px"
gridRowGap={[4, 6]}
gridColumnGap={3}
>
<Box display={["block", "none"]} gridColumn={["1/2", "1/3"]}>
<Link to="/~publish">{"<- All Notebooks"}</Link>
</Box>
<Box>
<Text> {notebook?.title}</Text>
<br />
<Text color="lightGray">by </Text>
<Text fontFamily={showNickname ? "sans" : "mono"}>
{showNickname ? contact?.nickname : ship}
</Text>
</Box>
<Row justifyContent={["flex-start", "flex-end"]}>
{isWriter && (
<Link to={`/~publish/notebook/${ship}/${book}/new`}>
<Button primary border>
New Post
</Button>
</Link>
)}
{!isOwn
? this.state.isUnsubscribing
? <Spinner awaiting={this.state.isUnsubscribing} classes="mt2 ml2" text="Unsubscribing..." />
: <Button ml={isWriter ? 2 : 0} error border onClick={() => {
this.setState({ isUnsubscribing: true });
api.publish.unsubscribeNotebook(deSig(ship), book).then(() => {
history.push("/~publish");
}).catch(() => {
this.setState({ isUnsubscribing: false });
});
}}>
Unsubscribe
</Button>
: null
}
</Row>
<Box gridColumn={["1/2", "1/3"]}>
<Tabs>
<TabList>
<Tab>All Posts</Tab>
<Tab>About</Tab>
{isAdmin && <Tab>Subscribers</Tab>}
{isOwn && <Tab>Settings</Tab>}
</TabList>
<TabPanels>
<TabPanel>
<NotebookPosts
notes={notes}
list={notesList}
host={ship}
book={book}
contacts={notebookContacts}
hideNicknames={hideNicknames}
/>
</TabPanel>
<TabPanel>
<Box color="black">{notebook?.about}</Box>
</TabPanel>
<TabPanel>
<Subscribers
host={ship}
book={book}
notebook={notebook}
api={api}
groups={groups}
/>
</TabPanel>
<TabPanel>
<Settings
host={ship}
book={book}
api={api}
notebook={notebook}
contacts={notebookContacts}
associations={associations}
groups={groups}
/>
</TabPanel>
</TabPanels>
</Tabs>
</Box>
</Box>
);
}
}
export default Notebook; export default Notebook;