Skip to content

Commit

Permalink
[#378] feat: create gov action transaction builder & submit
Browse files Browse the repository at this point in the history
  • Loading branch information
MSzalowski committed Mar 13, 2024
1 parent 03c70f3 commit 6a97391
Show file tree
Hide file tree
Showing 16 changed files with 885 additions and 570 deletions.
Original file line number Diff line number Diff line change
@@ -1,95 +1,29 @@
import { Dispatch, SetStateAction, useCallback, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Dispatch, SetStateAction, useCallback } from "react";
import { Box } from "@mui/material";
import OpenInNewIcon from "@mui/icons-material/OpenInNew";

import { Button, Spacer, Typography } from "@atoms";
import { ICONS, PATHS } from "@consts";
import { ICONS } from "@consts";
import { useCreateGovernanceActionForm, useTranslation } from "@hooks";
import { Step } from "@molecules";
import { BgCard, ControlledField, StatusModalState } from "@organisms";
import {
URL_REGEX,
downloadJson,
openInNewTab,
validateMetadataHash,
MetadataHashValidationErrors,
} from "@utils";
import { ModalState, useModal } from "@/context";
import I18n from "@/i18n";
import { BgCard, ControlledField } from "@organisms";
import { URL_REGEX, openInNewTab } from "@utils";

type StorageInformationProps = {
setStep: Dispatch<SetStateAction<number>>;
};

const externalDataDoesntMatchModal = {
type: "statusModal",
state: {
status: "warning",
title: I18n.t(
"createGovernanceAction.modals.externalDataDoesntMatch.title"
),
message: I18n.t(
"createGovernanceAction.modals.externalDataDoesntMatch.message"
),
buttonText: I18n.t(
"createGovernanceAction.modals.externalDataDoesntMatch.buttonText"
),
cancelText: I18n.t(
"createGovernanceAction.modals.externalDataDoesntMatch.cancelRegistrationText"
),
feedbackText: I18n.t(
"createGovernanceAction.modals.externalDataDoesntMatch.feedbackText"
),
},
} as const;

const urlCannotBeFound = {
type: "statusModal",
state: {
status: "warning",
title: I18n.t("createGovernanceAction.modals.urlCannotBeFound.title"),
message: I18n.t("createGovernanceAction.modals.urlCannotBeFound.message"),
link: "https://docs.sanchogov.tools",
linkText: I18n.t("createGovernanceAction.modals.urlCannotBeFound.linkText"),
buttonText: I18n.t(
"createGovernanceAction.modals.urlCannotBeFound.buttonText"
),
cancelText: I18n.t(
"createGovernanceAction.modals.urlCannotBeFound.cancelRegistrationText"
),
feedbackText: I18n.t(
"createGovernanceAction.modals.urlCannotBeFound.feedbackText"
),
},
} as const;

const storageInformationErrorModals: Record<
MetadataHashValidationErrors,
ModalState<
| (typeof externalDataDoesntMatchModal)["state"]
| (typeof urlCannotBeFound)["state"]
>
> = {
[MetadataHashValidationErrors.INVALID_URL]: urlCannotBeFound,
[MetadataHashValidationErrors.FETCH_ERROR]: urlCannotBeFound,
[MetadataHashValidationErrors.INVALID_JSON]: externalDataDoesntMatchModal,
[MetadataHashValidationErrors.INVALID_HASH]: externalDataDoesntMatchModal,
};

export const StorageInformation = ({ setStep }: StorageInformationProps) => {
const { t } = useTranslation();
const navigate = useNavigate();
const {
control,
errors,
createGovernanceAction,
generateJsonBody,
getValues,
watch,
} = useCreateGovernanceActionForm();
const { openModal, closeModal } = useModal();
const [isJsonDownloaded, setIsJsonDownloaded] = useState<boolean>(false);
onClickDownloadJson,
isLoading,
} = useCreateGovernanceActionForm(setStep);

// TODO: change on correct file name
const fileName = getValues("governance_action_type");
Expand All @@ -100,53 +34,18 @@ export const StorageInformation = ({ setStep }: StorageInformationProps) => {
[]
);

const isActionButtonDisabled = !watch("storingURL") || !isJsonDownloaded;
const isActionButtonDisabled = !watch("storingURL");

const onClickBack = useCallback(() => setStep(5), []);

const onClickDownloadJson = async () => {
const data = getValues();
const jsonBody = await generateJsonBody(data);
downloadJson(jsonBody, fileName);
setIsJsonDownloaded(true);
};

const backToDashboard = () => {
navigate(PATHS.dashboard);
closeModal();
};

const handleStoringURLJSONValidation = useCallback(async () => {
const storingURL = getValues("storingURL");
try {
await createGovernanceAction();

// TODO: To be replaced wtih the correct hash
await validateMetadataHash(storingURL, "hash");
} catch (error: any) {
if (Object.values(MetadataHashValidationErrors).includes(error.message)) {
openModal({
...storageInformationErrorModals[
error.message as MetadataHashValidationErrors
],
onSubmit: () => {
setStep(3);
},
onCancel: backToDashboard,
// TODO: Open usersnap feedback
onFeedback: backToDashboard,
} as ModalState<StatusModalState>);
}
}
}, [getValues, generateJsonBody]);

return (
<BgCard
actionButtonLabel={t("continue")}
backButtonLabel={t("back")}
isActionButtonDisabled={isActionButtonDisabled}
onClickActionButton={handleStoringURLJSONValidation}
onClickActionButton={createGovernanceAction}
onClickBackButton={onClickBack}
isLoadingActionButton={isLoading}
>
<Typography sx={{ textAlign: "center" }} variant="headline4">
{t("createGovernanceAction.storingInformationTitle")}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export const GOVERNANCE_ACTION_FIELDS: GovernanceActionFields = {
},
} as const;

const commonContext = {
export const GOVERNANCE_ACTION_CONTEXT = {
"@language": "en-us",
CIP100:
"https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#",
Expand Down Expand Up @@ -176,18 +176,3 @@ const commonContext = {
},
},
};

export const GOVERNANCE_ACTION_CONTEXTS = {
[GovernanceActionType.Info]: commonContext,
[GovernanceActionType.Treasury]: {
...commonContext,
body: {
...commonContext.body,
"@context": {
...commonContext.body["@context"],
amount: "CIP108:amount",
receivingAddress: "CIP108:receivingAddress",
},
},
},
};
5 changes: 5 additions & 0 deletions govtool/frontend/src/consts/governanceAction/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from "./fields";
export * from "./filters";
export * from "./sorting";
export * from "./modalConfig";
export * from "./metadataHashValidationErrors";
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum MetadataHashValidationErrors {
INVALID_URL = "Invalid URL",
INVALID_JSON = "Invalid JSON",
INVALID_HASH = "Invalid hash",
FETCH_ERROR = "Error fetching data",
}
50 changes: 50 additions & 0 deletions govtool/frontend/src/consts/governanceAction/modalConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ModalState } from "@/context";
import I18n from "@/i18n";

