1- import { FC , useState } from 'react' ;
1+ import { FC , useEffect , useMemo , useState } from 'react' ;
22import { Typography , Box , TextField , Stack , Paper } from '@mui/material' ;
33import Card from '@mui/material/Card' ;
44import CardContent from '@mui/material/CardContent' ;
55import LoadingButton from '@mui/lab/LoadingButton' ;
6+ import { useDispatch } from 'react-redux' ;
7+ import { openLoginModal } from '@redux/auth' ;
8+ import { useAuth } from '@src/hooks/use-auth.ts' ;
9+ import { useTransfer } from '@src/hooks/protocol/use-transfer.ts' ;
610import { Post } from '@src/graphql/generated/graphql.ts' ;
11+ import { notifyError , notifySuccess } from '@src/libs/notifications/internal-notifications.ts' ;
12+ import { ERRORS } from '@src/libs/notifications/errors.ts' ;
13+ import { SUCCESS } from '@src/libs/notifications/success.ts' ;
14+ import { GetTipsByBakerForPostDocument , useCreateTipMutation } from '@src/graphql/generated/hooks.tsx' ;
715
816const tipOptions = [
917 { value : '10' , title : '10' , subtitle : 'A token of appreciation' } ,
@@ -12,22 +20,75 @@ const tipOptions = [
1220] ;
1321
1422export const LeaveTipCard : FC < { post : Post } > = ( { post } ) => {
23+ const dispatch = useDispatch ( ) ;
24+ const { session } = useAuth ( ) ;
25+ const { transfer, loading : transferLoading , error } = useTransfer ( ) ;
26+ const [ createTip ] = useCreateTipMutation ( ) ;
27+
1528 const [ selectedTip , setSelectedTip ] = useState ( '10' ) ;
1629 const [ customTip , setCustomTip ] = useState ( '' ) ;
17- const [ successMessage , setSuccessMessage ] = useState ( false ) ;
30+
31+ useEffect ( ( ) => {
32+ if ( error ) {
33+ notifyError ( error as ERRORS ) ;
34+ }
35+ } , [ error ] ) ;
36+
37+ const amount = useMemo ( ( ) => {
38+ // Si hay custom, usa custom. Sino, usa el seleccionado.
39+ const raw = selectedTip ? selectedTip : customTip ;
40+ const parsed = Number ( raw ) ;
41+ // Evita NaN o negativos
42+ return Number . isFinite ( parsed ) && parsed > 0 ? parsed : 0 ;
43+ } , [ selectedTip , customTip ] ) ;
44+
45+ const recipient = post ?. author ?. address ?? '' ;
1846
1947 const handleTipChange = ( value : string ) => {
2048 setSelectedTip ( value ) ;
2149 setCustomTip ( '' ) ;
22- setSuccessMessage ( false ) ;
2350 } ;
2451
2552 const handleCustomTipChange = ( event : React . ChangeEvent < HTMLInputElement > ) => {
2653 setSelectedTip ( '' ) ;
2754 setCustomTip ( event . target . value ) ;
28- setSuccessMessage ( false ) ;
2955 } ;
3056
57+ const handleSendTip = async ( ) => {
58+ if ( ! session ?. authenticated ) return dispatch ( openLoginModal ( ) ) ;
59+ if ( ! recipient || amount <= 0 ) return ;
60+
61+ try {
62+ const pTransfer = transfer ( { amount, recipient } ) ;
63+
64+ const pCreateTip = pTransfer . then ( ( ) =>
65+ createTip ( {
66+ variables : {
67+ input : {
68+ postId : post . id ,
69+ creator : recipient ,
70+ amount,
71+ txHash : null ,
72+ message : 'tip' ,
73+ } ,
74+ } ,
75+ refetchQueries : [
76+ { query : GetTipsByBakerForPostDocument , variables : { postId : post . id } } ,
77+ ] ,
78+ awaitRefetchQueries : true ,
79+ } )
80+ ) ;
81+
82+ await Promise . all ( [ pTransfer , pCreateTip ] ) ;
83+
84+ notifySuccess ( SUCCESS . TIP_CREATED_SUCCESSFULLY ) ;
85+ } catch ( e ) {
86+ console . error ( 'Transfer error:' , e ) ;
87+ }
88+ } ;
89+
90+ const isDisabled = transferLoading || amount <= 0 || ! recipient ;
91+
3192 return (
3293 < Card sx = { { width : '100%' , maxWidth : { lg : 400 } , margin : 'auto' , backgroundColor : '#2B2D31' } } >
3394 < CardContent >
@@ -37,6 +98,7 @@ export const LeaveTipCard: FC<{ post: Post }> = ({ post }) => {
3798 < Typography variant = "body2" color = "textSecondary" sx = { { mb : 3 } } >
3899 Choose an amount to leave a tip and support the content you love.
39100 </ Typography >
101+
40102 < Stack spacing = { 2 } >
41103 < Stack spacing = { 2 } direction = "row" >
42104 { tipOptions . map ( ( option ) => (
@@ -56,56 +118,39 @@ export const LeaveTipCard: FC<{ post: Post }> = ({ post }) => {
56118 '&:hover' : { opacity : 1 } ,
57119 } }
58120 >
59- < Typography variant = "body1" fontWeight = "bold" align = { ' center' } >
121+ < Typography variant = "body1" fontWeight = "bold" align = " center" >
60122 { option . title }
61123 </ Typography >
62- < Typography
63- variant = "subtitle2"
64- align = { 'center' }
65- style = { {
66- color : 'text.secondary' ,
67- fontSize : '0.7rem' ,
68- } }
69- >
124+ < Typography variant = "subtitle2" align = "center" sx = { { fontSize : '0.7rem' } } >
70125 MMC
71126 </ Typography >
72127 </ Paper >
73128 ) ) }
74129 </ Stack >
130+
75131 < Box >
76132 < TextField
77133 type = "number"
78134 placeholder = "Enter custom tip in MMC"
79135 fullWidth
80136 value = { customTip }
81137 onChange = { handleCustomTipChange }
82- InputProps = { {
83- inputProps : { min : 1 } ,
84- } }
138+ InputProps = { { inputProps : { min : 1 } } }
85139 />
86140 </ Box >
87141 </ Stack >
88142
89143 < Stack direction = "row" justifyContent = "center" sx = { { mt : 4 } } >
90144 < LoadingButton
91145 variant = "contained"
92- disabled = { true }
93146 sx = { { width : '100%' , py : 1.5 } }
94- loading = { false }
147+ loading = { transferLoading }
148+ disabled = { isDisabled }
149+ onClick = { handleSendTip }
95150 >
96151 Leave a Tip
97152 </ LoadingButton >
98153 </ Stack >
99-
100- < Typography variant = "body2" color = "text.secondary" align = "center" sx = { { mt : 2 } } >
101- This feature is coming in the next release!
102- </ Typography >
103-
104- { successMessage && (
105- < Typography variant = "body2" color = "success.main" align = "center" sx = { { mt : 2 } } >
106- Tip sent successfully! Thank you for your support.
107- </ Typography >
108- ) }
109154 </ CardContent >
110155 </ Card >
111156 ) ;
0 commit comments