import {
Box,
CircularProgress,
Skeleton,
styled,
Tab,
Tabs,
} from "@mui/material";
import { Breadcrumbs } from "../Components/Molecules/Breadcrumbs";
import { useGetGovernanceActionQuery } from "../hooks/useGetGovernanceActionQuery";
import Header from "../Components/SingleAction/Header";
import { useMetadata } from "../hooks/useMetadata";
import References from "../Components/SingleAction/References";
import ActionIdentity from "../Components/SingleAction/ActionIdentity";
import { encodeCIP129Identifier, getFullGovActionId } from "../lib/utils";
import GovernanceVoting from "../Components/SingleAction/GovernanceVoting";
import { DataMissingInfoBox } from "../Components/Molecules/DataMissingInfoBox";
import GovernanceActionElement from "../Components/SingleAction/GovernanceActionElement";
import { useMemo, useState } from "react";
import { ReasoningTabContent } from "../Components/SingleAction/ReasoningTabContent";
import { GovernanceActionDetailsDiffView } from "../Components/SingleAction/GovernanceActionDetailsDiffView";
import { mapArrayToObjectByKeys } from "../lib/mapArrayToObjectByKeys";
import { filterUpdatableProtocolParams } from "../lib/filterUpdatableProtocolParams";
import { useNetworkMetrics } from "../hooks/useNetworkMetrics";
import { filterOutNullParams } from "../lib/filterOutNullParams";
import { GovernanceActionType } from "../types/api";
import { GovernanceActionNewCommitteeDetailsTabContent } from "../Components/SingleAction/GovernanceActionNewCommitteeDetailsTabContent";
import { GovernanceActionNewConstitutionDetailsTabContent } from "../Components/SingleAction/GovernanceActionNewConstitutionDetailsTabContent";
import { useScreenDimension } from "../hooks/useDimensions";
import { GovernanceActionCardTreasuryWithdrawalElement } from "../Components/SingleAction/GovernanceActionCardTreasuryWithdrawalElement";
import { HardForkDetailsTabContent } from "../Components/SingleAction/HardForkDetailsTabContent";
import { useGetProposalQuery } from "../hooks/useGetProposalQuery";
import ProposalCard from "../Components/SingleAction/ProposalCard";
import { Typography } from "../Components/Atoms/Typography";
import ProposalCardLoader from "../Components/Loaders/ProposalCardLoader";
import { useTranslation } from "../contexts/I18nContext";
import GovernanceActionAuthors from "../Components/Molecules/GovernanceActionAuthors";
import { ActionsEmptyState } from "../Components/Molecules/ActionsEmptyState";
type GovernanceActionProps = {
id: string;
};
type TabPanelProps = {
children?: React.ReactNode;
index: number;
value: number;
};
const CustomTabPanel = ({ children, value, index }: TabPanelProps) =>
value === index && {children};
type StyledTabProps = {
label: string;
isMobile: boolean;
};
const StyledTab = styled(({ isMobile, ...props }: StyledTabProps) => (
))(({ isMobile }) => ({
textTransform: "none",
fontWeight: 600,
fontSize: 16,
width: !isMobile ? "auto" : "50%",
color: "rgba(36, 34, 50, 0.5)",
"&.Mui-selected": {
color: "rgba(38, 37, 45, 1)",
},
}));
function GovernanceAction({ id }: GovernanceActionProps) {
const { isMobile } = useScreenDimension();
const { governanceAction, isGovernanceActionLoading, governanceActionError } =
useGetGovernanceActionQuery(id);
const { metadata, metadataValid, isMetadataLoading } =
useMetadata(governanceAction);
const { proposal, isProposalLoading } = useGetProposalQuery(
governanceAction?.tx_hash
);
const { t } = useTranslation();
const { epochParams } = useNetworkMetrics(governanceAction);
const [selectedTab, setSelectedTab] = useState(0);
const content = {
title: governanceAction?.title || metadata?.data?.title,
abstract: governanceAction?.abstract || metadata?.data?.abstract,
motivation: governanceAction?.motivation || metadata?.data?.motivation,
rationale: governanceAction?.rationale || metadata?.data?.rationale,
references:
governanceAction?.json_metadata?.body?.references ||
metadata?.data?.references ||
[],
};
const hasAnyContent =
content.abstract || content.motivation || content.rationale;
const isDataMissing = metadata?.metadataStatus || null;
const idCIP129 = encodeCIP129Identifier({
txID: governanceAction?.tx_hash,
index: governanceAction?.index.toString(16).padStart(2, "0"),
bech32Prefix: "gov_action",
});
const prevGovActionId =
governanceAction?.prev_gov_action_index &&
governanceAction?.prev_gov_action_tx_hash
? getFullGovActionId(
governanceAction?.prev_gov_action_tx_hash,
governanceAction?.prev_gov_action_index
)
: null;
const authors = governanceAction?.json_metadata
? governanceAction?.json_metadata?.authors
: metadata?.data?.authors;
const mappedArraysToObjectsProtocolParams = useMemo(
() =>
mapArrayToObjectByKeys(governanceAction?.proposal_params, [
"PlutusV1",
"PlutusV2",
"PlutusV3",
]),
[governanceAction?.proposal_params]
);
const updatableProtocolParams = useMemo(
() =>
filterUpdatableProtocolParams(
epochParams,
mappedArraysToObjectsProtocolParams,
["id", "registered_tx_id", "key"]
),
[epochParams, mappedArraysToObjectsProtocolParams]
);
const nonNullProtocolParams = useMemo(
() =>
filterOutNullParams(mappedArraysToObjectsProtocolParams, [
"id",
"registered_tx_id",
"key",
]),
[mappedArraysToObjectsProtocolParams]
);
const showReasoningTab = !isDataMissing && hasAnyContent;
const showParametersTab =
(governanceAction?.type === GovernanceActionType.ParameterChange ||
governanceAction?.type === GovernanceActionType.NewConstitution) &&
!!governanceAction?.proposal_params &&
!!epochParams;
const showHardforkDetailsTab =
governanceAction?.type === GovernanceActionType.HardForkInitiation &&
!!governanceAction?.description;
const showNewCommitteeTab =
governanceAction?.type === GovernanceActionType.NewCommittee &&
!!governanceAction?.description;
const showNewConstitutionTab =
governanceAction?.type === GovernanceActionType.NewConstitution &&
!!governanceAction?.description &&
!!governanceAction?.description?.anchor;
const tabDefinitions = useMemo(() => {
return [
{
label: t("outcome.tabs.reasoning"),
dataTestId: "reasoning-tab",
content: (
),
visible: showReasoningTab,
},
{
label: t("outcome.tabs.parameters"),
dataTestId: "parameters-tab",
content: (
),
visible: showParametersTab,
},
{
label: t("outcome.tabs.details"),
dataTestId: "hardfork-details-tab",
content: (
),
visible: showHardforkDetailsTab,
},
{
label: t("outcome.tabs.parameters"),
dataTestId: "new-committee-tab",
content: (
),
visible: showNewCommitteeTab,
},
{
label: t("outcome.tabs.details"),
dataTestId: "new-constitution-tab",
content: (
),
visible: showNewConstitutionTab,
},
];
}, [
content.abstract,
content.motivation,
content.rationale,
updatableProtocolParams,
nonNullProtocolParams,
governanceAction?.description,
prevGovActionId,
showReasoningTab,
showParametersTab,
showHardforkDetailsTab,
showNewCommitteeTab,
showNewConstitutionTab,
]);
const visibleTabs = useMemo(() => {
return tabDefinitions.filter((tab) => tab.visible);
}, [tabDefinitions]);
const handleChange: (
event: React.SyntheticEvent,
newValue: number
) => void = (_event, newValue) => {
setSelectedTab(newValue);
};
if (isGovernanceActionLoading) {
return (
);
}
if (governanceActionError || !governanceAction) {
return (
);
}
const renderAllTabContent = () => {
return tabDefinitions.map((tab) => (
visibleTab.dataTestId === tab.dataTestId
)}
>
{tab.visible && tab.content}
));
};
return (
{governanceAction && (
{!hasAnyContent && (!governanceAction || isMetadataLoading) && (
<>
>
)}
{visibleTabs.length > 0 && (
<>
{visibleTabs.length === 1 ? (
visibleTabs[0].content
) : (
<>
{visibleTabs.map((tab) => (
))}
{renderAllTabContent()}
>
)}
>
)}
{governanceAction?.description &&
governanceAction?.type ===
GovernanceActionType.TreasuryWithdrawals &&
Array.isArray(governanceAction?.description) &&
governanceAction?.description?.map((withdrawal) => (
))}
{governanceAction?.type !==
GovernanceActionType.NewConstitution && (
<>
>
)}
{metadataValid && content.references.length > 0 && (
)}
{t("proposalDiscussion.title")}
{isProposalLoading ? (
) : !!proposal?.data ? (
) : (
{t("proposalDiscussion.notFound")}
)}
)}
);
}
export default GovernanceAction;