import React, { useState, useEffect } from 'react'; import { Link, useParams } from 'react-router-dom'; import { HashLink } from 'react-router-hash-link'; import { Helmet } from 'react-helmet'; import moment from 'moment'; import localForage from 'localforage'; import { infoLine, ToggleDot } from './utils.js'; function countComments(c) { return c.comments.reduce((sum, x) => sum + countComments(x), 1); } function Comments({ cache }) { const { id } = useParams(); if (id in cache) console.log('cache hit'); const [story, setStory] = useState(cache[id] || false); const [error, setError] = useState(''); const [collapsed, setCollapsed] = useState([]); const [expanded, setExpanded] = useState([]); useEffect(() => { localForage.getItem(id) .then( (value) => { if (value) { setStory(value); } } ); fetch('/api/' + id) .then(res => { if (!res.ok) { throw new Error(`Server responded with ${res.status} ${res.statusText}`); } return res.json(); }) .then( (result) => { setStory(result.story); localForage.setItem(id, result.story); const hash = window.location.hash.substring(1); if (hash) { setTimeout(() => { const element = document.getElementById(hash); if (element) { element.scrollIntoView(); } }, 0); } }, (error) => { const errorMessage = `Failed to fetch comments (ID: ${id}). Your connection may be down or the server might be experiencing issues. ${error.toString()}.`; setError(errorMessage); } ); }, [id]); const collapseComment = (cid) => { setCollapsed(prev => [...prev, cid]); setExpanded(prev => prev.filter(x => x !== cid)); }; const expandComment = (cid) => { setCollapsed(prev => prev.filter(x => x !== cid)); setExpanded(prev => [...prev, cid]); }; const displayComment = (story, c, level) => { const cid = c.author+c.date; const isCollapsed = collapsed.includes(cid); const isExpanded = expanded.includes(cid); const hidden = isCollapsed || (level == 4 && !isExpanded); const hasChildren = c.comments.length !== 0; return (

{c.author === story.author ? '[OP]' : ''} {c.author || '[Deleted]'} {' '} | {moment.unix(c.date).fromNow()} {hidden || hasChildren && }

[Empty / deleted comment]

'}} /> {hidden && hasChildren ? : c.comments.map(i => displayComment(story, i, level + 1)) }
); }; return (
{error &&
Connection error? Click to expand.

{error}

{story &&

Loaded comments from cache.

}
} {story ?
{story.title} | QotNews

{story.title}

View article
{infoLine(story)}
{story.comments.map(c => displayComment(story, c, 0))}
:

loading...

}
); } export default Comments;