1+ "use client" ;
2+
13import React from "react" ;
24import Image from "next/image" ;
35import { AddressWithContact } from "./AddressWithContact" ;
46import { getExpandedHeaderText } from "./utils" ;
5- import { TxType , getTokenByAddress } from "@polypay/shared" ;
6- import { TransactionRowData , VoteStatus , useNetworkTokens } from "~~/hooks" ;
7+ import { TxType , ZERO_ADDRESS , formatTokenAmount , getTokenByAddress } from "@polypay/shared" ;
8+ import { Contact } from "@polypay/shared" ;
9+ import { BatchContactEntry } from "~~/components/modals/CreateBatchFromContactsModal" ;
10+ import { modalManager } from "~~/components/modals/ModalLayout" ;
11+ import { BatchTransfer , TransactionRowData , VoteStatus , useNetworkTokens } from "~~/hooks" ;
12+ import { useAccountStore } from "~~/services/store" ;
713import { formatAddress , formatAmount } from "~~/utils/format" ;
814
915interface TxHeaderProps {
@@ -14,6 +20,7 @@ interface TxHeaderProps {
1420 loading : boolean ;
1521 initiatorName ?: string ;
1622 initiatorCommitment : string ;
23+ batchData ?: BatchTransfer [ ] ;
1724}
1825
1926function SignerBadgeList ( { signerData } : { signerData : TransactionRowData [ "signerData" ] } ) {
@@ -56,46 +63,92 @@ export function TxHeader({
5663 loading,
5764 initiatorCommitment,
5865 initiatorName,
66+ batchData,
5967} : TxHeaderProps ) {
6068 const headerText = getExpandedHeaderText ( tx . type ) ;
6169 const shortCommitment = formatAddress ( initiatorCommitment , { start : 4 , end : 4 } ) ;
6270 const { chainId } = useNetworkTokens ( ) ;
71+ const { currentAccount } = useAccountStore ( ) ;
72+
73+ const handleDuplicate = ( ) => {
74+ if ( ! batchData ) return ;
75+
76+ const initialBatchItems : BatchContactEntry [ ] = batchData . map ( transfer => {
77+ const token = getTokenByAddress ( transfer . tokenAddress , chainId ) ;
78+ const amount = formatTokenAmount ( transfer . amount , token . decimals ) ;
79+
80+ const contact : Contact = {
81+ id : crypto . randomUUID ( ) ,
82+ name : transfer . contactName || formatAddress ( transfer . recipient , { start : 6 , end : 4 } ) ,
83+ address : transfer . recipient ,
84+ accountId : "" ,
85+ groups : [ ] ,
86+ createdAt : "" ,
87+ updatedAt : "" ,
88+ } as Contact ;
89+
90+ return {
91+ contact,
92+ amount,
93+ tokenAddress : transfer . tokenAddress || ZERO_ADDRESS ,
94+ isSynthetic : true ,
95+ } ;
96+ } ) ;
97+
98+ modalManager . openModal ?.( "createBatchFromContacts" , {
99+ accountId : currentAccount ?. id ,
100+ initialBatchItems,
101+ } ) ;
102+ } ;
63103
64104 const renderHeaderRow = ( ) => (
65105 < div className = "flex items-center justify-between mb-4" >
66106 < div className = "text-lg font-semibold" >
67107 { tx . type === TxType . BATCH ? (
68- < span > { tx . batchData ?. length ?? 0 } transactions </ span >
108+ < span > { tx . batchData ?. length ?? 0 } Transactions </ span >
69109 ) : (
70110 < span >
71111 { headerText } { initiatorName ? `${ initiatorName } (${ shortCommitment } )` : shortCommitment }
72112 </ span >
73113 ) }
74114 </ div >
75- { myVoteStatus === null && (
76- < div className = "flex items-center gap-2" >
77- < button
78- onClick = { e => {
79- e . stopPropagation ( ) ;
80- onDeny ( ) ;
81- } }
82- disabled = { loading }
83- className = "px-6 py-2 text-sm font-medium text-main-black bg-white rounded-full hover:bg-gray-100 transition-colors cursor-pointer disabled:opacity-50"
84- >
85- Deny
86- </ button >
115+ < div className = "flex items-center gap-2" >
116+ { tx . type === TxType . BATCH && batchData && (
87117 < button
88118 onClick = { e => {
89119 e . stopPropagation ( ) ;
90- onApprove ( ) ;
120+ handleDuplicate ( ) ;
91121 } }
92- disabled = { loading }
93- className = "px-6 py-2 text-sm font-medium text-main-black bg-pink-350 rounded-full hover:bg-pink-450 transition-colors cursor-pointer disabled:opacity-50"
122+ className = "bg-grey-100 rounded-lg px-6 h-7 text-sm font-medium text-main-black cursor-pointer hover:bg-grey-200 transition-colors"
94123 >
95- { loading ? "Processing..." : "Approve" }
124+ Duplicate
96125 </ button >
97- </ div >
98- ) }
126+ ) }
127+ { myVoteStatus === null && (
128+ < >
129+ < button
130+ onClick = { e => {
131+ e . stopPropagation ( ) ;
132+ onDeny ( ) ;
133+ } }
134+ disabled = { loading }
135+ className = "px-6 py-2 text-sm font-medium text-main-black bg-white rounded-full hover:bg-gray-100 transition-colors cursor-pointer disabled:opacity-50"
136+ >
137+ Deny
138+ </ button >
139+ < button
140+ onClick = { e => {
141+ e . stopPropagation ( ) ;
142+ onApprove ( ) ;
143+ } }
144+ disabled = { loading }
145+ className = "px-6 py-2 text-sm font-medium text-main-black bg-pink-350 rounded-full hover:bg-pink-450 transition-colors cursor-pointer disabled:opacity-50"
146+ >
147+ { loading ? "Processing..." : "Approve" }
148+ </ button >
149+ </ >
150+ ) }
151+ </ div >
99152 </ div >
100153 ) ;
101154
0 commit comments