Skip to content

Commit

Permalink
feat: Support to handle confirm button (E2E) (#198)
Browse files Browse the repository at this point in the history
Co-authored-by: Vrishab Srivatsa <136090360+vsrivatsa-juspay@users.noreply.github.com>
Co-authored-by: Vrishab Srivatsa <vrishab.srivatsa@juspay.in>
Co-authored-by: Arush <arush.kapoor@juspay.in>
  • Loading branch information
4 people committed Mar 11, 2024
1 parent 73ec2b5 commit a4ffecf
Show file tree
Hide file tree
Showing 21 changed files with 243 additions and 52 deletions.
1 change: 0 additions & 1 deletion Hyperswitch-React-Demo-App/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ app.get("/create-payment-intent", async (req, res) => {
amount: 2999,
},
],
currency: "USD",
confirm: false,
capture_method: "automatic",
authentication_type: "three_ds",
Expand Down
8 changes: 4 additions & 4 deletions Hyperswitch-React-Demo-App/src/Cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ function Cart() {
<div className="titleContainer">
<div class="title">
{" "}
<img className="logoImg" width="28px" src={logo} /> Hyperswicth
Playground App
<img className="logoImg" width="28px" src={logo} alt="" />{" "}
Hyperswitch Playground App
</div>
<div class="testMode">Test Mode</div>
</div>
Expand All @@ -19,7 +19,7 @@ function Cart() {
<div className="Item">
<div className="ItemContainer">
<div className="itemImg">
<img src={shirt} />
<img src={shirt} alt="" />
</div>
<div className="itemDetails">
<div className="name">HS Tshirt</div>
Expand All @@ -37,7 +37,7 @@ function Cart() {
<div className="Item">
<div className="ItemContainer">
<div className="itemImg">
<img src={cap} />
<img src={cap} alt="" />
</div>
<div className="itemDetails">
<div className="name">HS Cap</div>
Expand Down
8 changes: 8 additions & 0 deletions src/BrutalTheme.res
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ let brutal = {
colorIconCardError: "#ff1a1a",
spacingGridColumn: "20px",
spacingGridRow: "20px",
buttonBackgroundColor: "#f5fb1f",
buttonHeight: "48px",
buttonWidth: "thin",
buttonBorderRadius: "6px",
buttonBorderColor: "#566186",
buttonTextColor: "#000000",
buttonTextFontSize: "16px",
buttonTextFontWeight: "500",
}
let brutalRules = (theme: CardThemeType.themeClass) =>
{
Expand Down
41 changes: 41 additions & 0 deletions src/CardTheme.res
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ let getVariables = (str, dict, default, logger) => {
"spacingGridColumn",
"spacingGridRow",
"spacingAccordionItem",
"buttonBackgroundColor",
"buttonHeight",
"buttonWidth",
"buttonBorderRadius",
"buttonBorderColor",
"buttonTextColor",
"buttonTextFontSize",
"buttonTextFontWeight",
]
unknownKeysWarning(validKeys, json, "appearance.variables", ~logger)
{
Expand Down Expand Up @@ -244,6 +252,39 @@ let getVariables = (str, dict, default, logger) => {
~logger,
),
spacingGridRow: getWarningString(json, "spacingGridRow", default.spacingGridRow, ~logger),
buttonBackgroundColor: getWarningString(
json,
"buttonBackgroundColor",
default.spacingGridRow,
~logger,
),
buttonHeight: getWarningString(json, "buttonHeight", default.spacingGridRow, ~logger),
buttonWidth: getWarningString(json, "buttonWidth", default.spacingGridRow, ~logger),
buttonBorderRadius: getWarningString(
json,
"buttonBorderRadius",
default.spacingGridRow,
~logger,
),
buttonBorderColor: getWarningString(
json,
"buttonBorderColor",
default.spacingGridRow,
~logger,
),
buttonTextColor: getWarningString(json, "buttonTextColor", default.spacingGridRow, ~logger),
buttonTextFontSize: getWarningString(
json,
"buttonTextFontSize",
default.spacingGridRow,
~logger,
),
buttonTextFontWeight: getWarningString(
json,
"buttonTextFontWeight",
default.spacingGridRow,
~logger,
),
}
})
->Belt.Option.getWithDefault(default)
Expand Down
8 changes: 8 additions & 0 deletions src/CharcoalTheme.res
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ let charcoal = {
colorIconCardError: "#fd1717",
spacingGridColumn: "20px",
spacingGridRow: "20px",
buttonBackgroundColor: "#000000",
buttonHeight: "48px",
buttonWidth: "thin",
buttonBorderRadius: "6px",
buttonBorderColor: "#000000",
buttonTextColor: "#ffffff",
buttonTextFontSize: "16px",
buttonTextFontWeight: "500",
}

let charcoalRules = theme =>
Expand Down
67 changes: 49 additions & 18 deletions src/Components/PayNowButton.res
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@send external postMessage: (Window.window, Js.Json.t, string) => unit = "postMessage"
@send external postMessage: (Window.window, JSON.t, string) => unit = "postMessage"

external eventToJson: ReactEvent.Mouse.t => Js.Json.t = "%identity"
external eventToJson: ReactEvent.Mouse.t => JSON.t = "%identity"

module Loader = {
@react.component
Expand All @@ -14,41 +14,72 @@ module Loader = {
}
}
@react.component
let make = () => {
let {themeObj, localeString} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom)
let make = (
~cvcProps: CardUtils.cvcProps,
~cardProps: CardUtils.cardProps,
~expiryProps: CardUtils.expiryProps,
~selectedOption: PaymentModeType.payment,
) => {
open RecoilAtoms
let {themeObj, localeString} = Recoil.useRecoilValueFromAtom(configAtom)
let (isDisabled, setIsDisabled) = React.useState(() => false)
let (showLoader, setShowLoader) = React.useState(() => false)
let complete = Recoil.useRecoilValueFromAtom(RecoilAtoms.fieldsComplete)
let areRequiredFieldsValidValue = Recoil.useRecoilValueFromAtom(areRequiredFieldsValid)
let {sdkHandleConfirmPayment} = Recoil.useRecoilValueFromAtom(optionAtom)

let handleOnClick = _ev => {
let (isCVCValid, _, _, _, _, _, _, _, _, _) = cvcProps
let (isCardValid, _, _, _, _, _, _, _, _, _) = cardProps
let (isExpiryValid, _, _, _, _, _, _, _, _) = expiryProps

let validFormat =
isCVCValid->Option.getOr(false) &&
isCardValid->Option.getOr(false) &&
isExpiryValid->Option.getOr(false) &&
areRequiredFieldsValidValue

let confirmPayload = sdkHandleConfirmPayment->PaymentBody.confirmPayloadForSDKButton

let handleOnClick = _ => {
setIsDisabled(_ => true)
setShowLoader(_ => true)
Utils.handleOnConfirmPostMessage(~targetOrigin="*", ())
Utils.handlePostMessage([("handleSdkConfirm", confirmPayload)])
}
React.useEffect1(() => {
setIsDisabled(_ => !complete)
React.useEffect3(() => {
if selectedOption === Card {
setIsDisabled(_ => !validFormat)
} else {
setIsDisabled(_ => !areRequiredFieldsValidValue)
}
None
}, [complete])
}, (validFormat, areRequiredFieldsValidValue, selectedOption))

<div className="flex flex-col gap-1 h-auto w-full">
<div className="flex flex-col gap-1 h-auto w-full items-center">
<button
disabled=isDisabled
onClick=handleOnClick
className={`w-full flex flex-row justify-center items-center rounded-md`}
className={`w-full flex flex-row justify-center items-center`}
style={ReactDOMStyle.make(
~backgroundColor=themeObj.colorBackground,
~height="48px",
~borderRadius=themeObj.buttonBorderRadius,
~backgroundColor=themeObj.buttonBackgroundColor,
~height=themeObj.buttonHeight,
~cursor={isDisabled ? "not-allowed" : "pointer"},
~opacity={isDisabled ? "0.6" : "1"},
~borderWidth="thin",
~borderColor=themeObj.colorPrimary,
~width=themeObj.buttonWidth,
~borderColor=themeObj.buttonBorderColor,
(),
)}>
<span id="button-text" style={ReactDOMStyle.make(~color=themeObj.colorPrimary, ())}>
<span
id="button-text"
style={ReactDOMStyle.make(
~color=themeObj.buttonTextColor,
~fontSize=themeObj.buttonTextFontSize,
~fontWeight=themeObj.buttonTextFontWeight,
(),
)}>
{if showLoader {
<Loader />
} else {
{React.string(localeString.payNowButton)}
localeString.payNowButton->React.string
}}
</span>
</button>
Expand Down
8 changes: 8 additions & 0 deletions src/DefaultTheme.res
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ let default = {
colorIconCardError: "#fd1717",
spacingGridColumn: "20px",
spacingGridRow: "20px",
buttonBackgroundColor: "#006df9",
buttonHeight: "48px",
buttonWidth: "thin",
buttonBorderRadius: "6px",
buttonBorderColor: "#ffffff",
buttonTextColor: "#ffffff",
buttonTextFontSize: "16px",
buttonTextFontWeight: "500",
}
let defaultRules = theme =>
{
Expand Down
7 changes: 0 additions & 7 deletions src/Hooks/CommonHooks.res
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ type keys = {
publishableKey: string,
iframeId: string,
parentURL: string,
sdkHandleConfirmPayment: bool,
sdkHandleOneClickConfirmPayment: bool,
}
@val @scope("document") external querySelector: string => Js.Nullable.t<element> = "querySelector"
Expand Down Expand Up @@ -86,11 +85,6 @@ let updateKeys = (dict, keyPair, setKeys) => {
...prev,
parentURL: dict->Utils.getString(key, valueStr),
})
| "sdkHandleConfirmPayment" =>
setKeys(.prev => {
...prev,
sdkHandleConfirmPayment: dict->Utils.getBool(key, valueBool(false)),
})
| "sdkHandleOneClickConfirmPayment" =>
setKeys(.prev => {
...prev,
Expand All @@ -105,6 +99,5 @@ let defaultkeys = {
publishableKey: "",
iframeId: "",
parentURL: "*",
sdkHandleConfirmPayment: false,
sdkHandleOneClickConfirmPayment: true,
}
4 changes: 2 additions & 2 deletions src/LoaderController.res
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger) => {
setList(._ => updatedState)
logger.setLogInfo(~value="SemiLoaded", ~eventName=LOADER_CHANGED, ())
}
| LoadError(x) => logger.setLogError(
| LoadError(x) =>
logger.setLogError(
~value="LoadError: " ++ x->Js.Json.stringify,
~eventName=LOADER_CHANGED,
(),
Expand Down Expand Up @@ -269,7 +270,6 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger) => {
("iframeId", "no-element"->Js.Json.string),
("publishableKey", ""->Js.Json.string),
("parentURL", "*"->Js.Json.string),
("sdkHandleConfirmPayment", false->Js.Json.boolean),
("sdkHandleOneClickConfirmPayment", true->Js.Json.boolean),
]->Js.Array2.forEach(keyPair => {
dict->CommonHooks.updateKeys(keyPair, setKeys)
Expand Down
8 changes: 8 additions & 0 deletions src/MidnightTheme.res
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ let midnight = {
colorIconCardError: "#fd1717",
spacingGridColumn: "20px",
spacingGridRow: "20px",
buttonBackgroundColor: "#85d996",
buttonHeight: "48px",
buttonWidth: "thin",
buttonBorderRadius: "6px",
buttonBorderColor: "#85d996",
buttonTextColor: "#000000",
buttonTextFontSize: "16px",
buttonTextFontWeight: "500",
}

let midnightRules = theme =>
Expand Down
8 changes: 8 additions & 0 deletions src/NoTheme.res
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ let nakedValues = {
colorIconCardError: "#fd1717",
spacingGridColumn: "20px",
spacingGridRow: "20px",
buttonBackgroundColor: "",
buttonHeight: "48px",
buttonWidth: "thin",
buttonBorderRadius: "6px",
buttonBorderColor: "",
buttonTextColor: "",
buttonTextFontSize: "16px",
buttonTextFontWeight: "500",
}

let nakedValuesRules = _ => Js.Dict.empty()->Js.Json.object_
Expand Down
17 changes: 11 additions & 6 deletions src/PaymentElement.res
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ let make = (
let (sessions, setSessions) = React.useState(_ => Js.Dict.empty()->Js.Json.object_)
let (paymentOptions, setPaymentOptions) = React.useState(_ => [])
let (walletOptions, setWalletOptions) = React.useState(_ => [])
let {sdkHandleConfirmPayment} = Recoil.useRecoilValueFromAtom(keys)
let {sdkHandleConfirmPayment} = Recoil.useRecoilValueFromAtom(optionAtom)

let (list, setList) = React.useState(_ => PaymentMethodsRecord.defaultList)
let (cardsContainerWidth, setCardsContainerWidth) = React.useState(_ => 0)
Expand Down Expand Up @@ -392,11 +392,16 @@ let make = (
| Accordion => <AccordionContainer paymentOptions checkoutEle />
}}
</div>
<RenderIf condition={sdkHandleConfirmPayment}>
<div className="mt-4">
<PayNowButton />
</div>
</RenderIf>
</RenderIf>
<RenderIf condition={sdkHandleConfirmPayment.handleConfirm}>
<div className="mt-4">
<PayNowButton
cvcProps
cardProps
expiryProps
selectedOption={selectedOption->PaymentModeType.paymentMode}
/>
</div>
</RenderIf>
<PoweredBy />
{switch methodslist {
Expand Down
8 changes: 8 additions & 0 deletions src/SoftTheme.res
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ let soft = {
colorIconCardError: "#fe87a1",
spacingGridColumn: "20px",
spacingGridRow: "20px",
buttonBackgroundColor: "#3c3d3e",
buttonHeight: "48px",
buttonWidth: "thin",
buttonBorderRadius: "6px",
buttonBorderColor: "#7d8fff",
buttonTextColor: "#7d8fff",
buttonTextFontSize: "16px",
buttonTextFontWeight: "500",
}

let softRules = theme =>
Expand Down
8 changes: 8 additions & 0 deletions src/Types/CardThemeType.res
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ type themeClass = {
colorIconCardError: string,
spacingGridColumn: string,
spacingGridRow: string,
buttonBackgroundColor: string,
buttonHeight: string,
buttonWidth: string,
buttonBorderRadius: string,
buttonBorderColor: string,
buttonTextColor: string,
buttonTextFontSize: string,
buttonTextFontWeight: string,
}
type appearance = {
theme: theme,
Expand Down
Loading

0 comments on commit a4ffecf

Please sign in to comment.