@widergy/utilitygo-smart-bill-mobile 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [3.1.0](https://github.com/widergy/UtilityGO-Smart-Bill-Mobile/compare/v3.0.0...v3.1.0) (2025-09-23)
2
+
3
+
4
+ ### Features
5
+
6
+ * [EVEP-34] billing new structure ([#46](https://github.com/widergy/UtilityGO-Smart-Bill-Mobile/issues/46)) ([a4788b6](https://github.com/widergy/UtilityGO-Smart-Bill-Mobile/commit/a4788b6b4d77d83b375028734d3550820a32f8b4))
7
+
1
8
  # [3.0.0](https://github.com/widergy/UtilityGO-Smart-Bill-Mobile/compare/v2.8.0...v3.0.0) (2025-09-22)
2
9
 
3
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@widergy/utilitygo-smart-bill-mobile",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "UtilityGO SmartBill Mobile",
5
5
  "license": "MIT",
6
6
  "main": "src/lib/index.js",
@@ -2,8 +2,8 @@
2
2
  /* eslint-disable react/jsx-fragments */
3
3
  import React, { Fragment, useEffect, useState, useMemo } from 'react';
4
4
  import { UTButton, UTLoading, UTTabs } from '@widergy/mobile-ui';
5
- import { View } from 'react-native';
6
- import { arrayOf, bool, func, object, shape, string } from 'prop-types';
5
+ import { ScrollView } from 'react-native';
6
+ import { array, arrayOf, bool, func, object, shape, string } from 'prop-types';
7
7
  import isEmpty from 'lodash/isEmpty';
8
8
  import debounce from 'lodash/debounce';
9
9
 
@@ -11,9 +11,11 @@ import { TAB_COMPONENT_MAPPER } from './constants';
11
11
  import { getDefaultCurrentTab, getTabOptions } from './utils';
12
12
  import styles from './styles';
13
13
  import AIDrawer from './components/AIDrawer';
14
+ import BillHeader from './tabs/Billing/components/BillHeader';
14
15
 
15
16
  const SmartBillSummary = ({
16
17
  assets,
18
+ billingLayout,
17
19
  colors,
18
20
  components,
19
21
  constants = {},
@@ -114,10 +116,20 @@ const SmartBillSummary = ({
114
116
  tabs={filteredTabOptions}
115
117
  value={currentTab}
116
118
  />
117
-
118
- <View>
119
+ <ScrollView>
120
+ {filteredTabOptions.find(tab => tab.value === currentTab)?.header && (
121
+ <BillHeader
122
+ assets={assets}
123
+ colors={colors}
124
+ header={translations?.billingTab.header}
125
+ debtStatusLabel={smartBill?.debt_status_label}
126
+ smartBill={smartBill}
127
+ billNumber={smartBill?.bill_number}
128
+ />
129
+ )}
119
130
  {TAB_COMPONENT_MAPPER?.[currentTab]?.({
120
131
  assets,
132
+ billingLayout,
121
133
  colors,
122
134
  constants,
123
135
  handlers,
@@ -127,7 +139,7 @@ const SmartBillSummary = ({
127
139
  translations,
128
140
  utils
129
141
  })}
130
- </View>
142
+ </ScrollView>
131
143
 
132
144
  {aiQuestionsPanelEnabled && (
133
145
  <Fragment>
@@ -162,6 +174,7 @@ const SmartBillSummary = ({
162
174
 
163
175
  SmartBillSummary.propTypes = {
164
176
  assets: object,
177
+ billingLayout: array,
165
178
  colors: object,
166
179
  components: object,
167
180
  constants: object,
@@ -0,0 +1,43 @@
1
+ /* eslint-disable react/forbid-prop-types */
2
+ import React from 'react';
3
+ import { UTActionCard } from '@widergy/mobile-ui';
4
+ import { View } from 'react-native';
5
+ import { arrayOf, object } from 'prop-types';
6
+
7
+ import styles from './styles';
8
+
9
+ const ActionCards = ({ actionCards }) => {
10
+ return (
11
+ <View style={styles.actionCardsContainer}>
12
+ {actionCards?.map(({ onPress, Icon = 'IconChevronRight', statusAttributes = {}, title }) => (
13
+ <UTActionCard
14
+ classNames={{ headerTitles: styles.headerAndChildrenContainer }}
15
+ disabled={!onPress}
16
+ headerActions={
17
+ onPress
18
+ ? [
19
+ {
20
+ colorTheme: 'accent',
21
+ Icon,
22
+ isPrimary: true
23
+ }
24
+ ]
25
+ : []
26
+ }
27
+ key={title}
28
+ mainAction={onPress}
29
+ title={title}
30
+ titleProps={{ style: styles.titleActionCard }}
31
+ {...statusAttributes}
32
+ />
33
+ ))}
34
+ </View>
35
+ );
36
+ };
37
+
38
+ ActionCards.propTypes = {
39
+ actionCards: arrayOf(object),
40
+ colors: object
41
+ };
42
+
43
+ export default ActionCards;
@@ -0,0 +1,11 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ titleActionCard: {
5
+ marginBottom: 'auto',
6
+ marginTop: 'auto'
7
+ },
8
+ actionCardsContainer: {
9
+ gap: 16
10
+ }
11
+ });
@@ -0,0 +1,55 @@
1
+ /* eslint-disable react/forbid-prop-types */
2
+ import React from 'react';
3
+ import { Surface, UTLabel } from '@widergy/mobile-ui';
4
+ import { View, Image } from 'react-native';
5
+ import { string, object } from 'prop-types';
6
+
7
+ import DebtStatusLabel from '../DebtStatusLabel';
8
+ import { getCurrentPeriod, getFormattedDate } from '../../utils';
9
+
10
+ import { createStyles } from './styles';
11
+
12
+ const BillHeader = ({ assets, colors, header, debtStatusLabel, smartBill, billNumber }) => {
13
+ const styles = createStyles(colors);
14
+ const { UtilityLogo } = assets.billingTab;
15
+
16
+ const { billIssueDate, billTypeHelpText } = header;
17
+ const currentPeriod = getCurrentPeriod(smartBill);
18
+ const issuedOnDate = getFormattedDate(currentPeriod?.settlements?.current?.issued_on);
19
+ const debtStatusValidation = debtStatusLabel !== null;
20
+ return (
21
+ <Surface elevation={1} style={styles.billHeader}>
22
+ {UtilityLogo && <Image resizeMode="contain" source={UtilityLogo} height={35} />}
23
+ <View style={styles.billHeaderLabels}>
24
+ <View style={styles.valueAndHelpText}>
25
+ <UTLabel variant="small">{billNumber}</UTLabel>
26
+ <UTLabel colorTheme="gray" variant="small">
27
+ {billTypeHelpText}
28
+ </UTLabel>
29
+ </View>
30
+
31
+ <View style={styles.valueAndHelpText}>
32
+ <UTLabel variant="small">{issuedOnDate}</UTLabel>
33
+ <UTLabel colorTheme="gray" variant="small">
34
+ {billIssueDate}
35
+ </UTLabel>
36
+ </View>
37
+
38
+ {debtStatusValidation && (
39
+ <DebtStatusLabel colors={colors} debtStatusLabel={debtStatusLabel} isWarning={smartBill?.warning} />
40
+ )}
41
+ </View>
42
+ </Surface>
43
+ );
44
+ };
45
+
46
+ BillHeader.propTypes = {
47
+ assets: object,
48
+ colors: object,
49
+ header: object,
50
+ debtStatusLabel: string,
51
+ smartBill: object,
52
+ billNumber: string
53
+ };
54
+
55
+ export default BillHeader;
@@ -0,0 +1,28 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export const createStyles = colors =>
4
+ StyleSheet.create({
5
+ billHeaderLabels: {
6
+ alignItems: 'center',
7
+ columnGap: 32,
8
+ flexDirection: 'row',
9
+ justifyContent: 'space-between',
10
+ paddingTop: 16,
11
+ rowGap: 16,
12
+ flexWrap: 'wrap'
13
+ },
14
+ valueAndHelpText: {
15
+ flexDirection: 'column',
16
+ gap: 4
17
+ },
18
+ billHeader: {
19
+ backgroundColor: colors.light01,
20
+ borderRadius: 8,
21
+ flexDirection: 'column',
22
+ gap: 12,
23
+ justifyContent: 'space-between',
24
+ padding: 16,
25
+ marginHorizontal: 16,
26
+ marginTop: 16
27
+ }
28
+ });
@@ -0,0 +1,93 @@
1
+ /* eslint-disable react/forbid-prop-types */
2
+ import React from 'react';
3
+ import { Surface, UTLabel } from '@widergy/mobile-ui';
4
+ import { View } from 'react-native';
5
+ import { object } from 'prop-types';
6
+
7
+ import { createStyles } from './styles';
8
+
9
+ const TitularCard = ({ utils, client, titularCard, colors }) => {
10
+ const styles = createStyles(colors);
11
+ const { formatters = {} } = utils;
12
+ const { clientNumberFormatter } = formatters;
13
+ const {
14
+ account_address: accountAddress,
15
+ client_number: clientNumber = '',
16
+ holder_name: titularName,
17
+ postal_address: postalAddress,
18
+ iva_condition: ivaCondition
19
+ } = client || {};
20
+ const {
21
+ title: titularCardTitle,
22
+ addressHelpText,
23
+ titularHelpText,
24
+ clientNumberHelpText,
25
+ ivaConditionHelpText
26
+ } = titularCard;
27
+ const renderTitularFooter = clientNumber || ivaCondition;
28
+
29
+ return (
30
+ <Surface elevation={1} style={styles.titularCard}>
31
+ <UTLabel variant="title3" weight="medium">
32
+ {titularCardTitle}
33
+ </UTLabel>
34
+
35
+ <View style={styles.titularDataContainer}>
36
+ {accountAddress && (
37
+ <View style={styles.titularData}>
38
+ <UTLabel style={styles.titularDataTitle} weight="bold">
39
+ {accountAddress}
40
+ </UTLabel>
41
+
42
+ {accountAddress !== postalAddress && <UTLabel>{postalAddress}</UTLabel>}
43
+
44
+ <UTLabel colorTheme="gray">{addressHelpText}</UTLabel>
45
+ </View>
46
+ )}
47
+
48
+ {titularName && (
49
+ <View style={styles.titularData}>
50
+ <UTLabel style={styles.titularDataTitle} weight="bold">
51
+ {titularName}
52
+ </UTLabel>
53
+
54
+ <UTLabel colorTheme="gray">{titularHelpText}</UTLabel>
55
+ </View>
56
+ )}
57
+
58
+ {renderTitularFooter && (
59
+ <View style={styles.titularFooter}>
60
+ {clientNumber && (
61
+ <View style={styles.titularData}>
62
+ <UTLabel style={styles.titularDataTitle} weight="bold">
63
+ {clientNumberFormatter?.(clientNumber) || clientNumber}
64
+ </UTLabel>
65
+
66
+ <UTLabel colorTheme="gray">{clientNumberHelpText}</UTLabel>
67
+ </View>
68
+ )}
69
+
70
+ {ivaCondition && (
71
+ <View style={styles.titularData}>
72
+ <UTLabel style={styles.titularDataTitle} weight="bold">
73
+ {ivaCondition}
74
+ </UTLabel>
75
+
76
+ <UTLabel colorTheme="gray">{ivaConditionHelpText}</UTLabel>
77
+ </View>
78
+ )}
79
+ </View>
80
+ )}
81
+ </View>
82
+ </Surface>
83
+ );
84
+ };
85
+
86
+ TitularCard.propTypes = {
87
+ colors: object,
88
+ titularCard: object,
89
+ utils: object,
90
+ client: object
91
+ };
92
+
93
+ export default TitularCard;
@@ -0,0 +1,29 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export const createStyles = colors =>
4
+ StyleSheet.create({
5
+ titularCard: {
6
+ backgroundColor: colors.light01,
7
+ borderRadius: 8,
8
+ padding: 16,
9
+ flexDirection: 'column',
10
+ gap: 24
11
+ },
12
+ titularDataContainer: {
13
+ flexDirection: 'column'
14
+ },
15
+ titularData: {
16
+ flex: 1,
17
+ flexDirection: 'column',
18
+ gap: 8,
19
+ paddingVertical: 12
20
+ },
21
+ titularDataTitle: {
22
+ paddingVertical: 4
23
+ },
24
+ titularFooter: {
25
+ flexDirection: 'row',
26
+ justifyContent: 'space-between',
27
+ gap: 16
28
+ }
29
+ });
@@ -0,0 +1,49 @@
1
+ /* eslint-disable react/forbid-prop-types */
2
+ import React from 'react';
3
+ import { Surface, UTLabel } from '@widergy/mobile-ui';
4
+ import { View } from 'react-native';
5
+ import { arrayOf, object, func, string } from 'prop-types';
6
+
7
+ import { getFormattedDate } from '../../utils';
8
+
9
+ import { createStyles } from './styles';
10
+
11
+ const TotalCard = ({ detail, expirations, formatAmount, totalAmountLabel, totalCard, colors }) => {
12
+ const styles = createStyles(colors);
13
+ const { firstExpiration, secondExpiration } = totalCard;
14
+
15
+ const firstExpirationDate = getFormattedDate(expirations?.[0]?.date);
16
+ const secondExpirationDate = getFormattedDate(expirations?.[1]?.date);
17
+ const { total_amount: totalAmount } = detail || {};
18
+ return (
19
+ <Surface elevation={1} style={styles.totalCardStyles}>
20
+ <View style={styles.total}>
21
+ <UTLabel variant="subtitle1" weight="medium">
22
+ {totalAmountLabel}
23
+ </UTLabel>
24
+ <UTLabel colorTheme="accent" variant="title2" weight="medium">
25
+ {formatAmount?.(totalAmount, true)}
26
+ </UTLabel>
27
+ </View>
28
+ <View>
29
+ <UTLabel colorTheme="gray" variant="small" weight="medium">
30
+ {firstExpiration?.(firstExpirationDate)}
31
+ </UTLabel>
32
+ <UTLabel colorTheme="gray" variant="small" weight="medium">
33
+ {secondExpiration?.(secondExpirationDate)}
34
+ </UTLabel>
35
+ </View>
36
+ </Surface>
37
+ );
38
+ };
39
+
40
+ TotalCard.propTypes = {
41
+ detail: object,
42
+ expirations: arrayOf(object),
43
+ formatAmount: func,
44
+ totalAmountLabel: string,
45
+ totalCard: object,
46
+ colors: object
47
+ };
48
+
49
+ export default TotalCard;
@@ -0,0 +1,17 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export const createStyles = colors =>
4
+ StyleSheet.create({
5
+ totalCardStyles: {
6
+ backgroundColor: colors.light01,
7
+ borderRadius: 4,
8
+ flexDirection: 'column',
9
+ padding: 16,
10
+ gap: 24
11
+ },
12
+ total: {
13
+ flexDirection: 'row',
14
+ justifyContent: 'space-between',
15
+ gap: 8
16
+ }
17
+ });
@@ -0,0 +1,11 @@
1
+ import ActionCards from './components/ActionCards';
2
+ import TotalCard from './components/TotalCard';
3
+ import RateCard from './components/RateCard';
4
+ import TitularCard from './components/TitularCard';
5
+
6
+ export const COMPONENTS = {
7
+ ActionCards,
8
+ TotalCard,
9
+ RateCard,
10
+ TitularCard
11
+ };
@@ -1,13 +1,11 @@
1
1
  /* eslint-disable react/forbid-prop-types */
2
2
  import React from 'react';
3
- import { Image, ScrollView, View } from 'react-native';
4
- import { Surface, UTActionCard, UTLabel } from '@widergy/mobile-ui';
5
- import { func, object, shape, string } from 'prop-types';
3
+ import { View } from 'react-native';
4
+ import { array, func, object, shape, string } from 'prop-types';
6
5
 
7
- import { getCurrentPeriod, getFormattedDate } from './utils';
8
- import { createStyles } from './styles';
9
- import DebtStatusLabel from './components/DebtStatusLabel';
10
- import RateCard from './components/RateCard';
6
+ import { getCurrentPeriod } from './utils';
7
+ import styles from './styles';
8
+ import { COMPONENTS } from './constants';
11
9
 
12
10
  const Billing = ({
13
11
  assets,
@@ -15,15 +13,14 @@ const Billing = ({
15
13
  constants,
16
14
  currentAccount = {},
17
15
  handlers = {},
16
+ billingLayout,
18
17
  smartBill = {},
19
18
  translations,
20
19
  utils = {}
21
20
  }) => {
22
- const styles = createStyles(colors);
23
- const { UtilityLogo } = assets;
24
21
  const { adherenceStatus, consumptionLevels = [], subsidyLevels } = constants;
25
22
  const { formatters = {} } = utils;
26
- const { clientNumberFormatter, formatAmount } = formatters;
23
+ const { formatAmount } = formatters;
27
24
  const {
28
25
  bill_number: billNumber,
29
26
  client,
@@ -31,13 +28,6 @@ const Billing = ({
31
28
  detail,
32
29
  expirations
33
30
  } = smartBill;
34
- const {
35
- account_address: accountAddress,
36
- client_number: clientNumber = '',
37
- holder_name: titularName,
38
- postal_address: postalAddress,
39
- iva_condition: ivaCondition
40
- } = client || {};
41
31
  const {
42
32
  adhered,
43
33
  automaticDebit = {},
@@ -51,20 +41,7 @@ const Billing = ({
51
41
  totalAmountLabel,
52
42
  totalCard = {}
53
43
  } = translations;
54
- const {
55
- title: titularCardTitle,
56
- addressHelpText,
57
- titularHelpText,
58
- clientNumberHelpText,
59
- ivaConditionHelpText
60
- } = titularCard;
61
- const { firstExpiration } = totalCard;
62
- const { billIssueDate, billTypeHelpText } = header;
63
44
  const currentPeriod = getCurrentPeriod(smartBill);
64
- const issuedOnDate = getFormattedDate(currentPeriod?.settlements?.current?.issued_on);
65
- const debtStatusValidation = debtStatusLabel !== null;
66
- const firstExpirationDate = getFormattedDate(expirations?.[0]?.date);
67
- const { total_amount: totalAmount } = detail || {};
68
45
  const {
69
46
  handleAutomaticDebitAdherence = () => {},
70
47
  handleDownloadBill = () => {},
@@ -81,7 +58,6 @@ const Billing = ({
81
58
  const { title: automaticDebitTitle } = automaticDebit;
82
59
  const isAdheredToDigitalBill = client?.adherence_to_digital_bill;
83
60
  const isAdheredToAutomaticDebit = adherenceToAutomaticDebit === adherenceStatus?.subscribed;
84
- const renderTitularFooter = clientNumber || ivaCondition;
85
61
 
86
62
  const actionCards = [
87
63
  {
@@ -117,147 +93,45 @@ const Billing = ({
117
93
  }
118
94
  };
119
95
  });
120
-
96
+ const props = {
97
+ actionCards,
98
+ assets,
99
+ billNumber,
100
+ client,
101
+ colors,
102
+ constants,
103
+ consumptionLevels,
104
+ currentAccount,
105
+ currentPeriod,
106
+ debtStatusLabel,
107
+ detail,
108
+ expirations,
109
+ formatAmount,
110
+ handlers,
111
+ header,
112
+ normalizedRate,
113
+ rateCardTranslations,
114
+ ratesTableLink,
115
+ titularCard,
116
+ smartBill,
117
+ subsidy,
118
+ subsidyLevels,
119
+ totalAmountLabel,
120
+ totalCard,
121
+ trackRedirectionToExternalLink,
122
+ translations,
123
+ utils
124
+ };
121
125
  return (
122
- <ScrollView>
123
- <View style={styles.generalContainer}>
124
- <Surface elevation={1} style={styles.billHeader}>
125
- {UtilityLogo && <Image resizeMode="contain" source={UtilityLogo} height={35} />}
126
- <View style={styles.billHeaderLabels}>
127
- <View style={styles.valueAndHelpText}>
128
- <UTLabel variant="small">{billNumber}</UTLabel>
129
- <UTLabel colorTheme="gray" variant="small">
130
- {billTypeHelpText}
131
- </UTLabel>
132
- </View>
133
-
134
- <View style={styles.valueAndHelpText}>
135
- <UTLabel variant="small">{issuedOnDate}</UTLabel>
136
- <UTLabel colorTheme="gray" variant="small">
137
- {billIssueDate}
138
- </UTLabel>
139
- </View>
140
-
141
- {debtStatusValidation && (
142
- <DebtStatusLabel
143
- colors={colors}
144
- debtStatusLabel={debtStatusLabel}
145
- isWarning={smartBill?.warning}
146
- />
147
- )}
148
- </View>
149
- </Surface>
150
-
151
- <Surface elevation={1} style={styles.totalCard}>
152
- <View style={styles.total}>
153
- <UTLabel variant="subtitle1" weight="medium">
154
- {totalAmountLabel}
155
- </UTLabel>
156
- <UTLabel colorTheme="accent" variant="title2" weight="medium">
157
- {formatAmount?.(totalAmount, true)}
158
- </UTLabel>
159
- </View>
160
-
161
- <UTLabel colorTheme="gray" variant="small" weight="medium">
162
- {firstExpiration?.(firstExpirationDate)}
163
- </UTLabel>
164
- </Surface>
165
-
166
- <RateCard
167
- {...{
168
- colors,
169
- consumptionLevels,
170
- currentPeriod,
171
- formatAmount,
172
- normalizedRate,
173
- rateCardTranslations,
174
- ratesTableLink,
175
- smartBill,
176
- subsidy,
177
- subsidyLevels,
178
- trackRedirectionToExternalLink,
179
- translations
180
- }}
181
- />
182
-
183
- {actionCards?.map(({ onPress, Icon = 'IconChevronRight', statusAttributes = {}, title }) => (
184
- <UTActionCard
185
- classNames={{ headerTitles: styles.headerAndChildrenContainer }}
186
- disabled={!onPress}
187
- headerActions={
188
- onPress
189
- ? [
190
- {
191
- colorTheme: 'accent',
192
- Icon,
193
- isPrimary: true
194
- }
195
- ]
196
- : []
197
- }
198
- key={title}
199
- mainAction={onPress}
200
- title={title}
201
- titleProps={{ style: styles.titleActionCard }}
202
- {...statusAttributes}
203
- />
204
- ))}
205
-
206
- <Surface elevation={1} style={styles.titularCard}>
207
- <UTLabel variant="title3" weight="medium">
208
- {titularCardTitle}
209
- </UTLabel>
210
-
211
- <View style={styles.titularDataContainer}>
212
- {accountAddress && (
213
- <View style={styles.titularData}>
214
- <UTLabel style={styles.titularDataTitle} weight="bold">
215
- {accountAddress}
216
- </UTLabel>
217
-
218
- {accountAddress !== postalAddress && <UTLabel>{postalAddress}</UTLabel>}
219
-
220
- <UTLabel colorTheme="gray">{addressHelpText}</UTLabel>
221
- </View>
222
- )}
223
-
224
- {titularName && (
225
- <View style={styles.titularData}>
226
- <UTLabel style={styles.titularDataTitle} weight="bold">
227
- {titularName}
228
- </UTLabel>
229
-
230
- <UTLabel colorTheme="gray">{titularHelpText}</UTLabel>
231
- </View>
232
- )}
233
-
234
- {renderTitularFooter && (
235
- <View style={styles.titularFooter}>
236
- {clientNumber && (
237
- <View style={styles.titularData}>
238
- <UTLabel style={styles.titularDataTitle} weight="bold">
239
- {clientNumberFormatter?.(clientNumber) || clientNumber}
240
- </UTLabel>
241
-
242
- <UTLabel colorTheme="gray">{clientNumberHelpText}</UTLabel>
243
- </View>
244
- )}
245
-
246
- {ivaCondition && (
247
- <View style={styles.titularData}>
248
- <UTLabel style={styles.titularDataTitle} weight="bold">
249
- {ivaCondition}
250
- </UTLabel>
251
-
252
- <UTLabel colorTheme="gray">{ivaConditionHelpText}</UTLabel>
253
- </View>
254
- )}
255
- </View>
256
- )}
257
- </View>
258
- </Surface>
259
- </View>
260
- </ScrollView>
126
+ <View style={styles.generalContainer}>
127
+ {billingLayout.map(item => {
128
+ if (item.enabled) {
129
+ const Component = COMPONENTS[item.name];
130
+ return Component && <Component key={item.name} {...props} />;
131
+ }
132
+ return null;
133
+ })}
134
+ </View>
261
135
  );
262
136
  };
263
137
 
@@ -266,6 +140,7 @@ Billing.propTypes = {
266
140
  colors: object,
267
141
  constants: object,
268
142
  currentAccount: object,
143
+ billingLayout: array,
269
144
  handlers: shape({ [string]: func }),
270
145
  smartBill: object,
271
146
  translations: object,
@@ -1,73 +1,11 @@
1
1
  import { StyleSheet } from 'react-native';
2
2
 
3
- export const createStyles = colors =>
4
- StyleSheet.create({
5
- generalContainer: {
6
- flexDirection: 'column',
7
- gap: 24,
8
- paddingVertical: 24,
9
- paddingHorizontal: 16,
10
- marginBottom: 48
11
- },
12
- billHeader: {
13
- backgroundColor: colors.light01,
14
- borderRadius: 8,
15
- flexDirection: 'column',
16
- gap: 12,
17
- justifyContent: 'space-between',
18
- padding: 16
19
- },
20
- billHeaderLabels: {
21
- alignItems: 'center',
22
- columnGap: 32,
23
- flexDirection: 'row',
24
- justifyContent: 'space-between',
25
- paddingTop: 16,
26
- rowGap: 16,
27
- flexWrap: 'wrap'
28
- },
29
- valueAndHelpText: {
30
- flexDirection: 'column',
31
- gap: 4
32
- },
33
- totalCard: {
34
- backgroundColor: colors.light01,
35
- borderRadius: 4,
36
- flexDirection: 'column',
37
- padding: 16,
38
- gap: 24
39
- },
40
- total: {
41
- flexDirection: 'row',
42
- justifyContent: 'space-between',
43
- gap: 8
44
- },
45
- titularCard: {
46
- backgroundColor: colors.light01,
47
- borderRadius: 8,
48
- padding: 16,
49
- flexDirection: 'column',
50
- gap: 24
51
- },
52
- titularDataContainer: {
53
- flexDirection: 'column'
54
- },
55
- titularData: {
56
- flex: 1,
57
- flexDirection: 'column',
58
- gap: 8,
59
- paddingVertical: 12
60
- },
61
- titularDataTitle: {
62
- paddingVertical: 4
63
- },
64
- titularFooter: {
65
- flexDirection: 'row',
66
- justifyContent: 'space-between',
67
- gap: 16
68
- },
69
- titleActionCard: {
70
- marginBottom: 'auto',
71
- marginTop: 'auto'
72
- }
73
- });
3
+ export default StyleSheet.create({
4
+ generalContainer: {
5
+ flexDirection: 'column',
6
+ gap: 24,
7
+ paddingVertical: 24,
8
+ paddingHorizontal: 16,
9
+ marginBottom: 48
10
+ }
11
+ });
@@ -8,3 +8,9 @@ export const CONSUMPTION_CARDS = [
8
8
  key: 'billingCard'
9
9
  }
10
10
  ];
11
+
12
+ export const START = 'inicio';
13
+ export const END = 'fin';
14
+ export const DATE_FORMAT = 'D [de] MMMM';
15
+ export const DATE_FORMAT_WITH_YEAR = 'D [de] MMMM [de] YYYY';
16
+ export const DAY = 'day';
@@ -3,15 +3,35 @@ import React from 'react';
3
3
  import { UTActionCard, UTLabel } from '@widergy/mobile-ui';
4
4
  import { object } from 'prop-types';
5
5
  import { View } from 'react-native';
6
+ import dayjs from 'dayjs';
6
7
 
7
- import { CONSUMPTION_CARDS } from './constants';
8
+ import { CONSUMPTION_CARDS, START, END, DAY, DATE_FORMAT, DATE_FORMAT_WITH_YEAR } from './constants';
8
9
  import styles, { markdownStyles } from './styles';
9
10
 
10
- const BimestralConsumption = ({ assets, colors, texts }) => {
11
+ const BimestralConsumption = ({ assets, colors, texts, smartBill }) => {
11
12
  const bimestralConsumptionTexts = texts?.bimestralConsumption;
12
13
  const { title: bimestralTitle, description: bimestralDescription } = bimestralConsumptionTexts || {};
13
14
  const { BackgroundVector } = assets?.bimestral || {};
15
+ const readingPeriods = smartBill?.reading_periods || [];
16
+ const startDate = readingPeriods.find(period => period.moment === START)?.date;
17
+ const endDate = readingPeriods.find(period => period.moment === END)?.date;
14
18
 
19
+ const formatDate = (dateString, includeYear = false) => {
20
+ if (!dateString) return '';
21
+ const format = includeYear ? DATE_FORMAT_WITH_YEAR : DATE_FORMAT;
22
+ return dayjs(dateString).locale('es').format(format);
23
+ };
24
+
25
+ const calculateTotalDays = (start, end) => {
26
+ if (!start || !end) return 0;
27
+ const startMoment = dayjs(start);
28
+ const endMoment = dayjs(end);
29
+ return endMoment.diff(startMoment, DAY);
30
+ };
31
+
32
+ const formattedStartDate = formatDate(startDate, false);
33
+ const formattedEndDate = formatDate(endDate, true);
34
+ const totalDays = calculateTotalDays(startDate, endDate);
15
35
  return (
16
36
  <View>
17
37
  <View style={styles.bimestralConsumptionHeader}>
@@ -22,9 +42,12 @@ const BimestralConsumption = ({ assets, colors, texts }) => {
22
42
  </View>
23
43
  <View style={styles.bimestralConsumptionCards}>
24
44
  {CONSUMPTION_CARDS.map(({ icon, key }) => {
25
- const title = bimestralConsumptionTexts?.[key]?.title;
26
- const description = bimestralConsumptionTexts?.[key]?.description;
27
-
45
+ const { title, description } =
46
+ bimestralConsumptionTexts?.[key]?.({
47
+ formattedStartDate,
48
+ formattedEndDate,
49
+ totalDays
50
+ }) || {};
28
51
  return (
29
52
  <UTActionCard
30
53
  adornment={{
@@ -58,7 +81,8 @@ const BimestralConsumption = ({ assets, colors, texts }) => {
58
81
  BimestralConsumption.propTypes = {
59
82
  assets: object,
60
83
  colors: object,
61
- texts: object
84
+ texts: object,
85
+ smartBill: object
62
86
  };
63
87
 
64
88
  export default BimestralConsumption;
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable react/forbid-prop-types */
2
2
  import React from 'react';
3
3
  import { UTLabel } from '@widergy/mobile-ui';
4
- import { ScrollView, View } from 'react-native';
4
+ import { View } from 'react-native';
5
5
  import { object } from 'prop-types';
6
6
 
7
7
  import styles from './styles';
@@ -13,25 +13,23 @@ const Consumptions = ({ assets, colors, smartBill, translations }) => {
13
13
  const { title, description } = translations?.consumptions || {};
14
14
 
15
15
  return (
16
- <ScrollView>
17
- <View style={styles.generalContainer}>
18
- <BimestralConsumption assets={assets} colors={colors} smartBill={smartBill} texts={translations} />
16
+ <View style={styles.generalContainer}>
17
+ <BimestralConsumption assets={assets} colors={colors} smartBill={smartBill} texts={translations} />
19
18
 
20
- <View style={styles.consumptionDetail}>
21
- <View style={styles.consumptionDetailTitles}>
22
- <UTLabel variant="title3" weight="medium">
23
- {title}
24
- </UTLabel>
25
- <UTLabel>{description}</UTLabel>
26
- </View>
19
+ <View style={styles.consumptionDetail}>
20
+ <View style={styles.consumptionDetailTitles}>
21
+ <UTLabel variant="title3" weight="medium">
22
+ {title}
23
+ </UTLabel>
24
+ <UTLabel>{description}</UTLabel>
25
+ </View>
27
26
 
28
- <View style={styles.consumptionDetailColumns}>
29
- <CurrentConsumption colors={colors} assets={assets} smartBill={smartBill} texts={translations} />
30
- <Billing colors={colors} smartBill={smartBill} texts={translations} />
31
- </View>
27
+ <View style={styles.consumptionDetailColumns}>
28
+ <CurrentConsumption colors={colors} assets={assets} smartBill={smartBill} texts={translations} />
29
+ <Billing colors={colors} smartBill={smartBill} texts={translations} />
32
30
  </View>
33
31
  </View>
34
- </ScrollView>
32
+ </View>
35
33
  );
36
34
  };
37
35