diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9549ffeb6..5dc051fa9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [conven
- - -
+## 1.25.1 (2024-01-17)
+
+### Miscellaneous Tasks
+
+- Sidebar refactoring & permissions added ([#264](https://github.com/juspay/hyperswitch-control-center/pull/264)) ([`f428679`](https://github.com/juspay/hyperswitch-control-center/commit/f428679fa9b98e002e8bb1f670af65595ae64845))
+- Access Control Module added ([#266](https://github.com/juspay/hyperswitch-control-center/pull/266)) ([`59d0b53`](https://github.com/juspay/hyperswitch-control-center/commit/59d0b5387476536ed3a7f6a9f3468a3bd115232f))
+
+**Full Changelog:** [`v1.25.0...v1.25.1`](https://github.com/juspay/hyperswitch-control-center/compare/v1.25.0...v1.25.1)
+
+- - -
+
+
## 1.25.0 (2024-01-16)
### Features
diff --git a/src/components/EntityScaffold.res b/src/components/EntityScaffold.res
index bea10957d..68afbe809 100644
--- a/src/components/EntityScaffold.res
+++ b/src/components/EntityScaffold.res
@@ -1,89 +1,32 @@
-module ComingSoon = {
- @react.component
- let make = (~title) => {
-
-
{React.string(title)}
-
{React.string("Coming soon...")}
-
- }
-}
-
-module ShowPage = {
- @react.component
- let make = (~entityName, ~id) => {
-
-
- {React.string(`Show ${entityName} `)}
- {React.string(`#${id}`)}
-
-
{React.string("Coming soon...")}
-
- }
-}
-
-module UnauthorizedPage = {
- @react.component
- let make = (~entityName) => {
-
-
{React.string(entityName)}
-
{React.string("You don't have access to this module. Contact admin for access")}
-
- }
-}
-
@react.component
let make = (
~entityName="",
~remainingPath,
~isAdminAccount=false,
- ~access: AuthTypes.authorization=ReadWrite,
- ~renderList=() => ,
- ~renderNewForm=() => ,
+ ~access: AuthTypes.authorization=Access,
+ ~renderList,
+ ~renderNewForm=?,
~renderShow=?,
- ~renderOrder=?,
- ~renderEdit=_id => ,
- ~renderEditWithMultiId=(_id1, _id2) => ,
- ~renderClone=_id => ,
) => {
if access === NoAccess {
-
+
} else {
switch remainingPath {
| list{"new"} =>
switch access {
- | ReadWrite => renderNewForm()
- | Checker => isAdminAccount ? renderNewForm() :
- | _ =>
- }
- | list{id, "clone"} =>
- switch access {
- | ReadWrite => renderClone(id)
- | _ =>
+ | Access =>
+ switch renderNewForm {
+ | Some(element) => element()
+ | None => React.null
+ }
+ | NoAccess =>
}
| list{id} =>
let page = switch renderShow {
| Some(fn) => fn(id)
- | None =>
+ | None => React.null
}
page
- | list{id, "edit"} =>
- switch access {
- | ReadWrite => renderEdit(id)
- | Checker => isAdminAccount ? renderEdit(id) :
- | _ =>
- }
- | list{id1, id2, "edit"} =>
- switch access {
- | ReadWrite => renderEditWithMultiId(id1, id2)
- | Checker =>
- isAdminAccount ? renderEditWithMultiId(id1, id2) :
- | _ =>
- }
- | list{"order", id} =>
- switch renderOrder {
- | Some(fn) => fn(id)
- | None =>
- }
| list{} => renderList()
| _ =>
}
diff --git a/src/components/UnauthorizedPage.res b/src/components/UnauthorizedPage.res
new file mode 100644
index 000000000..55bddadc9
--- /dev/null
+++ b/src/components/UnauthorizedPage.res
@@ -0,0 +1,19 @@
+@react.component
+let make = (~message="You don't have access to this module. Contact admin for access") => {
+ let {setDashboardPageState} = React.useContext(GlobalProvider.defaultContext)
+ React.useEffect0(() => {
+ RescriptReactRouter.replace("/unauthorized")
+ None
+ })
+
+
+}
diff --git a/src/components/form/BoolInput.res b/src/components/form/BoolInput.res
index 64ec789f0..8ada7a9aa 100644
--- a/src/components/form/BoolInput.res
+++ b/src/components/form/BoolInput.res
@@ -114,7 +114,6 @@ let make = (
~boolCustomClass="",
~addAttributeId="",
) => {
- let accessLevel = React.useContext(FormAuthContext.formAuthContext)
let boolInput = baseInput->ffInputToBoolInput
let boolValue: Js.Json.t = boolInput.value
@@ -126,14 +125,8 @@ let make = (
let setIsSelected = boolInput.onChange
isCheckBox
- ?
+ ?
:
}
diff --git a/src/context/FormAuthContext.res b/src/context/FormAuthContext.res
index e59430a3d..6d87a6061 100644
--- a/src/context/FormAuthContext.res
+++ b/src/context/FormAuthContext.res
@@ -1,3 +1,3 @@
-let formAuthContext = React.createContext(AuthTypes.ReadWrite)
+let formAuthContext = React.createContext(AuthTypes.Access)
let make = React.Context.provider(formAuthContext)
diff --git a/src/entryPoints/hyperswitch/HyperSwitchApp.res b/src/entryPoints/hyperswitch/HyperSwitchApp.res
index 795a31657..f8d8e2979 100644
--- a/src/entryPoints/hyperswitch/HyperSwitchApp.res
+++ b/src/entryPoints/hyperswitch/HyperSwitchApp.res
@@ -4,19 +4,6 @@ open HSLocalStorage
open HSwitchGlobalVars
open APIUtils
-module FeatureFlagEnabledComponent = {
- @react.component
- let make = (~isEnabled, ~children) => {
- let {setDashboardPageState} = React.useContext(GlobalProvider.defaultContext)
- let updateRoute = () => {
- setDashboardPageState(_ => #HOME)
- RescriptReactRouter.replace("/home")
- React.null
- }
- <> {isEnabled ? children : updateRoute()} >
- }
-}
-
@react.component
let make = () => {
let url = RescriptReactRouter.useUrl()
@@ -40,7 +27,6 @@ let make = () => {
->QuickStartUtils.getTypedValueFromDict
let featureFlagDetails = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom
-
let getEnumDetails = EnumVariantHook.useFetchEnumDetails()
let verificationDays = getFromMerchantDetails("verification")->LogicUtils.getIntFromString(-1)
let userRole = getFromUserDetails("user_role")
@@ -55,12 +41,7 @@ let make = () => {
let isReconEnabled =
(merchantDetailsValue->MerchantAccountUtils.getMerchantDetails).recon_status === Active
- let hyperSwitchAppSidebars = SidebarValues.getHyperSwitchAppSidebars(
- ~isReconEnabled,
- ~featureFlagDetails,
- ~userRole,
- (),
- )
+ let hyperSwitchAppSidebars = SidebarValues.useGetSidebarValues(~isReconEnabled)
let comingSoonPage =
{
{switch url.path {
| list{"home"} =>
-
+
{featureFlagDetails.quickStart ? : }
-
+
| list{"fraud-risk-management", ...remainingPath} =>
-
+
{
renderNewForm={() => }
renderShow={_ => }
/>
-
+
| list{"connectors", ...remainingPath} =>
{
}
renderShow={id => }
/>
@@ -269,7 +250,7 @@ let make = () => {
}
renderShow={id => }
/>
@@ -278,20 +259,20 @@ let make = () => {
}
renderShow={id => }
/>
| list{"customers", ...remainingPath} =>
-
+
}
renderShow={id => }
/>
-
+
| list{"routing", ...remainingPath} =>
{
}
renderShow={_ => }
/>
@@ -317,12 +298,11 @@ let make = () => {
| list{"analytics-user-journey"} =>
-
+
-
+
| list{"monitoring"} => comingSoonPage
| list{"developer-api-keys"} =>
| list{"developer-system-metrics"} =>
@@ -342,35 +322,35 @@ let make = () => {
}
/>
| list{"recon"} =>
-
+
-
+
| list{"sdk"} =>
-
+
-
+
| list{"3ds"} =>
| list{"surcharge"} =>
-
+
-
+
| list{"account-settings"} =>
-
+
-
+
| list{"account-settings", "profile"} =>
| list{"business-details"} =>
-
+
-
+
| list{"business-profiles"} =>
-
+
-
+
| list{"quick-start"} => determineQuickStartPageState()
| list{"woocommerce"} => determineWooCommerce()
| list{"stripe-plus-paypal"} => determineStripePlusPayPal()
-
+ | list{"unauthorized"} =>
| _ =>
RescriptReactRouter.replace(`${hyperSwitchFEPrefix}/home`)
diff --git a/src/entryPoints/hyperswitch/HyperswitchAtom.res b/src/entryPoints/hyperswitch/HyperswitchAtom.res
index 11db93cca..9a600b266 100644
--- a/src/entryPoints/hyperswitch/HyperswitchAtom.res
+++ b/src/entryPoints/hyperswitch/HyperswitchAtom.res
@@ -10,8 +10,11 @@ let featureFlagAtom: Recoil.recoilAtom = Recoil.at
"featureFlag",
Js.Json.null->FeatureFlagUtils.featureFlagType,
)
-
let paypalAccountStatusAtom: Recoil.recoilAtom = Recoil.atom(.
"paypalAccountStatusAtom",
PayPalFlowTypes.Account_not_found,
)
+let userPermissionAtom: Recoil.recoilAtom> = Recoil.atom(.
+ "userPermissionAtom",
+ [],
+)
diff --git a/src/entryPoints/hyperswitch/SidebarValues.res b/src/entryPoints/hyperswitch/SidebarValues.res
index 3463c58bc..648d74cde 100644
--- a/src/entryPoints/hyperswitch/SidebarValues.res
+++ b/src/entryPoints/hyperswitch/SidebarValues.res
@@ -54,35 +54,35 @@ let home = isHomeEnabled =>
name: "Home",
icon: "hswitch-home",
link: "/home",
- access: ReadWrite,
+ access: Access,
})
: emptyComponent
let payments = SubLevelLink({
name: "Payments",
link: `/payments`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("View payment operations", "")],
})
let refunds = SubLevelLink({
name: "Refunds",
link: `/refunds`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("View refund operations", "")],
})
let disputes = SubLevelLink({
name: "Disputes",
link: `/disputes`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("View dispute operations", "")],
})
let customers = SubLevelLink({
name: "Customers",
link: `/customers`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("View customers", "")],
})
@@ -105,7 +105,7 @@ let connectors = (isConnectorsEnabled, isLiveMode) => {
name: "Processors",
link: `/connectors`,
icon: "connectors",
- access: ReadWrite,
+ access: Access,
searchOptions: HSwitchUtils.getSearchOptionsForProcessors(
~processorList=isLiveMode
? ConnectorUtils.connectorListForLive
@@ -119,21 +119,21 @@ let connectors = (isConnectorsEnabled, isLiveMode) => {
let paymentAnalytcis = SubLevelLink({
name: "Payments",
link: `/analytics-payments`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("View analytics", "")],
})
let refundAnalytics = SubLevelLink({
name: "Refunds",
link: `/analytics-refunds`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("View analytics", "")],
})
let userJourneyAnalytics = SubLevelLink({
name: "User Journey",
link: `/analytics-user-journey`,
- access: ReadWrite,
+ access: Access,
iconTag: "betaTag",
searchOptions: [("View analytics", "")],
})
@@ -153,7 +153,7 @@ let analytics = (isAnalyticsEnabled, userJourneyAnalyticsFlag) =>
let routing = SubLevelLink({
name: "Routing",
link: `/routing`,
- access: ReadWrite,
+ access: Access,
searchOptions: [
("Manage default routing configuration", "/default"),
("Create new volume based routing", "/volume"),
@@ -165,14 +165,14 @@ let routing = SubLevelLink({
let threeDs = SubLevelLink({
name: "3DS Decision Manager",
link: `/3ds`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("Configure 3ds", "")],
})
let surcharge = SubLevelLink({
name: "Surcharge",
link: `/surcharge`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("Add Surcharge", "")],
})
@@ -189,14 +189,14 @@ let workflow = (isWorkflowEnabled, isSurchargeEnabled) =>
let userManagement = SubLevelLink({
name: "Team",
link: `/users`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("View team management", "")],
})
let accountSettings = SubLevelLink({
name: "Account Settings",
link: `/account-settings`,
- access: ReadWrite,
+ access: Access,
searchOptions: [
("View profile", "/profile"),
("Change password", "/profile"),
@@ -207,14 +207,14 @@ let accountSettings = SubLevelLink({
let businessDetails = SubLevelLink({
name: "Business Details",
link: `/business-details`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("Configure business details", "")],
})
let businessProfiles = SubLevelLink({
name: "Business Profiles",
link: `/business-profiles`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("Configure business profiles", "")],
})
@@ -242,14 +242,14 @@ let settings = (~isSampleDataEnabled, ~isUserManagementEnabled, ~isBusinessProfi
let apiKeys = SubLevelLink({
name: "API Keys",
link: `/developer-api-keys`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("View API Keys", "")],
})
let systemMetric = SubLevelLink({
name: "System Metrics",
link: `/developer-system-metrics`,
- access: ReadWrite,
+ access: Access,
iconTag: "betaTag",
searchOptions: [("View System Metrics", "")],
})
@@ -257,7 +257,7 @@ let systemMetric = SubLevelLink({
let paymentSettings = SubLevelLink({
name: "Payment Settings",
link: `/payment-settings`,
- access: ReadWrite,
+ access: Access,
searchOptions: [("View payment settings", ""), ("View webhooks", ""), ("View return url", "")],
})
@@ -282,7 +282,7 @@ let fraudAndRisk = isfraudAndRiskEnabled =>
name: "Fraud & Risk",
icon: "shield-alt",
link: `/fraud-risk-management`,
- access: isfraudAndRiskEnabled ? ReadWrite : NoAccess,
+ access: isfraudAndRiskEnabled ? Access : NoAccess,
searchOptions: [],
})
: emptyComponent
@@ -293,7 +293,7 @@ let payoutConnectors = isPayoutConnectorsEnabled =>
name: "Payout Processors",
link: `/payoutconnectors`,
icon: "connectors",
- access: ReadWrite,
+ access: Access,
searchOptions: HSwitchUtils.getSearchOptionsForProcessors(
~processorList=ConnectorUtils.payoutConnectorList,
~getNameFromString=ConnectorUtils.getConnectorNameString,
@@ -307,16 +307,14 @@ let reconTag = (recon, isReconEnabled) =>
name: "Reconcilation",
icon: isReconEnabled ? "recon" : "recon-lock",
link: `/recon`,
- access: ReadWrite,
+ access: Access,
})
: emptyComponent
-let getHyperSwitchAppSidebars = (
- ~isReconEnabled: bool,
- ~featureFlagDetails: FeatureFlagUtils.featureFlag,
- ~userRole,
- (),
-) => {
+let useGetSidebarValues = (~isReconEnabled: bool) => {
+ let userRole = HSLocalStorage.getFromUserDetails("user_role")
+ let featureFlagDetails = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom
+
let {
productionAccess,
frm,
@@ -332,6 +330,7 @@ let getHyperSwitchAppSidebars = (
isLiveMode,
customersModule,
} = featureFlagDetails
+
let sidebar = [
productionAccess->productionAccessComponent,
default->home,
diff --git a/src/screens/HyperSwitch/SDKPayment/SDKPage.res b/src/screens/HyperSwitch/SDKPayment/SDKPage.res
index 7d87fe11f..6542b3032 100644
--- a/src/screens/HyperSwitch/SDKPayment/SDKPage.res
+++ b/src/screens/HyperSwitch/SDKPayment/SDKPage.res
@@ -49,13 +49,13 @@ module SDKConfiguarationFields = {
InputFields.numericTextInput(
~input={
...input,
- value: (initialValues.amount / 100)->string_of_int->Js.Json.string,
+ value: (initialValues.amount /. 100.00)->Js.Float.toString->Js.Json.string,
onChange: {
ev => {
- let eventValueToInt =
- ev->Identity.formReactEventToString->LogicUtils.getIntFromString(0)
+ let eventValueToFloat =
+ ev->Identity.formReactEventToString->LogicUtils.getFloatFromString(0.00)
let valInCents =
- (eventValueToInt * 100)->string_of_int->Identity.stringToFormReactEvent
+ (eventValueToFloat *. 100.00)->Js.Float.toString->Identity.stringToFormReactEvent
input.onChange(valInCents)
}
},
@@ -63,6 +63,7 @@ module SDKConfiguarationFields = {
~isDisabled=false,
~customStyle="w-full",
~placeholder="Enter amount",
+ ~precision=2,
(),
),
(),
diff --git a/src/screens/HyperSwitch/SDKPayment/SDKPaymentTypes.res b/src/screens/HyperSwitch/SDKPayment/SDKPaymentTypes.res
index 631956251..2b1b8e2f2 100644
--- a/src/screens/HyperSwitch/SDKPayment/SDKPaymentTypes.res
+++ b/src/screens/HyperSwitch/SDKPayment/SDKPaymentTypes.res
@@ -27,7 +27,7 @@ type billing = {
type orderDetails = {
product_name: string,
quantity: int,
- amount: int,
+ amount: float,
}
type metadata = {order_details: orderDetails}
@@ -55,13 +55,13 @@ type mandateData = {
}
type paymentType = {
- amount: int,
+ amount: float,
mutable currency: string,
profile_id: string,
customer_id: string,
description: string,
capture_method: string,
- amount_to_capture: Js.Nullable.t,
+ amount_to_capture: Js.Nullable.t,
email: string,
name: string,
phone: string,
diff --git a/src/screens/HyperSwitch/SDKPayment/SDKPaymentUtils.res b/src/screens/HyperSwitch/SDKPayment/SDKPaymentUtils.res
index 31e35445a..39bcc56f0 100644
--- a/src/screens/HyperSwitch/SDKPayment/SDKPaymentUtils.res
+++ b/src/screens/HyperSwitch/SDKPayment/SDKPaymentUtils.res
@@ -1,6 +1,6 @@
let initialValueForForm: HSwitchSettingTypes.profileEntity => SDKPaymentTypes.paymentType = defaultBusinessProfile => {
{
- amount: 10000,
+ amount: 10000.00,
currency: "United States-USD",
profile_id: defaultBusinessProfile.profile_id,
description: "Default value",
@@ -48,11 +48,11 @@ let initialValueForForm: HSwitchSettingTypes.profileEntity => SDKPaymentTypes.pa
order_details: {
product_name: "Apple iphone 15",
quantity: 1,
- amount: 100,
+ amount: 100.00,
},
},
capture_method: "automatic",
- amount_to_capture: Js.Nullable.return(100),
+ amount_to_capture: Js.Nullable.return(100.00),
return_url: `${Window.Location.origin}${Window.Location.pathName}`,
}
}
@@ -95,7 +95,7 @@ let getTypedValueForPayment: Js.Json.t => SDKPaymentTypes.paymentType = values =
},
},
}
- let amount = dictOfValues->getInt("amount", 100)
+ let amount = dictOfValues->getFloat("amount", 100.00)
{
amount,
@@ -150,10 +150,10 @@ let getTypedValueForPayment: Js.Json.t => SDKPaymentTypes.paymentType = values =
},
},
capture_method: "automatic",
- amount_to_capture: amount === 0 ? Js.Nullable.null : Js.Nullable.return(amount),
+ amount_to_capture: amount === 0.00 ? Js.Nullable.null : Js.Nullable.return(amount),
return_url: dictOfValues->getString("return_url", ""),
- payment_type: amount === 0 ? Js.Nullable.return("setup_mandate") : Js.Nullable.null,
- setup_future_usage: amount === 0 ? Js.Nullable.return("off_session") : Js.Nullable.null,
- mandate_data: amount === 0 ? Js.Nullable.return(mandateData) : Js.Nullable.null,
+ payment_type: amount === 0.00 ? Js.Nullable.return("setup_mandate") : Js.Nullable.null,
+ setup_future_usage: amount === 0.00 ? Js.Nullable.return("off_session") : Js.Nullable.null,
+ mandate_data: amount === 0.00 ? Js.Nullable.return(mandateData) : Js.Nullable.null,
}
}
diff --git a/src/screens/HyperSwitch/SDKPayment/WebSDK.res b/src/screens/HyperSwitch/SDKPayment/WebSDK.res
index 170873f83..505a32eaf 100644
--- a/src/screens/HyperSwitch/SDKPayment/WebSDK.res
+++ b/src/screens/HyperSwitch/SDKPayment/WebSDK.res
@@ -232,7 +232,7 @@ module CheckoutForm = {
| WIDGET =>
}}