import { useState, useEffect } from 'react';
import { Link, useLocation, useParams, Navigate, useSearchParams } from 'react-router-dom';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
dayjs.extend(utc);
import Message from './Message';
import Spinner from './Spinner';
import UserInfo from './UserInfo';
import { getMessages } from '../api';
import { useVisitor } from './VisitorContext';
import { Helmet } from 'react-helmet';
/**
* @typedef {object} Query
* @property {string} baseUrl
* @property {object=} search
* @property {string} pageParam
*/
/**
* @typedef {object} PageProps
* @property {string=} search
* @property {import('../api').Message[]=} msgs
*/
function RequireAuth({ children }) {
let location = useLocation();
let [visitor] = useVisitor();
if (!visitor.hash) {
// Redirect them to the /login page, but save the current location they were
// trying to go to when they were redirected. This allows us to send them
// along to that page after they login, which is a nicer user experience
// than dropping them off on the home page.
return ;
}
return children;
}
/**
*
*/
export function Discover() {
const [search] = useSearchParams();
const query = {
baseUrl: '/api/messages',
search: search,
pageParam: search.search ? 'page' : 'before_mid'
};
return (
<>
Discover
>
);
}
/**
*
*/
export function Discussions() {
const query = {
baseUrl: '/api/messages/discussions',
pageParam: 'to'
};
return (
<>
Discussions
>
);
}
/**
*
*/
export function Blog() {
const { user } = useParams();
const [params] = useSearchParams();
const search = {
...params,
uname: user
};
const query = {
baseUrl: '/api/messages',
search: search,
pageParam: search.search ? 'page' : 'before_mid'
};
const blogTitle = `${user} blog`;
const pageTitle = search.tag ? `${blogTitle}: #${search.tag}` : blogTitle;
return (
<>
{pageTitle}
>
);
}
/**
*
*/
export function Tag() {
const params = useParams();
const { tag } = params;
const query = {
baseUrl: '/api/messages',
search: {
tag: tag
},
pageParam: 'before_mid'
};
return (
<>
#{tag}
>
);
}
/**
*
*/
export function Home() {
const query = {
baseUrl: '/api/home',
pageParam: 'before_mid'
};
return (
);
}
/**
* @typedef {object} FeedState
* @property { import('../api').Message[]= } msgs
* @property { Query} query
*/
/**
* @param {FeedState} props
*/
function Feed({ query }) {
const location = useLocation();
const [visitor] = useVisitor();
const [state, setState] = useState({
hash: visitor.hash,
msgs: [],
nextpage: null,
error: false,
tag: ''
});
const [loading, setLoading] = useState(true);
const [filter] = useSearchParams();
useEffect(() => {
setLoading(true);
let getPageParam = (pageParam, lastMessage, /** @type { URLSearchParams } */ filterParams) => {
const pageValue = pageParam === 'before_mid' ? lastMessage.mid : pageParam === 'page' ? (Number(filterParams.page) || 0) + 1 : dayjs.utc(lastMessage.updated).valueOf();
filterParams.append(pageParam, pageValue);
return `?${filterParams.toString()}`;
};
let params = { ...Object.fromEntries(filter), ...query.search };
let url = query.baseUrl;
getMessages(url, params)
.then(response => {
const { data } = response;
const { pageParam } = query;
const lastMessage = data.slice(-1)[0] || {};
const nextpage = getPageParam(pageParam, lastMessage, new URLSearchParams(params));
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
setState((prevState) => {
return {
...prevState,
msgs: data,
nextpage: nextpage,
tag: filter['tag'] || ''
};
});
setLoading(false);
}).catch(() => {
setState((prevState) => {
return {
...prevState,
error: true
};
});
});
}, [query, filter]);
return (state.msgs.length > 0 ? (
{
state.tag && (
← All posts with tag {state.tag}
)
}
{
state.msgs.map(msg =>
)
}
{
state.msgs.length >= 20 && (
Next →
)
}
) : state.error ? error
: loading ?
: No more messages
);
}