Skip to content

Commit

Permalink
feat: recon module changes (#926)
Browse files Browse the repository at this point in the history
  • Loading branch information
Riddhiagrawal001 authored Jul 11, 2024
1 parent d579569 commit f5669fa
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 2 deletions.
4 changes: 3 additions & 1 deletion config/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ agreement_url=""
agreement_version=""
apple_pay_certificate_url=""
mixpanel_token=""
recon_iframe_url=""
[default.features]
test_live_toggle=false
is_live_mode=false
Expand Down Expand Up @@ -38,4 +39,5 @@ configure_pmts=false
branding=false
totp=false
live_users_counter=false
granularity=false
granularity=false
recon_v2=false
2 changes: 2 additions & 0 deletions src/entryPoints/FeatureFlagUtils.res
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type featureFlag = {
totp: bool,
liveUsersCounter: bool,
granularity: bool,
reconV2: bool,
}

let featureFlagType = (featureFlags: JSON.t) => {
Expand Down Expand Up @@ -63,6 +64,7 @@ let featureFlagType = (featureFlags: JSON.t) => {
totp: dict->getBool("totp", false),
liveUsersCounter: dict->getBool("live_users_counter", false),
granularity: dict->getBool("granularity", false),
reconV2: dict->getBool("recon_v2", false),
}
typedFeatureFlag
}
10 changes: 10 additions & 0 deletions src/entryPoints/HyperSwitchApp.res
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,16 @@ let make = () => {
<AccessControl isEnabled=featureFlagDetails.recon permission=Access>
<Recon />
</AccessControl>
| list{"upload-files"}
| list{"run-recon"}
| list{"recon-analytics"}
| list{"reports"}
| list{"config-settings"}
| list{"file-processor"} =>
<AccessControl isEnabled=featureFlagDetails.reconV2 permission=Access>
<ReconModule urlList={url.path->urlPath} />
</AccessControl>

| list{"sdk"} =>
<AccessControl
isEnabled={!featureFlagDetails.isLiveMode} permission=Access>
Expand Down
1 change: 1 addition & 0 deletions src/entryPoints/HyperSwitchEntry.res
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ module HyperSwitchEntryComponent = {
->getString("apple_pay_certificate_url", "")
->getNonEmptyString,
agreementVersion: dict->getString("agreement_version", "")->getNonEmptyString,
reconIframeUrl: dict->getString("recon_iframe_url", "")->getNonEmptyString,
}
DOMUtils.window._env_ = value
configureFavIcon(value.faviconUrl)->ignore
Expand Down
75 changes: 74 additions & 1 deletion src/entryPoints/SidebarValues.res
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,59 @@ let developers = (isDevelopersEnabled, userRole, systemMetrics, ~permissionJson)
: emptyComponent
}

let reconTag = (recon, isReconEnabled) =>
let uploadReconFiles = {
SubLevelLink({
name: "Upload Recon Files",
link: `/upload-files`,
access: Access,
searchOptions: [("Upload recon files", "")],
})
}

let runRecon = {
SubLevelLink({
name: "Run Recon",
link: `/run-recon`,
access: Access,
searchOptions: [("Run recon", "")],
})
}

let reconAnalytics = {
SubLevelLink({
name: "Analytics",
link: `/recon-analytics`,
access: Access,
searchOptions: [("Recon analytics", "")],
})
}
let reconReports = {
SubLevelLink({
name: "Reports",
link: `reports`,
access: Access,
searchOptions: [("Recon reports", "")],
})
}

let reconConfigurator = {
SubLevelLink({
name: "Configurator",
link: `config-settings`,
access: Access,
searchOptions: [("Recon configurator", "")],
})
}
let reconFileProcessor = {
SubLevelLink({
name: "File Processor",
link: `file-processor`,
access: Access,
searchOptions: [("Recon file processor", "")],
})
}

let reconTag = (recon, isReconEnabled) => {
recon
? Link({
name: "Reconcilation",
Expand All @@ -475,6 +527,25 @@ let reconTag = (recon, isReconEnabled) =>
access: Access,
})
: emptyComponent
}

let reconAndSettlement = (recon_v2, isReconEnabled) => {
recon_v2 && isReconEnabled
? Section({
name: "Recon And Settlement",
icon: "recon",
showSection: true,
links: [
uploadReconFiles,
runRecon,
reconAnalytics,
reconReports,
reconConfigurator,
reconFileProcessor,
],
})
: emptyComponent
}

let useGetSidebarValues = (~isReconEnabled: bool) => {
let {user_role: userRole} =
Expand All @@ -497,6 +568,7 @@ let useGetSidebarValues = (~isReconEnabled: bool) => {
quickStart,
disputeAnalytics,
configurePmts,
reconV2,
} = featureFlagDetails

let sidebar = [
Expand All @@ -518,6 +590,7 @@ let useGetSidebarValues = (~isReconEnabled: bool) => {
),
default->workflow(isSurchargeEnabled, ~permissionJson, ~isPayoutEnabled=payOut),
recon->reconTag(isReconEnabled),
reconV2->reconAndSettlement(isReconEnabled),
default->developers(userRole, systemMetrics, ~permissionJson),
settings(
~isSampleDataEnabled=sampleData,
Expand Down
1 change: 1 addition & 0 deletions src/entryPoints/configs/HyperSwitchConfigTypes.res
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type urlConfig = {
agreementUrl: option<string>,
agreementVersion: option<string>,
applePayCertificateUrl: option<string>,
reconIframeUrl: option<string>,
}

type customStyle = {
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/Window.res
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ type t

type listener<'ev> = 'ev => unit

type event = {data: string}

@val @scope("window")
external parent: 't = "parent"

Expand Down
95 changes: 95 additions & 0 deletions src/screens/Recon/ReconModule.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
@react.component
let make = (~urlList) => {
open APIUtils
open LogicUtils

let getURL = useGetURL()
let fetchDetails = useGetMethod()
let (redirectToken, setRedirectToken) = React.useState(_ => "")
let (screenState, setScreenState) = React.useState(_ => PageLoaderWrapper.Loading)
let (iframeLoaded, setIframeLoaded) = React.useState(_ => false)
let iframeRef = React.useRef(Js.Nullable.null)

let getReconToken = async () => {
try {
let url = getURL(~entityName=RECON, ~reconType=#TOKEN, ~methodType=Get, ())
let res = await fetchDetails(url)
let token = res->LogicUtils.getDictFromJsonObject->LogicUtils.getString("token", "")
setRedirectToken(_ => token)
setScreenState(_ => PageLoaderWrapper.Success)
} catch {
| _ => setScreenState(_ => PageLoaderWrapper.Error("Something went wrong!"))
}
}

let redirectUrl = switch urlList {
| list{"upload-files"}
| list{"run-recon"}
| list{"reports"}
| list{"config-settings"}
| list{"file-processor"} =>
urlList->List.toArray->Array.joinWithUnsafe("/")
| list{"recon-analytics"} => "analytics"
| _ => ""
}

React.useEffect2(() => {
getReconToken()->ignore
None
}, (iframeLoaded, redirectUrl))

<>
{
switch iframeRef.current->Js.Nullable.toOption {
| Some(iframeEl) => {
let tokenDict = [("token", redirectToken->JSON.Encode.string)]->Dict.fromArray
let dict =
[
("eventType", "AuthenticationDetails"->JSON.Encode.string),
("payload", tokenDict->JSON.Encode.object),
]->Dict.fromArray
iframeEl->IframeUtils.iframePostMessage(dict)
}

| None => ()
}
<PageLoaderWrapper screenState>
{if redirectToken->isNonEmptyString {
<div className="h-85-vh overflow-scroll">
<iframe
onLoad={_ev => {
setIframeLoaded(_ => true)
}}
id="recon-module"
className="h-full w-full"
src={`${Window.env.reconIframeUrl->Option.getOr("")}/${redirectUrl}`}
height="100%"
width="100%"
ref={iframeRef->ReactDOM.Ref.domRef}
/>
</div>
} else {
<div
className={`bg-white dark:bg-jp-gray-lightgray_background border-2 rounded dark:border-jp-gray-850 grid grid-cols-1 md:gap-5 p-2 md:p-8 h-2/3 items-center`}>
<div className={`flex flex-col items-center w-4/6 md:w-2/6 justify-self-center gap-1`}>
<div
className={`text-center text-semibold text-s text-grey-700 opacity-60 dark:text-white`}>
{"If you encounter any errors, please refresh the page to resolve the issue."->React.string}
</div>
<Button
text="Refresh recon tab"
buttonType={Primary}
customButtonStyle="w-2/3 rounded-sm !bg-jp-blue-button_blue border border-jp-blue-border_blue mt-4"
buttonSize={Small}
buttonState={Normal}
onClick={_v => {
getReconToken()->ignore
}}
/>
</div>
</div>
}}
</PageLoaderWrapper>
}
</>
}
24 changes: 24 additions & 0 deletions src/utils/IframeUtils.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@val external document: 'a = "document"
type window
type parent
@val external window: window = "window"
@val @scope("window") external iframeParent: parent = "parent"
type event = {data: string}
@get
external contentWindow: Dom.element => Dom.element = "contentWindow"

@send external postMessageToParent: (parent, JSON.t, string) => unit = "postMessage"
let handlePostMessage = (~targetOrigin="*", messageArr) => {
iframeParent->postMessageToParent(messageArr->Dict.fromArray->JSON.Encode.object, targetOrigin)
}

@send external postMessageToChildren: (Dom.element, string, string) => unit = "postMessage"
let sendPostMessage = (element, message, ~targetOrigin="*") => {
element->postMessageToChildren(message->JSON.Encode.object->JSON.stringify, targetOrigin)
}

let iframePostMessage = (iframeRef: Dom.element, message) => {
iframeRef
->contentWindow
->sendPostMessage(message)
}
1 change: 1 addition & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module.exports = {
"50-rem": "50rem",
"93-per": "93%",
"80-vh": "80vh",
"85-vh": "85vh",
"30-vh": "30vh",
"40-vh": "40vh",
"75-vh": "75vh",
Expand Down

0 comments on commit f5669fa

Please sign in to comment.