Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
sweepstake
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Arjun Jhukal
sweepstake
Commits
e3f1ecba
Commit
e3f1ecba
authored
Mar 26, 2026
by
Arjun Jhukal
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
minor changes
parent
a15facb5
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
87 additions
and
11 deletions
+87
-11
PaymentModal.tsx
src/components/molecules/PaymentModal.tsx
+55
-7
index.tsx
src/components/pages/auth/register/index.tsx
+31
-3
auth.ts
src/types/auth.ts
+1
-1
No files found.
src/components/molecules/PaymentModal.tsx
View file @
e3f1ecba
...
@@ -37,6 +37,12 @@ export interface PaymentModalProps {
...
@@ -37,6 +37,12 @@ export interface PaymentModalProps {
successMessage
?:
string
;
successMessage
?:
string
;
/**
/**
* HTTP path segments / URLs that indicate the provider redirected to app success route
* Useful for redirect flows like Acuity /login on success.
*/
successRedirectPaths
?:
string
[];
/**
* Title shown while loading
* Title shown while loading
*/
*/
title
?:
string
;
title
?:
string
;
...
@@ -97,6 +103,7 @@ export default function PaymentModal({
...
@@ -97,6 +103,7 @@ export default function PaymentModal({
onSuccess
,
onSuccess
,
onError
,
onError
,
successMessage
=
'success'
,
successMessage
=
'success'
,
successRedirectPaths
=
[
'/login'
,
'/success'
],
title
=
'Processing Payment'
,
title
=
'Processing Payment'
,
maxWidth
=
'sm'
,
maxWidth
=
'sm'
,
height
=
600
height
=
600
...
@@ -104,19 +111,55 @@ export default function PaymentModal({
...
@@ -104,19 +111,55 @@ export default function PaymentModal({
const
iframeRef
=
useRef
<
HTMLIFrameElement
>
(
null
);
const
iframeRef
=
useRef
<
HTMLIFrameElement
>
(
null
);
const
[
isLoading
,
setIsLoading
]
=
useState
(
true
);
const
[
isLoading
,
setIsLoading
]
=
useState
(
true
);
const
[
error
,
setError
]
=
useState
<
PaymentError
|
null
>
(
null
);
const
[
error
,
setError
]
=
useState
<
PaymentError
|
null
>
(
null
);
const
[
hasDetectedSuccess
,
setHasDetectedSuccess
]
=
useState
(
false
);
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
!
isOpen
)
{
if
(
!
isOpen
)
{
setIsLoading
(
true
);
setIsLoading
(
true
);
setError
(
null
);
setError
(
null
);
setHasDetectedSuccess
(
false
);
return
;
return
;
}
}
const
checkRedirectSuccess
=
():
void
=>
{
if
(
hasDetectedSuccess
||
!
iframeRef
.
current
?.
contentWindow
)
return
;
try
{
const
currentUrl
=
iframeRef
.
current
.
contentWindow
.
location
.
href
;
if
(
!
currentUrl
)
return
;
const
normalized
=
currentUrl
.
toLowerCase
();
const
found
=
successRedirectPaths
.
some
((
pattern
)
=>
{
const
normalizedPattern
=
pattern
.
toLowerCase
();
if
(
normalizedPattern
.
startsWith
(
'http://'
)
||
normalizedPattern
.
startsWith
(
'https://'
))
{
return
normalized
===
normalizedPattern
;
}
return
normalized
.
includes
(
normalizedPattern
);
});
if
(
found
)
{
console
.
log
(
'[PaymentModal] Detected success redirect URL:'
,
currentUrl
);
setHasDetectedSuccess
(
true
);
setIsLoading
(
false
);
onSuccess
?.();
setTimeout
(()
=>
onClose
(),
300
);
}
}
catch
{
// cross-origin iframe URL access will throw during external provider flow, ignore until same-origin
}
};
const
handleMessage
=
(
event
:
MessageEvent
):
void
=>
{
const
handleMessage
=
(
event
:
MessageEvent
):
void
=>
{
try
{
try
{
// Security: Verify message origin
// Ignore messages from React DevTools and other injected frames
if
(
event
.
source
!==
iframeRef
.
current
?.
contentWindow
)
{
console
.
debug
(
'[PaymentModal] Ignoring message from non-iframe source'
,
event
.
origin
);
return
;
}
// Security: Verify message origin; allow provider origin and same-host fallback
const
paymentOrigin
=
new
URL
(
url
).
origin
;
const
paymentOrigin
=
new
URL
(
url
).
origin
;
if
(
event
.
origin
!==
paymentOrigin
)
{
const
trustedOrigins
=
new
Set
([
paymentOrigin
,
window
.
location
.
origin
]);
if
(
!
trustedOrigins
.
has
(
event
.
origin
))
{
console
.
warn
(
console
.
warn
(
`[PaymentModal] Ignoring message from untrusted origin:
${
event
.
origin
}
`
`[PaymentModal] Ignoring message from untrusted origin:
${
event
.
origin
}
`
);
);
...
@@ -144,6 +187,8 @@ export default function PaymentModal({
...
@@ -144,6 +187,8 @@ export default function PaymentModal({
if
(
isSuccess
)
{
if
(
isSuccess
)
{
console
.
log
(
'[PaymentModal] Payment successful! Closing modal...'
);
console
.
log
(
'[PaymentModal] Payment successful! Closing modal...'
);
setHasDetectedSuccess
(
true
);
setIsLoading
(
false
);
onSuccess
?.();
onSuccess
?.();
setTimeout
(()
=>
onClose
(),
500
);
// Small delay for animation
setTimeout
(()
=>
onClose
(),
500
);
// Small delay for animation
return
;
return
;
...
@@ -165,16 +210,17 @@ export default function PaymentModal({
...
@@ -165,16 +210,17 @@ export default function PaymentModal({
setError
(
paymentError
);
setError
(
paymentError
);
onError
?.(
paymentError
);
onError
?.(
paymentError
);
}
}
}
catch
(
error
)
{
}
catch
{
console
.
error
(
'[PaymentModal] Error handling message:
'
,
error
);
console
.
error
(
'[PaymentModal] Error handling message:
unknown error'
);
}
}
};
};
// Add message listener
const
redirectInterval
=
window
.
setInterval
(
checkRedirectSuccess
,
450
);
window
.
addEventListener
(
'message'
,
handleMessage
);
window
.
addEventListener
(
'message'
,
handleMessage
);
// Notify iframe that parent is ready (for some providers)
// Notify iframe that parent is ready (for some providers)
setTimeout
(()
=>
{
const
readyTimeout
=
window
.
setTimeout
(()
=>
{
if
(
iframeRef
.
current
?.
contentWindow
)
{
if
(
iframeRef
.
current
?.
contentWindow
)
{
iframeRef
.
current
.
contentWindow
.
postMessage
(
iframeRef
.
current
.
contentWindow
.
postMessage
(
{
type
:
'parent:ready'
},
{
type
:
'parent:ready'
},
...
@@ -184,9 +230,11 @@ export default function PaymentModal({
...
@@ -184,9 +230,11 @@ export default function PaymentModal({
},
1000
);
},
1000
);
return
()
=>
{
return
()
=>
{
window
.
clearInterval
(
redirectInterval
);
window
.
clearTimeout
(
readyTimeout
);
window
.
removeEventListener
(
'message'
,
handleMessage
);
window
.
removeEventListener
(
'message'
,
handleMessage
);
};
};
},
[
isOpen
,
url
,
onClose
,
onSuccess
,
onError
,
successMessage
]);
},
[
isOpen
,
url
,
onClose
,
onSuccess
,
onError
,
successMessage
,
successRedirectPaths
,
hasDetectedSuccess
]);
const
handleIframeLoad
=
():
void
=>
{
const
handleIframeLoad
=
():
void
=>
{
console
.
log
(
'[PaymentModal] iframe loaded'
);
console
.
log
(
'[PaymentModal] iframe loaded'
);
...
...
src/components/pages/auth/register/index.tsx
View file @
e3f1ecba
'use client'
;
'use client'
;
import
PasswordField
from
'@/components/molecules/PasswordField'
;
import
PasswordField
from
'@/components/molecules/PasswordField'
;
import
PaymentModal
from
'@/components/molecules/PaymentModal'
;
import
{
US_STATES
}
from
'@/constants/state'
;
import
{
US_STATES
}
from
'@/constants/state'
;
import
{
useAppDispatch
}
from
'@/hooks/hook'
;
import
{
useAppDispatch
}
from
'@/hooks/hook'
;
import
{
PATH
}
from
'@/routes/PATH'
;
import
{
PATH
}
from
'@/routes/PATH'
;
...
@@ -14,6 +15,8 @@ import { ArrowLeft } from '@wandersonalwes/iconsax-react';
...
@@ -14,6 +15,8 @@ import { ArrowLeft } from '@wandersonalwes/iconsax-react';
import
dayjs
,
{
Dayjs
}
from
'dayjs'
;
import
dayjs
,
{
Dayjs
}
from
'dayjs'
;
import
{
useFormik
}
from
'formik'
;
import
{
useFormik
}
from
'formik'
;
import
Link
from
'next/link'
;
import
Link
from
'next/link'
;
import
{
useRouter
}
from
'next/navigation'
;
import
{
useState
}
from
'react'
;
import
*
as
Yup
from
'yup'
;
import
*
as
Yup
from
'yup'
;
import
AuthMessageBlock
from
'../authMessageBlock'
;
import
AuthMessageBlock
from
'../authMessageBlock'
;
...
@@ -104,6 +107,9 @@ const validationSchema = Yup.object().shape({
...
@@ -104,6 +107,9 @@ const validationSchema = Yup.object().shape({
export
default
function
RegisterPage
()
{
export
default
function
RegisterPage
()
{
const
[
registerUser
,
{
isLoading
}]
=
useRegisterUserMutation
();
const
[
registerUser
,
{
isLoading
}]
=
useRegisterUserMutation
();
const
dispatch
=
useAppDispatch
();
const
dispatch
=
useAppDispatch
();
const
[
isAcuityModalOpen
,
setIsAcuityModalOpen
]
=
useState
(
false
);
const
[
acuityUrl
,
setAcuityUrl
]
=
useState
(
''
);
const
route
=
useRouter
();
const
initialValues
=
{
const
initialValues
=
{
first_name
:
''
,
first_name
:
''
,
middle_name
:
''
,
middle_name
:
''
,
...
@@ -157,9 +163,12 @@ export default function RegisterPage() {
...
@@ -157,9 +163,12 @@ export default function RegisterPage() {
autoTime
:
true
,
autoTime
:
true
,
}),
}),
);
);
console
.
log
(
"Register response:"
,
response
?.
data
?.
redirect_url
);
console
.
log
(
"Register response:"
,
response
?.
data
?.
redirection_url
);
if
(
response
?.
data
?.
redirect_url
)
{
if
(
response
?.
data
?.
redirection_url
)
{
window
.
open
(
response
?.
data
?.
redirect_url
,
'_blank'
);
window
.
open
(
response
?.
data
?.
redirection_url
,
"_blank"
);
setAcuityUrl
(
response
.
data
.
redirection_url
);
// setIsAcuityModalOpen(true);
route
.
replace
(
PATH
.
AUTH
.
LOGIN
.
ROOT
)
}
}
}
}
...
@@ -487,6 +496,25 @@ export default function RegisterPage() {
...
@@ -487,6 +496,25 @@ export default function RegisterPage() {
</
form
>
</
form
>
</
Box
>
</
Box
>
<
PaymentModal
url=
{
acuityUrl
}
isOpen=
{
isAcuityModalOpen
}
onClose=
{
()
=>
setIsAcuityModalOpen
(
false
)
}
onSuccess=
{
()
=>
{
setIsAcuityModalOpen
(
false
);
dispatch
(
showToast
({
message
:
'Verification complete!'
,
variant
:
ToastVariant
.
SUCCESS
,
autoTime
:
true
}));
}
}
onError=
{
(
error
:
{
message
:
string
})
=>
{
console
.
error
(
'Acuity verification error'
,
error
);
dispatch
(
showToast
({
message
:
error
.
message
||
'Verification failed'
,
variant
:
ToastVariant
.
ERROR
,
autoTime
:
true
}));
}
}
successMessage=
"verified"
title=
"Acuity identity verification"
maxWidth=
"md"
height=
{
700
}
/>
</>
</>
)
)
}
}
src/types/auth.ts
View file @
e3f1ecba
...
@@ -29,7 +29,7 @@ export interface LoginResponse {
...
@@ -29,7 +29,7 @@ export interface LoginResponse {
access_token
:
string
,
access_token
:
string
,
// expires_in: 3600,
// expires_in: 3600,
user
:
User
,
user
:
User
,
redirect_url
:
string
;
redirect
ion
_url
:
string
;
}
}
message
:
string
message
:
string
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment