Skip to content

Commit

Permalink
Merge f401bf7 into 07c3820
Browse files Browse the repository at this point in the history
  • Loading branch information
MrOrz committed Oct 10, 2022
2 parents 07c3820 + f401bf7 commit 3dfbc78
Show file tree
Hide file tree
Showing 6 changed files with 313 additions and 18 deletions.
247 changes: 247 additions & 0 deletions components/ProfilePage/CommentTab.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
import gql from 'graphql-tag';
import { useQuery } from '@apollo/react-hooks';
import { useRouter } from 'next/router';
import Link from 'next/link';
import { t, ngettext, msgid } from 'ttag';
import { makeStyles } from '@material-ui/core/styles';
import {
Tools,
TimeRange,
SortInput,
LoadMore,
} from 'components/ListPageControls';
import { CardHeader, CardContent } from 'components/Card';
import Infos from 'components/Infos';
import TimeInfo from 'components/Infos/TimeInfo';
import ExpandableText from 'components/ExpandableText';
import ReplyRequestReason from 'components/ReplyRequestReason';
import Thumbnail from 'components/Thumbnail';

const COMMENTS_ORDER = [
{
value: 'createdAt',
label: t`Commented at`,
},
];
const DEFAULT_ORDER = COMMENTS_ORDER[0].value;

const LOAD_USER_COMMENTS = gql`
query LoadUserComments(
$filter: ListReplyRequestFilter!
$orderBy: [ListReplyRequestOrderBy]
$after: String
) {
ListReplyRequests(
filter: $filter
orderBy: $orderBy
after: $after
first: 15
) {
edges {
node {
id
...ReplyRequestInfo
article {
id
replyRequestCount
replyCount
createdAt
text
...ThumbnailArticleData
}
}
...LoadMoreEdge
}
}
}
${ReplyRequestReason.fragments.ReplyRequestInfo}
${LoadMore.fragments.LoadMoreEdge}
${Thumbnail.fragments.ThumbnailArticleData}
`;

const LOAD_USER_COMMENTS_STAT = gql`
query LoadUserCommentsStat(
$filter: ListReplyRequestFilter!
$orderBy: [ListReplyRequestOrderBy]
) {
ListReplyRequests(filter: $filter, orderBy: $orderBy) {
totalCount
...LoadMoreConnectionForStats
}
}
${LoadMore.fragments.LoadMoreConnectionForStats}
`;

const useStyles = makeStyles(theme => ({
tools: {
[theme.breakpoints.up('sm')]: {
marginLeft: 'var(--card-px)',
marginRight: 'var(--card-px)',
},
},
divider: {
border: 0,
margin: '16px 0 0',
borderBottom: `1px dashed ${theme.palette.secondary[100]}`,
},
infos: {
marginBottom: 4,
[theme.breakpoints.up('md')]: {
marginBottom: 12,
},
},
}));

/**
* @param {object} urlQuery - URL query object and urserId
* @param {string} userId - The author ID of article reply to look for
* @returns {object} ListArticleFilter
*/
function urlQuery2Filter(query = {}, userId) {
const filterObj = { userId };

const [start, end] = TimeRange.getValues(query);

if (start) {
filterObj.createdAt = {
...filterObj.createdAt,
GTE: start,
};
}
if (end) {
filterObj.createdAt = {
...filterObj.createdAt,
LTE: end,
};
}

return filterObj;
}

function CommentTab({ userId }) {
const classes = useStyles();
const { query } = useRouter();

const listQueryVars = {
filter: urlQuery2Filter(query, userId),
orderBy: [{ [SortInput.getValue(query) || DEFAULT_ORDER]: 'DESC' }],
};

const {
loading,
fetchMore,
data: listCommentsData,
error: listCommentsError,
} = useQuery(LOAD_USER_COMMENTS, {
skip: !userId,
variables: listQueryVars,
notifyOnNetworkStatusChange: true, // Make loading true on `fetchMore`
});

// Separate these stats query so that it will be cached by apollo-client and sends no network request
// on page change, but still works when filter options are updated.
//
const { data: listStatData } = useQuery(LOAD_USER_COMMENTS_STAT, {
skip: !userId,
variables: listQueryVars,
});

// List data
const commentEdges = listCommentsData?.ListReplyRequests?.edges || [];
const statsData = listStatData?.ListReplyRequests || {};
const totalCount = statsData?.totalCount;

if (!userId) {
return null;
}

return (
<>
<Tools className={classes.tools}>
<TimeRange />
<SortInput defaultOrderBy={DEFAULT_ORDER} options={COMMENTS_ORDER} />
</Tools>
{loading && !totalCount ? (
<CardContent>{t`Loading...`}</CardContent>
) : listCommentsError ? (
<CardContent>{listCommentsError.toString()}</CardContent>
) : totalCount === 0 ? (
<CardContent>{t`This user does not provide comments to any message in the specified date range.`}</CardContent>
) : (
<>
<CardHeader>
{ngettext(
msgid`${totalCount} comment matching criteria`,
`${totalCount} comments matching criteria`,
totalCount
)}
</CardHeader>
{commentEdges.map(({ node: { article, ...comment } }) => (
<CardContent key={comment.id} style={{ paddingBottom: 0 }}>
<Infos className={classes.infos}>
<>
{ngettext(
msgid`${article.replyRequestCount} occurrence`,
`${article.replyRequestCount} occurrences`,
article.replyRequestCount
)}
</>
<TimeInfo time={article.createdAt}>
{timeAgo => (
<Link href="/article/[id]" as={`/article/${article.id}`}>
{t`First reported ${timeAgo}`}
</Link>
)}
</TimeInfo>
{article.replyCount > 0 && (
<>
{ngettext(
msgid`${article.replyCount} reply`,
`${article.replyCount} replies`,
article.replyCount
)}
</>
)}
</Infos>
<Thumbnail article={article} />
{article.text && (
<ExpandableText lineClamp={3}>{article.text}</ExpandableText>
)}

<hr className={classes.divider} />

<ReplyRequestReason
articleId={article.id}
replyRequest={comment}
/>
</CardContent>
))}

<LoadMore
edges={commentEdges}
pageInfo={statsData?.pageInfo}
loading={loading}
onMoreRequest={args =>
fetchMore({
variables: args,
updateQuery(prev, { fetchMoreResult }) {
if (!fetchMoreResult) return prev;
const newCommentData = fetchMoreResult?.ListReplyRequests;
return {
...prev,
ListArticles: {
...newCommentData,
edges: [...commentEdges, ...newCommentData.edges],
},
};
},
})
}
/>
</>
)}
</>
);
}

