post: refactor routes

This commit is contained in:
Liam Fitzgerald 2021-06-15 14:45:26 +10:00
parent 405e55dce2
commit 90c9c2ee87
No known key found for this signature in database
GPG Key ID: D390E12C61D1CFFB
6 changed files with 191 additions and 174 deletions

View File

@ -0,0 +1,27 @@
import { Graph } from '@urbit/api';
import { BigInteger } from 'big-integer';
import _ from 'lodash';
import useMetadataState from '~/logic/state/metadata';
export function getNodeFromGraph(graph: Graph, index: BigInteger[]) {
return _.reduce(
index.slice(1),
(acc, val) => {
return acc?.children?.get(val);
},
graph.get(index[0])
);
}
export function getPostRoute(
graph: string,
index: BigInteger[],
thread = false
) {
const association = useMetadataState.getState().associations.graph[graph];
const segment = thread ? 'thread' : 'replies';
return `/~landscape${association.group}/feed/${segment}/${index
.map(i => i.toString())
.join('/')}`;
}

View File

@ -10,7 +10,7 @@ import useGroupState from '~/logic/state/group';
import useMetadataState from '~/logic/state/metadata';
import { Loading } from '~/views/components/Loading';
import { GroupFeedHeader } from './GroupFeedHeader';
import PostReplies from './Post/PostReplies';
import { PostRepliesRoutes } from './Post/PostReplies';
import PostTimeline from './Post/PostTimeline';
import airlock from '~/logic/api';
@ -41,7 +41,6 @@ function GroupFeed(props) {
const association = associations.graph[graphPath];
const history = useHistory();
const locationUrl = history.location.pathname;
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
const graph = graphs[graphId];
@ -76,42 +75,26 @@ function GroupFeed(props) {
graphResource={graphResource}
/>
<Switch>
<Route
exact
path={[relativePath('/'), relativePath('/feed')]}
render={(routeProps) => {
return (
<PostTimeline
baseUrl={baseUrl}
history={history}
graphPath={graphPath}
group={group}
association={association}
vip={vip}
graph={graph}
pendingSize={pendingSize}
/>
);
}}
/>
<Route
path={relativePath('/feed/replies/:index+')}
render={(routeProps) => {
return (
<PostReplies
locationUrl={locationUrl}
baseUrl={baseUrl}
history={history}
graphPath={graphPath}
group={group}
association={association}
vip={vip}
graph={graph}
pendingSize={pendingSize}
/>
);
}}
/>
<Route exact path={relativePath('/feed')}>
<PostTimeline
baseUrl={relativePath('/feed')}
history={history}
graphPath={graphPath}
group={group}
association={association}
vip={vip}
graph={graph}
pendingSize={pendingSize}
/>
</Route>
<Route path={relativePath('/feed/replies')}>
<PostRepliesRoutes
baseUrl={relativePath('/feed/replies')}
association={association}
vip={vip}
pendingSize={pendingSize}
/>
</Route>
</Switch>
</Col>
);

View File

@ -9,11 +9,11 @@ import { useGroup } from '~/logic/state/group';
import { useAssocForGraph } from '~/logic/state/metadata';
import { Loading } from '~/views/components/Loading';
import { GroupFeedHeader } from './GroupFeedHeader';
import PostThread from './Post/PostThread';
import { PostThreadRoutes } from './Post/PostThread';
import PostFlatTimeline from './Post/PostFlatTimeline';
import PostReplies from './Post/PostReplies';
import airlock from '~/logic/api';
import { markCountAsRead } from '@urbit/api';
import { PostRepliesRoutes } from './Post/PostReplies';
function GroupFlatFeed(props) {
const {
@ -35,7 +35,6 @@ function GroupFlatFeed(props) {
const relativePath = path => baseUrl + path;
const history = useHistory();
const locationUrl = history.location.pathname;
const getDeepOlderThan = useGraphState(s => s.getDeepOlderThan);
useEffect(() => {
@ -67,56 +66,32 @@ function GroupFlatFeed(props) {
graphResource={graphRid}
/>
<Switch>
<Route
exact
path={[relativePath('/'), relativePath('/feed')]}
render={(routeProps) => {
return (
<PostFlatTimeline
baseUrl={baseUrl}
graphPath={graphPath}
group={group}
association={association}
vip={vip}
pendingSize={pendingSize}
/>
);
}}
/>
<Route
path={relativePath('/feed/thread/:index+')}
render={(routeProps) => {
return (
<PostThread
locationUrl={locationUrl}
baseUrl={baseUrl}
history={history}
graphPath={graphPath}
group={group}
association={association}
vip={vip}
pendingSize={pendingSize}
/>
);
}}
/>
<Route
path={relativePath('/feed/replies/:index+')}
render={(routeProps) => {
return (
<PostReplies
locationUrl={locationUrl}
baseUrl={baseUrl}
history={history}
graphPath={graphPath}
group={group}
association={association}
vip={vip}
pendingSize={pendingSize}
/>
);
}}
/>
<Route exact path={[relativePath('/'), relativePath('/feed')]}>
<PostFlatTimeline
baseUrl={relativePath('/feed')}
graphPath={graphPath}
group={group}
association={association}
vip={vip}
pendingSize={pendingSize}
/>
</Route>
<Route path={relativePath('/feed/thread')}>
<PostThreadRoutes
baseUrl={relativePath('/feed/thread')}
association={association}
vip={vip}
pendingSize={pendingSize}
/>
</Route>
<Route path={relativePath('/feed/replies')}>
<PostRepliesRoutes
baseUrl={relativePath('/feed/replies')}
association={association}
vip={vip}
pendingSize={pendingSize}
/>
</Route>
</Switch>
</Col>
);

View File

@ -3,6 +3,7 @@ import { Association, GraphNode, Group, Post } from '@urbit/api';
import { BigInteger } from 'big-integer';
import { History } from 'history';
import React, { Ref } from 'react';
import { getPostRoute } from '~/logic/lib/graph';
import { isWriter } from '~/logic/lib/group';
import { withHovering } from '~/logic/lib/util';
import { Mention } from '~/views/components/MentionText';
@ -70,21 +71,19 @@ class PostItem extends React.Component<PostItemProps, PostItemState> {
}
navigateToChildren() {
const { history, baseUrl, index, isParent, isThread, isHierarchical } = this.props;
const {
isHierarchical,
history,
index,
isParent,
isThread,
association
} = this.props;
if (isParent) {
return;
}
let indexString = '';
index.forEach((i) => {
indexString = indexString + '/' + i.toString();
});
if (!isThread && !isHierarchical) {
history.push(`${baseUrl}/feed/thread${indexString}`);
} else {
history.push(`${baseUrl}/feed/replies${indexString}`);
}
history.push(getPostRoute(association.resource, index, !isThread && !isHierarchical));
}
submitCallback() {

View File

@ -1,5 +1,5 @@
import { Box, Col, Text } from '@tlon/indigo-react';
import { GraphNode } from '@urbit/api';
import { Association, PermVariation } from '@urbit/api';
import React, { useEffect } from 'react';
import { resourceFromPath } from '~/logic/lib/group';
import useGraphState, { GraphState, useGraph } from '~/logic/state/graph';
@ -7,31 +7,64 @@ import { Loading } from '~/views/components/Loading';
import PostFeed from './PostFeed';
import PostItem from './PostItem/PostItem';
import { stringToArr, arrToString } from '~/views/components/ArrayVirtualScroller';
import { useHistory } from 'react-router';
const graphSel = (s: GraphState) => s.getNode;
import { useGroupForAssoc } from '~/logic/state/group';
import { Switch, useParams, Route, useHistory } from 'react-router';
import bigInt, { BigInteger } from 'big-integer';
import { getNodeFromGraph } from '~/logic/lib/graph';
export default function PostReplies(props) {
interface PostRepliesProps {
baseUrl: string;
association: Association;
pendingSize: number;
vip: PermVariation;
index?: BigInteger[];
}
export function PostRepliesRoutes(props: PostRepliesProps) {
const { atom } = useParams<{ atom?: string }>();
const index = atom
? [...(props.index || []), bigInt(atom)]
: (props.index || []);
const { baseUrl } = props;
const makePath = (s: string) => baseUrl + s;
return (
<Switch>
<Route path={makePath('/:atom')} render={(routeProps) => {
const { url } = routeProps.match;
return (
<PostRepliesRoutes {...props} baseUrl={url} index={index} />
);
}}
/>
<Route path={baseUrl}>
<PostReplies {...props} index={index} />
</Route>
</Switch>
);
}
export default function PostReplies(props: PostRepliesProps) {
const {
baseUrl,
association,
graphPath,
group,
vip,
pendingSize
pendingSize,
index
} = props;
const history = useHistory();
const getNode = useGraphState(graphSel);
const group = useGroupForAssoc(association);
const graphPath = association.resource;
const graphRid = resourceFromPath(graphPath);
let graph = useGraph(graphRid.ship, graphRid.name);
const graph = useGraph(graphRid.ship, graphRid.name);
const shouldRenderFeed = Boolean(graph);
const locationUrl =
props.locationUrl.replace(`${baseUrl}/feed/replies`, '');
const index = stringToArr(locationUrl);
useEffect(() => {
if (graphRid.ship === '~zod' && graphRid.name === 'null') {
return;
@ -41,17 +74,8 @@ export default function PostReplies(props) {
return;
}
const i = [];
for (const k of index) {
i.push(k);
// TODO: why can't I use await?
getNode(
graphRid.ship,
graphRid.name,
arrToString(i)
);
}
}, [graphPath, arrToString(index)]);
getNode(graphRid.ship, graphRid.name, `/${index[0]}`);
}, [association.resource, index]);
if (!shouldRenderFeed) {
return (
@ -61,31 +85,17 @@ export default function PostReplies(props) {
);
}
let node: GraphNode;
let parentNode;
index.forEach((i, idx) => {
if (!graph) {
return null;
}
node = graph.get(i);
if(idx < index.length - 1) {
parentNode = node;
}
if (!node) {
return null;
}
graph = node.children;
});
const node = getNodeFromGraph(graph, index);
const parentNode = index.length > 1 && getNodeFromGraph(graph, index.slice(0, -1));
if (!node || !graph) {
return null;
}
const first = graph.peekLargest()?.[0];
const first = node?.children?.peekLargest()?.[0];
if (!first) {
return (
<Col
key={`/replies/${locationUrl}`}
width="100%"
height="100%"
alignItems="center" overflowY="scroll"
@ -98,10 +108,10 @@ export default function PostReplies(props) {
association={association}
index={index}
baseUrl={baseUrl}
history={history}
isParent={true}
parentPost={parentNode?.post}
vip={vip}
history={history}
group={group}
/>
</Box>
@ -125,9 +135,9 @@ export default function PostReplies(props) {
return (
<Box height="calc(100% - 48px)" width="100%" alignItems="center" pl={1} pt={3}>
<PostFeed
key={`/replies/${locationUrl}`}
key={location.pathname}
graphPath={graphPath}
graph={graph}
graph={node.children}
grandparentNode={parentNode}
parentNode={node}
pendingSize={pendingSize}

View File

@ -1,6 +1,7 @@
import { Box, Col, Text } from '@tlon/indigo-react';
import bigInt from 'big-integer';
import bigInt, { BigInteger } from 'big-integer';
import React, {
useCallback,
useEffect
} from 'react';
import { resourceFromPath } from '~/logic/lib/group';
@ -9,46 +10,68 @@ import { arrToString } from '~/views/components/ArrayVirtualScroller';
import useGraphState from '~/logic/state/graph';
import PostFlatFeed from './PostFlatFeed';
import PostInput from './PostInput';
import { Association, PermVariation } from '@urbit/api';
import { useParams, Switch, Route } from 'react-router';
import {useGroupForAssoc} from '~/logic/state/group';
export default function PostThread(props) {
export function PostThreadRoutes(props: PostThreadProps) {
const { atom } = useParams<{ atom?: string }>();
const index = atom
? [...(props.index || []), bigInt(atom)]
: (props.index || []);
const { baseUrl } = props;
const makePath = (s: string) => baseUrl + s;
return (
<Switch>
<Route path={makePath('/:atom')} render={(routeProps) => {
const { url } = routeProps.match;
return (
<PostThreadRoutes {...props} baseUrl={url} index={index} />
);
}}
/>
<Route path={baseUrl}>
<PostThread {...props} index={index} />
</Route>
</Switch>
);
}
interface PostThreadProps {
baseUrl: string;
association: Association;
pendingSize: number;
vip: PermVariation;
index?: BigInteger[];
}
export default function PostThread(props: PostThreadProps) {
const {
baseUrl,
association,
graphPath,
group,
vip,
pendingSize
pendingSize,
index = []
} = props;
const getFirstborn = useGraphState(s => s.getFirstborn);
const group = useGroupForAssoc(association);
const graphResource =
graphPath ? resourceFromPath(graphPath) : resourceFromPath('/ship/~zod/null');
const locationUrl = props.locationUrl.replace(`${baseUrl}/feed/thread`, '');
const index = locationUrl.split('/').slice(1).map(ind => bigInt(ind));
const { ship, name } = resourceFromPath(association.resource);
useEffect(() => {
if (graphResource.ship === '~zod' && graphResource.name === 'null') {
return;
}
if (index.length < 1) {
return;
}
getFirstborn(
graphResource.ship,
graphResource.name,
arrToString(index)
);
}, [graphPath, props.locationUrl]);
getFirstborn(ship, name, `/${index.map(i => i.toString()).join('/')}`);
}, [association.resource, index]);
const threadGraphs = useGraphState(state => state.threadGraphs);
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
const graphId = `${ship.slice(1)}/${name}`;
const threadGraph = useGraphState(useCallback(s => s.threadGraphs[graphId] || {}, [graphId]));
const shouldRenderFeed =
graphId in threadGraphs && arrToString(index) in threadGraphs[graphId];
const shouldRenderFeed = arrToString(index) in threadGraph;
if (!shouldRenderFeed) {
return (
@ -60,9 +83,9 @@ export default function PostThread(props) {
// TODO: improve performance characteristics of the useGraphState required
// to fetch this
const threadGraph = threadGraphs[graphId][arrToString(index)];
const thread = threadGraph[arrToString(index)];
const first = threadGraph.peekLargest()?.[0];
const first = thread.peekLargest()?.[0];
if (!first) {
return (
<Col
@ -81,7 +104,7 @@ export default function PostThread(props) {
alignItems="center"
>
<PostInput
graphPath={graphPath}
graphPath={association.resource}
group={group}
association={association}
vip={vip}
@ -107,9 +130,9 @@ export default function PostThread(props) {
return (
<Box height="calc(100% - 48px)" width="100%" alignItems="center" pl={1}>
<PostFlatFeed
key={`/thread/${locationUrl}`}
graphPath={graphPath}
flatGraph={threadGraph}
key={location.pathname}
graphPath={association.resource}
flatGraph={thread}
pendingSize={pendingSize}
association={association}
group={group}