11"use client" ;
22
3- import { FormControl , Textarea } from "@chakra-ui/react" ;
4- import { Button } from "chakra/button" ;
5- import { FormErrorMessage , FormLabel } from "chakra/form" ;
63import { PlusIcon } from "lucide-react" ;
74import { useState } from "react" ;
85import { useForm } from "react-hook-form" ;
@@ -11,102 +8,123 @@ import type { ThirdwebContract } from "thirdweb";
118import * as VoteExt from "thirdweb/extensions/vote" ;
129import { useSendAndConfirmTransaction } from "thirdweb/react" ;
1310import { TransactionButton } from "@/components/tx-button" ;
11+ import { Button } from "@/components/ui/button" ;
12+ import {
13+ Form ,
14+ FormControl ,
15+ FormField ,
16+ FormItem ,
17+ FormLabel ,
18+ FormMessage ,
19+ } from "@/components/ui/form" ;
1420import {
1521 Sheet ,
1622 SheetContent ,
1723 SheetHeader ,
1824 SheetTitle ,
1925 SheetTrigger ,
2026} from "@/components/ui/sheet" ;
27+ import { Textarea } from "@/components/ui/textarea" ;
28+ import { parseError } from "@/utils/errorParser" ;
2129
22- interface VoteButtonProps {
23- contract : ThirdwebContract ;
24- isLoggedIn : boolean ;
25- }
26-
27- const PROPOSAL_FORM_ID = "proposal-form-id" ;
28-
29- export const ProposalButton : React . FC < VoteButtonProps > = ( {
30+ export function ProposalButton ( {
3031 contract,
3132 isLoggedIn,
32- } ) => {
33+ } : {
34+ contract : ThirdwebContract ;
35+ isLoggedIn : boolean ;
36+ } ) {
3337 const [ open , setOpen ] = useState ( false ) ;
3438 const sendTx = useSendAndConfirmTransaction ( ) ;
35- const {
36- register,
37- handleSubmit,
38- formState : { errors } ,
39- } = useForm < { description : string } > ( ) ;
39+ const form = useForm < { description : string } > ( {
40+ defaultValues : {
41+ description : "" ,
42+ } ,
43+ } ) ;
44+
45+ async function onSubmit ( data : { description : string } ) {
46+ const tx = VoteExt . propose ( {
47+ calldatas : [ "0x" ] ,
48+ contract,
49+ description : data . description ,
50+ targets : [ contract . address ] ,
51+ values : [ 0n ] ,
52+ } ) ;
53+
54+ await sendTx . mutateAsync ( tx , {
55+ onError : ( error ) => {
56+ toast . error ( "Failed to create proposal" , {
57+ description : parseError ( error ) ,
58+ } ) ;
59+ console . error ( error ) ;
60+ } ,
61+ onSuccess : ( ) => {
62+ toast . success ( "Proposal created successfully" ) ;
63+ setOpen ( false ) ;
64+ } ,
65+ } ) ;
66+ }
4067
4168 return (
4269 < Sheet onOpenChange = { setOpen } open = { open } >
4370 < SheetTrigger asChild >
44- < Button
45- colorScheme = "primary"
46- leftIcon = { < PlusIcon className = "size-5" /> }
47- >
71+ < Button className = "gap-2" size = "sm" >
72+ < PlusIcon className = "size-3.5" />
4873 Create Proposal
4974 </ Button >
5075 </ SheetTrigger >
51- < SheetContent className = "w-full sm:w-[540px] sm: max-w-[90%] lg:w-[700px] " >
76+ < SheetContent className = "! w-full lg:! max-w-lg " >
5277 < SheetHeader >
5378 < SheetTitle > Create new proposal</ SheetTitle >
5479 </ SheetHeader >
55- < form
56- className = "mt-10 flex flex-col gap-6"
57- id = { PROPOSAL_FORM_ID }
58- onSubmit = { handleSubmit ( ( data ) => {
59- const tx = VoteExt . propose ( {
60- calldatas : [ "0x" ] ,
61- contract,
62- description : data . description ,
63- targets : [ contract . address ] ,
64- values : [ 0n ] ,
65- } ) ;
66- toast . promise (
67- sendTx . mutateAsync ( tx , {
68- onError : ( error ) => {
69- console . error ( error ) ;
70- } ,
71- onSuccess : ( ) => {
72- setOpen ( false ) ;
73- } ,
74- } ) ,
75- {
76- error : "Failed to create proposal" ,
77- loading : "Creating proposal..." ,
78- success : "Proposal created successfully" ,
79- } ,
80- ) ;
81- } ) }
82- >
83- < FormControl isInvalid = { ! ! errors . description } isRequired >
84- < FormLabel > Description</ FormLabel >
85- < Textarea { ...register ( "description" ) } />
86- < FormErrorMessage > { errors ?. description ?. message } </ FormErrorMessage >
87- </ FormControl >
88- </ form >
89- < div className = "mt-6 flex flex-row justify-end gap-3" >
90- < Button
91- isDisabled = { sendTx . isPending }
92- onClick = { ( ) => setOpen ( false ) }
93- variant = "outline"
80+ < Form { ...form } >
81+ < form
82+ className = "mt-4 flex flex-col gap-6"
83+ onSubmit = { form . handleSubmit ( onSubmit ) }
9484 >
95- Cancel
96- </ Button >
97- < TransactionButton
98- client = { contract . client }
99- form = { PROPOSAL_FORM_ID }
100- isLoggedIn = { isLoggedIn }
101- isPending = { sendTx . isPending }
102- transactionCount = { 1 }
103- txChainID = { contract . chain . id }
104- type = "submit"
105- >
106- Submit
107- </ TransactionButton >
108- </ div >
85+ < FormField
86+ control = { form . control }
87+ name = "description"
88+ render = { ( { field } ) => (
89+ < FormItem >
90+ < FormLabel > Description</ FormLabel >
91+ < FormControl >
92+ < Textarea
93+ className = "bg-card"
94+ placeholder = "Enter proposal description..."
95+ { ...field }
96+ />
97+ </ FormControl >
98+ < FormMessage />
99+ </ FormItem >
100+ ) }
101+ rules = { {
102+ required : "Description is required" ,
103+ } }
104+ />
105+
106+ < div className = "mt-6 flex flex-row justify-end gap-3" >
107+ < Button
108+ disabled = { sendTx . isPending }
109+ onClick = { ( ) => setOpen ( false ) }
110+ variant = "outline"
111+ >
112+ Cancel
113+ </ Button >
114+ < TransactionButton
115+ client = { contract . client }
116+ isLoggedIn = { isLoggedIn }
117+ isPending = { sendTx . isPending }
118+ transactionCount = { 1 }
119+ txChainID = { contract . chain . id }
120+ type = "submit"
121+ >
122+ Submit
123+ </ TransactionButton >
124+ </ div >
125+ </ form >
126+ </ Form >
109127 </ SheetContent >
110128 </ Sheet >
111129 ) ;
112- } ;
130+ }
0 commit comments