export default CommentTab;
14 changes: 12 additions & 2 deletions components/ProfilePage/ProfilePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import AppLayout from 'components/AppLayout';
import { Card } from 'components/Card';
import UserPageHeader from './UserPageHeader';
import RepliedArticleTab from './RepliedArticleTab';
import CommentTab from './CommentTab';
import ContributionChart from 'components/ContributionChart';
import { startOfWeek, subDays, format } from 'date-fns';

Expand Down Expand Up @@ -63,6 +64,9 @@ const LOAD_CONTRIBUTION = gql`
commentedReplies: ListArticleReplyFeedbacks(filter: { userId: $id }) {
totalCount
}
comments: ListReplyRequests(filter: { userId: $id }) {
totalCount
}
}
`;

Expand All @@ -75,6 +79,7 @@ function ProfilePage({ id, slug }) {
const { data: contributionData } = useQuery(LOAD_CONTRIBUTION, {
variables: { id: data?.GetUser?.id },
skip: !data?.GetUser?.id,
ssr: false, // Speed up SSR
});

const isSelf = currentUser && data?.GetUser?.id === currentUser.id;
Expand Down Expand Up @@ -123,8 +128,11 @@ function ProfilePage({ id, slug }) {
let contentElem = null;
switch (tab) {
case 'replies':
default:
contentElem = <RepliedArticleTab userId={data?.GetUser?.id} />;
break;
case 'comments':
contentElem = <CommentTab userId={data?.GetUser?.id} />;
break;
}
const today = format(new Date(), 'yyyy-MM-dd');
const aYearAgo = format(
Expand All @@ -144,6 +152,7 @@ function ProfilePage({ id, slug }) {
stats={{
repliedArticles: contributionData?.repliedArticles?.totalCount,
commentedReplies: contributionData?.commentedReplies?.totalCount,
comments: contributionData?.comments?.totalCount,
}}
/>
<ContributionChart
Expand All @@ -159,10 +168,11 @@ function ProfilePage({ id, slug }) {
indicatorColor="primary"
textColor="primary"
onChange={(e, tab) => {
router.push({ query: { tab } });
router.push({ query: { tab, id, slug } });
}}
>
<Tab value="replies" label={t`Replied messages`} />
<Tab value="comments" label={t`Comments`} />
</Tabs>
{contentElem}
</Card>
Expand Down
7 changes: 6 additions & 1 deletion components/ProfilePage/RepliedArticleTab.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import gql from 'graphql-tag';
import { useQuery } from '@apollo/react-hooks';
import { useRouter } from 'next/router';
import Link from 'next/link';
import { t, ngettext, msgid } from 'ttag';
import { Box } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
Expand Down Expand Up @@ -272,7 +273,11 @@ function RepliedArticleTab({ userId }) {
)}
</>
<TimeInfo time={article.createdAt}>
{timeAgo => t`First reported ${timeAgo}`}
{timeAgo => (
<Link href="/article/[id]" as={`/article/${article.id}`}>
{t`First reported ${timeAgo}`}
</Link>
)}
</TimeInfo>
</Infos>
<Thumbnail article={article} />
Expand Down
1 change: 1 addition & 0 deletions components/ProfilePage/Stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ function Stats({ stats }) {
return (
<ul className={classes.root}>
<Stat label={t`replied messages`} value={stats?.repliedArticles} />
<Stat label={t`comments`} value={stats?.comments} />
<Stat label={t`voted replies`} value={stats?.commentedReplies} />
</ul>
);
Expand Down
2 changes: 1 addition & 1 deletion components/ProfilePage/UserPageHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ const useStyles = makeStyles(theme => ({
*
* @param {object} props.user
* @param {boolean} props.isSelf - If the current user is the one in `user` prop
* @param {{repliedArticles: number, commentedReplies: number}} props.stats
* @param {{repliedArticles: number, commentedReplies: number, comments: number}} props.stats
*/
function UserPageHeader({ user, isSelf, stats }) {
const classes = useStyles();
Expand Down
Loading

0 comments on commit 3dfbc78

Please sign in to comment.