diff options
Diffstat (limited to 'vnext/src/ui/Feeds.js')
-rw-r--r-- | vnext/src/ui/Feeds.js | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/vnext/src/ui/Feeds.js b/vnext/src/ui/Feeds.js new file mode 100644 index 00000000..c7b857b7 --- /dev/null +++ b/vnext/src/ui/Feeds.js @@ -0,0 +1,171 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import ReactRouterPropTypes from 'react-router-prop-types'; +import { Link } from 'react-router-dom'; +import qs from 'qs'; +import moment from 'moment'; + +import Message from './Message'; +import Spinner from './Spinner'; + +import UserInfo from './UserInfo'; + +import { getMessages } from '../api'; +import { UserType } from './Types'; + +export function Discover(props) { + let search = qs.parse(props.location.search.substring(1)); + const query = { + baseUrl: '/api/messages', + search: search, + pageParam: search.search ? 'page' : 'before_mid' + }; + return (<Feed authRequired={false} query={query} {...props} />); +} + +export function Discussions(props) { + const query = { + baseUrl: '/api/messages/discussions', + pageParam: 'to' + }; + return (<Feed authRequired={false} query={query} {...props} />); +} + +export function Blog(props) { + const { user } = props.match.params; + let search = qs.parse(props.location.search.substring(1)); + search.uname = user; + const query = { + baseUrl: '/api/messages', + search: search, + pageParam: search.search ? 'page' : 'before_mid' + }; + return ( + <> + <div className="msg-cont"> + <UserInfo user={user} /> + </div> + <Feed authRequired={false} query={query} {...props} /> + </> + ); +} + +export function Tag(props) { + const { tag } = props.match.params; + const query = { + baseUrl: '/api/messages', + search: { + tag: tag + }, + pageParam: 'before_mid' + }; + return (<Feed authRequired={false} query={query} {...props} />); +} + +export function Home(props) { + const query = { + baseUrl: '/api/home', + pageParam: 'before_mid' + }; + return (<Feed authRequired={true} query={query} {...props} />); +} + +function Feed(props) { + const [msgs, setMsgs] = useState([]); + const [loading, setLoading] = useState(true); + const [nextpage, setNextpage] = useState(null); + const [error, setError] = useState(false); + + useEffect(() => { + let loadMessages = (hash = '', filter = '') => { + document.body.scrollTop = 0; + document.documentElement.scrollTop = 0; + setMsgs([]); + const filterParams = qs.parse(filter); + let params = Object.assign({}, filterParams || {}, props.query.search || {}); + let url = props.query.baseUrl; + if (hash) { + params.hash = hash; + } + if (!params.hash && props.authRequired) { + props.history.push('/'); + } + getMessages(url, params) + .then(response => { + const { data } = response; + const { pageParam } = props.query; + const lastMessage = data.slice(-1)[0] || {}; + const nextpage = getPageParam(pageParam, lastMessage, filterParams); + setMsgs(data); + setLoading(false); + setNextpage(nextpage); + }).catch(ex => { + setError(true); + }); + }; + loadMessages(props.visitor.hash, props.location.search.substring(1)); + }, [props]); + + let getPageParam = (pageParam, lastMessage, filterParams) => { + const pageValue = pageParam === 'before_mid' ? lastMessage.mid : pageParam === 'page' ? (Number(filterParams.page) || 0) + 1 : moment.utc(lastMessage.updated).valueOf(); + let newFilter = { ...filterParams }; + newFilter[pageParam] = pageValue; + return `?${qs.stringify(newFilter)}`; + }; + const { tag } = qs.parse(location.search.substring(1) || {}); + const nodes = ( + <> + { + tag && ( + <p className="page"> + <Link to={{ pathname: `/tag/${tag}` }}> + <span>← All posts with tag </span><b>{tag}</b> + </Link> + </p> + ) + } + { + msgs.map(msg => + <Message key={msg.mid} data={msg} visitor={props.visitor} />) + } + { + msgs.length >= 20 && ( + <p className="page"> + <Link to={{ pathname: props.location.pathname, search: nextpage }} rel="prev">Next →</Link> + </p> + ) + } + </> + ); + return msgs.length > 0 ? ( + <div className="msgs">{nodes}</div> + ) : error ? <div>error</div> : loading ? <div className="msgs"><Spinner /><Spinner /><Spinner /><Spinner /></div> : <div>No more messages</div>; +} + +Discover.propTypes = { + location: ReactRouterPropTypes.location.isRequired, + search: PropTypes.string +}; + +Blog.propTypes = { + match: ReactRouterPropTypes.match.isRequired, + location: ReactRouterPropTypes.location.isRequired, + search: PropTypes.string +}; + +Tag.propTypes = { + match: ReactRouterPropTypes.match.isRequired +}; + +Feed.propTypes = { + authRequired: PropTypes.bool, + visitor: UserType, + history: ReactRouterPropTypes.history.isRequired, + location: ReactRouterPropTypes.location.isRequired, + msgs: PropTypes.array, + query: PropTypes.shape({ + baseUrl: PropTypes.string.isRequired, + search: PropTypes.object, + pageParam: PropTypes.string.isRequired + }) +}; |