@@ -4,13 +4,14 @@ import { Suspense, useCallback, useEffect, useMemo, useState } from "react";
44import Image from "next/image" ;
55import { useRouter , useSearchParams } from "next/navigation" ;
66import { useParams } from "next/navigation" ;
7- import { Hex , decodeAbiParameters , formatUnits } from "viem" ;
7+ import { Hex , decodeAbiParameters , formatUnits , keccak256 , stringToHex } from "viem" ;
88import { useAccount } from "wagmi" ;
99import { useMiniapp } from "~~/components/MiniappProvider" ;
1010import FcAddressRating from "~~/components/marketplace/FcAddressRating" ;
1111import { PayButton } from "~~/components/marketplace/PayButton" ;
1212import { Address } from "~~/components/scaffold-eth/Address/Address" ;
1313import { useScaffoldReadContract } from "~~/hooks/scaffold-eth/useScaffoldReadContract" ;
14+ import { useScaffoldWriteContract } from "~~/hooks/scaffold-eth/useScaffoldWriteContract" ;
1415import { resolveIpfsUrl } from "~~/services/ipfs/fetch" ;
1516
1617const ListingDetailsPageInner = ( ) => {
@@ -20,9 +21,12 @@ const ListingDetailsPageInner = () => {
2021 const [ data , setData ] = useState < any | null > ( null ) ;
2122 const [ indexed , setIndexed ] = useState < any | null > ( null ) ;
2223 const [ lightboxOpen , setLightboxOpen ] = useState < boolean > ( false ) ;
24+ const [ deleting , setDeleting ] = useState ( false ) ;
25+ const [ showDeleteModal , setShowDeleteModal ] = useState ( false ) ;
2326 const { composeCast, isMiniApp } = useMiniapp ( ) ;
2427 const idNum = useMemo ( ( ) => ( params ?. id ? BigInt ( params . id ) : undefined ) , [ params ?. id ] ) ;
25- useAccount ( ) ;
28+ const { address : connectedAddress } = useAccount ( ) ;
29+ const { writeContractAsync : writeMarketplace } = useScaffoldWriteContract ( { contractName : "Marketplace" } ) ;
2630
2731 const { data : ptr } = useScaffoldReadContract ( {
2832 contractName : "Marketplace" ,
@@ -131,6 +135,48 @@ const ListingDetailsPageInner = () => {
131135 const active = data ?. decoded ?. active ?? indexed ?. active ?? true ;
132136 const seller = data ?. pointer ?. creator || indexed ?. creator || undefined ;
133137
138+ const isCreator = useMemo ( ( ) => {
139+ if ( ! connectedAddress || ! seller ) return false ;
140+ return connectedAddress . toLowerCase ( ) === seller . toLowerCase ( ) ;
141+ } , [ connectedAddress , seller ] ) ;
142+
143+ const handleDelete = useCallback ( ( ) => {
144+ setShowDeleteModal ( true ) ;
145+ } , [ ] ) ;
146+
147+ const confirmDelete = useCallback ( async ( ) => {
148+ if ( idNum === undefined ) {
149+ return ;
150+ }
151+
152+ setShowDeleteModal ( false ) ;
153+ setDeleting ( true ) ;
154+ try {
155+ // Call the close action to deactivate the listing instead of deleting it
156+ const sigHash = keccak256 ( stringToHex ( "close(uint256,address,bool,address,bytes)" ) ) ;
157+ const selector = `0x${ sigHash . slice ( 2 , 10 ) } ` as `0x${string } `;
158+ const action = ( selector + "0" . repeat ( 64 - 8 ) ) as `0x${string } `;
159+
160+ await writeMarketplace ( {
161+ functionName : "callAction" ,
162+ args : [ idNum , action , "0x" ] ,
163+ } ) ;
164+ router . push ( "/" ) ;
165+ } catch ( error ) {
166+ console . error ( "Error closing listing:" , error ) ;
167+ alert ( "Failed to close listing. Please try again." ) ;
168+ setDeleting ( false ) ;
169+ }
170+ } , [ idNum , writeMarketplace , router ] ) ;
171+
172+ const handleOpenEdit = useCallback ( ( ) => {
173+ const idStr = params ?. id ;
174+ if ( ! idStr ) return ;
175+ const base = `/listing/new?edit=${ encodeURIComponent ( idStr ) } ` ;
176+ const from = indexed ?. locationId ;
177+ router . push ( from ? `${ base } &loc=${ encodeURIComponent ( from ) } ` : base ) ;
178+ } , [ params ?. id , indexed ?. locationId , router ] ) ;
179+
134180 const tags = useMemo ( ( ) => {
135181 const raw = ( data ?. tags ?? ( indexed as any ) ?. tags ) as unknown ;
136182 if ( ! raw ) return [ ] as string [ ] ;
@@ -251,7 +297,28 @@ const ListingDetailsPageInner = () => {
251297 Share
252298 </ button >
253299 ) : null }
254- < div className = { `badge ${ active ? "badge-success" : "" } ml-auto` } > { active ? "Active" : "Sold" } </ div >
300+ < div className = "flex items-center gap-2 ml-auto" >
301+ < div className = { `badge ${ active ? "badge-success" : "" } ` } > { active ? "Active" : "Sold" } </ div >
302+ { isCreator && (
303+ < div className = "dropdown dropdown-end" >
304+ < div tabIndex = { 0 } role = "button" className = "btn btn-ghost btn-sm text-lg" >
305+ ⋯
306+ </ div >
307+ < ul tabIndex = { 0 } className = "dropdown-content menu bg-base-100 rounded-box z-[1] w-32 p-2 shadow" >
308+ < li >
309+ < button onClick = { handleOpenEdit } className = "w-full text-left" >
310+ Edit
311+ </ button >
312+ </ li >
313+ < li >
314+ < button onClick = { handleDelete } disabled = { deleting } className = "w-full text-left text-error" >
315+ { deleting ? "Deleting..." : "Delete" }
316+ </ button >
317+ </ li >
318+ </ ul >
319+ </ div >
320+ ) }
321+ </ div >
255322 </ div >
256323
257324 < div className = "flex items-center mb-0" >
@@ -372,6 +439,23 @@ const ListingDetailsPageInner = () => {
372439 </ div >
373440 </ div >
374441 ) : null }
442+
443+ { showDeleteModal && (
444+ < div className = "modal modal-open" onClick = { ( ) => setShowDeleteModal ( false ) } >
445+ < div className = "modal-box" onClick = { e => e . stopPropagation ( ) } >
446+ < h3 className = "font-bold text-lg" > Delete Listing</ h3 >
447+ < p className = "py-4" > Are you sure you want to delete this listing? This action cannot be undone.</ p >
448+ < div className = "modal-action" >
449+ < button className = "btn btn-secondary" onClick = { ( ) => setShowDeleteModal ( false ) } disabled = { deleting } >
450+ Cancel
451+ </ button >
452+ < button className = "btn btn-error" onClick = { confirmDelete } disabled = { deleting } >
453+ { deleting ? "Deleting..." : "Delete" }
454+ </ button >
455+ </ div >
456+ </ div >
457+ </ div >
458+ ) }
375459 </ div >
376460 ) ;
377461} ;
0 commit comments