11'use client' ;
22
33import { CheckCircle2 , Link as LinkIcon , XCircle } from 'lucide-react' ;
4- import { Modal } from '@/app/components/ui/modal' ;
5- import { Button } from '@/app/components/ui/button' ;
6- import type { BridgeExecutionState , BridgeStep as BridgeStepType } from '@/app/types/bridge' ;
7- import type { Token } from '@/app/types/token' ;
8- import { BridgeStep , StepState } from '@/app/components/bridge/bridgeTransactionModal/bridgeStep' ;
4+ import { BridgeStep } from '@/app/components/bridge/bridgeTransactionModal/bridgeStep' ;
95import { BridgeSuccessView } from '@/app/components/bridge/bridgeTransactionModal/bridgeSuccessView' ;
10- import { RouteVisual } from '@/app/components/bridge/bridgeTransactionModal/routeVisual' ;
116import { BridgeSummary } from '@/app/components/bridge/bridgeTransactionModal/bridgeSummary' ;
12-
13- type ModalMode = 'pending' | 'success' | 'error' ;
14-
15- type ModalContent = {
16- mode : ModalMode ;
17- headline : string ;
18- subheadline : string ;
19- showLoader : boolean ;
20- shouldAlternateHeadline : boolean ;
21- approveStepState : StepState ;
22- bridgeStepState : StepState ;
23- } ;
24-
25- type ModalContext = {
26- tokenSymbol : string ;
27- amount : string ;
28- fromChainName : string ;
29- toChainName : string ;
30- needsApproval : boolean ;
31- } ;
7+ import { BridgeRoute } from '@/app/components/bridge/bridgeTransactionModal/bridgeRoute' ;
8+ import { resolveBridgeTransactionModalContent } from '@/app/components/bridge/bridgeTransactionModal/bridgeTransactionModalContent' ;
9+ import { Button } from '@/app/components/ui/button' ;
10+ import { Modal } from '@/app/components/ui/modal' ;
11+ import { cn } from '@/app/utils/common' ;
12+ import type { BridgeExecutionState } from '@/app/types/bridge' ;
13+ import type { Token } from '@/app/types/token' ;
3214
3315const ALTERNATE_HEADLINE = 'Do not refresh page' ;
3416
35- const getStepState = (
36- step : 'approve' | 'bridge' ,
37- currentStep : BridgeStepType ,
38- hasApprovalTx : boolean ,
39- hasBridgeTx : boolean ,
40- ) : StepState => {
41- if ( step === 'approve' ) {
42- if ( currentStep === 'approving' ) return 'pending' ;
43- if ( currentStep === 'error' && hasApprovalTx && ! hasBridgeTx ) return 'error' ;
44- if ( hasApprovalTx ) return 'success' ;
45- return 'idle' ;
46- }
47- if ( currentStep === 'bridging' ) return 'pending' ;
48- if ( currentStep === 'success' ) return 'success' ;
49- if ( currentStep === 'error' && hasBridgeTx ) return 'error' ;
50- return 'idle' ;
51- } ;
52-
53- const formatErrorMessage = ( message ?: string ) : string => {
54- if ( ! message ) return 'Something went wrong. Please try again.' ;
55- const normalized = message . toLowerCase ( ) ;
56- if ( normalized . includes ( 'user rejected' ) || normalized . includes ( 'rejected the request' ) ) {
57- return 'You rejected the request.' ;
58- }
59- return 'Something went wrong. Please try again.' ;
60- } ;
61-
62- const resolveModalContent = ( state : BridgeExecutionState , context : ModalContext ) : ModalContent => {
63- const { tokenSymbol, amount, fromChainName, toChainName } = context ;
64- const { currentStep, isExecuting, approvalTxHash, bridgeTxHash, error } = state ;
65-
66- const hasApprovalTx = Boolean ( approvalTxHash ) ;
67- const hasBridgeTx = Boolean ( bridgeTxHash ) ;
68- const hasSubmittedTx = hasApprovalTx || hasBridgeTx ;
69-
70- const approveStepState = getStepState ( 'approve' , currentStep , hasApprovalTx , hasBridgeTx ) ;
71- const bridgeStepState = getStepState ( 'bridge' , currentStep , hasApprovalTx , hasBridgeTx ) ;
72-
73- if ( currentStep === 'success' ) {
74- return {
75- mode : 'success' ,
76- headline : 'Transaction successful' ,
77- subheadline : 'Your assets are on the way.' ,
78- showLoader : false ,
79- shouldAlternateHeadline : false ,
80- approveStepState,
81- bridgeStepState,
82- } ;
83- }
84-
85- if ( currentStep === 'error' ) {
86- return {
87- mode : 'error' ,
88- headline : 'Transaction failed' ,
89- subheadline : formatErrorMessage ( error ?. message ) ,
90- showLoader : false ,
91- shouldAlternateHeadline : false ,
92- approveStepState,
93- bridgeStepState,
94- } ;
95- }
96-
97- const bridgingDescription = `Bridging ${ amount } ${ tokenSymbol } from ${ fromChainName } to ${ toChainName } .` ;
98- const isAwaitingConfirmation = isExecuting && hasSubmittedTx ;
99-
100- if ( currentStep === 'approving' ) {
101- return {
102- mode : 'pending' ,
103- headline : `Approve ${ tokenSymbol } ` ,
104- subheadline : bridgingDescription ,
105- showLoader : true ,
106- shouldAlternateHeadline : isAwaitingConfirmation ,
107- approveStepState,
108- bridgeStepState,
109- } ;
110- }
111-
112- if ( currentStep === 'bridging' ) {
113- return {
114- mode : 'pending' ,
115- headline : 'Bridging assets' ,
116- subheadline : bridgingDescription ,
117- showLoader : true ,
118- shouldAlternateHeadline : isAwaitingConfirmation ,
119- approveStepState,
120- bridgeStepState,
121- } ;
122- }
123-
124- return {
125- mode : 'pending' ,
126- headline : 'Confirm in wallet' ,
127- subheadline : bridgingDescription ,
128- showLoader : true ,
129- shouldAlternateHeadline : false ,
130- approveStepState,
131- bridgeStepState,
132- } ;
133- } ;
134-
13517interface BridgeTransactionModalProps {
13618 open : boolean ;
13719 onClose : ( ) => void ;
@@ -159,18 +41,17 @@ export const BridgeTransactionModal = ({
15941 needsApproval,
16042 explorerUrl,
16143} : BridgeTransactionModalProps ) => {
162- const content = resolveModalContent ( state , {
44+ const content = resolveBridgeTransactionModalContent ( state , {
16345 tokenSymbol : token . symbol ,
16446 amount,
16547 fromChainName,
16648 toChainName,
167- needsApproval,
16849 } ) ;
16950
170- const isPending = state . isExecuting ;
51+ const isExecuting = state . isExecuting ;
17152
17253 const handleClose = ( ) => {
173- if ( isPending ) return ;
54+ if ( isExecuting ) return ;
17455 onClose ( ) ;
17556 } ;
17657
@@ -179,21 +60,22 @@ export const BridgeTransactionModal = ({
17960 open = { open }
18061 onClose = { handleClose }
18162 title = "Bridge assets"
182- showCloseButton = { ! isPending }
183- dismissible = { ! isPending }
63+ showCloseButton = { ! isExecuting }
64+ dismissible = { ! isExecuting }
18465 contentClassName = "space-y-6"
18566 >
18667 < div className = "space-y-4 text-center" >
18768 { content . mode === 'success' || content . mode === 'error' ? (
18869 < div
189- className = { `mx-auto flex size-14 items-center justify-center rounded-full ${
190- content . mode === 'success' ? 'bg-green-light text-green' : 'bg-red-light text-red'
191- } `}
70+ className = { cn (
71+ 'mx-auto flex size-14 items-center justify-center rounded-full' ,
72+ content . mode === 'success' ? 'bg-green-light text-green' : 'bg-red-light text-red' ,
73+ ) }
19274 >
19375 { content . mode === 'success' ? < CheckCircle2 className = "size-7" /> : < XCircle className = "size-7" /> }
19476 </ div >
19577 ) : (
196- < RouteVisual
78+ < BridgeRoute
19779 fromChainIcon = { fromChainIcon }
19880 toChainIcon = { toChainIcon }
19981 fromChainName = { fromChainName }
@@ -234,7 +116,7 @@ export const BridgeTransactionModal = ({
234116 />
235117 ) }
236118 { content . mode === 'error' && (
237- < div className = "space-y-4 text-center" >
119+ < div className = "space-y-3 text-center" >
238120 { state . error ?. txHash && explorerUrl && (
239121 < a
240122 href = { `${ explorerUrl } /tx/${ state . error . txHash } ` }
0 commit comments