Skip to content

Commit

Permalink
feat: failed payment distribution graph (#1528)
Browse files Browse the repository at this point in the history
Co-authored-by: Jeeva Ramachandran <[email protected]>
Co-authored-by: Sagar Naik <[email protected]>
  • Loading branch information
3 people authored Oct 8, 2024
1 parent d32e536 commit 470b582
Show file tree
Hide file tree
Showing 10 changed files with 337 additions and 18 deletions.
2 changes: 2 additions & 0 deletions src/screens/NewAnalytics/NewAnalyticsTypes.res
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ type metrics = [
| #payment_method_type
| #card_network
| #authentication_type
| #payments_distribution
| #smart_retried_amount
| #payments_success_rate
| #refund_success_count
| #dispute_status_metric
| #payment_failed_rate
]
type granularity = [
| #G_ONEDAY
Expand Down
2 changes: 2 additions & 0 deletions src/screens/NewAnalytics/NewAnalyticsUtils.res
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ let requestBody = (
~applyFilterFor as _: option<array<status>>=None,
~delta: option<bool>=None,
~granularity: option<string>=None,
~distributionValues: option<JSON.t>=None,
) => {
let metrics = metrics->Array.map(v => (v: metrics :> string))
let filter = Dict.make()->JSON.Encode.object->Some
Expand All @@ -68,6 +69,7 @@ let requestBody = (
~startDateTime=startTime,
~endDateTime=endTime,
~granularity,
~distributionValues,
)->JSON.Encode.object,
]->JSON.Encode.array
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
open NewAnalyticsTypes
open NewAnalyticsHelper
open NewPaymentAnalyticsEntity
open BarGraphTypes
open FailedPaymentsDistributionUtils

module TableModule = {
@react.component
let make = (~data, ~className="", ~selectedTab: string) => {
let (offset, setOffset) = React.useState(_ => 0)
let defaultSort: Table.sortedObject = {
key: "",
order: Table.INC,
}
let tableBorderClass = "border-2 border-solid border-jp-gray-940 border-collapse border-opacity-30 dark:border-jp-gray-dark_table_border_color dark:border-opacity-30"
let visibleColumns = visibleColumns->Array.concat([selectedTab->getDimentionType])
let tableData = getTableData(data)

<div className>
<LoadedTable
visibleColumns
title=" "
hideTitle=true
actualData={tableData}
entity=failedPaymentsDistributionTableEntity
resultsPerPage=10
totalResults={tableData->Array.length}
offset
setOffset
defaultSort
currrentFetchCount={tableData->Array.length}
tableLocalFilter=false
tableheadingClass=tableBorderClass
tableBorderClass
ignoreHeaderBg=true
tableDataBorderClass=tableBorderClass
isAnalyticsModule=true
/>
</div>
}
}

module FailedPaymentsDistributionHeader = {
@react.component
let make = (~viewType, ~setViewType, ~groupBy, ~setGroupBy) => {
let setViewType = value => {
setViewType(_ => value)
}

let setGroupBy = value => {
setGroupBy(_ => value)
}

<div className="w-full px-7 py-8 flex justify-between">
<Tabs option={groupBy} setOption={setGroupBy} options={tabs} />
<div className="flex gap-2">
<TabSwitch viewType setViewType />
</div>
</div>
}
}

@react.component
let make = (
~entity: moduleEntity,
~chartEntity: chartEntity<barGraphPayload, barGraphOptions, JSON.t>,
) => {
open LogicUtils
open APIUtils
let getURL = useGetURL()
let updateDetails = useUpdateMethod()
let {filterValueJson} = React.useContext(FilterContext.filterContext)
let (screenState, setScreenState) = React.useState(_ => PageLoaderWrapper.Success)
let (failedPaymentsDistribution, setfailedPaymentsDistribution) = React.useState(_ =>
JSON.Encode.array([])
)
let (viewType, setViewType) = React.useState(_ => Graph)
let (groupBy, setGroupBy) = React.useState(_ => defaulGroupBy)
let startTimeVal = filterValueJson->getString("startTime", "")
let endTimeVal = filterValueJson->getString("endTime", "")

let getFailedPaymentsDistribution = async () => {
try {
setScreenState(_ => PageLoaderWrapper.Loading)
let url = getURL(
~entityName=ANALYTICS_PAYMENTS,
~methodType=Post,
~id=Some((entity.domain: domain :> string)),
)

let body = NewAnalyticsUtils.requestBody(
~dimensions=[],
~startTime=startTimeVal,
~endTime=endTimeVal,
~delta=entity.requestBodyConfig.delta,
~filters=entity.requestBodyConfig.filters,
~metrics=entity.requestBodyConfig.metrics,
~groupByNames=[groupBy.value]->Some,
~customFilter=entity.requestBodyConfig.customFilter,
~applyFilterFor=entity.requestBodyConfig.applyFilterFor,
)

let response = await updateDetails(url, body, Post)
let responseData = response->getDictFromJsonObject->getArrayFromDict("queryData", [])
let arr =
response
->getDictFromJsonObject
->getArrayFromDict("queryData", [])

if arr->Array.length > 0 {
setfailedPaymentsDistribution(_ => responseData->JSON.Encode.array)
setScreenState(_ => PageLoaderWrapper.Success)
} else {
setScreenState(_ => PageLoaderWrapper.Custom)
}
} catch {
| _ => setScreenState(_ => PageLoaderWrapper.Custom)
}
}

React.useEffect(() => {
if startTimeVal->isNonEmptyString && endTimeVal->isNonEmptyString {
getFailedPaymentsDistribution()->ignore
}
None
}, [startTimeVal, endTimeVal, groupBy.value])

<div>
<ModuleHeader title={entity.title} />
<Card>
<PageLoaderWrapper
screenState customLoader={<Shimmer layoutId=entity.title />} customUI={<NoData />}>
<FailedPaymentsDistributionHeader viewType setViewType groupBy setGroupBy />
<div className="mb-5">
{switch viewType {
| Graph =>
<BarGraph
entity={chartEntity}
object={chartEntity.getObjects(
~data=failedPaymentsDistribution,
~xKey=getXKey(~isSmartRetry=false),
~yKey=groupBy.value,
)}
className="mr-3"
/>
| Table =>
<TableModule
data={failedPaymentsDistribution} className="mx-7" selectedTab={groupBy.value}
/>
}}
</div>
</PageLoaderWrapper>
</Card>
</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type failedPaymentsDistributionObject = {
payments_failure_rate_distribution: int,
connector: string,
payment_method: string,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
open NewPaymentAnalyticsUtils
open FailedPaymentsDistributionTypes
open LogicUtils

let getDimentionType = string => {
switch string {
| "connector" => #connector
| "payment_method" => #payment_method
| "payment_method_type" => #payment_method_type
| "card_network" => #card_network
| "authentication_type" | _ => #authentication_type
}
}

let getXKey = (~isSmartRetry) => {
switch isSmartRetry {
| true => "payments_failure_rate_distribution"
| false => "payments_failure_rate_distribution_without_smart_retries"
}
}

let failedPaymentsDistributionMapper = (
~data: JSON.t,
~xKey: string,
~yKey: string,
): BarGraphTypes.barGraphPayload => {
open BarGraphTypes
let categories = [data]->JSON.Encode.array->getCategories(0, yKey)
let barGraphData = getBarGraphObj(
~array=data->getArrayFromJson([]),
~key=xKey,
~name=xKey->snakeToTitle,
~color="#BA3535",
)
let title = {
text: "",
}
{categories, data: [barGraphData], title}
}

open NewAnalyticsTypes
let visibleColumns: array<metrics> = [#payment_failed_rate]

let tableItemToObjMapper: Dict.t<JSON.t> => failedPaymentsDistributionObject = dict => {
{
payments_failure_rate_distribution: dict->getInt("payments_failure_rate_distribution", 0),
connector: dict->getString((#connector: metrics :> string), ""),
payment_method: dict->getString((#payment_method: metrics :> string), ""),
}
}

let getObjects: JSON.t => array<failedPaymentsDistributionObject> = json => {
json
->LogicUtils.getArrayFromJson([])
->Array.map(item => {
tableItemToObjMapper(item->getDictFromJsonObject)
})
}

let getHeading = (colType: metrics) => {
switch colType {
| #payment_failed_rate =>
Table.makeHeaderInfo(
~key=(#payment_failed_rate: metrics :> string),
~title="Payments Failed Rate",
~dataType=TextType,
)
| #connector =>
Table.makeHeaderInfo(
~key=(#connector: metrics :> string),
~title="Connector",
~dataType=TextType,
)
| #payment_method | _ =>
Table.makeHeaderInfo(
~key=(#payment_method: metrics :> string),
~title="Payment Method",
~dataType=TextType,
)
}
}

let getCell = (obj, colType: metrics): Table.cell => {
switch colType {
| #payment_failed_rate => Text(obj.payments_failure_rate_distribution->Int.toString)
| #connector => Text(obj.connector)
| #payment_method | _ => Text(obj.payment_method)
}
}

let getTableData = json => {
json->getArrayDataFromJson(tableItemToObjMapper)->Array.map(Nullable.make)
}

let tabs = [
{
label: "Connector",
value: (#connector: dimension :> string),
},
{
label: "Payment Method",
value: (#payment_method: dimension :> string),
},
{
label: "Payment Method Type",
value: (#payment_method_type: dimension :> string),
},
{
label: "Authentication Type",
value: (#authentication_type: dimension :> string),
},
]

let defaulGroupBy = {
label: "Connector",
value: (#connector: dimension :> string),
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ let make = () => {
entity={successfulPaymentsDistributionEntity}
chartEntity={successfulPaymentsDistributionChartEntity}
/>
<FailedPaymentsDistribution
entity={failedPaymentsDistributionEntity} chartEntity={failedPaymentsDistributionChartEntity}
/>
</div>
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ let paymentsSuccessRateChartEntity: chartEntity<
getChatOptions: LineGraphUtils.getLineGraphOptions,
}

// Payments Distribution
// Successful Payments Distribution
let successfulPaymentsDistributionEntity: moduleEntity = {
requestBodyConfig: {
delta: false,
metrics: [#payment_success_rate],
metrics: [#payments_distribution],
},
title: "Payments Distribution",
title: "Successful Payments Distribution",
domain: #payments,
}

Expand All @@ -112,3 +112,36 @@ let successfulPaymentsDistributionTableEntity = {
~getHeading,
)
}

// Failed Payments Distribution
let failedPaymentsDistributionEntity: moduleEntity = {
requestBodyConfig: {
delta: false,
metrics: [#payments_distribution],
},
title: "Failed Payments Distribution",
domain: #payments,
}

let failedPaymentsDistributionChartEntity: chartEntity<
BarGraphTypes.barGraphPayload,
BarGraphTypes.barGraphOptions,
JSON.t,
> = {
getObjects: FailedPaymentsDistributionUtils.failedPaymentsDistributionMapper,
getChatOptions: BarGraphUtils.getBarGraphOptions,
}

let failedPaymentsDistributionTableEntity = {
open FailedPaymentsDistributionUtils
EntityType.makeEntity(
~uri=``,
~getObjects,
~dataKey="queryData",
~defaultColumns=visibleColumns,
~requiredSearchFieldsList=[],
~allColumns=visibleColumns,
~getCell,
~getHeading,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ let getBarGraphObj = (
dataObj
}

let getBarGraphData = (json: JSON.t, key: string): BarGraphTypes.data => {
let getBarGraphData = (json: JSON.t, key: string, barColor: string): BarGraphTypes.data => {
json
->getArrayFromJson([])
->Array.mapWithIndex((item, index) => {
Expand All @@ -90,7 +90,7 @@ let getBarGraphData = (json: JSON.t, key: string): BarGraphTypes.data => {
showInLegend: false,
name: `Series ${(index + 1)->Int.toString}`,
data,
color: "#7CC88F",
color: barColor,
}
dataObj
})
Expand Down
Loading

0 comments on commit 470b582

Please sign in to comment.