delegate(dRepData.drepId)}
- size="extraLarge"
- sx={{ width: "100%", maxWidth: screenWidth < 1024 ? "100%" : 286 }}
- variant="contained"
- >
- {t("delegate")}
-
- )}
- {!isConnected && ["Active", "Inactive"].includes(status) && (
-
- )}
+ {!isValidating &&
+ isConnected &&
+ ["Active", "Inactive"].includes(status) &&
+ !isMyDrep && (
+
+ )}
+ {!isValidating &&
+ !isConnected &&
+ ["Active", "Inactive"].includes(status) && (
+
+ )}
{/* BUTTONS END */}
{/* CIP-119 DATA */}
- {!metadataStatus && (
+ {!metadataStatus.current && (
<>
{
if (!children && !text) return null;
const dataTestIdInfoItemCategoryPrefix = "info-item";
@@ -319,30 +359,49 @@ const DRepDetailsInfoItem = ({
},
}}
>
-
-
+ ) : (
+
- {label}
-
-
+
+ {label}
+
+
+ )}
- {text && (
-
- {text}
-
+ {isValidating ? (
+
+ ) : (
+ <>
+ {text && (
+
+ {text}
+
+ )}
+ {children}
+ >
)}
- {children}
);
diff --git a/govtool/frontend/src/components/organisms/DRepDetailsCardHeader.tsx b/govtool/frontend/src/components/organisms/DRepDetailsCardHeader.tsx
index 0ac2edc94..992ef2afc 100644
--- a/govtool/frontend/src/components/organisms/DRepDetailsCardHeader.tsx
+++ b/govtool/frontend/src/components/organisms/DRepDetailsCardHeader.tsx
@@ -11,18 +11,22 @@ type DRepDetailsProps = {
dRepData: DRepData;
isMe?: boolean;
isMyDrep?: boolean;
+ isValidating?: boolean;
+ metadataStatus?: MetadataValidationStatus;
};
export const DRepDetailsCardHeader = ({
dRepData,
isMe,
isMyDrep,
+ isValidating,
+ metadataStatus,
}: DRepDetailsProps) => {
const { t } = useTranslation();
const navigate = useNavigate();
const { screenWidth } = useScreenDimension();
- const { givenName, metadataStatus, image } = dRepData;
+ const { givenName, image } = dRepData;
const navigateToEditDRep = () => {
navigate(PATHS.editDrepMetadata, {
@@ -84,6 +88,7 @@ export const DRepDetailsCardHeader = ({
image={image}
isDataMissing={metadataStatus}
titleStyle={{ wordBreak: "break-word", whiteSpace: "wrap" }}
+ isValidating={isValidating}
/>
);
diff --git a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx
index 589a5d8df..f78b5190a 100644
--- a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx
+++ b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx
@@ -1,11 +1,11 @@
-import { useCallback } from "react";
+import { useCallback, useEffect, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { Trans } from "react-i18next";
import { IMAGES, PATHS } from "@consts";
import { PendingTransaction } from "@context";
import { useGetDRepDetailsQuery, useTranslation } from "@hooks";
-import { CurrentDelegation, VoterInfo } from "@models";
+import { CurrentDelegation, MetadataStandard, VoterInfo } from "@models";
import {
DashboardActionCard,
DashboardActionCardProps,
@@ -21,6 +21,7 @@ import {
AutomatedVotingOptionDelegationId,
} from "@/types/automatedVotingOptions";
import { LINKS } from "@/consts/links";
+import { useValidateMutation } from "@/hooks/mutations";
type DelegateDashboardCardProps = {
currentDelegation: CurrentDelegation;
@@ -43,6 +44,22 @@ export const DelegateDashboardCard = ({
delegateTx?.resourceId ?? currentDelegation?.dRepHash,
);
+ const metadataStatus = useRef();
+ const { validateMetadata } = useValidateMutation();
+
+ useEffect(() => {
+ const validate = async () => {
+ const { status } = await validateMetadata({
+ standard: MetadataStandard.CIP108,
+ url: myDRepDelegationData?.url ?? "",
+ hash: myDRepDelegationData?.metadataHash ?? "",
+ });
+
+ metadataStatus.current = status;
+ };
+ validate();
+ }, []);
+
const learnMoreButton = {
children: t("learnMore"),
dataTestId: "delegate-learn-more-button",
@@ -117,7 +134,7 @@ export const DelegateDashboardCard = ({
navigate(
PATHS.dashboardDRepDirectoryDRep.replace(
":dRepId",
- displayedDelegationId || "",
+ displayedDelegationId ?? "",
),
{ state: { enteredFromWithinApp: true } },
),
@@ -153,10 +170,8 @@ export const DelegateDashboardCard = ({
drepName={
isLoading
? "Loading..."
- : myDRepDelegationData?.metadataStatus
- ? getMetadataDataMissingStatusTranslation(
- myDRepDelegationData.metadataStatus,
- )
+ : metadataStatus.current
+ ? getMetadataDataMissingStatusTranslation(metadataStatus.current)
: myDRepDelegationData?.givenName ?? ""
}
dRepId={displayedDelegationId}
diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx
index d5ffa61c2..5db1bd7cc 100644
--- a/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx
+++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx
@@ -1,4 +1,4 @@
-import { useEffect } from "react";
+import { useEffect, useRef, useState } from "react";
import {
useNavigate,
useLocation,
@@ -19,7 +19,8 @@ import {
import { getFullGovActionId, getShortenedGovActionId } from "@utils";
import { GovernanceActionDetailsCard } from "@organisms";
import { Breadcrumbs } from "@molecules";
-import { ProposalData, ProposalVote } from "@/models";
+import { MetadataStandard, ProposalData, ProposalVote } from "@/models";
+import { useValidateMutation } from "@/hooks/mutations";
type DashboardGovernanceActionDetailsState = {
proposal?: ProposalData;
@@ -51,6 +52,26 @@ export const DashboardGovernanceActionDetails = () => {
const proposal = (data ?? state)?.proposal;
const vote = (data ?? state)?.vote;
+ const [isValidating, setIsValidating] = useState(false);
+ const metadataStatus = useRef();
+ const { validateMetadata } = useValidateMutation();
+
+ useEffect(() => {
+ const validate = async () => {
+ setIsValidating(true);
+
+ const { status } = await validateMetadata({
+ standard: MetadataStandard.CIP108,
+ url: proposal?.url ?? "",
+ hash: proposal?.metadataHash ?? "",
+ });
+
+ metadataStatus.current = status;
+ setIsValidating(false);
+ };
+ validate();
+ }, []);
+
useEffect(() => {
const isProposalNotFound =
(error as AxiosError)?.response?.data ===
@@ -75,7 +96,7 @@ export const DashboardGovernanceActionDetails = () => {
elementOne={t("govActions.title")}
elementOnePath={PATHS.dashboardGovernanceActions}
elementTwo={proposal?.title ?? ""}
- isDataMissing={proposal?.metadataStatus ?? null}
+ isDataMissing={metadataStatus?.current ?? null}
/>
{
}}
onClick={() =>
navigate(
- state && state.openedFromCategoryPage
+ state?.openedFromCategoryPage
? generatePath(PATHS.dashboardGovernanceActionsCategory, {
category: state?.proposal?.type,
})
@@ -127,12 +148,13 @@ export const DashboardGovernanceActionDetails = () => {
isVoter={
voter?.isRegisteredAsDRep || voter?.isRegisteredAsSoleVoter
}
- isDataMissing={proposal.metadataStatus ?? null}
+ isDataMissing={metadataStatus?.current}
isInProgress={
pendingTransaction.vote?.resourceId ===
fullProposalId?.replace("#", "")
}
isDashboard
+ isValidating={isValidating}
/>
) : (
diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActionsVotedOn.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActionsVotedOn.tsx
index 552f63061..465be1aff 100644
--- a/govtool/frontend/src/components/organisms/DashboardGovernanceActionsVotedOn.tsx
+++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActionsVotedOn.tsx
@@ -3,8 +3,7 @@ import { Box, Typography, CircularProgress } from "@mui/material";
import { useCardano } from "@context";
import { useScreenDimension, useTranslation } from "@hooks";
-import { GovernanceVotedOnCard } from "@molecules";
-import { Slider } from "@organisms";
+import { Slider, ValidatedGovernanceVotedOnCard } from "@organisms";
import { getFullGovActionId, getProposalTypeLabel } from "@utils";
import { VotedProposal } from "@/models";
@@ -74,7 +73,7 @@ export const DashboardGovernanceActionsVotedOn = ({
key={`${action?.proposal.id}${action.vote?.vote}`}
style={{ overflow: "visible", width: "auto" }}
>
- {
@@ -63,6 +65,7 @@ export const GovernanceActionDetailsCard = ({
isOneColumn={isOneColumn}
isSubmitted={isVoteSubmitted}
proposal={proposal}
+ isValidating={isValidating}
/>
(
type GovernanceActionDetailsCardDataProps = {
isDashboard?: boolean;
- isDataMissing: MetadataValidationStatus | null;
+ isDataMissing?: MetadataValidationStatus;
isInProgress?: boolean;
isOneColumn: boolean;
isSubmitted?: boolean;
+ isValidating?: boolean;
proposal: ProposalData;
};
@@ -72,6 +73,7 @@ export const GovernanceActionDetailsCardData = ({
isInProgress,
isOneColumn,
isSubmitted,
+ isValidating,
proposal: {
abstract,
createdDate,
@@ -243,11 +245,13 @@ export const GovernanceActionDetailsCardData = ({
>
@@ -256,25 +260,31 @@ export const GovernanceActionDetailsCardData = ({
text={label}
textVariant="pill"
dataTestId={`${getProposalTypeNoEmptySpaces(label)}-type`}
+ isValidating={isValidating}
/>
- {isDataMissing && (
-
- )}
+ {isDataMissing &&
+ (isValidating ? (
+
+ ) : (
+
+ ))}
1600 ? "longText" : "oneLine"}
+ isValidating={isValidating}
/>
1600 ? "longText" : "oneLine"}
isSemiTransparent
+ isValidating={isValidating}
/>
{tabs?.length === 1 ? (
@@ -322,7 +333,8 @@ export const GovernanceActionDetailsCardData = ({
))}
>
)}
- {details &&
+ {!isValidating &&
+ details &&
type === GovernanceActionType.TreasuryWithdrawals &&
Array.isArray(details) &&
details.map((withdrawal) => (
@@ -333,7 +345,7 @@ export const GovernanceActionDetailsCardData = ({
/>
))}
{/* NewConstitution metadata hash and url is visible in details tab */}
- {type !== GovernanceActionType.NewConstitution && (
+ {!isValidating && type !== GovernanceActionType.NewConstitution && (
<>
1600 ? "longText" : "oneLine"}
dataTestId="anchor-url"
isLinkButton
+ isValidating={isValidating}
/>
1600 ? "longText" : "oneLine"}
dataTestId="anchor-hash"
isCopyButton
+ isValidating={isValidating}
/>
>
)}
@@ -361,7 +375,10 @@ const ReasoningTabContent = ({
abstract,
motivation,
rationale,
-}: Pick) => {
+ isValidating,
+}: Pick & {
+ isValidating?: boolean;
+}) => {
const { t } = useTranslation();
return (
@@ -372,6 +389,7 @@ const ReasoningTabContent = ({
textVariant="longText"
dataTestId="abstract"
isMarkdown
+ isValidating={isValidating}
/>
>
);
@@ -394,7 +414,9 @@ const ReasoningTabContent = ({
const HardforkDetailsTabContent = ({
details,
prevGovActionId,
-}: Pick & { prevGovActionId: string | null }) => {
+}: Pick & {
+ prevGovActionId: string | null;
+}) => {
const { epochParams } = useAppContext();
const { t } = useTranslation();
diff --git a/govtool/frontend/src/components/organisms/ValidatedGovernanceActionCard.tsx b/govtool/frontend/src/components/organisms/ValidatedGovernanceActionCard.tsx
new file mode 100644
index 000000000..df6a8991a
--- /dev/null
+++ b/govtool/frontend/src/components/organisms/ValidatedGovernanceActionCard.tsx
@@ -0,0 +1,54 @@
+import { useState, useRef, useEffect } from "react";
+
+import { useValidateMutation } from "@/hooks/mutations";
+import { MetadataStandard, ProposalData } from "@/models";
+import { GovernanceActionCard } from "../molecules";
+
+type ActionTypeProps = Omit<
+ ProposalData,
+ | "yesVotes"
+ | "noVotes"
+ | "abstainVotes"
+ | "id"
+ | "details"
+ | "rationale"
+ | "motivation"
+> & {
+ onClick?: () => void;
+ inProgress?: boolean;
+};
+export const ValidatedGovernanceActionCard = ({
+ url,
+ metadataHash,
+ ...props
+}: ActionTypeProps) => {
+ const [isValidating, setIsValidating] = useState(false);
+ const metadataStatus = useRef();
+ const { validateMetadata } = useValidateMutation();
+
+ useEffect(() => {
+ const validate = async () => {
+ setIsValidating(true);
+
+ const { status } = await validateMetadata({
+ standard: MetadataStandard.CIP108,
+ url: url ?? "",
+ hash: metadataHash ?? "",
+ });
+
+ metadataStatus.current = status;
+ setIsValidating(false);
+ };
+ validate();
+ }, []);
+
+ return (
+
+ );
+};
diff --git a/govtool/frontend/src/components/organisms/ValidatedGovernanceVotedOnCard.tsx b/govtool/frontend/src/components/organisms/ValidatedGovernanceVotedOnCard.tsx
new file mode 100644
index 000000000..ec551d4c7
--- /dev/null
+++ b/govtool/frontend/src/components/organisms/ValidatedGovernanceVotedOnCard.tsx
@@ -0,0 +1,43 @@
+import { useState, useRef, useEffect } from "react";
+
+import { useValidateMutation } from "@/hooks/mutations";
+import { MetadataStandard, VotedProposal } from "@/models";
+import { GovernanceVotedOnCard } from "../molecules";
+
+type Props = {
+ votedProposal: VotedProposal;
+ inProgress?: boolean;
+};
+export const ValidatedGovernanceVotedOnCard = ({
+ votedProposal,
+ inProgress,
+}: Props) => {
+ const [isValidating, setIsValidating] = useState(false);
+ const metadataStatus = useRef();
+ const { validateMetadata } = useValidateMutation();
+
+ useEffect(() => {
+ const validate = async () => {
+ setIsValidating(true);
+
+ const { status } = await validateMetadata({
+ standard: MetadataStandard.CIP108,
+ url: votedProposal.proposal.url,
+ hash: votedProposal.proposal.metadataHash,
+ });
+
+ metadataStatus.current = status;
+ setIsValidating(false);
+ };
+ validate();
+ }, []);
+
+ return (
+
+ );
+};
diff --git a/govtool/frontend/src/components/organisms/index.ts b/govtool/frontend/src/components/organisms/index.ts
index 590f29691..f1c136904 100644
--- a/govtool/frontend/src/components/organisms/index.ts
+++ b/govtool/frontend/src/components/organisms/index.ts
@@ -25,5 +25,7 @@ export * from "./RegisterAsDRepSteps";
export * from "./Slider";
export * from "./TopNav";
export * from "./UncontrolledImageInput";
+export * from "./ValidatedGovernanceActionCard";
+export * from "./ValidatedGovernanceVotedOnCard";
export * from "./VoteContext";
export * from "./WrongRouteInfo";
diff --git a/govtool/frontend/src/context/governanceAction.test.tsx b/govtool/frontend/src/context/governanceAction.test.tsx
index 3eb4e06b4..0ecfd2cb2 100644
--- a/govtool/frontend/src/context/governanceAction.test.tsx
+++ b/govtool/frontend/src/context/governanceAction.test.tsx
@@ -80,7 +80,7 @@ describe("GovernanceActionProvider", () => {
const hash = await createHash(jsonld!);
expect(hash).toBeDefined();
expect(hash).toBe(
- "816b63124f5c5d5bdfc016ad0aea238baf374fecbdadd389eab2dab94bc2383c",
+ "9f7b2f83113e003d36231bd815cafbcc677c3a9513281d751a241720893cc877",
);
};
test();
diff --git a/govtool/frontend/src/models/api.ts b/govtool/frontend/src/models/api.ts
index f298b41f0..bc374ccad 100644
--- a/govtool/frontend/src/models/api.ts
+++ b/govtool/frontend/src/models/api.ts
@@ -1,4 +1,3 @@
-import { MetadataValidationStatus } from "@models";
import { GovernanceActionType } from "@/types/governanceAction";
export type EpochParams = {
@@ -176,8 +175,6 @@ export type DRepData = DrepDataDTO & {
qualifications: string | null;
references: Reference[];
doNotList: boolean;
- metadataStatus: MetadataValidationStatus | null;
- metadataValid: boolean;
imageUrl: string | null;
// either base64 for IPFS image or URL for regular image
image: string | null;
@@ -210,7 +207,7 @@ export type SubmittedVotesData = {
protocolParams: EpochParams | null;
};
-export type ProposalDataDTO = {
+export type ProposalData = {
createdDate: string;
createdEpochNo: number;
details?: ActionDetailsType;
@@ -232,21 +229,11 @@ export type ProposalDataDTO = {
protocolParams: EpochParams | null;
} & SubmittedVotesData;
-export type ProposalData = ProposalDataDTO & {
- metadataStatus: MetadataValidationStatus | null;
- metadataValid: boolean;
-};
-
export type NewConstitutionAnchor = {
dataHash: string;
url: string;
};
-export type VotedProposalDTO = {
- vote: ProposalVote | null;
- proposal: ProposalDataDTO;
-};
-
export type VotedProposal = {
vote: ProposalVote | null;
proposal: ProposalData;
diff --git a/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx b/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx
index 9084bf070..fb366fc67 100644
--- a/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx
+++ b/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx
@@ -8,7 +8,6 @@ import { useCardano, useDataActionsBar } from "@context";
import {
DataActionsBar,
EmptyStateGovernanceActionsCategory,
- GovernanceActionCard,
} from "@molecules";
import {
useFetchNextPageDetector,
@@ -23,6 +22,7 @@ import {
getProposalTypeLabel,
removeDuplicatedProposals,
} from "@utils";
+import { ValidatedGovernanceActionCard } from "@/components/organisms";
export const DashboardGovernanceActionsCategory = () => {
const { category } = useParams();
@@ -133,7 +133,7 @@ export const DashboardGovernanceActionsCategory = () => {
>
{mappedData.map((item) => (
- {
);
const proposal = (data ?? state)?.proposal;
+ const metadataStatus = useRef();
+ const { validateMetadata } = useValidateMutation();
+
+ useEffect(() => {
+ const validate = async () => {
+ const { status } = await validateMetadata({
+ standard: MetadataStandard.CIP108,
+ url: proposal?.url ?? "",
+ hash: proposal?.metadataHash ?? "",
+ });
+
+ metadataStatus.current = status;
+ };
+ validate();
+ }, [proposal?.url, proposal?.metadataHash]);
+
useEffect(() => {
const isProposalNotFound =
(error as AxiosError)?.response?.data ===
@@ -105,7 +122,7 @@ export const GovernanceActionDetails = () => {
elementOne={t("govActions.title")}
elementOnePath={PATHS.governanceActions}
elementTwo={proposal?.title ?? ""}
- isDataMissing={proposal?.metadataStatus ?? null}
+ isDataMissing={metadataStatus?.current ?? null}
/>
{
}}
onClick={() =>
navigate(
- state && state.openedFromCategoryPage
+ state?.openedFromCategoryPage
? generatePath(PATHS.governanceActionsCategory, {
category: state?.proposal?.type,
})
@@ -144,7 +161,7 @@ export const GovernanceActionDetails = () => {
) : proposal ? (
diff --git a/govtool/frontend/src/pages/GovernanceActionsCategory.tsx b/govtool/frontend/src/pages/GovernanceActionsCategory.tsx
index 51d982f79..7eda23034 100644
--- a/govtool/frontend/src/pages/GovernanceActionsCategory.tsx
+++ b/govtool/frontend/src/pages/GovernanceActionsCategory.tsx
@@ -8,9 +8,8 @@ import { useCardano, useDataActionsBar } from "@context";
import {
DataActionsBar,
EmptyStateGovernanceActionsCategory,
- GovernanceActionCard,
} from "@molecules";
-import { Footer, TopNav } from "@organisms";
+import { Footer, TopNav, ValidatedGovernanceActionCard } from "@organisms";
import {
useGetProposalsInfiniteQuery,
useFetchNextPageDetector,
@@ -139,7 +138,7 @@ export const GovernanceActionsCategory = () => {
>
{mappedData.map((item) => (
- {
saveScrollPosition();
diff --git a/govtool/frontend/src/services/requests/getDRepVotes.ts b/govtool/frontend/src/services/requests/getDRepVotes.ts
index 1b2bbf1e6..008e720bf 100644
--- a/govtool/frontend/src/services/requests/getDRepVotes.ts
+++ b/govtool/frontend/src/services/requests/getDRepVotes.ts
@@ -1,6 +1,5 @@
-import { VotedProposal, VotedProposalDTO } from "@models";
+import { VotedProposal } from "@models";
import { API } from "../API";
-import { mapDtoToProposal } from "@/utils";
type GetDRepVotesParams = {
type?: string[];
@@ -17,14 +16,7 @@ export const getDRepVotes = async ({
}): Promise => {
const urlBase = `/drep/getVotes/${dRepID}`;
- const { data } = await API.get(urlBase, { params });
+ const { data } = await API.get(urlBase, { params });
- const validatedData = await Promise.all(
- data.map(async (votedProposal) => ({
- ...votedProposal,
- proposal: await mapDtoToProposal(votedProposal.proposal),
- }))
- );
-
- return validatedData;
+ return data;
};
diff --git a/govtool/frontend/src/services/requests/getProposal.ts b/govtool/frontend/src/services/requests/getProposal.ts
index c82aa6199..65744d6d0 100644
--- a/govtool/frontend/src/services/requests/getProposal.ts
+++ b/govtool/frontend/src/services/requests/getProposal.ts
@@ -1,5 +1,5 @@
-import { VotedProposal, VotedProposalDTO } from "@/models";
-import { decodeCIP129Identifier, mapDtoToProposal } from "@/utils";
+import { VotedProposal } from "@/models";
+import { decodeCIP129Identifier } from "@/utils";
import { API } from "../API";
@@ -15,12 +15,9 @@ export const getProposal = async (
const encodedHash = encodeURIComponent(proposalId);
- const { data } = await API.get(
+ const { data } = await API.get(
`/proposal/get/${encodedHash}?drepId=${drepId}`,
);
- return {
- ...data,
- proposal: await mapDtoToProposal(data.proposal),
- };
+ return data;
};
diff --git a/govtool/frontend/src/services/requests/getProposals.ts b/govtool/frontend/src/services/requests/getProposals.ts
index 9d09751be..765fd211c 100644
--- a/govtool/frontend/src/services/requests/getProposals.ts
+++ b/govtool/frontend/src/services/requests/getProposals.ts
@@ -1,11 +1,7 @@
-import { Infinite, ProposalData, ProposalDataDTO } from "@models";
+import { Infinite, ProposalData } from "@models";
import { API } from "../API";
-import {
- decodeCIP129Identifier,
- getFullGovActionId,
- mapDtoToProposal,
-} from "@/utils";
+import { decodeCIP129Identifier, getFullGovActionId } from "@/utils";
export type GetProposalsArguments = {
dRepID?: string;
@@ -34,7 +30,7 @@ export const getProposals = async ({
return rawSearchPhrase;
})();
- const response = await API.get>("/proposal/list", {
+ const response = await API.get>("/proposal/list", {
params: {
page,
pageSize,
@@ -47,14 +43,5 @@ export const getProposals = async ({
},
});
- const validatedResponse = {
- ...response.data,
- elements: await Promise.all(
- response.data.elements.map((proposalDTO) =>
- mapDtoToProposal(proposalDTO),
- ),
- ),
- };
-
- return validatedResponse;
+ return response.data;
};
diff --git a/govtool/frontend/src/stories/DRepDetailsCard.stories.ts b/govtool/frontend/src/stories/DRepDetailsCard.stories.ts
index c91b396d3..17754f8c9 100644
--- a/govtool/frontend/src/stories/DRepDetailsCard.stories.ts
+++ b/govtool/frontend/src/stories/DRepDetailsCard.stories.ts
@@ -1,6 +1,6 @@
import { ComponentProps } from "react";
import type { Meta, StoryObj } from "@storybook/react";
-import { DRepData, DRepStatus, MetadataValidationStatus } from "@models";
+import { DRepData, DRepStatus } from "@models";
import { DRepDetailsCard } from "@organisms";
const meta = {
@@ -22,33 +22,40 @@ const meta = {
votingPower: 1000000,
paymentAddress: "examplePaymentAddress",
givenName: "John Smith",
- objectives: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ornare pellentesque hendrerit. Pellentesque et placerat ex. Curabitur vitae pharetra ligula. Nullam euismod, odio sit amet suscipit facilisis, neque erat ultricies velit, sed rutrum neque nisi ac dui. Donec lobortis metus pulvinar varius gravida. Duis blandit, tortor non placerat commodo, metus lorem aliquam augue, eget ultricies nunc massa eu arcu. Etiam pellentesque urna nisl, facilisis placerat elit congue quis. Nulla quis dolor ac eros ullamcorper convallis ac ut enim. Proin faucibus urna at mi blandit, ut gravida sapien lacinia. Sed pretium, magna non tempor sollicitudin, tellus odio efficitur enim, ut feugiat nisi ligula non dolor. Fusce volutpat condimentum arcu, eu tempus neque convallis non. Suspendisse mattis sit amet libero et fringilla. Suspendisse eget erat eu nisl feugiat varius. Interdum et malesuada fames ac ante ipsum primis in faucibus. Curabitur vehicula eleifend lectus, vel eleifend felis vestibulum.",
- motivations: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras semper tortor ullamcorper volutpat vehicula. Duis varius orci a elit luctus, in fringilla nisl fringilla. Fusce pellentesque convallis dapibus. In hac habitasse platea dictumst. Nunc efficitur ipsum at ipsum blandit, ac eleifend purus pulvinar. Pellentesque orci quam, interdum eget massa id, sollicitudin lacinia turpis. Nullam lectus quam, congue commodo sollicitudin in, pretium sit amet metus. Integer pretium, odio eu dictum posuere.",
- qualifications: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc porta iaculis sodales. Praesent non nisi fermentum, porta sem in, porta arcu. In dignissim pulvinar est eu dignissim. Duis vitae vehicula dui. Praesent posuere egestas lacus, at pulvinar elit tempus ut. Etiam vulputate, lorem in accumsan.",
- references: [{
- "@type": "Link",
- label: "Link Reference",
- uri: "https://example.com/",
- }, {
- "@type": "Link",
- label: "Another Link Reference",
- uri: "https://example.com/",
- }, {
- "@type": "Identity",
- label: "Identity Reference",
- uri: "https://example.com/",
- }, {
- "@type": "GovernanceMetadata",
- label: "GovernanceMetadata Reference",
- uri: "https://example.com/",
- }, {
- "@type": "Other",
- label: "Other Reference",
- uri: "https://example.com/",
- }],
+ objectives:
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ornare pellentesque hendrerit. Pellentesque et placerat ex. Curabitur vitae pharetra ligula. Nullam euismod, odio sit amet suscipit facilisis, neque erat ultricies velit, sed rutrum neque nisi ac dui. Donec lobortis metus pulvinar varius gravida. Duis blandit, tortor non placerat commodo, metus lorem aliquam augue, eget ultricies nunc massa eu arcu. Etiam pellentesque urna nisl, facilisis placerat elit congue quis. Nulla quis dolor ac eros ullamcorper convallis ac ut enim. Proin faucibus urna at mi blandit, ut gravida sapien lacinia. Sed pretium, magna non tempor sollicitudin, tellus odio efficitur enim, ut feugiat nisi ligula non dolor. Fusce volutpat condimentum arcu, eu tempus neque convallis non. Suspendisse mattis sit amet libero et fringilla. Suspendisse eget erat eu nisl feugiat varius. Interdum et malesuada fames ac ante ipsum primis in faucibus. Curabitur vehicula eleifend lectus, vel eleifend felis vestibulum.",
+ motivations:
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras semper tortor ullamcorper volutpat vehicula. Duis varius orci a elit luctus, in fringilla nisl fringilla. Fusce pellentesque convallis dapibus. In hac habitasse platea dictumst. Nunc efficitur ipsum at ipsum blandit, ac eleifend purus pulvinar. Pellentesque orci quam, interdum eget massa id, sollicitudin lacinia turpis. Nullam lectus quam, congue commodo sollicitudin in, pretium sit amet metus. Integer pretium, odio eu dictum posuere.",
+ qualifications:
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc porta iaculis sodales. Praesent non nisi fermentum, porta sem in, porta arcu. In dignissim pulvinar est eu dignissim. Duis vitae vehicula dui. Praesent posuere egestas lacus, at pulvinar elit tempus ut. Etiam vulputate, lorem in accumsan.",
+ references: [
+ {
+ "@type": "Link",
+ label: "Link Reference",
+ uri: "https://example.com/",
+ },
+ {
+ "@type": "Link",
+ label: "Another Link Reference",
+ uri: "https://example.com/",
+ },
+ {
+ "@type": "Identity",
+ label: "Identity Reference",
+ uri: "https://example.com/",
+ },
+ {
+ "@type": "GovernanceMetadata",
+ label: "GovernanceMetadata Reference",
+ uri: "https://example.com/",
+ },
+ {
+ "@type": "Other",
+ label: "Other Reference",
+ uri: "https://example.com/",
+ },
+ ],
doNotList: false,
- metadataStatus: null,
- metadataValid: true,
} as DRepData,
},
tags: ["autodocs"],
@@ -93,12 +100,3 @@ export const UserNotConnected: Story = {
isConnected: false,
},
};
-
-export const InvalidData: Story = {
- args: {
- dRepData: {
- ...meta.args.dRepData,
- metadataStatus: MetadataValidationStatus.INCORRECT_FORMAT,
- },
- },
-};
diff --git a/govtool/frontend/src/stories/GovernanceAction.stories.ts b/govtool/frontend/src/stories/GovernanceAction.stories.ts
index 3119c83c5..085e69df4 100644
--- a/govtool/frontend/src/stories/GovernanceAction.stories.ts
+++ b/govtool/frontend/src/stories/GovernanceAction.stories.ts
@@ -1,4 +1,3 @@
-import { MetadataValidationStatus } from "@models";
import {
expect,
screen,
@@ -16,6 +15,7 @@ import {
} from "@utils";
import { GovernanceActionCard } from "@/components/molecules";
import { GovernanceActionType } from "@/types/governanceAction";
+import { MetadataValidationStatus } from "@/models";
const meta = {
title: "Example/GovernanceActionCard",
@@ -30,8 +30,8 @@ export default meta;
type Story = StoryObj;
-const commonArgs = {
- about: "About this Governance Action",
+const commonArgs: Story["args"] = {
+ abstract: "About this Governance Action",
createdDate: "1970-01-01T00:00:00Z",
createdEpochNo: 302,
expiryDate: "1970-02-01T00:00:00Z",
@@ -42,8 +42,6 @@ const commonArgs = {
title: "Example title",
txHash: "sad78afdsf7jasd98d",
type: GovernanceActionType.InfoAction,
- metadataValid: true,
- metadataStatus: null,
dRepYesVotes: 1,
dRepNoVotes: 0,
dRepAbstainVotes: 0,
@@ -56,6 +54,8 @@ const commonArgs = {
protocolParams: null,
prevGovActionIndex: null,
prevGovActionTxHash: null,
+ metadataHash: "exampleMetadataHash",
+ url: "https://exampleMetadataUrl.com",
};
const cip129GovActionId = encodeCIP129Identifier({
@@ -102,10 +102,7 @@ export const GovernanceActionCardComponent: Story = {
};
export const GovernanceActionCardIsLoading: Story = {
- args: {
- ...commonArgs,
- inProgress: true,
- },
+ args: { ...commonArgs, inProgress: true },
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(canvas.getByText(/in progress/i)).toBeVisible();
@@ -116,7 +113,6 @@ export const GovernanceActionCardDataMissing: Story = {
args: {
...commonArgs,
metadataStatus: MetadataValidationStatus.URL_NOT_FOUND,
- metadataValid: false,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
@@ -135,8 +131,7 @@ export const GovernanceActionCardDataMissing: Story = {
export const GovernanceActionCardIncorectFormat: Story = {
args: {
...commonArgs,
- metadataStatus: MetadataValidationStatus.INVALID_JSONLD,
- metadataValid: false,
+ metadataStatus: MetadataValidationStatus.INCORRECT_FORMAT,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
@@ -158,7 +153,6 @@ export const GovernanceActionCardNotVerifiable: Story = {
args: {
...commonArgs,
metadataStatus: MetadataValidationStatus.INVALID_HASH,
- metadataValid: false,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
diff --git a/govtool/frontend/src/stories/GovernanceActionDetailsCard.stories.ts b/govtool/frontend/src/stories/GovernanceActionDetailsCard.stories.ts
index 9d62c35f9..67e6001f7 100644
--- a/govtool/frontend/src/stories/GovernanceActionDetailsCard.stories.ts
+++ b/govtool/frontend/src/stories/GovernanceActionDetailsCard.stories.ts
@@ -57,8 +57,6 @@ const commonArgs = {
prevGovActionIndex: null,
prevGovActionTxHash: null,
metadataHash: "exampleMetadataHash",
- metadataStatus: null,
- metadataValid: true,
references: [
{
"@type": "Reference",
@@ -118,6 +116,7 @@ async function assertGovActionDetails(
export const GovernanceActionDetailsCardComponent: Story = {
args: {
...commonArgs,
+ isDataMissing: undefined,
proposal: {
...commonArgs.proposal,
abstract: "Example about section",
@@ -159,6 +158,7 @@ export const GovernanceActionDetailsDrep: Story = {
...commonArgs,
isDashboard: true,
isVoter: true,
+ isDataMissing: undefined,
proposal: {
...commonArgs.proposal,
abstract: "Example about section",
diff --git a/govtool/frontend/src/stories/GovernanceActionVoted.stories.ts b/govtool/frontend/src/stories/GovernanceActionVoted.stories.ts
index 6b43f2452..d5eb8de53 100644
--- a/govtool/frontend/src/stories/GovernanceActionVoted.stories.ts
+++ b/govtool/frontend/src/stories/GovernanceActionVoted.stories.ts
@@ -4,6 +4,7 @@ import { expect, userEvent, waitFor, within, screen } from "@storybook/test";
import { GovernanceVotedOnCard } from "@molecules";
import { formatDisplayDate, getProposalTypeNoEmptySpaces } from "@/utils";
import { GovernanceActionType } from "@/types/governanceAction";
+import { MetadataValidationStatus } from "@/models/metadataValidation";
const meta = {
title: "Example/GovernanceVotedOnCard",
@@ -68,8 +69,6 @@ export const GovernanceVotedOnCardComponent: Story = {
proposal: {
createdEpochNo: 232,
expiryEpochNo: 323,
- metadataStatus: null,
- metadataValid: true,
createdDate: "1970-01-01T00:00:00Z",
expiryDate: "1970-02-01T00:00:00Z",
id: "exampleId",
@@ -115,8 +114,6 @@ export const GovernanceVotedOnCardAbstain: Story = {
proposal: {
createdEpochNo: 232,
expiryEpochNo: 323,
- metadataStatus: null,
- metadataValid: true,
createdDate: "1970-01-01T00:00:00Z",
expiryDate: "1970-02-01T00:00:00Z",
id: "exampleId",
@@ -163,8 +160,6 @@ export const GovernanceVotedOnCardYes: Story = {
proposal: {
createdEpochNo: 232,
expiryEpochNo: 323,
- metadataStatus: null,
- metadataValid: true,
createdDate: "1970-01-01T00:00:00Z",
expiryDate: "1970-02-01T00:00:00Z",
id: "exampleId",
@@ -211,8 +206,6 @@ export const GovernanceVotedOnCardNo: Story = {
proposal: {
createdEpochNo: 232,
expiryEpochNo: 323,
- metadataStatus: null,
- metadataValid: true,
createdDate: "1970-01-01T00:00:00Z",
expiryDate: "1970-02-01T00:00:00Z",
id: "exampleId",
@@ -242,3 +235,91 @@ export const GovernanceVotedOnCardNo: Story = {
expect(canvas.getByText(/no/i)).toBeInTheDocument();
},
};
+
+export const GovernanceVotedOnCardDataFormattedIncorrectly: Story = {
+ args: {
+ votedProposal: {
+ vote: {
+ date: new Date().toLocaleDateString(),
+ drepId: "drep1_exampledrepid1231231",
+ epochNo: 222,
+ metadataHash: "ababa1ababab1abababa1ababab1ababa1aba1",
+ proposalId: "exampleproposalid12dsadasdasda",
+ url: "https://exampleurl.com",
+ vote: "no",
+ txHash: "dwq78dqw78qwd78wdq78dqw78dqw",
+ },
+ proposal: {
+ createdEpochNo: 232,
+ expiryEpochNo: 323,
+ createdDate: "1970-01-01T00:00:00Z",
+ expiryDate: "1970-02-01T00:00:00Z",
+ id: "exampleId",
+ type: GovernanceActionType.InfoAction,
+ index: 1,
+ txHash: "exampleHash",
+ url: "https://example.com",
+ metadataHash: "exampleHash",
+ dRepYesVotes: 1,
+ dRepNoVotes: 0,
+ dRepAbstainVotes: 2,
+ poolYesVotes: 1,
+ poolNoVotes: 0,
+ poolAbstainVotes: 2,
+ ccYesVotes: 1,
+ ccNoVotes: 0,
+ ccAbstainVotes: 2,
+ protocolParams: null,
+ prevGovActionIndex: null,
+ prevGovActionTxHash: null,
+ },
+ },
+ metadataStatus: MetadataValidationStatus.INCORRECT_FORMAT,
+ },
+ play: async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+ expect(canvas.getByText(/Data Formatted Incorrectly/i)).toBeInTheDocument();
+ },
+};
+
+export const GovernanceVotedOnCardValidating: Story = {
+ args: {
+ votedProposal: {
+ vote: {
+ date: new Date().toLocaleDateString(),
+ drepId: "drep1_exampledrepid1231231",
+ epochNo: 222,
+ metadataHash: "ababa1ababab1abababa1ababab1ababa1aba1",
+ proposalId: "exampleproposalid12dsadasdasda",
+ url: "https://exampleurl.com",
+ vote: "no",
+ txHash: "dwq78dqw78qwd78wdq78dqw78dqw",
+ },
+ proposal: {
+ createdEpochNo: 232,
+ expiryEpochNo: 323,
+ createdDate: "1970-01-01T00:00:00Z",
+ expiryDate: "1970-02-01T00:00:00Z",
+ id: "exampleId",
+ type: GovernanceActionType.InfoAction,
+ index: 1,
+ txHash: "exampleHash",
+ url: "https://example.com",
+ metadataHash: "exampleHash",
+ dRepYesVotes: 1,
+ dRepNoVotes: 0,
+ dRepAbstainVotes: 2,
+ poolYesVotes: 1,
+ poolNoVotes: 0,
+ poolAbstainVotes: 2,
+ ccYesVotes: 1,
+ ccNoVotes: 0,
+ ccAbstainVotes: 2,
+ protocolParams: null,
+ prevGovActionIndex: null,
+ prevGovActionTxHash: null,
+ },
+ },
+ isValidating: true,
+ },
+};
diff --git a/govtool/frontend/src/utils/generateJsonld.ts b/govtool/frontend/src/utils/generateJsonld.ts
index b2481c762..1ed0700ba 100644
--- a/govtool/frontend/src/utils/generateJsonld.ts
+++ b/govtool/frontend/src/utils/generateJsonld.ts
@@ -19,6 +19,7 @@ export const generateJsonld = async <
const doc = {
"@context": context,
hashAlgorithm: "blake2b-256",
+ authors: [],
body,
};
diff --git a/govtool/frontend/src/utils/index.ts b/govtool/frontend/src/utils/index.ts
index dfeaca81f..38c403872 100644
--- a/govtool/frontend/src/utils/index.ts
+++ b/govtool/frontend/src/utils/index.ts
@@ -27,7 +27,6 @@ export * from "./jsonUtils";
export * from "./localStorage";
export * from "./mapArrayToObjectByKeys";
export * from "./mapDtoToDrep";
-export * from "./mapDtoToProposal";
export * from "./numberValidation";
export * from "./openInNewTab";
export * from "./removeDuplicatedProposals";
diff --git a/govtool/frontend/src/utils/mapDtoToDrep.ts b/govtool/frontend/src/utils/mapDtoToDrep.ts
index b0f1e4b1f..12036d8ba 100644
--- a/govtool/frontend/src/utils/mapDtoToDrep.ts
+++ b/govtool/frontend/src/utils/mapDtoToDrep.ts
@@ -1,10 +1,4 @@
-import {
- DRepData,
- DRepMetadata,
- DrepDataDTO,
- MetadataStandard,
-} from "@/models";
-import { postValidate } from "@/services";
+import { DRepData, DrepDataDTO } from "@/models";
import { fixViewForScriptBasedDRep } from "./dRep";
const imageFetchDefaultOptions: RequestInit = {
@@ -63,23 +57,6 @@ export const mapDtoToDrep = async (dto: DrepDataDTO): Promise => {
});
}
- if (dto.metadataHash && dto.url) {
- const validationResponse = await postValidate({
- url: dto.url,
- hash: dto.metadataHash,
- standard: MetadataStandard.CIP119,
- });
- return {
- ...dto,
- ...emptyMetadata,
- ...validationResponse.metadata,
- metadataStatus: validationResponse.status || null,
- metadataValid: validationResponse.valid,
- image: isIPFSImage ? base64Image : dto.imageUrl,
- view,
- };
- }
-
return {
...dto,
...emptyMetadata,
diff --git a/govtool/frontend/src/utils/mapDtoToProposal.ts b/govtool/frontend/src/utils/mapDtoToProposal.ts
deleted file mode 100644
index 9f3635350..000000000
--- a/govtool/frontend/src/utils/mapDtoToProposal.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import {
- MetadataStandard,
- ProposalData,
- ProposalDataDTO,
- ProposalMetadata,
-} from "@/models";
-import { postValidate } from "@/services";
-
-export const mapDtoToProposal = async (
- dto: ProposalDataDTO,
-): Promise => {
- if (dto.url && dto.metadataHash) {
- const validationResponse = await postValidate({
- url: dto.url,
- hash: dto.metadataHash,
- standard: MetadataStandard.CIP108,
- });
-
- return {
- ...dto,
- title: dto.title || validationResponse.metadata?.title,
- abstract: dto.abstract || validationResponse.metadata?.abstract,
- motivation: dto.motivation || validationResponse.metadata?.motivation,
- rationale: dto.rationale || validationResponse.metadata?.rationale,
- references: validationResponse.metadata?.references || [],
- metadataStatus: validationResponse.status || null,
- metadataValid: validationResponse.valid,
- };
- }
-
- return {
- ...dto,
- metadataStatus: null,
- metadataValid: true,
- };
-};
diff --git a/govtool/frontend/src/utils/tests/dRep.test.ts b/govtool/frontend/src/utils/tests/dRep.test.ts
index 66f41fe63..00a06a4f2 100644
--- a/govtool/frontend/src/utils/tests/dRep.test.ts
+++ b/govtool/frontend/src/utils/tests/dRep.test.ts
@@ -15,8 +15,6 @@ const EXAMPLE_DREP: DRepData = {
type: "DRep" as TDRepType,
givenName: "name",
references: [],
- metadataStatus: null,
- metadataValid: true,
latestRegistrationDate: "2024-07-10",
paymentAddress: null,
objectives: null,
diff --git a/govtool/frontend/src/utils/tests/removeDuplicatedProposals.test.ts b/govtool/frontend/src/utils/tests/removeDuplicatedProposals.test.ts
index 29260ed57..aa9adee76 100644
--- a/govtool/frontend/src/utils/tests/removeDuplicatedProposals.test.ts
+++ b/govtool/frontend/src/utils/tests/removeDuplicatedProposals.test.ts
@@ -30,8 +30,6 @@ const uniqueProposals: ProposalData[] = [
ccAbstainVotes: 4324,
title: "Proposal 1322 Title",
abstract: "This is about Proposal 1322",
- metadataStatus: null,
- metadataValid: false,
motivation: "Motivation behind Proposal 1322",
rationale: "Rationale for Proposal 1322",
protocolParams: null,
@@ -65,8 +63,6 @@ const uniqueProposals: ProposalData[] = [
ccAbstainVotes: 4324,
title: "Proposal 1338 Title",
abstract: "This is about Proposal 1338",
- metadataStatus: null,
- metadataValid: false,
motivation: "Motivation behind Proposal 1338",
rationale: "Rationale for Proposal 1338",
protocolParams: null,
@@ -100,8 +96,6 @@ const uniqueProposals: ProposalData[] = [
ccAbstainVotes: 4324,
title: "Proposal 1335 Title",
abstract: "This is about Proposal 1335",
- metadataStatus: null,
- metadataValid: false,
motivation: "Motivation behind Proposal 1335",
rationale: "Rationale for Proposal 1335",
protocolParams: null,
diff --git a/govtool/metadata-validation/src/app.service.ts b/govtool/metadata-validation/src/app.service.ts
index a44669a89..82f0bb1af 100644
--- a/govtool/metadata-validation/src/app.service.ts
+++ b/govtool/metadata-validation/src/app.service.ts
@@ -7,7 +7,7 @@ import * as jsonld from 'jsonld';
import { ValidateMetadataDTO } from '@dto';
import { LoggerMessage, MetadataValidationStatus } from '@enums';
import { validateMetadataStandard, parseMetadata, getStandard } from '@utils';
-import { ValidateMetadataResult } from '@types';
+import { MetadataStandard, ValidateMetadataResult } from '@types';
@Injectable()
export class AppService {
@@ -57,6 +57,13 @@ export class AppService {
throw MetadataValidationStatus.INCORRECT_FORMAT;
}
+ if (
+ standard === MetadataStandard.CIP108 &&
+ !Array.isArray(parsedData.authors)
+ ) {
+ throw MetadataValidationStatus.INCORRECT_FORMAT;
+ }
+
if (!parsedData?.body) {
throw MetadataValidationStatus.INCORRECT_FORMAT;
}