• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cofacts / rumors-site / 20064430986

09 Dec 2025 01:03PM UTC coverage: 67.864%. Remained the same
20064430986

Pull #615

github

web-flow
Merge 249e0b61c into c69bec0c9
Pull Request #615: fix: Redirect to new user profile URL after the user removes their slug settings #563

400 of 721 branches covered (55.48%)

Branch coverage included in aggregate %.

960 of 1283 relevant lines covered (74.82%)

11.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.62
/components/ArticleReplyFeedbackControl/ReasonsDisplay.js
1
import React, { useState, useEffect } from 'react';
2
import { t } from 'ttag';
3
import gql from 'graphql-tag';
4
import { useQuery } from '@apollo/react-hooks';
5
import { withStyles, makeStyles } from '@material-ui/core/styles';
6
import { Box, Tab, Tabs, CircularProgress } from '@material-ui/core';
7
import { ThumbUpIcon, ThumbDownIcon } from 'components/icons';
8
import { LoadMore } from 'components/ListPageControls';
9
import { useIsUserBlocked } from 'lib/isUserBlocked';
10
import Feedback from './Feedback';
11

12
const useStyles = makeStyles(() => ({
1✔
13
  feedbacks: {
14
    marginTop: 16,
15
    maxHeight: 300,
16
    overflow: 'auto',
17
  },
18
}));
19

20
const CustomTab = withStyles({
1✔
21
  root: {
22
    position: 'relative',
23
    minHeight: 0,
24
  },
25
  wrapper: {
26
    '& > svg': {
27
      position: 'absolute',
28
      left: 0,
29
    },
30
  },
31
})(Tab);
32

33
const ReasonsDisplayData = gql`
1✔
34
  fragment ReasonsDisplayData on ArticleReply {
35
    articleId
36
    replyId
37
    positiveFeedbackCount
38
    negativeFeedbackCount
39
  }
40
`;
41

42
export const LOAD_FEEDBACKS = gql`
1✔
43
  query LoadFeadbacksForArticleReply(
44
    $articleId: String!
45
    $replyId: String!
46
    $statuses: [ArticleReplyFeedbackStatusEnum!]
47
  ) {
48
    ListArticleReplyFeedbacks(
49
      filter: { articleId: $articleId, replyId: $replyId, statuses: $statuses }
50
      first: 1000
51
    ) {
52
      edges {
53
        node {
54
          id
55
          vote
56
          createdAt
57
          user {
58
            id
59
          }
60
          ...ReasonDisplayFeedbackData
61
        }
62
      }
63
    }
64
    GetReply(id: $replyId) {
65
      id
66
      text
67
    }
68
  }
69
  ${Feedback.fragments.ReasonDisplayFeedbackData}
70
`;
71

72
function isEmptyComment(comment) {
73
  return comment === '' || comment === null;
×
74
}
75

76
function processedFeedbacks(feedbacks, voteType, isLoadMore) {
77
  return feedbacks
×
78
    .filter(({ vote }) => vote === voteType)
×
79
    .sort(
80
      (a, b) =>
81
        isEmptyComment(a.comment) - isEmptyComment(b.comment) ||
×
82
        b.createdAt.localeCompare(a.createdAt)
83
    )
84
    .slice(0, isLoadMore ? feedbacks.length : Math.min(feedbacks.length, 10));
×
85
}
86

87
function ReasonsDisplay({ articleReply, onSizeChange = () => {} }) {
×
88
  const classes = useStyles();
×
89
  const isUserBlocked = useIsUserBlocked();
×
90
  const [tab, setTab] = useState(0);
×
91
  const [isLoadMoreUpvote, setIsLoadMoreUpvote] = useState(false);
×
92
  const [isLoadMoreDownvote, setIsLoadMoreDownvote] = useState(false);
×
93
  const { data, loading } = useQuery(LOAD_FEEDBACKS, {
×
94
    variables: {
95
      articleId: articleReply.articleId,
96
      replyId: articleReply.replyId,
97
      statuses: isUserBlocked ? ['NORMAL', 'BLOCKED'] : ['NORMAL'],
×
98
    },
99
    fetchPolicy: 'cache-and-network',
100
    ssr: false,
101
  });
102

103
  // Invoking onSizeChange on load and tab switch
104
  //
105
  useEffect(() => {
×
106
    if (!loading && onSizeChange) {
×
107
      return onSizeChange();
×
108
    }
109
  }, [loading, onSizeChange]);
110

111
  useEffect(() => {
×
112
    if (onSizeChange) return onSizeChange();
×
113
  }, [tab, onSizeChange]);
114

115
  const feedbacks =
116
    data?.ListArticleReplyFeedbacks?.edges.map(({ node }) => node) || [];
×
117

118
  if (loading) {
×
119
    return (
×
120
      <Box textAlign="center">
121
        <CircularProgress />
122
      </Box>
123
    );
124
  }
125

126
  return (
×
127
    <>
128
      {data?.GetReply?.text}
129
      <Tabs
130
        value={tab}
131
        onChange={(e, value) => setTab(value)}
×
132
        indicatorColor="primary"
133
        textColor="primary"
134
        variant="fullWidth"
135
      >
136
        <CustomTab
137
          icon={<ThumbUpIcon />}
138
          label={t`Helpful ${articleReply.positiveFeedbackCount}`}
139
        />
140
        <CustomTab
141
          icon={<ThumbDownIcon />}
142
          label={t`Not Helpful ${articleReply.negativeFeedbackCount}`}
143
        />
144
      </Tabs>
145
      <Box display={tab === 0 ? 'block' : 'none'} className={classes.feedbacks}>
×
146
        {processedFeedbacks(feedbacks, 'UPVOTE', isLoadMoreUpvote).map(
147
          feedback => (
148
            <Feedback
×
149
              key={feedback.id}
150
              articleId={articleReply.articleId}
151
              replyId={articleReply.replyId}
152
              feedback={feedback}
153
            />
154
          )
155
        )}
156
        {feedbacks.length > 10 && !isLoadMoreUpvote && (
×
157
          <LoadMore
158
            edges={feedbacks}
159
            loading={loading}
160
            onMoreRequest={() => {
161
              setIsLoadMoreUpvote(true);
×
162
            }}
163
          />
164
        )}
165
      </Box>
166
      <Box display={tab === 1 ? 'block' : 'none'} className={classes.feedbacks}>
×
167
        {processedFeedbacks(feedbacks, 'DOWNVOTE', isLoadMoreDownvote).map(
168
          feedback => (
169
            <Feedback
×
170
              key={feedback.id}
171
              articleId={articleReply.articleId}
172
              replyId={articleReply.replyId}
173
              feedback={feedback}
174
            />
175
          )
176
        )}
177
        {feedbacks.length > 10 && !isLoadMoreDownvote && (
×
178
          <LoadMore
179
            edges={feedbacks}
180
            loading={loading}
181
            onMoreRequest={() => {
182
              setIsLoadMoreDownvote(true);
×
183
            }}
184
          />
185
        )}
186
      </Box>
187
    </>
188
  );
189
}
190

191
ReasonsDisplay.fragments = {
1✔
192
  ReasonsDisplayData,
193
};
194

195
export default ReasonsDisplay;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc