Skip to content
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ changes.

### Added

- Add Proposal discussion context that manages username [Issue 3341](https://github.com/IntersectMBO/govtool/issues/3341)
- Add epochParams and ada holder balance to Proposal Discussion Pillar [Issue 2243](https://github.com/IntersectMBO/govtool/issues/2243)

### Fixed

- Fix scroll on a drawer on smaller resolution
Expand Down
25 changes: 14 additions & 11 deletions govtool/frontend/src/context/contextProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { DataActionsBarProvider } from "./dataActionsBar";
import { FeatureFlagProvider } from "./featureFlag";
import { GovernanceActionProvider } from "./governanceAction";
import { AdaHandleProvider } from "./adaHandle";
import { ProposalDiscussionProvider } from "./proposalDiscussion";

interface Props {
children: React.ReactNode;
Expand All @@ -14,17 +15,19 @@ interface Props {
const ContextProviders = ({ children }: Props) => (
<AppContextProvider>
<GovernanceActionProvider>
<FeatureFlagProvider>
<AdaHandleProvider>
<ModalProvider>
<SnackbarProvider>
<DataActionsBarProvider>
<CardanoProvider>{children}</CardanoProvider>
</DataActionsBarProvider>
</SnackbarProvider>
</ModalProvider>
</AdaHandleProvider>
</FeatureFlagProvider>
<ProposalDiscussionProvider>
<FeatureFlagProvider>
<AdaHandleProvider>
<ModalProvider>
<SnackbarProvider>
<DataActionsBarProvider>
<CardanoProvider>{children}</CardanoProvider>
</DataActionsBarProvider>
</SnackbarProvider>
</ModalProvider>
</AdaHandleProvider>
</FeatureFlagProvider>
</ProposalDiscussionProvider>
</GovernanceActionProvider>
</AppContextProvider>
);
Expand Down
1 change: 1 addition & 0 deletions govtool/frontend/src/context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from "./usersnapContext";
export * from "./wallet";
export * from "./featureFlag";
export * from "./governanceAction";
export * from "./proposalDiscussion";
54 changes: 54 additions & 0 deletions govtool/frontend/src/context/proposalDiscussion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
PropsWithChildren,
useMemo,
createContext,
useContext,
useState,
} from "react";

type ProposalDiscussionContextType = {
username: string;
setUsername: (username: string) => void;
} | null;

const ProposalDiscussionContext =
createContext<ProposalDiscussionContextType>(null);

/**
* Provides proposal discussion context to its children components.
*
* @param children - The child components to render.
*/
const ProposalDiscussionProvider = ({ children }: PropsWithChildren) => {
const [username, setUsername] = useState<string>("");

const value = useMemo(
() => ({
username,
setUsername,
}),
[username],
);

return (
<ProposalDiscussionContext.Provider value={value}>
{children}
</ProposalDiscussionContext.Provider>
);
};

/**
* Custom hook to use the ProposalDiscussionContext.
* @returns The context value.
*/
const useProposalDiscussion = () => {
const context = useContext(ProposalDiscussionContext);
if (!context) {
throw new Error(
"useProposalDiscussion must be used within a ProposalDiscussionProvider",
);
}
return context;
};

export { ProposalDiscussionProvider, useProposalDiscussion };
5 changes: 4 additions & 1 deletion govtool/frontend/src/pages/GovernanceActionOutComes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Box, CircularProgress } from "@mui/material";
import React, { Suspense } from "react";
import { Footer, TopNav } from "@/components/organisms";
import { useCardano } from "@/context";
import { useScreenDimension } from "@/hooks";
import { useScreenDimension, useTranslation } from "@/hooks";
import { Background } from "@/components/atoms";

const GovernanceActionsOutcomes = React.lazy(
Expand All @@ -12,6 +12,8 @@ const GovernanceActionsOutcomes = React.lazy(
export const GovernanceActionOutComesPillar = () => {
const { pagePadding } = useScreenDimension();
const { walletApi, ...context } = useCardano();
const { i18n } = useTranslation();

return (
<Background>
<Box
Expand Down Expand Up @@ -49,6 +51,7 @@ export const GovernanceActionOutComesPillar = () => {
apiUrl={import.meta.env.VITE_OUTCOMES_API_URL}
ipfsGateway={import.meta.env.VITE_IPFS_GATEWAY}
walletAPI={{ ...context, ...walletApi }}
i18n={i18n}
/>
</Suspense>
</Box>
Expand Down
20 changes: 18 additions & 2 deletions govtool/frontend/src/pages/ProposalDiscussion.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,35 @@
import React, { ComponentProps, Suspense } from "react";
import { Box, CircularProgress } from "@mui/material";
import "@intersect.mbo/pdf-ui/style";
import { useCardano, useGovernanceActions } from "@/context";
import {
useAppContext,
useCardano,
useGovernanceActions,
useProposalDiscussion,
} from "@/context";
import { useValidateMutation } from "@/hooks/mutations";
import { useScreenDimension } from "@/hooks/useScreenDimension";
import { Footer, TopNav } from "@/components/organisms";
import { useGetDRepVotingPowerList, useGetVoterInfo } from "@/hooks";
import {
useGetAdaHolderVotingPowerQuery,
useGetDRepVotingPowerList,
useGetVoterInfo,
} from "@/hooks";

const ProposalDiscussion = React.lazy(
() => import("@intersect.mbo/pdf-ui/cjs"),
);

export const ProposalDiscussionPillar = () => {
const { epochParams } = useAppContext();
const { pagePadding } = useScreenDimension();
const { validateMetadata } = useValidateMutation();
const { walletApi, ...context } = useCardano();
const { voter } = useGetVoterInfo();
const { createGovernanceActionJsonLD, createHash } = useGovernanceActions();
const { fetchDRepVotingPowerList } = useGetDRepVotingPowerList();
const { username, setUsername } = useProposalDiscussion();
const { votingPower } = useGetAdaHolderVotingPowerQuery(context.stakeKey);

return (
<Box
Expand Down Expand Up @@ -67,6 +79,10 @@ export const ProposalDiscussionPillar = () => {
>["validateMetadata"]
}
fetchDRepVotingPowerList={fetchDRepVotingPowerList}
username={username}
setUsername={setUsername}
epochParams={epochParams}
votingPower={votingPower}
/>
</Suspense>
</Box>
Expand Down
65 changes: 36 additions & 29 deletions govtool/frontend/src/types/@intersect.mbo.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,46 @@ enum MetadataValidationStatus {
INVALID_HASH = "INVALID_HASH",
INCORRECT_FORMAT = "INCORRECT_FORMAT",
}
declare module "@intersect.mbo/pdf-ui/cjs" {
import { EpochParams } from "@/models";

type ProposalDiscussionProps = {
pdfApiUrl: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
walletAPI: any;
pathname: string;
locale?: string;
validateMetadata: ({
url,
hash,
standard,
}: {
url: string;
hash: string;
standard: "CIP108";
}) => Promise<
type ProposalDiscussionProps = {
pdfApiUrl: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| { status?: MetadataValidationStatus; metadata?: any; valid: boolean }
| undefined
>;
fetchDRepVotingPowerList: (
identifiers: string[],
) => Promise<DRepVotingPowerListResponse>;
};
walletAPI: any;
pathname: string;
locale?: string;
validateMetadata: ({
url,
hash,
standard,
}: {
url: string;
hash: string;
standard: "CIP108";
}) => Promise<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| { status?: MetadataValidationStatus; metadata?: any; valid: boolean }
| undefined
>;
fetchDRepVotingPowerList: (
identifiers: string[],
) => Promise<DRepVotingPowerListResponse>;
epochParams?: EpochParams;
votingPower: number;
username: string;
setUsername: (username: string) => void;
};

type GovernanceActionsOutcomesProps = {
apiUrl?: string;
ipfsGateway?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
walletAPI?: any;
};
type GovernanceActionsOutcomesProps = {
apiUrl?: string;
ipfsGateway?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
walletAPI?: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
i18n?: any;
};

declare module "@intersect.mbo/pdf-ui/cjs" {
export default function ProposalDiscussion(
props: ProposalDiscussionProps,
): JSX.Element;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,10 @@ const kuberService = {
},

multipleDRepRegistration: (metadataAndWallets: WalletAndAnchorType[]) => {
const kuber = new Kuber(faucetWallet.address, faucetWallet.payment.private);
const kuber = new Kuber(
proposalFaucetWallet.address,
proposalFaucetWallet.payment.private
);
const req = {
certificates: metadataAndWallets.map((metadataAndWallet) =>
Kuber.generateCert(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ test.describe("Budget proposal logged in state", () => {
});

test("11I. Should comments on any proposal", async ({}) => {
const comment = faker.lorem.paragraph(2);
const comment = faker.lorem.paragraph(1);
await budgetDiscussionDetailsPage.addComment(comment);
await expect(
budgetDiscussionDetailsPage.currentPage
Expand All @@ -59,7 +59,7 @@ test.describe("Budget proposal logged in state", () => {
});

test("11J. Should reply to any comments", async ({}) => {
const randComment = faker.lorem.paragraph(2);
const randComment = faker.lorem.paragraph(1);
const randReply = faker.lorem.words(5);

await budgetDiscussionDetailsPage.addComment(randComment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ test("11E. Should view comments with count indications on a budget proposal", as
page,
}) => {
let responsePromise = page.waitForResponse((response) =>
response.url().includes(`/api/comments`)
response.url().includes(`/api/bds/`)
);

const budgetDiscussionPage = new BudgetDiscussionPage(page);
Expand All @@ -197,13 +197,23 @@ test("11E. Should view comments with count indications on a budget proposal", as
await budgetDiscussionPage.viewFirstProposal();
const response = await responsePromise;

const comments: CommentResponse[] = (await response.json()).data;
const proposalResponse = await response.json();

await responsePromise;
const actualTotalComments =
await budgetDiscussionDetailsPage.totalComments.textContent();
const expectedTotalComments =
proposalResponse.data.attributes.prop_comments_number.toString();
const isEqual = actualTotalComments === expectedTotalComments;

await expect(budgetDiscussionDetailsPage.totalComments).toHaveText(
comments.length.toString()
);
const currentPageUrl = budgetDiscussionDetailsPage.currentPage.url();

const proposalId = extractProposalIdFromUrl(currentPageUrl);

await expect(
budgetDiscussionDetailsPage.totalComments,
!isEqual &&
`Total comments do not match in ${environments.frontendUrl}/budget_discussion/${proposalId}`
).toHaveText(expectedTotalComments);
});

test.describe("Restricted access to interact budget proposal", () => {
Expand Down