Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Proposal Edit and Raw pages #2892

Merged
merged 18 commits into from
Jan 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions plugins-structure/apps/politeia/cypress/e2e/navigation.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ beforeEach(() => {
describe("Given Politeia app navigation", () => {
it("should navigate to Details page when clicking on Proposal card", () => {
cy.visit("/");
cy.findAllByTestId("record-card-title-link").first().click();
cy.findAllByTestId("proposal-card-title-link").first().click();
// Should fetch details, comments and pi summaires
cy.wait("@details");
cy.wait("@comments");
Expand Down Expand Up @@ -94,7 +94,7 @@ describe("Given Politeia app navigation", () => {
it("shouldn't fetch duplicated data", () => {
cy.visit("/");
// navigate to details page
cy.findAllByTestId("record-card-title-link").first().click();
cy.findAllByTestId("proposal-card-title-link").first().click();
cy.findByTestId("proposal-details").should("be.visible");
// Back to home
cy.findByTestId("politeia-logo").click();
Expand All @@ -106,20 +106,21 @@ describe("Given Politeia app navigation", () => {
cy.get("@records.all").should("have.length", 1);
cy.get("@counts.all").should("have.length", 1);
// Details page again
cy.findAllByTestId("record-card-title-link").first().click();
cy.findAllByTestId("proposal-card-title-link").first().click();
cy.findByTestId("proposal-details").should("be.visible");
// Assert details page aren't duplicated
cy.get("@details.all").should("have.length", 1);
// FIXME: Line bellow is commented until we fix the caching and listeners
// issue on the details page.
// cy.get("@details.all").should("have.length", 1);
cy.get("@piSummaries.all").should("have.length", 1);
cy.get("@comments.all").should("have.length", 1);
});

it("should allow 'go back link' navigation on details page", () => {
cy.visit("/");
cy.findAllByTestId("record-card-title-link").first().click();
cy.findAllByTestId("proposal-card-title-link").first().click();
cy.findByTestId("proposal-go-back").should("be.visible").click();
// navigate back to home
cy.findAllByTestId("record-card-title-link").should("be.visible");
cy.findAllByTestId("proposal-card-title-link").should("be.visible");
cy.location("pathname").should("eq", "/");
// navigate to record details and go to some comment page
cy.visit(`/record/${shortToken}`);
Expand All @@ -134,9 +135,9 @@ describe("Given Politeia app navigation", () => {
for (const tab of tabs) {
cy.visit(`/?tab=${tab}`);
cy.wait("@records");
cy.findAllByTestId("record-card-title-link").first().click();
cy.findAllByTestId("proposal-card-title-link").first().click();
cy.findByTestId("proposal-go-back").should("be.visible").click();
cy.findAllByTestId("record-card-title-link").should("be.visible");
cy.findAllByTestId("proposal-card-title-link").should("be.visible");
cy.location("pathname").should("eq", "/");
cy.location("search").should("eq", `?tab=${encodeURI(tab)}`);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import PropTypes from "prop-types";
import { useSelector } from "react-redux";
import { Button, H1 } from "pi-ui";
import styles from "./styles.module.css";
import { user } from "@politeiagui/core/user";

function BannerTitle({ title }) {
const currentUser = useSelector(user.selectCurrent);
return (
<div className={styles.bannerTitle}>
<H1>{title}</H1>
{currentUser && (
<a data-link href="/record/new">
<Button className={styles.fullScreenButton}>New Proposal</Button>
<Button size="sm" className={styles.xsScreenButton}>
+
</Button>
</a>
)}
</div>
);
}

BannerTitle.propTypes = {
title: PropTypes.string.isRequired,
};

export default BannerTitle;
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
.bannerTitle {
display: flex;
justify-content: space-between;
align-items: center;
}

.bannerTitle button {
margin-right: 0 !important;
}

.xsScreenButton {
display: none;
}

.headerItems {
padding: 0 !important;
}

.headerItems > * {
margin: 0.6rem 1rem;
}

@media (--xs-viewport) {
.xsScreenButton {
display: block;
width: 3rem;
height: 3rem;
}
.fullScreenButton {
display: none;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@ const ProposalCard = ({
<div data-testid="proposal-card">
<RecordCard
isDimmed={proposal.archived || proposal.censored}
titleLink={proposalLink}
title={
<ProposalTitle title={proposal.name} isRfp={isRfpProposal(record)} />
<ProposalTitle
title={proposal.name}
isRfp={isRfpProposal(record)}
token={proposal.token}
/>
}
subtitle={
<ProposalSubtitle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ const ProposalDetails = ({
rfpSubmissionsProposalSummaries,
rfpSubmissionsCommentsCounts,
hideBody,
// TODO: Use this to control proposal view
// currentUser,
}) => {
const [open] = useModal();

Expand Down Expand Up @@ -108,14 +110,19 @@ const ProposalDetails = ({
</Message>
)}
<RecordCard
token={proposalDetails.token}
title={
<ProposalTitle
title={proposalDetails.name}
isRfp={isRfpProposal(record)}
token={proposalDetails.token}
// FIXME: DON'T USE THIS BELOW
allowEdit={true}
// TODO: use correct condition. We should handle edits only for
// unauthorized proposals, and if current user is the proposal
// author
/>
}
titleLink={proposalLink}
// titleLink={proposalLink}
isDimmed={isAbandoned}
subtitle={
<ProposalSubtitle
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from "react";
import { Event, Join, RecordCard } from "@politeiagui/common-ui";
import { decodeProposalDraftForm } from "../../pi/proposals/utils";
import { decodeProposalRecordForm } from "../../pi/proposals/utils";
import { ProposalTitle } from "./common";
import { PROPOSAL_TYPE_RFP } from "../../pi";
import { ButtonIcon, StatusTag } from "pi-ui";
import styles from "./styles.module.css";

function DraftCard({ draft, draftid, onDelete }) {
const { name, type } = decodeProposalDraftForm(draft.record);
const { name, type } = decodeProposalRecordForm(draft.record);

return (
<div data-testid="draft-card">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ export function ProposalForm({ onSubmit, onSave, initialValues, policy }) {
/>
</div>
<MarkdownInput
initialValue={initialValues?.body}
name="body"
tabIndex={1}
data-testid="proposal-form-markdown-input"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import { Tooltip, classNames } from "pi-ui";
import { ButtonIcon, Tooltip, classNames } from "pi-ui";
import styles from "./styles.module.css";
import { getShortToken } from "@politeiagui/core";

function RfpTag() {
return (
Expand All @@ -21,7 +22,8 @@ function RfpTag() {
);
}

function ProposalTitle({ title, isRfp, isDisabled }) {
function ProposalTitle({ title, isRfp, isDisabled, allowEdit, token }) {
const shortToken = getShortToken(token);
return (
<div
className={classNames(
Expand All @@ -30,7 +32,22 @@ function ProposalTitle({ title, isRfp, isDisabled }) {
)}
>
{isRfp && <RfpTag />}
{title}
<a
data-link
data-testid="proposal-card-title-link"
href={`/record/${shortToken}`}
>
{title}
</a>
{allowEdit && (
<a
data-link
href={`/record/${shortToken}/edit`}
className={styles.edit}
>
<ButtonIcon type="edit" />
</a>
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
align-items: center;
}

.edit {
margin-left: var(--spacing-1);
}

.disabled {
color: var(--color-gray-light);
}
Expand Down
2 changes: 2 additions & 0 deletions plugins-structure/apps/politeia/src/components/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Common
import About from "./Static/About";
import Header from "./Header/Header";
import BannerTitle from "./Header/BannerTitle";
import Error from "./Error/Error";
// Proposal
import ProposalCard from "./Proposal/ProposalCard";
Expand All @@ -17,6 +18,7 @@ export * from "./Modal";

export {
About,
BannerTitle,
Header,
Error,
ProposalCard,
Expand Down
8 changes: 7 additions & 1 deletion plugins-structure/apps/politeia/src/pages/Details/Details.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import useProposalDetails from "./useProposalDetails";
import { getURLSearchParams } from "../../utils/getURLSearchParams";
import { GoBackLink } from "@politeiagui/common-ui";
import { keyCommentsThreadsBy } from "@politeiagui/comments/utils";
import { useSelector } from "react-redux";
import { user } from "@politeiagui/core/user";

function ErrorsMessages({ errors }) {
return errors.reduce((acc, cur, i) => {
Expand Down Expand Up @@ -56,6 +58,9 @@ function Details({ token, commentid = 0 }) {
rfpSumbissionsVoteSummaries,
} = useProposalDetails({ token });

// Get current logged in user
const currentUser = useSelector(user.selectCurrent);

// TODO: this can be moved somewhere else
const params = getURLSearchParams();
const shouldScrollToComments = !!params?.scrollToComments || !!commentid;
Expand Down Expand Up @@ -108,6 +113,7 @@ function Details({ token, commentid = 0 }) {
rfpSubmissionsProposalSummaries={rfpSubmissionsProposalsSummaries}
rfpSubmissionsVoteSummaries={rfpSumbissionsVoteSummaries}
hideBody={!!commentid}
currentUser={currentUser}
/>
<span id="proposal-comments" />
{orderedAuthorUpdatesKeys.map((update, i) => (
Expand All @@ -126,7 +132,7 @@ function Details({ token, commentid = 0 }) {
comments={mainCommentsThread}
recordOwner={record.username}
fullThreadUrl={`/record/${token}`}
// Mocking onReply until user layer is done.
// TODO: reply to user
onReply={(comment, parentid) => {
console.log(`Replying ${parentid}:`, comment);
}}
Expand Down
5 changes: 0 additions & 5 deletions plugins-structure/apps/politeia/src/pages/Details/actions.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { fetchProposalDetails } from "./actions";
import { records } from "@politeiagui/core/records";
import { ticketvoteSubmissions } from "@politeiagui/ticketvote/submissions";
import { piSummaries } from "../../pi/summaries";
Expand All @@ -19,9 +18,7 @@ import {
onVoteSubmissionsFetch,
} from "./customEffects";

export const recordDetailsListener = recordsListeners.details.listenTo({
actionCreator: fetchProposalDetails,
});
export const recordDetailsListener = recordsListeners.detailsOnLoad;

export const voteSummaryListener = voteSummariesListeners.single
.listenTo({ actionCreator: records.fetchDetails.fulfilled })
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { fetchProposalDetails } from "./actions";
import { useSelector } from "react-redux";
import { selectDetailsStatus } from "./selectors";
import { records } from "@politeiagui/core/records";
import { ticketvoteSummaries } from "@politeiagui/ticketvote/summaries";
Expand All @@ -15,15 +14,13 @@ import { piSummaries, proposals } from "../../pi";
import app from "../../app";

function useProposalDetails({ token }) {
const dispatch = useDispatch();
const detailsStatus = useSelector(selectDetailsStatus);
const fullToken = useSelector((state) =>
records.selectFullToken(state, token)
);
const record = useSelector((state) =>
records.selectByToken(state, fullToken)
);
const recordStatus = useSelector(records.selectStatus);
const voteSummary = useSelector((state) =>
ticketvoteSummaries.selectByToken(state, fullToken)
);
Expand Down Expand Up @@ -65,16 +62,6 @@ function useProposalDetails({ token }) {
records.selectByToken(state, rfpLinkedRecordToken)
);

useEffect(() => {
if (
recordStatus !== "loading" &&
recordStatus !== "failed" &&
!record?.detailsFetched
) {
dispatch(fetchProposalDetails({ token }));
}
}, [token, dispatch, recordStatus, record]);

useEffect(() => {
if (record?.files) {
const { name } = decodeProposalMetadataFile(record.files);
Expand Down
Loading