Skip to content

Commit 5e64705

Browse files
Abhishek ChorotiyaAbhishek Chorotiya
authored andcommitted
feat: integration for redsys 3ds
1 parent ff1bfa7 commit 5e64705

File tree

6 files changed

+294
-94
lines changed

6 files changed

+294
-94
lines changed

src/App.res

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ let make = () => {
6767
</div>
6868
| "qrData" => <QRCodeDisplay />
6969
| "3dsAuth" => <ThreeDSAuth />
70+
| "redsys3ds" => <Redsys3ds />
7071
| "3ds" => <ThreeDSMethod />
7172
| "voucherData" => <VoucherDisplay />
7273
| "preMountLoader" => {

src/Redsys3ds.res

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
open Utils
2+
3+
@react.component
4+
let make = () => {
5+
let logger = HyperLogger.make(~source=Elements(Payment))
6+
let isCompleteAuthorizeCalledRef = React.useRef(false)
7+
let timeoutRef = React.useRef(None)
8+
let eventsToSendToParent = ["confirmParams", "poll_status", "openurl_if_required"]
9+
let completeAuthorize = PaymentHelpers.useRedsysCompleteAuthorize(Some(logger))
10+
11+
let handleCompleteAuthorizeCall = (
12+
threeDsMethodComp,
13+
paymentIntentId,
14+
publishableKey,
15+
headers,
16+
returnUrl,
17+
) => {
18+
let body = [
19+
("client_secret", paymentIntentId->JSON.Encode.string),
20+
("threeds_method_comp_ind", threeDsMethodComp->JSON.Encode.string),
21+
]
22+
completeAuthorize(
23+
~bodyArr=body,
24+
~confirmParam={
25+
return_url: returnUrl,
26+
publishableKey,
27+
},
28+
~headers,
29+
~iframeId="redsys3ds",
30+
~clientSecret=Some(paymentIntentId),
31+
)
32+
}
33+
34+
eventsToSendToParent->UtilityHooks.useSendEventsToParent
35+
36+
React.useEffect0(() => {
37+
messageParentWindow([("iframeMountedCallback", true->JSON.Encode.bool)])
38+
let handle = (ev: Window.event) => {
39+
try {
40+
let json = ev.data->safeParse
41+
let dict = json->getDictFromJson
42+
if dict->Dict.get("fullScreenIframeMounted")->Option.isSome {
43+
let metadata = dict->getJsonObjectFromDict("metadata")
44+
let metaDataDict = metadata->JSON.Decode.object->Option.getOr(Dict.make())
45+
let paymentIntentId = metaDataDict->getString("paymentIntentId", "")
46+
let publishableKey = metaDataDict->getString("publishableKey", "")
47+
48+
logger.setClientSecret(paymentIntentId)
49+
logger.setMerchantId(publishableKey)
50+
51+
let headersDict = metaDataDict->getDictFromDict("headers")
52+
53+
let headers = headersDict->convertDictToArrayOfKeyStringTuples
54+
55+
let confirmParam = metaDataDict->getDictFromObj("confirmParams")
56+
let returnUrl = confirmParam->getString("return_url", "")
57+
let iframeDataDict = metaDataDict->getDictFromObj("iframeData")
58+
let methodKey = iframeDataDict->getString("method_key", "threeDSMethodData")
59+
let threeDsMethodUrl = iframeDataDict->getString("three_ds_method_url", "")
60+
let threeDsMethodData = iframeDataDict->getString("three_ds_method_data", "")
61+
let threeDsIframe = CommonHooks.querySelector("#threeDsAuthFrame")
62+
63+
switch Window.querySelector("#threeDsDiv")->Nullable.toOption {
64+
| Some(elem) =>
65+
if threeDsMethodUrl !== "" {
66+
let form = elem->makeForm(threeDsMethodUrl, "threeDsHiddenPostMethod")
67+
let input = Types.createElement("input")
68+
input.name = encodeURIComponent(methodKey)
69+
input.value = encodeURIComponent(threeDsMethodData)
70+
form.target = "threeDsAuthFrame"
71+
form.appendChild(input)
72+
form.submit()
73+
}
74+
| None => ()
75+
}
76+
77+
timeoutRef.current->Option.forEach(clearTimeout)
78+
79+
timeoutRef.current = Some(setTimeout(() => {
80+
isCompleteAuthorizeCalledRef.current = true
81+
handleCompleteAuthorizeCall(
82+
"N",
83+
paymentIntentId,
84+
publishableKey,
85+
headers,
86+
returnUrl,
87+
)->ignore
88+
}, 10000))
89+
90+
switch threeDsIframe->Nullable.toOption {
91+
| Some(elem) =>
92+
elem->CommonHooks.addEventListener("load", _ => {
93+
timeoutRef.current->Option.forEach(clearTimeout)
94+
if !isCompleteAuthorizeCalledRef.current {
95+
handleCompleteAuthorizeCall(
96+
"Y",
97+
paymentIntentId,
98+
publishableKey,
99+
headers,
100+
returnUrl,
101+
)->ignore
102+
}
103+
})
104+
| None => ()
105+
}
106+
}
107+
} catch {
108+
| _ =>
109+
postFailedSubmitResponse(
110+
~errortype="complete_authorize_failed",
111+
~message="Something went wrong.",
112+
)
113+
}
114+
}
115+
Window.addEventListener("message", handle)
116+
Some(
117+
() => {
118+
Window.removeEventListener("message", handle)
119+
timeoutRef.current->Option.forEach(clearTimeout)
120+
},
121+
)
122+
})
123+
124+
<div id="threeDsDiv" className="max-w-1 max-h-1 opacity-0 fixed left-[-9999px]">
125+
<iframe id="threeDsAuthFrame" name="threeDsAuthFrame" title="3D Secure Authentication Frame" />
126+
</div>
127+
}

src/ThreeDSAuth.res

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,7 @@ let make = () => {
4848
->JSON.Decode.object
4949
->Option.getOr(Dict.make())
5050
->getString("three_ds_authorize_url", "")
51-
let headers =
52-
headersDict
53-
->Dict.toArray
54-
->Array.map(entries => {
55-
let (x, val) = entries
56-
(x, val->JSON.Decode.string->Option.getOr(""))
57-
})
51+
let headers = headersDict->convertDictToArrayOfKeyStringTuples
5852

5953
let threeDsMethodComp = metaDataDict->getString("3dsMethodComp", "U")
6054
open Promise

src/Types/PaymentConfirmTypes.res

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type nextAction = {
4545
next_action_data: option<JSON.t>,
4646
display_text: option<string>,
4747
border_color: option<string>,
48+
iframe_data: option<JSON.t>,
4849
}
4950
type intent = {
5051
nextAction: nextAction,
@@ -74,6 +75,7 @@ let defaultNextAction = {
7475
next_action_data: None,
7576
display_text: None,
7677
border_color: None,
78+
iframe_data: None,
7779
}
7880
let defaultIntent = {
7981
nextAction: defaultNextAction,
@@ -170,6 +172,7 @@ let getNextAction = (dict, str) => {
170172
next_action_data: Some(json->getDictFromDict("next_action_data")->JSON.Encode.object),
171173
display_text: json->getOptionString("display_text"),
172174
border_color: json->getOptionString("border_color"),
175+
iframe_data: Some(json->Utils.getJsonObjectFromDict("iframe_data")),
173176
}
174177
})
175178
->Option.getOr(defaultNextAction)

0 commit comments

Comments
 (0)