From c20e86caae9dab6d6e05bacf14e8d0a340bff866 Mon Sep 17 00:00:00 2001 From: Joseph Chalabi <100090645+chalabi2@users.noreply.github.com> Date: Mon, 2 Dec 2024 11:52:38 -0700 Subject: [PATCH] feat: fix message params | add message expanded view (#96) --------- Co-authored-by: Felix C. Morency <1102868+fmorency@users.noreply.github.com> --- .../__tests__/voteDetailsModal.test.tsx | 12 +- components/groups/modals/voteDetailsModal.tsx | 476 ++++++++++-------- 2 files changed, 276 insertions(+), 212 deletions(-) diff --git a/components/groups/modals/__tests__/voteDetailsModal.test.tsx b/components/groups/modals/__tests__/voteDetailsModal.test.tsx index 3035299c..9583c84a 100644 --- a/components/groups/modals/__tests__/voteDetailsModal.test.tsx +++ b/components/groups/modals/__tests__/voteDetailsModal.test.tsx @@ -76,9 +76,15 @@ describe('VoteDetailsModal', () => { test('renders messages section with correct data', () => { renderWithChainProvider(); expect(screen.getByText('MESSAGES')).toBeInTheDocument(); - expect(screen.getByText('Send')).toBeInTheDocument(); - expect(screen.getByText('from_address:')).toBeInTheDocument(); - expect(screen.getByText('to_address:')).toBeInTheDocument(); + expect(screen.getByLabelText('msg')).toBeInTheDocument(); + + for (const m of ['Send', 'from_address:', 'to_address:']) { + const field = screen.getAllByText(m); + + for (const f of field) { + expect(f).toBeInTheDocument(); + } + } }); test('conditionally renders execute button when proposal is accepted', () => { diff --git a/components/groups/modals/voteDetailsModal.tsx b/components/groups/modals/voteDetailsModal.tsx index 34e7b37b..0e91bced 100644 --- a/components/groups/modals/voteDetailsModal.tsx +++ b/components/groups/modals/voteDetailsModal.tsx @@ -22,7 +22,8 @@ import { useTheme } from '@/contexts/theme'; import CountdownTimer from '../components/CountdownTimer'; import { useFeeEstimation } from '@/hooks'; -import { ShareIcon, TrashIcon, CheckIcon } from '@heroicons/react/24/outline'; +import { TrashIcon, CheckIcon } from '@heroicons/react/24/outline'; +import { ArrowUpIcon, CopyIcon } from '@/components/icons'; const Chart = dynamic(() => import('react-apexcharts'), { ssr: false, }) as any; @@ -336,6 +337,14 @@ function VoteDetailsModal({ '/cosmos.group.v1.MsgVote': ['proposal_id', 'voter', 'option', 'metadata'], '/cosmos.group.v1.MsgExec': ['proposal_id', 'executor'], '/cosmos.group.v1.MsgLeaveGroup': ['address', 'group_id'], + '/liftedinit.manifest.v1.MsgPayout': ['authority', 'payout_pairs'], + '/liftedinit.manifest.v1.MsgBurnHeldBalance': ['authority', 'burn_coins'], + '/cosmos.group.v1.MsgUpdateGroupPolicyDecisionPolicy': ['group_id', 'decision_policy'], + '/cosmos.group.v1.MsgUpdateGroupPolicyMetadata': ['group_id', 'metadata'], + '/osmosis.tokenfactory.v1beta1.MsgCreateDenom': ['subdenom'], + '/osmosis.tokenfactory.v1beta1.MsgSetDenomMetadata': ['metadata'], + '/osmosis.tokenfactory.v1beta1.MsgMint': ['mint_to_address', 'amount'], + '/osmosis.tokenfactory.v1beta1.MsgBurn': ['burn_from_address', 'amount'], // Add more message types and their important fields here }; @@ -428,244 +437,293 @@ function VoteDetailsModal({ setTimeout(() => setCopied(false), 2000); }; + const handleExpandMessages = () => { + const messagesModal = document.getElementById('messages_modal') as HTMLDialogElement; + if (messagesModal) { + messagesModal.showModal(); + } + }; + return ( - -
-
- -
-
-
-
-

- #{proposal?.id?.toString() ?? '0'} -

- - {getStatusLabel(proposal)} + <> + +
+
+ +
+
+
+
+

+ #{proposal?.id?.toString() ?? '0'} +

+ + {getStatusLabel(proposal)} + +
+ {userHasVoted && ( +
+ Your vote: + + {userVoteOption !== null ? voteMapping[userVoteOption ?? ''] : null} + +
+ )} +
+
+

TITLE

+

+ {proposal?.title} +

+ + SUBMITTED + + + {new Date(proposal?.submit_time).toDateString().toLocaleString()}
- {userHasVoted && ( -
- Your vote: - - {userVoteOption !== null ? voteMapping[userVoteOption ?? ''] : null} - +
+ {proposal?.summary && ( +
+

SUMMARY

+
+

{proposal?.summary}

+
)} -
-
-

TITLE

-

- {proposal?.title} -

- - SUBMITTED - - - {new Date(proposal?.submit_time).toDateString().toLocaleString()} - -
-
- {proposal?.summary && (
-

SUMMARY

-
-

{proposal?.summary}

+
+

MESSAGES

+
-
- )} -
-

MESSAGES

-
- {proposal?.messages?.map((message: any, index: number) => { - const messageType = message['@type']; - const fieldsToShow = importantFields[messageType] || defaultFields; - - return ( -
-

- {messageType.split('.').pop().replace('Msg', '')} -

-
- {fieldsToShow.map(field => renderMessageField(field, message[field]))} +
+ {proposal?.messages?.map((message: any, index: number) => { + const messageType = message['@type']; + const fieldsToShow = importantFields[messageType] || defaultFields; + + return ( +
+

+ {messageType.split('.').pop().replace('Msg', '')} +

+
+ {fieldsToShow.map(field => renderMessageField(field, message[field]))} +
-
- ); - })} + ); + })} +
-
-
-

- VOTING COUNTDOWN -

- -
-
- -
-
-
-
-
-

TALLY

-
- + +
+
+
-
-

MEMBERS

-
-
- - - - - - - - - - {normalizedMembers?.map((member, index) => { - const memberVote = voteMap[member?.address]; - return ( - - - - - - ); - })} - -
- Address - - Weight - - Vote -
- - {member?.weight} - {optionToVote(memberVote?.toString()) || 'N/A'} -
+
+
+
+

TALLY

+
+
-
-
-

- VOTING COUNTDOWN -

- -
-
- -
-
- {getButtonState.action && ( + +
+
- )} - {proposal?.proposers?.includes(address ?? '') && - proposal?.status !== ('PROPOSAL_STATUS_CLOSED' as unknown as ProposalStatus) && - !proposalClosed && - userHasVoted === false && ( +
+
+ {getButtonState.action && ( )} -
+ {proposal?.proposers?.includes(address ?? '') && + proposal?.status !== ('PROPOSAL_STATUS_CLOSED' as unknown as ProposalStatus) && + !proposalClosed && + userHasVoted === false && ( + + )} +
- { - refetchVotes(); - refetchTally(); - refetchProposals(); - }} - /> + { + refetchVotes(); + refetchTally(); + refetchProposals(); + }} + /> +
-
-
- -
-
+
+ +
+
+ + +
+
+ +
+

Proposal Messages

+
+ {proposal?.messages?.map((message: any, index: number) => { + const messageType = message['@type']; + const fieldsToShow = importantFields[messageType] || defaultFields; + + return ( +
+

+ {messageType.split('.').pop().replace('Msg', '')} +

+
{fieldsToShow.map(field => renderMessageField(field, message[field]))}
+
+ ); + })} +
+
+
+ +
+
+ ); }