phanpy/src/pages/home.jsx

198 lines
5.5 KiB
React
Raw Normal View History

2022-12-10 12:14:48 +03:00
import { Link } from 'preact-router/match';
import { useEffect, useRef, useState } from 'preact/hooks';
import { InView } from 'react-intersection-observer';
import { useSnapshot } from 'valtio';
import Icon from '../components/icon';
import Loader from '../components/loader';
import Status from '../components/status';
import states from '../utils/states';
const LIMIT = 20;
2022-12-16 08:27:04 +03:00
function Home({ hidden }) {
2022-12-10 12:14:48 +03:00
const snapStates = useSnapshot(states);
const [uiState, setUIState] = useState('default');
const [showMore, setShowMore] = useState(false);
2022-12-18 06:52:53 +03:00
const homeIterator = useRef(
masto.v1.timelines.listHome({
2022-12-10 12:14:48 +03:00
limit: LIMIT,
}),
);
2022-12-10 12:14:48 +03:00
async function fetchStatuses(firstLoad) {
if (firstLoad) {
// Reset iterator
homeIterator.current = masto.v1.timelines.listHome({
limit: LIMIT,
});
}
const allStatuses = await homeIterator.current.next();
2022-12-10 12:14:48 +03:00
if (allStatuses.value <= 0) {
return { done: true };
}
const homeValues = allStatuses.value.map((status) => {
states.statuses.set(status.id, status);
if (status.reblog) {
states.statuses.set(status.reblog.id, status.reblog);
}
return {
id: status.id,
reblog: status.reblog?.id,
reply: !!status.inReplyToAccountId,
};
});
if (firstLoad) {
states.home = homeValues;
} else {
states.home.push(...homeValues);
}
states.homeLastFetchTime = Date.now();
return allStatuses;
}
const loadStatuses = (firstLoad) => {
setUIState('loading');
(async () => {
try {
const { done } = await fetchStatuses(firstLoad);
setShowMore(!done);
setUIState('default');
} catch (e) {
console.warn(e);
setUIState('error');
}
})();
};
useEffect(() => {
loadStatuses(true);
}, []);
const scrollableRef = useRef();
return (
<div class="deck-container" hidden={hidden} ref={scrollableRef}>
<div class="timeline-deck deck">
<header
onClick={() => {
scrollableRef.current?.scrollTo({ top: 0, behavior: 'smooth' });
}}
onDblClick={() => {
loadStatuses(true);
}}
2022-12-10 12:14:48 +03:00
>
<div class="header-side">
<button
type="button"
class="plain"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
states.showSettings = true;
}}
>
<Icon icon="gear" size="l" alt="Settings" />
</button>
</div>
<h1>Home</h1>
<div class="header-side">
<Loader hidden={uiState !== 'loading'} />{' '}
<a
href="#/notifications"
class={`button plain ${
snapStates.notificationsNew.length > 0 ? 'has-badge' : ''
}`}
onClick={(e) => {
e.stopPropagation();
}}
2022-12-10 12:14:48 +03:00
>
<Icon icon="notification" size="l" alt="Notifications" />
</a>
</div>
{snapStates.homeNew.length > 1 && (
2022-12-10 12:14:48 +03:00
<button
class="updates-button"
type="button"
onClick={() => {
const uniqueHomeNew = snapStates.homeNew.filter(
(status) => !states.home.some((s) => s.id === status.id),
);
states.home.unshift(...uniqueHomeNew);
loadStatuses(true);
states.homeNew = [];
scrollableRef.current?.scrollTo({
top: 0,
behavior: 'smooth',
});
}}
>
<Icon icon="arrow-up" /> New posts
</button>
)}
</header>
{snapStates.home.length ? (
<>
<ul class="timeline">
{snapStates.home.map(({ id: statusID, reblog }) => {
const actualStatusID = reblog || statusID;
return (
<li key={statusID}>
<Link
activeClassName="active"
class="status-link"
href={`#/s/${actualStatusID}`}
>
<Status statusID={statusID} />
</Link>
</li>
);
})}
{showMore && (
<>
<InView
as="li"
2022-12-10 12:14:48 +03:00
style={{
height: '20vh',
}}
onChange={(inView) => {
if (inView) loadStatuses();
2022-12-10 12:14:48 +03:00
}}
>
<Status skeleton />
</InView>
2022-12-10 12:14:48 +03:00
<li
style={{
height: '25vh',
}}
>
<Status skeleton />
</li>
</>
2022-12-10 12:14:48 +03:00
)}
</ul>
</>
) : (
<>
{uiState === 'loading' && (
<ul class="timeline">
{Array.from({ length: 5 }).map((_, i) => (
<li key={i}>
<Status skeleton />
</li>
))}
</ul>
)}
{uiState === 'error' && (
<p class="ui-state">Error loading statuses</p>
)}
</>
)}
</div>
</div>
);
2022-12-16 08:27:04 +03:00
}
export default Home;