aboutsummaryrefslogtreecommitdiff
path: root/vnext/src/ui/Feeds.js
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2019-10-29 17:11:07 +0300
committerGravatar Vitaly Takmazov2023-01-13 10:37:55 +0300
commit522a1cdbaf0f478fb23a9f770b9caf732ea13803 (patch)
tree2baf7497f4c4717ee423c227e2ba24a22b44c27c /vnext/src/ui/Feeds.js
parent713566a435fea6c00cbd2e37d7c8c2a54ef2895d (diff)
Hide header on scroll (mobile only)
Diffstat (limited to 'vnext/src/ui/Feeds.js')
-rw-r--r--vnext/src/ui/Feeds.js137
1 files changed, 74 insertions, 63 deletions
diff --git a/vnext/src/ui/Feeds.js b/vnext/src/ui/Feeds.js
index 8c79f779..e687f1e2 100644
--- a/vnext/src/ui/Feeds.js
+++ b/vnext/src/ui/Feeds.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
import qs from 'qs';
@@ -23,9 +23,9 @@ import { getMessages } from '../api';
* @property {import('history').History} history
* @property {import('history').Location} location
* @property {import('react-router').match} match
- * @property {string} search
+ * @property {string=} search
* @property {import('../api').SecureUser} visitor
- * @property {import('../api').Message[]} msgs
+ * @property {import('../api').Message[]=} msgs
*/
/**
@@ -101,84 +101,95 @@ export function Home(props) {
}
/**
- * @param {{
- authRequired?: boolean,
- visitor: import('../api').SecureUser,
- history: import('history').History,
- location: import('history').Location,
- msgs: import('../api').Message[],
- query: Query
-}} props
+ * @typedef {Object} FeedState
+ * @property authRequired?: boolean
+ * @property visitor: import('../api').SecureUser
+ * @property history: import('history').History
+ * @property location: import('history').Location
+ * @property msgs: import('../api').Message[]
+ * @property query: Query
+ */
+
+/**
+ * @param {FeedState} props
*/
function Feed(props) {
- const [msgs, setMsgs] = useState([]);
- const [loading, setLoading] = useState(true);
- const [nextpage, setNextpage] = useState(null);
- const [error, setError] = useState(false);
+ const [state, setState] = useState({
+ history: props.history,
+ authRequired: props.authRequired,
+ query: props.query,
+ hash: props.visitor.hash,
+ filter: props.location.search.substring(1),
+ msgs: [],
+ loading: true,
+ nextpage: null,
+ error: false,
+ tag: ''
+ });
+
+ const stateRef = useRef(state);
useEffect(() => {
- let loadMessages = (hash = '', filter = '') => {
- document.body.scrollTop = 0;
- document.documentElement.scrollTop = 0;
- setMsgs([]);
- setLoading(true);
- 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);
- });
+ 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)}`;
};
- 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 = (
- <>
+ document.body.scrollTop = 0;
+ document.documentElement.scrollTop = 0;
+ const filterParams = qs.parse(stateRef.current.filter);
+ let params = Object.assign({}, filterParams || {}, stateRef.current.query.search || {});
+ let url = stateRef.current.query.baseUrl;
+ if (stateRef.current.hash) {
+ params.hash = stateRef.current.hash;
+ }
+ if (!params.hash && stateRef.current.authRequired) {
+ stateRef.current.history.push('/');
+ }
+ getMessages(url, params)
+ .then(response => {
+ const { data } = response;
+ const { pageParam } = stateRef.current.query;
+ const lastMessage = data.slice(-1)[0] || {};
+ const nextpage = getPageParam(pageParam, lastMessage, filterParams);
+ setState({
+ ...stateRef.current,
+ msgs: data,
+ loading: false,
+ nextpage: nextpage,
+ tag: qs.parse(location.search.substring(1))['tag'] || ''
+ });
+ }).catch(ex => {
+ setState({
+ ...stateRef.current,
+ error: true
+ });
+ });
+ }, []);
+ return (state.msgs.length > 0 ? (
+ <div className="msgs">
{
- tag && (
+ state.tag && (
<p className="page">
- <Link to={{ pathname: `/tag/${tag}` }}>
- <span>← All posts with tag&nbsp;</span><b>{tag}</b>
+ <Link to={{ pathname: `/tag/${state.tag}` }}>
+ <span>← All posts with tag&nbsp;</span><b>{state.tag}</b>
</Link>
</p>
)
}
{
- msgs.map(msg =>
+ state.msgs.map(msg =>
<Message key={msg.mid} data={msg} visitor={props.visitor} />)
}
{
- msgs.length >= 20 && (
+ state.msgs.length >= 20 && (
<p className="page">
- <Link to={{ pathname: props.location.pathname, search: nextpage }} rel="prev">Next →</Link>
+ <Link to={{ pathname: props.location.pathname, search: state.nextpage }} rel="prev">Next →</Link>
</p>
)
}
- </>
+ </div>
+ ) : state.error ? <div>error</div> : state.loading ? <div className="msgs"><Spinner /><Spinner /><Spinner /><Spinner /></div> : <div>No more messages</div>
);
- 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>;
}