diff --git a/src/components/Proposal/Proposal.jsx b/src/components/Proposal/Proposal.jsx index cfb2412fe..b854798a9 100644 --- a/src/components/Proposal/Proposal.jsx +++ b/src/components/Proposal/Proposal.jsx @@ -474,7 +474,6 @@ const Proposal = React.memo(function Proposal({ )} - {extended && } )} {extended && files.length > 1 && ( @@ -546,7 +545,7 @@ const Proposal = React.memo(function Proposal({ getVotesReceived(voteSummary) > 0 && ( )} - {extended && ( + {!isCensored && (isVetted || isAuthor || isAdmin) && ( )} diff --git a/src/containers/Comments/Comment/Comment.jsx b/src/containers/Comments/Comment/Comment.jsx index 7c79bda21..60d3a1700 100644 --- a/src/containers/Comments/Comment/Comment.jsx +++ b/src/containers/Comments/Comment/Comment.jsx @@ -81,6 +81,7 @@ const Comment = ({ const currentTimeSec = new Date().getTime() / 1000; const isEditable = authorID === userid && + !disableReply && allowedits && currentTimeSec < createdAt + editperiod; const remaining = createdAt + editperiod - currentTimeSec; @@ -182,7 +183,7 @@ const Comment = ({ {({ timeAgo }) => ( - {version > 1 && Edited } + {version > 1 && edited } {timeAgo} )} @@ -284,7 +285,7 @@ Comment.propTypes = { censored: PropTypes.bool, censoredBy: PropTypes.string, reason: PropTypes.string, - sectionId: PropTypes.string, + sectionId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), highlightAuthor: PropTypes.bool, disableLikes: PropTypes.bool, likesCount: PropTypes.number, diff --git a/src/containers/Proposal/Detail/Detail.jsx b/src/containers/Proposal/Detail/Detail.jsx index 2a266cef0..89c4380a1 100644 --- a/src/containers/Proposal/Detail/Detail.jsx +++ b/src/containers/Proposal/Detail/Detail.jsx @@ -82,6 +82,7 @@ const ProposalDetail = ({ Main, match, history }) => { proposalToken || tokenFromUrl ); const areCommentsAllowed = + !isCensoredProposal(proposal) && !isVotingFinishedProposal(voteSummary) && !isAbandonedProposal(proposalSummary); const areAuthorUpdatesAllowed = isActiveProposal(proposalSummary); @@ -172,7 +173,12 @@ const ProposalDetail = ({ Main, match, history }) => { const proposalComments = useMemo( () => ( <> - {!(currentUser && isSingleThread) && ( + {readOnly && ( + + {readOnlyReason} + + )} + {!(currentUser && isSingleThread) && !readOnly && ( @@ -185,11 +191,6 @@ const ProposalDetail = ({ Main, match, history }) => { } > - {readOnly && ( - - {readOnlyReason} - - )} {!isPaid && paywallEnabled && currentUser && (

@@ -200,7 +201,7 @@ const ProposalDetail = ({ Main, match, history }) => {

)} - {!readOnly && !!identityError && } + {!!identityError && } {areAuthorUpdatesAllowed && !isCurrentUserProposalAuthor && ( Replies & upvotes/downvotes are allowed only on the latest @@ -306,8 +307,7 @@ const ProposalDetail = ({ Main, match, history }) => {

)} - {!isCensoredProposal(proposal) && - !commentsLoading && + {!commentsLoading && commentsFinishedLoading && proposalComments} diff --git a/src/containers/Proposal/Detail/helpers.js b/src/containers/Proposal/Detail/helpers.js index 337ff1186..dc0c8a4a8 100644 --- a/src/containers/Proposal/Detail/helpers.js +++ b/src/containers/Proposal/Detail/helpers.js @@ -2,7 +2,8 @@ import { isAbandonedProposal, isRejectedProposal, isClosedProposal, - isCompletedProposal + isCompletedProposal, + isCensoredProposalSummary } from "../helpers"; export const getCommentBlockedReason = (proposalSummary) => { @@ -14,6 +15,10 @@ export const getCommentBlockedReason = (proposalSummary) => { return "Voting has finished for this proposal. No additional changes are allowed."; } + if (isCensoredProposalSummary(proposalSummary)) { + return "This proposal has been censored. No additional changes are allowed."; + } + if (isClosedProposal(proposalSummary)) { return "Proposal is closed. No additional changes are allowed."; } diff --git a/src/containers/Proposal/helpers.js b/src/containers/Proposal/helpers.js index cec40bdb3..bc8114f10 100644 --- a/src/containers/Proposal/helpers.js +++ b/src/containers/Proposal/helpers.js @@ -12,10 +12,12 @@ import { PROPOSAL_STATUS_CENSORED, PROPOSAL_STATE_VETTED, PROPOSAL_STATE_UNVETTED, + PROPOSAL_SUMMARY_STATUS_CENSORED, PROPOSAL_SUMMARY_STATUS_CLOSED, PROPOSAL_SUMMARY_STATUS_COMPLETED, PROPOSAL_SUMMARY_STATUS_ACTIVE, PROPOSAL_SUMMARY_STATUS_UNVETTED_ABANDONED, + PROPOSAL_SUMMARY_STATUS_UNVETTED_CENSORED, PROPOSAL_SUMMARY_STATUS_ABANDONED, PROPOSAL_SUMMARY_STATUS_REJECTED, AUTHORIZED, @@ -215,6 +217,16 @@ export const isAbandonedProposal = (proposalSummary) => (proposalSummary.status === PROPOSAL_SUMMARY_STATUS_ABANDONED || proposalSummary.status === PROPOSAL_SUMMARY_STATUS_UNVETTED_ABANDONED); +/** + * Returns true if the given proposal summary is censored + * @param {Object} proposalSummary + * @returns {Boolean} isCensored + */ +export const isCensoredProposalSummary = (proposalSummary) => + !!proposalSummary && + (proposalSummary.status === PROPOSAL_SUMMARY_STATUS_UNVETTED_CENSORED || + proposalSummary.status === PROPOSAL_SUMMARY_STATUS_CENSORED); + /** * Returns true if the given proposal is approved * @param {Object} proposal diff --git a/src/lib/errors.js b/src/lib/errors.js index 8310f5ee4..e8ee3d3ae 100644 --- a/src/lib/errors.js +++ b/src/lib/errors.js @@ -306,6 +306,7 @@ function PiPluginError(code, context) { 11: `Proposal domain is invalid, ${context}`, 15: `${context}`, 16: `${context}`, + 17: "Comment replies are only allowed on the most recent author update thread", 18: "Author update title is missing" }; diff --git a/src/utils.js b/src/utils.js index 483cd5b95..fdccdcd83 100644 --- a/src/utils.js +++ b/src/utils.js @@ -91,11 +91,13 @@ export const isIdentityError = (error) => { export function formatTimestampsFromMessage(msg) { let newMsg = msg; const timestamps = msg.match(/[0-9]+/g); - timestamps.forEach((t) => { - const formattedTime = formatDateToInternationalString( - formatUnixTimestampToObj(t) - ); - newMsg = newMsg.replace(t, formattedTime); - }); + if (timestamps) { + timestamps.forEach((t) => { + const formattedTime = formatDateToInternationalString( + formatUnixTimestampToObj(t) + ); + newMsg = newMsg.replace(t, formattedTime); + }); + } return newMsg; }