Skip to content

Commit 393c1b1

Browse files
feat: added overview table component and added pagination for transaction view
1 parent a84fb86 commit 393c1b1

File tree

9 files changed

+173
-19304
lines changed

9 files changed

+173
-19304
lines changed

src/APIUtils/APIUtils.res

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ let getV2Url = (
151151

152152
let useGetURL = () => {
153153
let {getUserInfoData} = React.useContext(UserInfoProvider.defaultContext)
154+
let hypersenseBaseURL = "hypersense"
154155

155156
let getUrl = (
156157
~entityName: entityTypeWithVersion,
@@ -702,7 +703,7 @@ let useGetURL = () => {
702703

703704
/* RECONCILIATION */
704705
| RECON => `recon/${(reconType :> string)->String.toLowerCase}`
705-
| HYPERSENSE => `hypersense/${(hypersenseType :> string)->String.toLowerCase}`
706+
| HYPERSENSE => `${hypersenseBaseURL}/${(hypersenseType :> string)->String.toLowerCase}`
706707

707708
/* REPORTS */
708709
| PAYMENT_REPORT =>
@@ -1189,8 +1190,11 @@ let useGetURL = () => {
11891190
| INTEGRATION_DETAILS => `user/get_sandbox_integration_details`
11901191
| SDK_PAYMENT => "payments"
11911192
| CHAT_BOT => `chat/ai/data`
1192-
| FEE_OVERVIEW_ESTIMATE => `hypersense/fee_estimate/get-overview-estimate`
1193-
| FEE_TRANSACTION_ESTIMATE => `hypersense/fee_estimate/get-transaction-fee-estimation`
1193+
| FEE_OVERVIEW_ESTIMATE => `${hypersenseBaseURL}/fee_estimate/get-overview-estimate`
1194+
| FEE_TRANSACTION_ESTIMATE =>
1195+
`${hypersenseBaseURL}/fee_estimate/get-transaction-fee-estimation`
1196+
| FEE_OVERVIEW_ESTIMATE_BREAKDOWN =>
1197+
`${hypersenseBaseURL}/fee_estimate/get-overview-estimate-table`
11941198
}
11951199

11961200
| V2(entityNameForv2) =>

src/APIUtils/APIUtilsTypes.res

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ type entityName =
8787
| CHAT_BOT
8888
| FEE_OVERVIEW_ESTIMATE
8989
| FEE_TRANSACTION_ESTIMATE
90+
| FEE_OVERVIEW_ESTIMATE_BREAKDOWN
9091

9192
type v2entityNameType =
9293
| CUSTOMERS

src/Recoils/TableAtoms.res

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ let apiDefaultCols = Recoil.atom("hyperSwitchApiDefaultCols", DeveloperUtils.def
1212

1313
let customersMapDefaultCols = Recoil.atom("customersMapDefaultCols", CustomersEntity.defaultColumns)
1414

15+
let feeEstimationTransactionViewMapDefaultCols = Recoil.atom("feeEstimationTransactionViewMapDefaultCols", FeeEstimationEntity.defaultColumns)
16+
1517
let revenueRecoveryMapDefaultCols = Recoil.atom(
1618
"revenueRecoveryMapDefaultCols",
1719
RevenueRecoveryEntity.defaultColumns,

src/screens/Analytics/FeeEstimation/FeeEstimation.res

Lines changed: 108 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,74 @@ open FeeEstimationHelper
55
open Typography
66
open LogicUtils
77

8-
module OverviewContainer = {
8+
module OverviewBreakdown = {
99
@react.component
1010
let make = (~monthFilters) => {
1111
let getURL = APIUtils.useGetURL()
1212
let showToast = ToastState.useShowToast()
1313
let updateDetails = APIUtils.useUpdateMethod(~showErrorToast=false)
14+
let defaultValue: LoadedTable.pageDetails = {offset: 0, resultsPerPage: 10}
15+
let pageDetailDict = Recoil.useRecoilValueFromAtom(LoadedTable.table_pageDetails)
16+
let pageDetail = pageDetailDict->Dict.get(costBreakDownTableKey)->Option.getOr(defaultValue)
1417

18+
let (screenState, setScreenState) = React.useState(_ => PageLoaderWrapper.Loading)
19+
let (overViewBreakdownRawData, setOverViewBreakdownRawData) = React.useState(_ =>
20+
Dict.make()->FeeEstimationUtils.overviewBreakdownMapper
21+
)
22+
let (overViewBreakdownTableData, setOverViewBreakdownTableData) = React.useState(_ => [])
23+
24+
let fetchOverviewTableData = async () => {
25+
try {
26+
setScreenState(_ => PageLoaderWrapper.Loading)
27+
let url = getURL(~entityName=V1(FEE_OVERVIEW_ESTIMATE_BREAKDOWN), ~methodType=Post)
28+
let body = {
29+
"offset": pageDetail.offset,
30+
"limit": pageDetail.resultsPerPage,
31+
"startDate": monthFilters["startDate"],
32+
"endDate": monthFilters["endDate"],
33+
}->Identity.genericTypeToJson
34+
35+
let response = await updateDetails(url, body, Fetch.Post)
36+
let overViewBreakdownDataResponse =
37+
response
38+
->getDictFromJsonObject
39+
->getDictfromDict("response")
40+
->FeeEstimationUtils.overviewBreakdownMapper
41+
42+
Console.log2("overview breakdown data fetched:", overViewBreakdownDataResponse)
43+
setOverViewBreakdownRawData(_ => overViewBreakdownDataResponse)
44+
setOverViewBreakdownTableData(_ => overViewBreakdownDataResponse.overviewBreakdown)
45+
setScreenState(_ => PageLoaderWrapper.Success)
46+
} catch {
47+
| _ => {
48+
setScreenState(_ => PageLoaderWrapper.Error(""))
49+
showToast(
50+
~message="Error while fetching overview data. Please try again",
51+
~toastType=ToastError,
52+
)
53+
}
54+
}
55+
}
56+
57+
React.useEffect(() => {
58+
fetchOverviewTableData()->ignore
59+
None
60+
}, [pageDetail.offset, pageDetail.resultsPerPage])
61+
<PageLoaderWrapper
62+
screenState
63+
customUI={<NewAnalyticsHelper.NoData height="h-56" message="No data available" />}
64+
customLoader={<Shimmer styleClass="w-full h-56 rounded-xl" />}>
65+
<CostBreakDown overViewBreakdownRawData overViewBreakdownTableData />
66+
</PageLoaderWrapper>
67+
}
68+
}
69+
70+
module OverviewContainer = {
71+
@react.component
72+
let make = (~monthFilters) => {
73+
let getURL = APIUtils.useGetURL()
74+
let showToast = ToastState.useShowToast()
75+
let updateDetails = APIUtils.useUpdateMethod(~showErrorToast=false)
1576
let (screenState, setScreenState) = React.useState(_ => PageLoaderWrapper.Loading)
1677
let (overviewRawData, setOverviewRawData) = React.useState(_ =>
1778
Dict.make()->FeeEstimationUtils.overviewDataMapper
@@ -26,25 +87,21 @@ module OverviewContainer = {
2687
setScreenState(_ => PageLoaderWrapper.Loading)
2788
let url = getURL(~entityName=V1(FEE_OVERVIEW_ESTIMATE), ~methodType=Post)
2889
let body = {
29-
"payload": {
30-
"offset": pageDetail.offset,
31-
"limit": pageDetail.resultsPerPage,
32-
"startDate": monthFilters["startDate"],
33-
"endDate": monthFilters["endDate"],
34-
},
90+
"offset": pageDetail.offset,
91+
"limit": pageDetail.resultsPerPage,
92+
"startDate": monthFilters["startDate"],
93+
"endDate": monthFilters["endDate"],
3594
}->Identity.genericTypeToJson
3695

37-
let response = switch GlobalVars.hostType {
38-
| Local | Integ => FeeEstimationMockData.overViewMockData
39-
| _ => await updateDetails(url, body, Fetch.Post)
40-
}
41-
96+
let response = await updateDetails(url, body, Fetch.Post)
4297
let overViewData =
4398
response
4499
->getDictFromJsonObject
45100
->getDictfromDict("response")
46101
->FeeEstimationUtils.overviewDataMapper
102+
47103
setOverviewRawData(_ => overViewData)
104+
Console.log2("overview data fetched:", overViewData)
48105
setScreenState(_ => PageLoaderWrapper.Success)
49106
} catch {
50107
| _ => {
@@ -60,7 +117,7 @@ module OverviewContainer = {
60117
React.useEffect(() => {
61118
fetchOverviewData()->ignore
62119
None
63-
}, [pageDetail.offset, pageDetail.resultsPerPage])
120+
}, [])
64121

65122
<PageLoaderWrapper
66123
screenState
@@ -71,7 +128,7 @@ module OverviewContainer = {
71128
feeBreakdownData=overviewRawData.feeBreakdownBasedOnGeoLocation
72129
currency=overviewRawData.currency
73130
/>
74-
<CostBreakDown costBreakDownRawData={overviewRawData} />
131+
<OverviewBreakdown monthFilters />
75132
</PageLoaderWrapper>
76133
}
77134
}
@@ -89,9 +146,10 @@ module TransactionViewContainer = {
89146
let (selectedTransaction, setSelectedTransaction) = React.useState(_ =>
90147
JSON.Encode.null->FeeEstimationUtils.feeEstimateBreakdownMapper
91148
)
92-
let (transactionData, setTransactionData) = React.useState(_ =>
149+
let (transactionRawData, setTransactionRawData) = React.useState(_ =>
93150
Dict.make()->FeeEstimationUtils.feeEstimationMapper
94151
)
152+
let (transactionData, setTransactionData) = React.useState(_ => [])
95153

96154
let defaultValue: LoadedTable.pageDetails = {offset: 0, resultsPerPage: 10}
97155
let pageDetailDict = Recoil.useRecoilValueFromAtom(LoadedTable.table_pageDetails)
@@ -107,24 +165,30 @@ module TransactionViewContainer = {
107165
setScreenState(_ => PageLoaderWrapper.Loading)
108166
let url = getURL(~entityName=V1(FEE_TRANSACTION_ESTIMATE), ~methodType=Post)
109167
let body = {
110-
"payload": {
111-
"offset": pageDetail.offset,
112-
"limit": pageDetail.resultsPerPage,
113-
"startDate": monthFilters["startDate"],
114-
"endDate": monthFilters["endDate"],
115-
},
168+
"offset": offset,
169+
"limit": pageDetail.resultsPerPage,
170+
"startDate": monthFilters["startDate"],
171+
"endDate": monthFilters["endDate"],
116172
}->Identity.genericTypeToJson
117-
let response = switch GlobalVars.hostType {
118-
| Local | Integ => FeeEstimationMockData.mockData
119-
| _ => await updateDetails(url, body, Fetch.Post)
120-
}
121173

174+
let response = await updateDetails(url, body, Fetch.Post)
122175
let transactionData =
123176
response
124177
->getDictFromJsonObject
125178
->getDictfromDict("response")
126179
->FeeEstimationUtils.feeEstimationMapper
127-
setTransactionData(_ => transactionData)
180+
181+
let paddedRows = Array.make(
182+
~length=offset,
183+
JSON.Encode.object(Dict.make())
184+
->FeeEstimationUtils.feeEstimateBreakdownMapper
185+
->Nullable.make,
186+
)
187+
let paginatedTransactionData =
188+
paddedRows->Array.concat(transactionData.breakdown->Array.map(Nullable.make))
189+
190+
setTransactionRawData(_ => transactionData)
191+
setTransactionData(_ => paginatedTransactionData)
128192
setScreenState(_ => PageLoaderWrapper.Success)
129193
} catch {
130194
| _ => {
@@ -140,32 +204,36 @@ module TransactionViewContainer = {
140204
React.useEffect(_ => {
141205
fetchData()->ignore
142206
None
143-
}, [pageDetail.offset, pageDetail.resultsPerPage])
207+
}, [offset, pageDetail.resultsPerPage])
144208

145209
<div className="py-6">
146210
<PageLoaderWrapper
147211
screenState
148212
customUI={<NewAnalyticsHelper.NoData height="h-56" message="No data available" />}
149213
customLoader={<Shimmer styleClass="w-full h-56 rounded-xl" />}>
150-
<RenderIf condition={transactionData.breakdown->Array.length == 0}>
214+
<RenderIf condition={transactionData->Array.length == 0}>
151215
<NoDataFound message="No data available for selected month" />
152216
</RenderIf>
153-
<RenderIf condition={transactionData.breakdown->Array.length > 0}>
154-
<LoadedTable
217+
<RenderIf condition={transactionData->Array.length > 0}>
218+
<LoadedTableWithCustomColumns
155219
title=transactionViewTableKey
156220
hideTitle=true
157-
actualData={transactionData.breakdown->Array.map(Nullable.make)}
158-
totalResults={transactionData.totalRecords}
159-
resultsPerPage=10
221+
actualData={transactionData}
222+
entity={FeeEstimationEntity.feeEstimationEntity()}
223+
resultsPerPage=pageDetail.resultsPerPage
224+
totalResults=transactionRawData.totalRecords
160225
offset
161226
setOffset
162-
headingCenter=false
163-
alignCellContent="flex items-center"
164-
entity={FeeEstimationEntity.feeEstimationEntity()}
165-
currrentFetchCount={transactionData.breakdown->Array.length}
227+
currrentFetchCount={transactionData->Array.length}
228+
defaultColumns={FeeEstimationEntity.defaultColumns}
229+
customColumnMapper={TableAtoms.feeEstimationTransactionViewMapDefaultCols}
230+
showSerialNumberInCustomizeColumns=false
166231
onEntityClick={selectedData => handleSelectedTransactionData(selectedData)}
167-
collapseTableRow=false
232+
showResultsPerPageSelector=true
233+
sortingBasedOnDisabled=false
168234
showAutoScroll=true
235+
isDraggable=true
236+
allowNullableRows=true
169237
/>
170238
</RenderIf>
171239
</PageLoaderWrapper>
@@ -183,12 +251,11 @@ module TransactionViewContainer = {
183251

184252
@react.component
185253
let make = () => {
186-
let getDate = (~month, ~year, ~date) => Date.makeWithYMD(~year, ~month, ~date)
187254
let formattedDate = date => date->Date.toString->DateTimeUtils.getFormattedDate("YYYY-MM-DD")
188255
let (monthFilters, setMonthFilters) = React.useState(_ =>
189256
{
190-
"startDate": formattedDate(getDate(~month=10, ~year=2025, ~date=1)),
191-
"endDate": formattedDate(getDate(~month=10, ~year=2025, ~date=-1)),
257+
"startDate": Date.makeWithYMDH(~month=8, ~year=2025, ~date=1, ~hours=10)->formattedDate,
258+
"endDate": Date.makeWithYMDH(~month=9, ~year=2025, ~date=0, ~hours=10)->formattedDate,
192259
}
193260
)
194261
let tabs: array<Tabs.tab> = [

src/screens/Analytics/FeeEstimation/FeeEstimationComponents/FeeEstimationOverview.res

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ module FeeBreakdownBasedOnGeoLocation = {
5353
~yAxisLabelFormatter=Some(labelFormatter(currency)),
5454
)
5555

56-
<div className="border border-nd_gray-200 rounded-xl">
56+
<div className="border border-nd_gray-200 rounded-xl overflow-hidden">
5757
<div className="bg-nd_gray-25 py-4 px-4 rounded-t-xl">
5858
<p className={`${body.lg.semibold} text-nd_gray-600`}>
5959
{"Fee Breakdown Based on Geolocation"->React.string}
@@ -134,7 +134,7 @@ module CostBreakDownSideModal = {
134134

135135
let options = React.useMemo(() => {
136136
let breakdownContributions = fundingSourceGroupedRef->Array.map(
137-
((brand, value, _otherValue)) => {
137+
((brand, value, _)) => {
138138
cardBrand: brand,
139139
currency: selectedTransaction.transactionCurrency,
140140
value,
@@ -201,12 +201,12 @@ module CostBreakDownSideModal = {
201201

202202
module CostBreakDown = {
203203
@react.component
204-
let make = (~costBreakDownRawData: overviewFeeEstimate) => {
204+
let make = (~overViewBreakdownRawData: overViewBreakdownData, ~overViewBreakdownTableData) => {
205205
let (offset, setOffset) = React.useState(_ => 0)
206206
let (showModal, setShowModal) = React.useState(_ => false)
207207
let (checkedFields, setCheckedFields) = React.useState(_ => [])
208208
let (filteredCostBreakDownTableData, setFilteredCostBreakDownTableData) = React.useState(_ =>
209-
costBreakDownRawData.overviewBreakdown
209+
overViewBreakdownTableData
210210
)
211211
let (selectedTransaction, setSelectedTransaction) = React.useState(_ =>
212212
JSON.Encode.null->overviewBreakdownItemMapper
@@ -216,26 +216,26 @@ module CostBreakDown = {
216216

217217
let filterValuesOptions = React.useMemo(() => {
218218
let cardBrandsSet = Set.make()
219-
costBreakDownRawData.overviewBreakdown->Array.forEach(value => {
219+
overViewBreakdownRawData.overviewBreakdown->Array.forEach(value => {
220220
cardBrandsSet->Set.add(value.cardBrand)
221221
})
222222
let cardBrandsArray = []
223223
cardBrandsSet->Set.forEach(value => {
224224
cardBrandsArray->Array.push(value)
225225
})
226226
cardBrandsArray
227-
}, [costBreakDownRawData.overviewBreakdown])
227+
}, [overViewBreakdownRawData])
228228

229229
let cardBreakdownData = React.useMemo(() => {
230-
let dataToUse = switch checkedFields->Array.length {
231-
| 0 => costBreakDownRawData.topValuesBasedOnCardBrand
232-
| _ =>
233-
costBreakDownRawData.topValuesBasedOnCardBrand->Array.filter(item =>
234-
checkedFields->Array.includes(item.cardBrand)
235-
)
236-
}
237-
calculateCardBreakdownData(dataToUse, costBreakDownRawData.currency)
238-
}, (checkedFields, costBreakDownRawData.topValuesBasedOnCardBrand))
230+
let dataToUse =
231+
checkedFields->Array.length == 0
232+
? overViewBreakdownRawData.topValuesBasedOnCardBrand
233+
: overViewBreakdownRawData.topValuesBasedOnCardBrand->Array.filter(item =>
234+
checkedFields->Array.includes(item.cardBrand)
235+
)
236+
237+
calculateCardBreakdownData(dataToUse, overViewBreakdownRawData.currency)
238+
}, (checkedFields, overViewBreakdownRawData.topValuesBasedOnCardBrand))
239239

240240
let handleSelectedTransactionData = selectedData => {
241241
setSelectedTransaction(_ => selectedData)
@@ -245,11 +245,11 @@ module CostBreakDown = {
245245
let onChangeSelect = ev => {
246246
let fieldNameArr = ev->Identity.formReactEventToArrayOfString
247247
let filteredData = if fieldNameArr->Array.length > 0 {
248-
costBreakDownRawData.overviewBreakdown->Array.filter(item =>
248+
overViewBreakdownRawData.overviewBreakdown->Array.filter(item =>
249249
fieldNameArr->Array.includes(item.cardBrand)
250250
)
251251
} else {
252-
costBreakDownRawData.overviewBreakdown
252+
overViewBreakdownRawData.overviewBreakdown
253253
}
254254

255255
setCheckedFields(_ => fieldNameArr)
@@ -319,8 +319,8 @@ module CostBreakDown = {
319319
<LoadedTable
320320
title=costBreakDownTableKey
321321
hideTitle=true
322-
actualData={filteredCostBreakDownTableData->Array.map(Nullable.make)}
323-
totalResults={costBreakDownRawData.totalRecords}
322+
actualData={overViewBreakdownTableData->Array.map(Nullable.make)}
323+
totalResults={overViewBreakdownRawData.totalRecords}
324324
resultsPerPage=10
325325
offset
326326
setOffset

0 commit comments

Comments
 (0)