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;