diff --git a/src/components/DynamicSingleStat.res b/src/components/DynamicSingleStat.res index 22a562b9a..5bde5b271 100644 --- a/src/components/DynamicSingleStat.res +++ b/src/components/DynamicSingleStat.res @@ -115,7 +115,6 @@ let make = ( ~startTimeFilterKey, ~endTimeFilterKey, ~moduleName="", - ~setTotalVolume, ~showPercentage=true, ~chartAlignment=#column, ~isHomePage=false, @@ -304,37 +303,6 @@ let make = ( let data = dataArr->Array.map( item => { let (sectionName, json) = item - switch entity.totalVolumeCol { - | Some(val) => { - let totalVolumeKeyVal = - json - ->LogicUtils.getDictFromJsonObject - ->LogicUtils.getJsonObjectFromDict("queryData") - ->LogicUtils.getArrayFromJson([]) - ->Belt.Array.get(0) - ->Option.getWithDefault(Js.Json.object_(Dict.make())) - ->LogicUtils.getDictFromJsonObject - ->Dict.toArray - ->Array.find( - item => { - let (key, _) = item - key === val - }, - ) - switch totalVolumeKeyVal { - | Some(data) => { - let (_key, value) = data - setTotalVolume( - _ => value->Js.Json.decodeNumber->Option.getWithDefault(0.)->Belt.Float.toInt, - ) - } - - | None => () - } - } - - | None => () - } let data = entity.getObjects(json) let deltaTime = deltaItemToObjMapper(json) diff --git a/src/entryPoints/hyperswitch/HyperSwitchApp.res b/src/entryPoints/hyperswitch/HyperSwitchApp.res index 929e51945..1cf34ac70 100644 --- a/src/entryPoints/hyperswitch/HyperSwitchApp.res +++ b/src/entryPoints/hyperswitch/HyperSwitchApp.res @@ -322,6 +322,9 @@ let make = () => { + + + | list{"analytics-refunds"} => diff --git a/src/screens/HyperSwitch/Analytics/Analytics.res b/src/screens/HyperSwitch/Analytics/Analytics.res index 140ca923e..f9984ae7a 100644 --- a/src/screens/HyperSwitch/Analytics/Analytics.res +++ b/src/screens/HyperSwitch/Analytics/Analytics.res @@ -516,8 +516,6 @@ let make = ( let {filterValue, updateExistingKeys, filterValueJson} = React.useContext( FilterContext.filterContext, ) - - let (_totalVolume, setTotalVolume) = React.useState(_ => 0) let defaultFilters = [startTimeFilterKey, endTimeFilterKey] let (filteredTabKeys, filteredTabVales) = (tabKeys, tabValues) let chartEntity1 = chartEntity.default // User Journey - SemiDonut (Payment Metrics), Others - Default Chart Entity @@ -720,7 +718,6 @@ let make = ( endTimeFilterKey filterKeys=chartEntity.allFilterDimension moduleName - setTotalVolume showPercentage=false statSentiment={singleStatEntity.statSentiment->Option.getWithDefault(Dict.make())} /> diff --git a/src/screens/HyperSwitch/Analytics/AnalyticsTypes.res b/src/screens/HyperSwitch/Analytics/AnalyticsTypes.res index c4db779e0..e6cca7ea5 100644 --- a/src/screens/HyperSwitch/Analytics/AnalyticsTypes.res +++ b/src/screens/HyperSwitch/Analytics/AnalyticsTypes.res @@ -151,12 +151,22 @@ let allPaymentColumns = [ PaymentErrorMessage, AvgTicketSize, ] + +type smartRetrySingleState = { + retries_count: int, + retries_amount_processe: float, +} + +type smartRetrySingleStateSeries = { + retries_count: int, + retries_amount_processe: float, + time_series: string, +} + type paymentsSingleState = { payment_success_rate: float, payment_count: int, payment_success_count: int, - retries_count: int, - retries_amount_processe: float, connector_success_rate: float, payment_processed_amount: float, payment_avg_ticket_size: float, @@ -165,8 +175,6 @@ type paymentsSingleState = { type paymentsSingleStateSeries = { payment_success_rate: float, payment_count: int, - retries_count: int, - retries_amount_processe: float, connector_success_rate: float, payment_success_count: int, time_series: string, @@ -215,3 +223,5 @@ type nestedEntityType = { userBarChart?: DynamicChart.entity, userFunnelChart?: DynamicChart.entity, } + +type analyticsAPIEndPoints = [#PAYMENTS | #REFUNDS | #API_EVENTS | #SDK_EVENTS] diff --git a/src/screens/HyperSwitch/Analytics/HomePageOverview/HomePageOverviewComponent.res b/src/screens/HyperSwitch/Analytics/HomePageOverview/HomePageOverviewComponent.res index eeca86bb1..ca5139e4b 100644 --- a/src/screens/HyperSwitch/Analytics/HomePageOverview/HomePageOverviewComponent.res +++ b/src/screens/HyperSwitch/Analytics/HomePageOverview/HomePageOverviewComponent.res @@ -89,8 +89,6 @@ module SystemMetricsInsights = { open AnalyticsTypes @react.component let make = () => { - let (_totalVolume, setTotalVolume) = React.useState(_ => 0) - let getStatData = ( singleStatData: systemMetricsObjectType, timeSeriesData: array, @@ -186,7 +184,6 @@ module SystemMetricsInsights = { moduleName="SystemMetrics" defaultStartDate={dateDict.start_time} defaultEndDate={dateDict.end_time} - setTotalVolume showPercentage=false isHomePage=true wrapperClass="flex flex-wrap w-full h-full" diff --git a/src/screens/HyperSwitch/Analytics/HomePageOverview/PaymentsOverview/PaymentOverview.res b/src/screens/HyperSwitch/Analytics/HomePageOverview/PaymentsOverview/PaymentOverview.res index 16b456c14..117b2b7db 100644 --- a/src/screens/HyperSwitch/Analytics/HomePageOverview/PaymentsOverview/PaymentOverview.res +++ b/src/screens/HyperSwitch/Analytics/HomePageOverview/PaymentsOverview/PaymentOverview.res @@ -1,7 +1,6 @@ @react.component let make = () => { open HSAnalyticsUtils - let (_totalVolume, setTotalVolume) = React.useState(_ => 0) let metrics = [ "payment_success_rate", @@ -22,7 +21,6 @@ let make = () => { moduleName="Payments" defaultStartDate={dateDict.start_time} defaultEndDate={dateDict.end_time} - setTotalVolume showPercentage=false isHomePage=true statSentiment={singleStatEntity.statSentiment->Option.getWithDefault(Dict.make())} diff --git a/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/PaymentAnalytics.res b/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/PaymentAnalytics.res index df922a8b5..32d8a0ab6 100644 --- a/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/PaymentAnalytics.res +++ b/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/PaymentAnalytics.res @@ -15,7 +15,16 @@ let make = () => { try { let infoUrl = getURL(~entityName=ANALYTICS_PAYMENTS, ~methodType=Get, ~id=Some(domain), ()) let infoDetails = await fetchDetails(infoUrl) - setMetrics(_ => infoDetails->getDictFromJsonObject->getArrayFromDict("metrics", [])) + let metrics = + infoDetails + ->getDictFromJsonObject + ->getArrayFromDict("metrics", []) + ->Array.filter(item => { + let dict = item->getDictFromJsonObject + dict->Dict.get("name")->Belt.Option.getWithDefault(""->Js.Json.string) !== + "retries_count"->Js.Json.string + }) + setMetrics(_ => metrics) setDimensions(_ => infoDetails->getDictFromJsonObject->getArrayFromDict("dimensions", [])) setScreenState(_ => PageLoaderWrapper.Success) } catch { diff --git a/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/PaymentAnalyticsEntity.res b/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/PaymentAnalyticsEntity.res index 23a84d5c4..fc242299b 100644 --- a/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/PaymentAnalyticsEntity.res +++ b/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/PaymentAnalyticsEntity.res @@ -5,7 +5,8 @@ open DynamicSingleStat open HSAnalyticsUtils open AnalyticsTypes -let domain = "payments" +let apiPath: analyticsAPIEndPoints = #PAYMENTS +let domain = (apiPath :> string)->String.toLowerCase let makeMultiInputFieldInfo = FormRenderer.makeMultiInputFieldInfo let makeInputFieldInfo = FormRenderer.makeInputFieldInfo @@ -239,8 +240,6 @@ let paymentTableEntity = EntityType.makeEntity( let singleStateInitialValue = { payment_success_rate: 0.0, payment_count: 0, - retries_count: 0, - retries_amount_processe: 0.0, payment_success_count: 0, connector_success_rate: 0.0, payment_processed_amount: 0.0, @@ -250,8 +249,6 @@ let singleStateInitialValue = { let singleStateSeriesInitialValue = { payment_success_rate: 0.0, payment_count: 0, - retries_count: 0, - retries_amount_processe: 0.0, payment_success_count: 0, time_series: "", payment_processed_amount: 0.0, @@ -269,8 +266,6 @@ let singleStateItemToObjMapper = json => { payment_success_count: dict->getInt("payment_success_count", 0), payment_processed_amount: dict->getFloat("payment_processed_amount", 0.0), payment_avg_ticket_size: dict->getFloat("avg_ticket_size", 0.0), - retries_count: dict->getInt("retries_count", 0), - retries_amount_processe: dict->getFloat("retries_amount_processed", 0.0), connector_success_rate: dict->getFloat("connector_success_rate", 0.0), }) ->Option.getWithDefault({ @@ -289,8 +284,6 @@ let singleStateSeriesItemToObjMapper = json => { time_series: dict->getString("time_bucket", ""), payment_processed_amount: dict->getFloat("payment_processed_amount", 0.0)->setPrecision(), payment_avg_ticket_size: dict->getFloat("avg_ticket_size", 0.0)->setPrecision(), - retries_count: dict->getInt("retries_count", 0), - retries_amount_processe: dict->getFloat("retries_amount_processed", 0.0), connector_success_rate: dict->getFloat("connector_success_rate", 0.0), }) ->getWithDefault({ @@ -323,25 +316,8 @@ let getColumns: bool => array> = connector_succe { sectionName: "", columns: connector_success_rate - ? [ - SuccessRate, - Count, - SuccessCount, - ProcessedAmount, - AvgTicketSize, - RetriesCount, - RetriesAmountProcessed, - ConnectorSuccessRate, - ] - : [ - SuccessRate, - Count, - SuccessCount, - ProcessedAmount, - AvgTicketSize, - RetriesCount, - RetriesAmountProcessed, - ], + ? [SuccessRate, Count, SuccessCount, ProcessedAmount, AvgTicketSize, ConnectorSuccessRate] + : [SuccessRate, Count, SuccessCount, ProcessedAmount, AvgTicketSize], }, ] @@ -394,17 +370,6 @@ let constructData = ( ob.payment_avg_ticket_size /. 100.00, )) ->Js.Array2.sortInPlaceWith(compareLogic) - | "retries_count" => - singlestatTimeseriesData->Array.map(ob => ( - ob.time_series->DateTimeUtils.parseAsFloat, - ob.retries_count->Belt.Int.toFloat, - )) - | "retries_amount_processed" => - singlestatTimeseriesData - ->Array.map(ob => ( - ob.time_series->DateTimeUtils.parseAsFloat, - ob.retries_amount_processe /. 100.00, - )) ->Js.Array2.sortInPlaceWith(compareLogic) | "connector_success_rate" => singlestatTimeseriesData @@ -512,42 +477,8 @@ let getStatData = ( statType: "Volume", showDelta: false, } - | RetriesCount => { - title: "Smart Retries made", - tooltipText: "Total number of retries that were attempted after a failed payment attempt (Note: Only date range filters are supoorted currently)", - deltaTooltipComponent: AnalyticsUtils.singlestatDeltaTooltipFormat( - singleStatData.retries_count->Belt.Int.toFloat, - deltaTimestampData.currentSr, - ), - value: singleStatData.retries_count->Belt.Int.toFloat, - delta: { - singleStatData.retries_count->Belt.Int.toFloat - }, - data: constructData("retries_count", timeSeriesData), - statType: "Volume", - showDelta: false, - } - | RetriesAmountProcessed => { - title: `Smart Retries Savings`, - tooltipText: "Total savings in amount terms from retrying failed payments again through a second processor (Note: Only date range filters are supoorted currently)", - deltaTooltipComponent: AnalyticsUtils.singlestatDeltaTooltipFormat( - singleStatData.retries_amount_processe /. 100.00, - deltaTimestampData.currentSr, - ), - value: singleStatData.retries_amount_processe /. 100.00, - delta: { - Js.Float.fromString( - Js.Float.toFixedWithPrecision( - singleStatData.retries_amount_processe /. 100.00, - ~digits=2, - ), - ) - }, - data: constructData("retries_amount_processe", timeSeriesData), - statType: "Amount", - showDelta: false, - } - | ConnectorSuccessRate => { + + | ConnectorSuccessRate | _ => { title: "Payment Success Rate", tooltipText: "Total successful payments processed out of all user confirmed payments", deltaTooltipComponent: AnalyticsUtils.singlestatDeltaTooltipFormat( diff --git a/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/SmartRetries/SmartRetriesAnalytics.res b/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/SmartRetries/SmartRetriesAnalytics.res new file mode 100644 index 000000000..d5a5d3379 --- /dev/null +++ b/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/SmartRetries/SmartRetriesAnalytics.res @@ -0,0 +1,77 @@ +module SmartRetries = { + @react.component + let make = ( + ~pageTitle="", + ~startTimeFilterKey: string, + ~endTimeFilterKey: string, + ~tabKeys: array, + ~initialFixedFilters: Js.Json.t => array>, + ~singleStatEntity: DynamicSingleStat.entityType<'singleStatColType, 'b, 'b2>, + ~moduleName: string, + ) => { + let {updateExistingKeys, filterValueJson} = React.useContext(FilterContext.filterContext) + let defaultFilters = [startTimeFilterKey, endTimeFilterKey] + + let setInitialFilters = HSwitchRemoteFilter.useSetInitialFilters( + ~updateExistingKeys, + ~startTimeFilterKey, + ~endTimeFilterKey, + ) + + React.useEffect0(() => { + setInitialFilters() + None + }) + + let headerTextStyle = HSwitchUtils.getTextClass(~textVariant=H1, ()) + + Js.Dict.entries->Array.length > 0}> + + {pageTitle->React.string} + + + + Belt.Option.getWithDefault(Dict.make())} + /> + + + } +} + +@react.component +let make = () => { + open SmartRetriesAnalyticsEntity + + let metrics = [[("name", "retries_count"->Js.Json.string)]->LogicUtils.getJsonFromArrayOfJson] + + +} diff --git a/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/SmartRetries/SmartRetriesAnalyticsEntity.res b/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/SmartRetries/SmartRetriesAnalyticsEntity.res new file mode 100644 index 000000000..fb4b4b71f --- /dev/null +++ b/src/screens/HyperSwitch/Analytics/PaymentsAnalytics/SmartRetries/SmartRetriesAnalyticsEntity.res @@ -0,0 +1,149 @@ +open LogicUtils +open DynamicSingleStat +open HSAnalyticsUtils +open AnalyticsTypes +let apiPath: analyticsAPIEndPoints = #PAYMENTS +let domain = (apiPath :> string)->String.toLowerCase +let (startTimeFilterKey, endTimeFilterKey, optFilterKey) = ("startTime", "endTime", "opt") + +let singleStateInitialValue = { + retries_count: 0, + retries_amount_processe: 0.0, +} + +let singleStateItemToObjMapper = json => { + open Belt.Option + json + ->Js.Json.decodeObject + ->map(dict => { + retries_count: dict->getInt("retries_count", 0), + retries_amount_processe: dict->getFloat("retries_amount_processed", 0.0), + }) + ->Belt.Option.getWithDefault({ + singleStateInitialValue + }) +} + +let itemToObjMapper = json => { + let data = json->getQueryData->Array.map(singleStateItemToObjMapper) + switch data[0] { + | Some(ele) => ele + | None => singleStateInitialValue + } +} + +let singleStateSeriesInitialValue = { + retries_count: 0, + retries_amount_processe: 0.0, + time_series: "", +} + +let singleStateSeriesItemToObjMapper = json => { + open Belt.Option + json + ->Js.Json.decodeObject + ->map(dict => { + retries_count: dict->getInt("retries_count", 0), + retries_amount_processe: dict->getFloat("retries_amount_processed", 0.0), + time_series: dict->getString("time_bucket", ""), + }) + ->getWithDefault({ + singleStateSeriesInitialValue + }) +} + +let timeSeriesObjMapper = json => + json->getQueryData->Array.map(json => singleStateSeriesItemToObjMapper(json)) + +type metricsType = + | RetriesCount + | RetriesAmountProcessed + +let defaultColumns: array> = [ + { + sectionName: "", + columns: [RetriesCount, RetriesAmountProcessed], + }, +] + +let constructData = ( + key, + singlestatTimeseriesData: array, +) => { + switch key { + | "retries_count" => + singlestatTimeseriesData->Array.map(ob => ( + ob.time_series->DateTimeUtils.parseAsFloat, + ob.retries_count->Belt.Int.toFloat, + )) + | "retries_amount_processed" => + singlestatTimeseriesData + ->Array.map(ob => ( + ob.time_series->DateTimeUtils.parseAsFloat, + ob.retries_amount_processe /. 100.00, + )) + ->Js.Array2.sortInPlaceWith(compareLogic) + | _ => [] + } +} + +let getStatData = ( + singleStatData: smartRetrySingleState, + timeSeriesData: array, + deltaTimestampData: DynamicSingleStat.deltaRange, + colType, + _mode, +) => { + switch colType { + | RetriesCount => { + title: "Smart Retries made", + tooltipText: "Total number of retries that were attempted after a failed payment attempt (Note: Only date range filters are supoorted currently)", + deltaTooltipComponent: AnalyticsUtils.singlestatDeltaTooltipFormat( + singleStatData.retries_count->Belt.Int.toFloat, + deltaTimestampData.currentSr, + ), + value: singleStatData.retries_count->Belt.Int.toFloat, + delta: { + singleStatData.retries_count->Belt.Int.toFloat + }, + data: constructData("retries_count", timeSeriesData), + statType: "Volume", + showDelta: false, + } + | RetriesAmountProcessed => { + title: `Smart Retries Savings`, + tooltipText: "Total savings in amount terms from retrying failed payments again through a second processor (Note: Only date range filters are supoorted currently)", + deltaTooltipComponent: AnalyticsUtils.singlestatDeltaTooltipFormat( + singleStatData.retries_amount_processe /. 100.00, + deltaTimestampData.currentSr, + ), + value: singleStatData.retries_amount_processe /. 100.00, + delta: { + Js.Float.fromString( + Js.Float.toFixedWithPrecision( + singleStatData.retries_amount_processe /. 100.00, + ~digits=2, + ), + ) + }, + data: constructData("retries_amount_processe", timeSeriesData), + statType: "Amount", + showDelta: false, + } + } +} + +let getSingleStatEntity = metrics => { + urlConfig: [ + { + uri: `${HSwitchGlobalVars.hyperSwitchApiPrefix}/analytics/v1/metrics/${domain}`, + metrics: metrics->getStringListFromArrayDict, + }, + ], + getObjects: itemToObjMapper, + getTimeSeriesObject: timeSeriesObjMapper, + defaultColumns, + getData: getStatData, + totalVolumeCol: None, + matrixUriMapper: _ => `${HSwitchGlobalVars.hyperSwitchApiPrefix}/analytics/v1/metrics/${domain}`, +} diff --git a/src/screens/HyperSwitch/Analytics/RefundsAnalytics/RefundsAnalyticsEntity.res b/src/screens/HyperSwitch/Analytics/RefundsAnalytics/RefundsAnalyticsEntity.res index d247529fc..f8bbadc3a 100644 --- a/src/screens/HyperSwitch/Analytics/RefundsAnalytics/RefundsAnalyticsEntity.res +++ b/src/screens/HyperSwitch/Analytics/RefundsAnalytics/RefundsAnalyticsEntity.res @@ -3,7 +3,11 @@ open DynamicSingleStat open AnalyticsTypes open HSAnalyticsUtils -let domain = "refunds" +let apiPath: analyticsAPIEndPoints = #REFUNDS +let domain = (apiPath :> string)->String.toLowerCase +let makeMultiInputFieldInfo = FormRenderer.makeMultiInputFieldInfo +let makeInputFieldInfo = FormRenderer.makeInputFieldInfo +let makeFieldInfo = FormRenderer.makeFieldInfo let colMapper = (col: refundColType) => { switch col { diff --git a/src/screens/HyperSwitch/Analytics/SystemMetrics/SystemMetricsAnalytics.res b/src/screens/HyperSwitch/Analytics/SystemMetrics/SystemMetricsAnalytics.res index 17f47078e..21e86f8f2 100644 --- a/src/screens/HyperSwitch/Analytics/SystemMetrics/SystemMetricsAnalytics.res +++ b/src/screens/HyperSwitch/Analytics/SystemMetrics/SystemMetricsAnalytics.res @@ -233,7 +233,6 @@ module SystemMetricsAnalytics = { let startTimeVal = getModuleFilters->getString(startTimeFilterKey, "") let endTimeVal = getModuleFilters->getString(endTimeFilterKey, "") let {updateExistingKeys} = FilterContext.filterContext->React.useContext - let (_totalVolume, setTotalVolume) = React.useState(_ => 0) let defaultFilters = [startTimeFilterKey, endTimeFilterKey] let chartEntity1 = chartEntity.default @@ -315,7 +314,6 @@ module SystemMetricsAnalytics = { endTimeFilterKey filterKeys=chartEntity.allFilterDimension moduleName - setTotalVolume showPercentage=false statSentiment={singleStatEntity.statSentiment->Option.getWithDefault(Dict.make())} /> diff --git a/src/screens/HyperSwitch/Analytics/SystemMetrics/SystemMetricsAnalyticsUtils.res b/src/screens/HyperSwitch/Analytics/SystemMetrics/SystemMetricsAnalyticsUtils.res index ca0df0048..caaa74110 100644 --- a/src/screens/HyperSwitch/Analytics/SystemMetrics/SystemMetricsAnalyticsUtils.res +++ b/src/screens/HyperSwitch/Analytics/SystemMetrics/SystemMetricsAnalyticsUtils.res @@ -2,7 +2,8 @@ open LogicUtils open DynamicSingleStat open HSAnalyticsUtils open AnalyticsTypes -let domain = "api_events" +let apiPath: analyticsAPIEndPoints = #API_EVENTS +let domain = (apiPath :> string)->String.toLowerCase let singleStateInitialValue = { latency: 0.0, diff --git a/src/screens/HyperSwitch/Analytics/UserAnalytics/UserJourneyAnalyticsEntity.res b/src/screens/HyperSwitch/Analytics/UserAnalytics/UserJourneyAnalyticsEntity.res index 9d4358465..506175a2a 100644 --- a/src/screens/HyperSwitch/Analytics/UserAnalytics/UserJourneyAnalyticsEntity.res +++ b/src/screens/HyperSwitch/Analytics/UserAnalytics/UserJourneyAnalyticsEntity.res @@ -3,7 +3,12 @@ open DynamicSingleStat open HSAnalyticsUtils open AnalyticsTypes -let domain = "sdk_events" +let apiPath: analyticsAPIEndPoints = #SDK_EVENTS +let domain = (apiPath :> string)->String.toLowerCase +let makeMultiInputFieldInfo = FormRenderer.makeMultiInputFieldInfo +let makeInputFieldInfo = FormRenderer.makeInputFieldInfo + +let makeFieldInfo = FormRenderer.makeFieldInfo // edited //// single stat