From 4693520ea4ac550d510d2f15fe2d01c5ba5c925b Mon Sep 17 00:00:00 2001 From: Sagar naik Date: Mon, 16 Dec 2024 12:11:25 +0530 Subject: [PATCH] feat: refunds success rate (#1917) --- src/container/NewAnalyticsContainer.res | 2 +- .../NewAnalytics/NewAnalyticsTypes.res | 2 +- .../NewRefundsAnalytics.res | 10 + .../NewRefundsAnalyticsEntity.res | 20 ++ .../RefundsSuccessRate/RefundsSuccessRate.res | 183 ++++++++++++++++++ .../RefundsSuccessRateTypes.res | 10 + .../RefundsSuccessRateUtils.res | 58 ++++++ 7 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 src/screens/NewAnalytics/NewRefundsAnalytics/NewRefundsAnalytics.res create mode 100644 src/screens/NewAnalytics/NewRefundsAnalytics/NewRefundsAnalyticsEntity.res create mode 100644 src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRate.res create mode 100644 src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRateTypes.res create mode 100644 src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRateUtils.res diff --git a/src/container/NewAnalyticsContainer.res b/src/container/NewAnalyticsContainer.res index 8da65d5f2..7cd36b08d 100644 --- a/src/container/NewAnalyticsContainer.res +++ b/src/container/NewAnalyticsContainer.res @@ -84,7 +84,7 @@ let make = () => { if newAnalyticsRefunds { tabs->Array.push({ title: "Refunds", - renderContent: () => React.null, + renderContent: () => , }) } diff --git a/src/screens/NewAnalytics/NewAnalyticsTypes.res b/src/screens/NewAnalytics/NewAnalyticsTypes.res index 06f162b9a..39049e549 100644 --- a/src/screens/NewAnalytics/NewAnalyticsTypes.res +++ b/src/screens/NewAnalytics/NewAnalyticsTypes.res @@ -18,7 +18,7 @@ type dimension = [ | #refund_error_message | #refund_reason ] -type status = [#charged | #failure] +type status = [#charged | #failure | #success | #pending] type metrics = [ | #sessionized_smart_retried_amount | #sessionized_payments_success_rate diff --git a/src/screens/NewAnalytics/NewRefundsAnalytics/NewRefundsAnalytics.res b/src/screens/NewAnalytics/NewRefundsAnalytics/NewRefundsAnalytics.res new file mode 100644 index 000000000..a8297c093 --- /dev/null +++ b/src/screens/NewAnalytics/NewRefundsAnalytics/NewRefundsAnalytics.res @@ -0,0 +1,10 @@ +@react.component +let make = () => { + open NewRefundsAnalyticsEntity + +
+ +
+} diff --git a/src/screens/NewAnalytics/NewRefundsAnalytics/NewRefundsAnalyticsEntity.res b/src/screens/NewAnalytics/NewRefundsAnalytics/NewRefundsAnalyticsEntity.res new file mode 100644 index 000000000..7630281d2 --- /dev/null +++ b/src/screens/NewAnalytics/NewRefundsAnalytics/NewRefundsAnalyticsEntity.res @@ -0,0 +1,20 @@ +open NewAnalyticsTypes + +// Refunds Success Rate +let refundsSuccessRateEntity: moduleEntity = { + requestBodyConfig: { + delta: false, + metrics: [#sessionized_refund_success_rate], + }, + title: "Refunds Success Rate", + domain: #refunds, +} + +let refundsSuccessRateChartEntity: chartEntity< + LineGraphTypes.lineGraphPayload, + LineGraphTypes.lineGraphOptions, + JSON.t, +> = { + getObjects: RefundsSuccessRateUtils.refundsSuccessRateMapper, + getChatOptions: LineGraphUtils.getLineGraphOptions, +} diff --git a/src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRate.res b/src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRate.res new file mode 100644 index 000000000..da137aa4e --- /dev/null +++ b/src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRate.res @@ -0,0 +1,183 @@ +open NewAnalyticsTypes +open NewAnalyticsHelper +open LineGraphTypes +open RefundsSuccessRateUtils + +module PaymentsSuccessRateHeader = { + open NewAnalyticsUtils + open LogicUtils + @react.component + let make = (~data, ~keyValue, ~granularity, ~setGranularity) => { + let setGranularity = value => { + setGranularity(_ => value) + } + let {filterValueJson} = React.useContext(FilterContext.filterContext) + let comparison = filterValueJson->getString("comparison", "")->DateRangeUtils.comparisonMapprer + + let primaryValue = getMetaDataValue(~data, ~index=0, ~key=keyValue) + let secondaryValue = getMetaDataValue(~data, ~index=1, ~key=keyValue) + + let (value, direction) = calculatePercentageChange(~primaryValue, ~secondaryValue) +
+ // will enable it in future +
+
+ {primaryValue->valueFormatter(Rate)->React.string} +
+ + valueFormatter(Rate)} /> + +
+ +
+ +
+
+
+
+ } +} + +@react.component +let make = ( + ~entity: moduleEntity, + ~chartEntity: chartEntity, +) => { + open LogicUtils + open APIUtils + let getURL = useGetURL() + let updateDetails = useUpdateMethod() + let (screenState, setScreenState) = React.useState(_ => PageLoaderWrapper.Loading) + + let (paymentsSuccessRateData, setPaymentsSuccessRateData) = React.useState(_ => + JSON.Encode.array([]) + ) + let (paymentsSuccessRateMetaData, setpaymentsProcessedMetaData) = React.useState(_ => + JSON.Encode.array([]) + ) + + let (granularity, setGranularity) = React.useState(_ => defaulGranularity) + let {filterValueJson} = React.useContext(FilterContext.filterContext) + let startTimeVal = filterValueJson->getString("startTime", "") + let endTimeVal = filterValueJson->getString("endTime", "") + let compareToStartTime = filterValueJson->getString("compareToStartTime", "") + let compareToEndTime = filterValueJson->getString("compareToEndTime", "") + let comparison = filterValueJson->getString("comparison", "")->DateRangeUtils.comparisonMapprer + + let getPaymentsSuccessRate = async () => { + setScreenState(_ => PageLoaderWrapper.Loading) + try { + let url = getURL( + ~entityName=ANALYTICS_REFUNDS, + ~methodType=Post, + ~id=Some((entity.domain: domain :> string)), + ) + + let primaryBody = NewAnalyticsUtils.requestBody( + ~startTime=startTimeVal, + ~endTime=endTimeVal, + ~delta=entity.requestBodyConfig.delta, + ~metrics=entity.requestBodyConfig.metrics, + ~granularity=granularity.value->Some, + ) + + let secondaryBody = NewAnalyticsUtils.requestBody( + ~startTime=compareToStartTime, + ~endTime=compareToEndTime, + ~delta=entity.requestBodyConfig.delta, + ~metrics=entity.requestBodyConfig.metrics, + ~granularity=granularity.value->Some, + ) + + let primaryResponse = await updateDetails(url, primaryBody, Post) + let primaryData = primaryResponse->getDictFromJsonObject->getArrayFromDict("queryData", []) + let primaryMetaData = primaryResponse->getDictFromJsonObject->getArrayFromDict("metaData", []) + + let (secondaryMetaData, secondaryModifiedData) = switch comparison { + | EnableComparison => { + let secondaryResponse = await updateDetails(url, secondaryBody, Post) + let secondaryData = + secondaryResponse->getDictFromJsonObject->getArrayFromDict("queryData", []) + let secondaryMetaData = + secondaryResponse->getDictFromJsonObject->getArrayFromDict("metaData", []) + let secondaryModifiedData = [secondaryData]->Array.map(data => { + NewAnalyticsUtils.fillMissingDataPoints( + ~data, + ~startDate=compareToStartTime, + ~endDate=compareToEndTime, + ~timeKey="time_bucket", + ~defaultValue={ + "payment_count": 0, + "payment_processed_amount": 0, + "time_bucket": startTimeVal, + }->Identity.genericTypeToJson, + ~granularity=granularity.value, + ) + }) + (secondaryMetaData, secondaryModifiedData) + } + | DisableComparison => ([], []) + } + if primaryData->Array.length > 0 { + let primaryModifiedData = [primaryData]->Array.map(data => { + NewAnalyticsUtils.fillMissingDataPoints( + ~data, + ~startDate=startTimeVal, + ~endDate=endTimeVal, + ~timeKey=Time_Bucket->getStringFromVariant, + ~defaultValue={ + "payment_count": 0, + "payment_success_rate": 0, + "time_bucket": startTimeVal, + }->Identity.genericTypeToJson, + ~granularity=granularity.value, + ) + }) + + setPaymentsSuccessRateData(_ => + primaryModifiedData->Array.concat(secondaryModifiedData)->Identity.genericTypeToJson + ) + setpaymentsProcessedMetaData(_ => + primaryMetaData->Array.concat(secondaryMetaData)->Identity.genericTypeToJson + ) + setScreenState(_ => PageLoaderWrapper.Success) + } else { + setScreenState(_ => PageLoaderWrapper.Custom) + } + } catch { + | _ => setScreenState(_ => PageLoaderWrapper.Custom) + } + } + + React.useEffect(() => { + if startTimeVal->isNonEmptyString && endTimeVal->isNonEmptyString { + getPaymentsSuccessRate()->ignore + } + None + }, (startTimeVal, endTimeVal, compareToStartTime, compareToEndTime, comparison)) + + let params = { + data: paymentsSuccessRateData, + xKey: Refund_Success_Rate->getStringFromVariant, + yKey: Time_Bucket->getStringFromVariant, + comparison, + } + +
+ + + } customUI={}> + getStringFromVariant} + granularity + setGranularity + /> +
+ +
+
+
+
+} diff --git a/src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRateTypes.res b/src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRateTypes.res new file mode 100644 index 000000000..b48571e82 --- /dev/null +++ b/src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRateTypes.res @@ -0,0 +1,10 @@ +type successRateCols = + | Refund_Success_Rate + | Total_Refund_Success_Rate + | Time_Bucket + +type payments_success_rate = { + refund_success_rate: float, + total_refund_success_rate: float, + time_bucket: string, +} diff --git a/src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRateUtils.res b/src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRateUtils.res new file mode 100644 index 000000000..af3f0b8e6 --- /dev/null +++ b/src/screens/NewAnalytics/NewRefundsAnalytics/RefundsSuccessRate/RefundsSuccessRateUtils.res @@ -0,0 +1,58 @@ +open NewAnalyticsUtils +open RefundsSuccessRateTypes + +let getStringFromVariant = value => { + switch value { + | Refund_Success_Rate => "refund_success_rate" + | Total_Refund_Success_Rate => "total_refund_success_rate" + | Time_Bucket => "time_bucket" + } +} + +let getVariantValueFromString = value => { + switch value { + | "refund_success_rate" => Refund_Success_Rate + | "total_refund_success_rate" => Total_Refund_Success_Rate + | "time_bucket" | _ => Time_Bucket + } +} + +let refundsSuccessRateMapper = ( + ~params: NewAnalyticsTypes.getObjects, +): LineGraphTypes.lineGraphPayload => { + open LineGraphTypes + let {data, xKey, yKey} = params + let comparison = switch params.comparison { + | Some(val) => Some(val) + | None => None + } + let primaryCategories = data->getCategories(0, yKey) + let secondaryCategories = data->getCategories(1, yKey) + + let lineGraphData = data->getLineGraphData(~xKey, ~yKey) + + let title = { + text: "Refunds Success Rate", + } + + { + categories: primaryCategories, + data: lineGraphData, + title, + yAxisMaxValue: 100->Some, + tooltipFormatter: tooltipFormatter( + ~secondaryCategories, + ~title="Refunds Success Rate", + ~metricType=Rate, + ~comparison, + ), + } +} + +open NewAnalyticsTypes +let tabs = [{label: "Daily", value: (#G_ONEDAY: granularity :> string)}] + +let defaulGranularity = { + label: "Hourly", + value: (#G_ONEDAY: granularity :> string), +}