web/front/ArticleList.tsx
import { useRouter } from 'next/router'
import React from 'react'
import CustomLink from 'front/CustomLink'
import LikeArticleButton from 'front/LikeArticleButton'
import Pagination, { PaginationPropsUrlFunc } from 'front/Pagination'
import UserLinkWithImage from 'front/UserLinkWithImage'
import { ArticleIcon, IssueIcon, LikeIcon, TimeIcon, UserIcon } from 'front'
import { articleLimit } from 'front/config'
import { formatDate } from 'front/date'
import routes from 'front/routes'
import { ArticleType } from 'front/types/ArticleType'
import { IssueType } from 'front/types/IssueType'
import { TopicType } from 'front/types/TopicType'
import { UserType } from 'front/types/UserType'
export type ArticleListProps = {
articles: (ArticleType & IssueType & TopicType)[];
articlesCount: number;
comments?: Comment[];
commentsCount?: number;
followed?: boolean;
issueArticle?: ArticleType;
itemType?: 'article' | 'discussion' | 'like' | 'topic';
loggedInUser?: UserType,
page: number;
paginationUrlFunc?: PaginationPropsUrlFunc;
showAuthor: boolean;
showBody?: boolean,
what?: string;
}
const ArticleList = ({
articles,
articlesCount,
followed=false,
itemType='article',
issueArticle,
loggedInUser,
page,
paginationUrlFunc,
showAuthor,
showBody=false,
what='all',
}: ArticleListProps) => {
const router = useRouter();
const { asPath, pathname, query } = router;
const { like, follow, tag, uid } = query;
let isIssue
switch (itemType) {
case 'discussion':
isIssue = true
break
case 'topic':
showAuthor = false
break
}
if (articles.length === 0) {
let message;
let voice;
if (loggedInUser?.username === uid) {
voice = "You have not"
} else {
voice = "This user has not"
}
switch (what) {
case 'likes':
message = `${voice} liked any articles yet.`
break
case 'user-articles':
message = `${voice} published any articles yet.`
break
case 'all':
if (followed) {
message = `Follow some users to see their posts here.`
} else {
message = (<>
There are no {isIssue ? 'discussions' : 'articles'} on this {isIssue ? 'article' : 'website'} yet.
Why don't you <CustomLink href={isIssue ? routes.issueNew(issueArticle.slug) : routes.articleNew()}>create a new one</CustomLink>?
</>)
}
break
default:
message = `There are no ${isIssue ? 'discussions' : 'articles'} matching this search`
}
return <div className="article-preview">
{message}
</div>;
}
let pagination
if (paginationUrlFunc) {
pagination = <Pagination {...{
currentPage: page,
what: isIssue ? 'discussions' : itemType === 'like' ? 'likes' : 'articles',
itemsCount: articlesCount,
itemsPerPage: articleLimit,
urlFunc: paginationUrlFunc,
}} />
if (showBody) {
pagination = <div className="content-not-ourbigbook">{pagination}</div>
}
} else {
pagination = <></>
}
return (
<div className="list-nav-container">
{showBody && pagination}
<div className="list-container">
{showBody
? articles?.map((article, i) => (
<div
key={itemType === 'discussion' ? article.number : itemType === 'article' ? article.slug : article.topicId}
className="item"
>
<div className="content-not-ourbigbook title-container">
<LikeArticleButton {...{
article,
isIssue,
issueArticle,
loggedInUser,
showText: false,
}} />
{' '}
<CustomLink
href={itemType === 'discussion' ? routes.issue(issueArticle.slug, article.number) :
itemType === 'article' ? routes.article(article.slug) :
routes.topic(article.topicId, { sort: 'score' })
}
>
<span
className="comment-body ourbigbook-title title"
dangerouslySetInnerHTML={{ __html: article.titleRender }}
/>
</CustomLink>
{' '}
{showAuthor &&
<>
by
{' '}
<UserLinkWithImage showUsername={false} user={article.author} />
{' '}
</>
}
<span title="Last updated">
<TimeIcon />
{' '}
{formatDate(article.updatedAt)}
</span>
</div>
<div
className="ourbigbook"
dangerouslySetInnerHTML={{ __html: article.render }}
/>
<div className="content-not-ourbigbook read-full">
<CustomLink
href={itemType === 'discussion' ? routes.issue(issueArticle.slug, article.number) :
itemType === 'article' ? routes.article(article.slug) :
routes.topic(article.topicId, { sort: 'score' })
}
>
<ArticleIcon /> Read the full article
</CustomLink>
</div>
</div>
))
: <table className="list">
<thead>
<tr>
{itemType === 'like' &&
<>
<th className="shrink"><LikeIcon /><TimeIcon /> Liked</th>
<th className="shrink"><LikeIcon /><UserIcon /> Liked By</th>
</>
}
{itemType === 'topic' &&
<th className="shrink right">Articles</th>
}
{(() => {
const score = itemType === 'topic'
? <></>
: <th className="shrink center"><LikeIcon /> Score</th>
const title = <>
{isIssue &&
<th className="shrink">
<span className="icon">#</span> id
</th>
}
<th className="expand">{ itemType === 'discussion' ? <IssueIcon /> : <ArticleIcon /> } Title</th>
</>
if (itemType === 'like') {
return <>{title}{score}</>
} else {
return <>{score}{title}</>
}
})()
}
{showAuthor &&
<th className="shrink"><UserIcon /> Author</th>
}
{(itemType !== 'topic') &&
<th className="shrink"><IssueIcon /> { isIssue ? 'Comments' : 'Discussions' }</th>
}
<th className="shrink"><TimeIcon /> Created</th>
<th className="shrink"><TimeIcon /> Updated</th>
</tr>
</thead>
<tbody>
{articles?.map((article, i) => {
let curIssueArticle
if (issueArticle) {
curIssueArticle = issueArticle
} else {
curIssueArticle = article.article
}
const mainHref =
itemType === 'article' || itemType === 'like' ? routes.article(article.slug) :
itemType === 'discussion' ? routes.issue(curIssueArticle.slug, article.number) :
itemType === 'topic' ? routes.topic(article.topicId, { sort: 'score' }) :
null
return <tr
key={
itemType === 'discussion'
? `${article.number}/${curIssueArticle.slug}` :
itemType === 'article'
? article.slug :
article.topicId
}>
{itemType === 'like' &&
<>
<td className="shrink right">{formatDate(article.likedByDate)}</td>
<td className="shrink ">
<UserLinkWithImage showUsername={false} user={article.likedBy} />
</td>
</>
}
{(itemType === 'topic') &&
<td className="shrink right bold">
<CustomLink href={mainHref}>{article.articleCount}</CustomLink>
</td>
}
{(() => {
const score = <>
{(itemType === 'topic')
? <></>
: <td className="shrink center like">
<LikeArticleButton {...{
article,
isIssue,
issueArticle: curIssueArticle,
loggedInUser,
showText: false,
}} />
</td>
}
</>
const title = <>
{isIssue &&
<td className="shrink bold">
<CustomLink href={mainHref}>{issueArticle ? '' : curIssueArticle.slug }#{article.number}</CustomLink>
</td>
}
<td className="expand title">
<CustomLink href={mainHref} >
<span
className="comment-body ourbigbook-title"
dangerouslySetInnerHTML={{ __html: article.titleRender }}
/>
</CustomLink>
</td>
</>
if (itemType === 'like') {
return <>{title}{score}</>
} else {
return <>{score}{title}</>
}
})()}
{showAuthor &&
<td className="shrink">
<UserLinkWithImage showUsername={false} user={article.author} />
</td>
}
{(itemType !== 'topic') &&
<td className="shrink right bold">
<CustomLink href={isIssue ? routes.issueComments(curIssueArticle.slug, article.number) : routes.issues(article.slug)}>
{isIssue ? article.commentCount : article.issueCount}
</CustomLink>
</td>
}
<td className="shrink">{formatDate(article.createdAt)}</td>
<td className="shrink">{formatDate(article.updatedAt)}</td>
</tr>
})}
</tbody>
</table>
}
</div>
{pagination}
</div>
);
};
export default ArticleList;