import { MetadataHashValidationErrors } from "./metadataHashValidationErrors";

const externalDataDoesntMatchModal = {
status: "warning",
title: I18n.t("createGovernanceAction.modals.externalDataDoesntMatch.title"),
message: I18n.t(
"createGovernanceAction.modals.externalDataDoesntMatch.message"
),
buttonText: I18n.t(
"createGovernanceAction.modals.externalDataDoesntMatch.buttonText"
),
cancelText: I18n.t(
"createGovernanceAction.modals.externalDataDoesntMatch.cancelRegistrationText"
),
feedbackText: I18n.t(
"createGovernanceAction.modals.externalDataDoesntMatch.feedbackText"
),
} as const;

const urlCannotBeFound = {
status: "warning",
title: I18n.t("createGovernanceAction.modals.urlCannotBeFound.title"),
message: I18n.t("createGovernanceAction.modals.urlCannotBeFound.message"),
link: "https://docs.sanchogov.tools",
linkText: I18n.t("createGovernanceAction.modals.urlCannotBeFound.linkText"),
buttonText: I18n.t(
"createGovernanceAction.modals.urlCannotBeFound.buttonText"
),
cancelText: I18n.t(
"createGovernanceAction.modals.urlCannotBeFound.cancelRegistrationText"
),
feedbackText: I18n.t(
"createGovernanceAction.modals.urlCannotBeFound.feedbackText"
),
};

export const storageInformationErrorModals: Record<
MetadataHashValidationErrors,
ModalState<
typeof externalDataDoesntMatchModal | typeof urlCannotBeFound
>["state"]
> = {
[MetadataHashValidationErrors.INVALID_URL]: urlCannotBeFound,
[MetadataHashValidationErrors.FETCH_ERROR]: urlCannotBeFound,
[MetadataHashValidationErrors.INVALID_JSON]: externalDataDoesntMatchModal,
[MetadataHashValidationErrors.INVALID_HASH]: externalDataDoesntMatchModal,
};
4 changes: 1 addition & 3 deletions govtool/frontend/src/consts/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
export * from "./colors";
export * from "./governanceActionFields";
export * from "./governanceActionsFilters";
export * from "./governanceActionsSorting";
export * from "./governanceAction";
export * from "./icons";
export * from "./images";
export * from "./navItems";
Expand Down
8 changes: 8 additions & 0 deletions govtool/frontend/src/context/wallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,13 @@ interface CardanoContext {
buildSignSubmitConwayCertTx: ({
certBuilder,
votingBuilder,
govActionBuilder,
type,
registrationType,
}: {
certBuilder?: CertificatesBuilder;
votingBuilder?: VotingBuilder;
govActionBuilder?: VotingProposalBuilder;
type?: "delegation" | "registration" | "soleVoterRegistration" | "vote";
proposalId?: string;
registrationType?: DRepActionType;
Expand Down Expand Up @@ -823,12 +825,14 @@ function CardanoProvider(props: Props) {
async ({
certBuilder,
votingBuilder,
govActionBuilder,
type,
proposalId,
registrationType,
}: {
certBuilder?: CertificatesBuilder;
votingBuilder?: VotingBuilder;
govActionBuilder?: VotingProposalBuilder;
type?: "delegation" | "registration" | "soleVoterRegistration" | "vote";
proposalId?: string;
registrationType?: DRepActionType;
Expand All @@ -854,6 +858,10 @@ function CardanoProvider(props: Props) {
txBuilder.set_voting_builder(votingBuilder);
}

if (govActionBuilder) {
txBuilder.set_voting_proposal_builder(govActionBuilder);
}

if (
!walletState.changeAddress ||
!walletState.usedAddress ||
Expand Down
Loading

0 comments on commit 6a97391

Please sign in to comment.