1- import { useMemo , useState , Fragment } from "react" ;
1+ import { useMemo , useState , Fragment , useEffect } from "react" ;
22import { Box , Tabs , Tab , styled , Skeleton } from "@mui/material" ;
33import { useLocation } from "react-router-dom" ;
4+ import CheckCircleIcon from "@mui/icons-material/CheckCircle" ;
5+ import CancelIcon from "@mui/icons-material/Cancel" ;
46
57import { CopyButton , ExternalModalButton , Tooltip , Typography } from "@atoms" ;
68import {
@@ -23,6 +25,7 @@ import {
2325 getFullGovActionId ,
2426 mapArrayToObjectByKeys ,
2527 encodeCIP129Identifier ,
28+ validateSignature ,
2629} from "@utils" ;
2730import { MetadataValidationStatus , ProposalData } from "@models" ;
2831import { GovernanceActionType } from "@/types/governanceAction" ;
@@ -77,6 +80,7 @@ export const GovernanceActionDetailsCardData = ({
7780 proposal : {
7881 abstract,
7982 authors,
83+ json : jsonContent ,
8084 createdDate,
8185 createdEpochNo,
8286 details,
@@ -373,21 +377,35 @@ export const GovernanceActionDetailsCardData = ({
373377 ? t ( "govActions.authors.noDataAvailable" )
374378 : ( authors ?? [ ] ) . map ( ( author , idx , arr ) => (
375379 < Fragment key = { author . publicKey } >
376- < Tooltip
377- heading = { `${ t ( "govActions.authors.witnessAlgorithm" ) } : ${
378- author . witnessAlgorithm
379- } `}
380- paragraphOne = { `${ t ( "govActions.authors.publicKey" ) } : ${
381- author . publicKey
382- } `}
383- paragraphTwo = { `${ t ( "govActions.authors.signature" ) } : ${
384- author . signature
385- } `}
386- placement = "bottom-end"
387- arrow
380+ < span
381+ style = { {
382+ display : "inline-flex" ,
383+ alignItems : "center" ,
384+ gap : 2 ,
385+ } }
388386 >
389- < span > { author . name } </ span >
390- </ Tooltip >
387+ < AuthorSignatureStatus
388+ signature = { author . signature }
389+ publicKey = { author . publicKey }
390+ algorithm = { author . witnessAlgorithm }
391+ jsonContent = { jsonContent }
392+ />
393+ < Tooltip
394+ heading = { `${ t ( "govActions.authors.witnessAlgorithm" ) } : ${
395+ author . witnessAlgorithm
396+ } `}
397+ paragraphOne = { `${ t ( "govActions.authors.publicKey" ) } : ${
398+ author . publicKey
399+ } `}
400+ paragraphTwo = { `${ t ( "govActions.authors.signature" ) } : ${
401+ author . signature
402+ } `}
403+ placement = "bottom-end"
404+ arrow
405+ >
406+ < span > { author . name } </ span >
407+ </ Tooltip >
408+ </ span >
391409 { idx < arr . length - 1 && < span > , </ span > }
392410 </ Fragment >
393411 ) )
@@ -498,3 +516,59 @@ const HardforkDetailsTabContent = ({
498516 </ Box >
499517 ) ;
500518} ;
519+
520+ const AuthorSignatureStatus = ( {
521+ algorithm,
522+ publicKey,
523+ signature,
524+ jsonContent,
525+ } : {
526+ algorithm ?: string ;
527+ publicKey ?: string ;
528+ signature ?: string ;
529+ jsonContent ?: Record < string , unknown > ;
530+ } ) => {
531+ const { t } = useTranslation ( ) ;
532+ const [ isSignatureValid , setIsSignatureValid ] = useState < boolean | null > (
533+ null ,
534+ ) ;
535+
536+ useEffect ( ( ) => {
537+ let cancelled = false ;
538+ async function checkSignature ( ) {
539+ const args = {
540+ jsonContent,
541+ algorithm,
542+ publicKey,
543+ signature,
544+ } ;
545+ const result = await validateSignature ( args ) ;
546+ if ( ! cancelled ) setIsSignatureValid ( result ) ;
547+ }
548+ checkSignature ( ) ;
549+ return ( ) => {
550+ cancelled = true ;
551+ } ;
552+ } , [ algorithm , jsonContent , publicKey , signature ] ) ;
553+
554+ if ( isSignatureValid === null ) {
555+ return < Skeleton variant = "text" width = { 16 } /> ;
556+ }
557+ return (
558+ < Tooltip
559+ heading = {
560+ isSignatureValid
561+ ? t ( "govActions.authors.singatureVerified" )
562+ : t ( "govActions.authors.signatureNotVerified" )
563+ }
564+ placement = "bottom-end"
565+ arrow
566+ >
567+ { isSignatureValid ? (
568+ < CheckCircleIcon sx = { { color : "success.main" , fontSize : 16 } } />
569+ ) : (
570+ < CancelIcon sx = { { color : "error.main" , fontSize : 16 } } />
571+ ) }
572+ </ Tooltip >
573+ ) ;
574+ } ;
0 commit comments