Skip to content

Commit

Permalink
feat: smart retry amount analytics (#1872)
Browse files Browse the repository at this point in the history
  • Loading branch information
sagarnaikjuspay authored Dec 9, 2024
1 parent e2d1591 commit c5c5542
Show file tree
Hide file tree
Showing 5 changed files with 588 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,6 @@ let paymentsProcessedMapper = (
),
}
}
// Need to modify
let getMetaData = json =>
json
->getArrayFromJson([])
->getValueFromArray(0, JSON.Encode.array([]))
->getDictFromJsonObject
->getArrayFromDict("metaData", [])
->getValueFromArray(0, JSON.Encode.array([]))
->getDictFromJsonObject

let visibleColumns = [Time_Bucket]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
open NewAnalyticsTypes
// Smart Retry Payments Processed
let smartRetryPaymentsProcessedEntity: moduleEntity = {
requestBodyConfig: {
delta: false,
metrics: [#sessionized_payment_processed_amount],
},
title: "Smart Retry Payments Processed",
domain: #payments,
}

let smartRetryPaymentsProcessedChartEntity: chartEntity<
LineGraphTypes.lineGraphPayload,
LineGraphTypes.lineGraphOptions,
JSON.t,
> = {
getObjects: SmartRetryPaymentsProcessedUtils.smartRetryPaymentsProcessedMapper,
getChatOptions: LineGraphUtils.getLineGraphOptions,
}

let smartRetryPaymentsProcessedTableEntity = {
open SmartRetryPaymentsProcessedUtils
EntityType.makeEntity(
~uri=``,
~getObjects,
~dataKey="queryData",
~defaultColumns=visibleColumns,
~requiredSearchFieldsList=[],
~allColumns=visibleColumns,
~getCell,
~getHeading,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
open NewAnalyticsTypes
open NewAnalyticsHelper
open LineGraphTypes
open SmartRetryPaymentsProcessedUtils
open SmartRetryPaymentsProcessedTypes
open NewSmartRetryAnalyticsEntity

module TableModule = {
open LogicUtils
@react.component
let make = (~data, ~className="") => {
let (offset, setOffset) = React.useState(_ => 0)
let defaultSort: Table.sortedObject = {
key: "",
order: Table.INC,
}
let tableBorderClass = "border-collapse border border-jp-gray-940 border-solid border-2 border-opacity-30 dark:border-jp-gray-dark_table_border_color dark:border-opacity-30"

let smartRetryPaymentsProcessed =
data
->Array.map(item => {
item->getDictFromJsonObject->tableItemToObjMapper
})
->Array.map(Nullable.make)

let defaultCols = [Payment_Processed_Amount, Payment_Processed_Count]
let visibleColumns = defaultCols->Array.concat(visibleColumns)

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

module SmartRetryPaymentsProcessedHeader = {
open NewAnalyticsUtils
open LogicUtils
@react.component
let make = (
~data: JSON.t,
~viewType,
~setViewType,
~selectedMetric,
~setSelectedMetric,
~granularity,
~setGranularity,
) => {
let {filterValueJson} = React.useContext(FilterContext.filterContext)
let comparison = filterValueJson->getString("comparison", "")->DateRangeUtils.comparisonMapprer

let primaryValue = getMetaDataValue(~data, ~index=0, ~key=selectedMetric.value)
let secondaryValue = getMetaDataValue(~data, ~index=1, ~key=selectedMetric.value)

let (primaryValue, secondaryValue) = if selectedMetric.value->isAmountMetric {
(primaryValue /. 100.0, secondaryValue /. 100.0)
} else {
(primaryValue, secondaryValue)
}

let (value, direction) = calculatePercentageChange(~primaryValue, ~secondaryValue)

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

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

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

let metricType = switch selectedMetric.value->getVariantValueFromString {
| Payment_Processed_Amount => Amount
| _ => Volume
}

let suffix = metricType == Amount ? "USD" : ""

<div className="w-full px-7 py-8 grid grid-cols-1">
<div className="flex gap-2 items-center">
<div className="text-fs-28 font-semibold">
{`${primaryValue->valueFormatter(metricType)} ${suffix}`->React.string} // TODO:Currency need to be picked from filter
</div>
<RenderIf condition={comparison == EnableComparison}>
<StatisticsCard value direction />
</RenderIf>
</div>
// will enable it in future
<RenderIf condition={false}>
<div className="flex justify-center">
<Tabs option={granularity} setOption={setGranularity} options={tabs} />
</div>
</RenderIf>
<div className="flex gap-2 justify-end">
<CustomDropDown
buttonText={selectedMetric} options={dropDownOptions} setOption={setSelectedMetric}
/>
<TabSwitch viewType setViewType />
</div>
</div>
}
}

@react.component
let make = (
~entity: moduleEntity,
~chartEntity: chartEntity<lineGraphPayload, lineGraphOptions, JSON.t>,
) => {
open LogicUtils
open APIUtils
let getURL = useGetURL()
let updateDetails = useUpdateMethod()
let (screenState, setScreenState) = React.useState(_ => PageLoaderWrapper.Loading)
let {filterValueJson} = React.useContext(FilterContext.filterContext)
let (smartRetryPaymentsProcessedData, setSmartRetryPaymentsProcessedData) = React.useState(_ =>
JSON.Encode.array([])
)
let (
smartRetryPaymentsProcessedTableData,
setSmartRetryPaymentsProcessedTableData,
) = React.useState(_ => [])
let (
smartRetryPaymentsProcessedMetaData,
setSmartRetryPaymentsProcessedMetaData,
) = React.useState(_ => JSON.Encode.array([]))
let (selectedMetric, setSelectedMetric) = React.useState(_ => defaultMetric)
let (granularity, setGranularity) = React.useState(_ => defaulGranularity)
let (viewType, setViewType) = React.useState(_ => Graph)
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 getSmartRetryPaymentsProcessed = async () => {
setScreenState(_ => PageLoaderWrapper.Loading)
try {
let url = getURL(
~entityName=ANALYTICS_PAYMENTS_V2,
~methodType=Post,
~id=Some((entity.domain: domain :> string)),
)

let primaryBody = NewAnalyticsUtils.requestBody(
~dimensions=[],
~startTime=startTimeVal,
~endTime=endTimeVal,
~delta=entity.requestBodyConfig.delta,
~metrics=entity.requestBodyConfig.metrics,
~granularity=granularity.value->Some,
)

let secondaryBody = NewAnalyticsUtils.requestBody(
~dimensions=[],
~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", [])
->PaymentsProcessedUtils.modifyQueryData
->modifySmartRetryQueryData
let primaryMetaData =
primaryResponse
->getDictFromJsonObject
->getArrayFromDict("metaData", [])
->modifySmartRetryMetaData
setSmartRetryPaymentsProcessedTableData(_ => primaryData)

let (secondaryMetaData, secondaryModifiedData) = switch comparison {
| EnableComparison => {
let secondaryResponse = await updateDetails(url, secondaryBody, Post)
let secondaryData =
secondaryResponse
->getDictFromJsonObject
->getArrayFromDict("queryData", [])
->PaymentsProcessedUtils.modifyQueryData
->modifySmartRetryQueryData
let secondaryMetaData =
secondaryResponse
->getDictFromJsonObject
->getArrayFromDict("metaData", [])
->modifySmartRetryMetaData

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",
~defaultValue={
"payment_count": 0,
"payment_processed_amount": 0,
"time_bucket": startTimeVal,
}->Identity.genericTypeToJson,
~granularity=granularity.value,
)
})

setSmartRetryPaymentsProcessedData(_ =>
primaryModifiedData->Array.concat(secondaryModifiedData)->Identity.genericTypeToJson
)
setSmartRetryPaymentsProcessedMetaData(_ =>
primaryMetaData->Array.concat(secondaryMetaData)->Identity.genericTypeToJson
)
setScreenState(_ => PageLoaderWrapper.Success)
} else {
setScreenState(_ => PageLoaderWrapper.Custom)
}
} catch {
| _ => setScreenState(_ => PageLoaderWrapper.Custom)
}
}
React.useEffect(() => {
if startTimeVal->isNonEmptyString && endTimeVal->isNonEmptyString {
getSmartRetryPaymentsProcessed()->ignore
}
None
}, (startTimeVal, endTimeVal, compareToStartTime, compareToEndTime, comparison))

let params = {
data: smartRetryPaymentsProcessedData,
xKey: selectedMetric.value,
yKey: Time_Bucket->getStringFromVariant,
comparison,
}

<div>
<ModuleHeader title={entity.title} />
<Card>
<PageLoaderWrapper
screenState customLoader={<Shimmer layoutId=entity.title />} customUI={<NoData />}>
<SmartRetryPaymentsProcessedHeader
data=smartRetryPaymentsProcessedMetaData
viewType
setViewType
selectedMetric
setSelectedMetric
granularity
setGranularity
/>
<div className="mb-5">
{switch viewType {
| Graph =>
<LineGraph
entity={chartEntity} data={chartEntity.getObjects(~params)} className="mr-3"
/>
| Table => <TableModule data={smartRetryPaymentsProcessedTableData} className="mx-7" />
}}
</div>
</PageLoaderWrapper>
</Card>
</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
type smartRetryPaymentsProcessedCols =
| Payment_Processed_Amount
| Payment_Processed_Count
| Total_Payment_Processed_Amount
| Total_Payment_Processed_Count
| Time_Bucket

type smartRetryPaymentsProcessedObject = {
smart_retry_payment_processed_amount_in_usd: float,
smart_retry_payment_processed_count: int,
total_payment_smart_retry_processed_amount_in_usd: float,
total_payment_smart_retry_processed_count: int,
time_bucket: string,
}
Loading

0 comments on commit c5c5542

Please sign in to comment.