@widergy/utilitygo-smart-bill-mobile 3.4.0 → 3.5.1

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,17 @@
1
+ ## [3.5.1](https://github.com/widergy/UtilityGO-Smart-Bill-Mobile/compare/v3.5.0...v3.5.1) (2025-12-10)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * updates npm token ([4286fa0](https://github.com/widergy/UtilityGO-Smart-Bill-Mobile/commit/4286fa0d1ca078db19eea0589e7be615d01e79d6))
7
+
8
+ # [3.5.0](https://github.com/widergy/UtilityGO-Smart-Bill-Mobile/compare/v3.4.0...v3.5.0) (2025-12-03)
9
+
10
+
11
+ ### Features
12
+
13
+ * [EVEP-52] onboarding ([#54](https://github.com/widergy/UtilityGO-Smart-Bill-Mobile/issues/54)) ([937db49](https://github.com/widergy/UtilityGO-Smart-Bill-Mobile/commit/937db4938f10e5f1de4e927585c0515cc6a4029f))
14
+
1
15
  # [3.4.0](https://github.com/widergy/UtilityGO-Smart-Bill-Mobile/compare/v3.3.0...v3.4.0) (2025-11-07)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@widergy/utilitygo-smart-bill-mobile",
3
- "version": "3.4.0",
3
+ "version": "3.5.1",
4
4
  "description": "UtilityGO SmartBill Mobile",
5
5
  "license": "MIT",
6
6
  "main": "src/lib/index.js",
@@ -19,3 +19,8 @@ export const TAB_COMPONENT_MAPPER = {
19
19
  [SMARTBILL_TABS.BILLING]: renderComponentWithProps(Billing, SMARTBILL_TABS.BILLING),
20
20
  [SMARTBILL_TABS.GLOSSARY]: renderComponentWithProps(Glossary, SMARTBILL_TABS.GLOSSARY)
21
21
  };
22
+
23
+ export const CONSUMPTIONS_TAB = 'consumptionsTab';
24
+ export const BILLING_TAB = 'billingTab';
25
+ export const GLOSSARY_TAB = 'glossaryTab';
26
+ export const AI_BUTTON = 'aiButton';
@@ -1,15 +1,15 @@
1
1
  /* eslint-disable react/forbid-prop-types */
2
2
  /* eslint-disable react/jsx-fragments */
3
- import React, { Fragment, useEffect, useState, useMemo } from 'react';
3
+ import React, { Fragment, useEffect, useState, useMemo, useCallback } from 'react';
4
4
  import { UTButton, UTLoading, UTTabs } from '@widergy/mobile-ui';
5
5
  import { ScrollView, View } from 'react-native';
6
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
 
10
- import { TAB_COMPONENT_MAPPER } from './constants';
10
+ import { AI_BUTTON, BILLING_TAB, CONSUMPTIONS_TAB, GLOSSARY_TAB, TAB_COMPONENT_MAPPER } from './constants';
11
11
  import { getDefaultCurrentTab, getTabOptions } from './utils';
12
- import styles from './styles';
12
+ import getStyles from './styles';
13
13
  import AIDrawer from './components/AIDrawer';
14
14
  import BillHeader from './tabs/Billing/components/BillHeader';
15
15
 
@@ -26,8 +26,10 @@ const SmartBillSummary = ({
26
26
  tabOptions,
27
27
  translations,
28
28
  utils,
29
- periodSpan
29
+ periodSpan,
30
+ walkthroughStep
30
31
  }) => {
32
+ const styles = getStyles(colors);
31
33
  const {
32
34
  aiQuestionsList,
33
35
  aiQuestionsListError,
@@ -84,6 +86,100 @@ const SmartBillSummary = ({
84
86
  resetSmartBillAIAnswers();
85
87
  };
86
88
 
89
+ const {
90
+ currentUserId,
91
+ LocalStorageService,
92
+ walkthroughEnabled,
93
+ useWalkthroughStep,
94
+ WalkthroughStep: WalkthroughComponent,
95
+ walkthroughSteps: walkthroughStepsConfig
96
+ } = walkthroughStep || {};
97
+
98
+ const OverlayComponent = useCallback(
99
+ props => {
100
+ if (isEmpty(walkthroughStepsConfig) || !WalkthroughComponent) return null;
101
+
102
+ return (
103
+ <WalkthroughComponent
104
+ {...props}
105
+ stepsConfig={walkthroughStepsConfig}
106
+ containerStyle={styles.tooltipContainer}
107
+ />
108
+ );
109
+ },
110
+ [walkthroughStepsConfig, WalkthroughComponent, styles.tooltipContainer]
111
+ );
112
+
113
+ const walkthroughStepNumber = name =>
114
+ (walkthroughStepsConfig?.steps.findIndex(step => step.name === name) ?? -1) + 1;
115
+
116
+ const {
117
+ onLayout: onLayoutTabBilling,
118
+ start,
119
+ isWalkthroughOn,
120
+ isVisible: isVisibleBillingTab
121
+ } = useWalkthroughStep({
122
+ number: walkthroughStepNumber(BILLING_TAB),
123
+ name: BILLING_TAB,
124
+ OverlayComponent
125
+ });
126
+
127
+ const { onLayout: onLayoutTabConsumption, isVisible: isVisibleConsumptionTab } = useWalkthroughStep({
128
+ number: walkthroughStepNumber(CONSUMPTIONS_TAB),
129
+ name: CONSUMPTIONS_TAB,
130
+ OverlayComponent
131
+ });
132
+
133
+ const { onLayout: onLayoutTabGlossary, isVisible: isVisibleGlossaryTab } = useWalkthroughStep({
134
+ number: walkthroughStepNumber(GLOSSARY_TAB),
135
+ name: GLOSSARY_TAB,
136
+ OverlayComponent
137
+ });
138
+
139
+ const { onLayout: onLayoutAIButton, isVisible: isVisibleAIButton } = useWalkthroughStep({
140
+ number: walkthroughStepNumber(AI_BUTTON),
141
+ name: AI_BUTTON,
142
+ OverlayComponent
143
+ });
144
+
145
+ const walkthroughLayouts = useMemo(
146
+ () => ({
147
+ billingTab: { onLayout: onLayoutTabBilling, isVisible: isVisibleBillingTab },
148
+ consumptionsTab: { onLayout: onLayoutTabConsumption, isVisible: isVisibleConsumptionTab },
149
+ glossaryTab: { onLayout: onLayoutTabGlossary, isVisible: isVisibleGlossaryTab }
150
+ }),
151
+ [
152
+ onLayoutTabBilling,
153
+ onLayoutTabConsumption,
154
+ onLayoutTabGlossary,
155
+ isVisibleBillingTab,
156
+ isVisibleConsumptionTab,
157
+ isVisibleGlossaryTab
158
+ ]
159
+ );
160
+
161
+ const tabsWithWalkthrough = filteredTabOptions.map(tab => ({
162
+ ...tab,
163
+ walkthrough: walkthroughLayouts[tab.value],
164
+ walkthroughStyle: [
165
+ isWalkthroughOn ? styles.borderContainer : null,
166
+ walkthroughLayouts[tab.value]?.isVisible ? styles.border : null
167
+ ]
168
+ }));
169
+
170
+ useEffect(() => {
171
+ const checkAndStartOnboarding = async () => {
172
+ const hasSeenOnboarding = await LocalStorageService.getSmartBillWalkthrough(currentUserId);
173
+ if (!isEmpty(smartBill) && walkthroughEnabled && hasSeenOnboarding !== 'true' && !isWalkthroughOn) {
174
+ start();
175
+ }
176
+ };
177
+
178
+ checkAndStartOnboarding();
179
+
180
+ // eslint-disable-next-line react-hooks/exhaustive-deps
181
+ }, [start, loading]);
182
+
87
183
  useEffect(() => {
88
184
  if (defaultCurrentTab && defaultCurrentTab !== currentTab) {
89
185
  changeCurrentTab(defaultCurrentTab);
@@ -116,7 +212,7 @@ const SmartBillSummary = ({
116
212
  key={tabsKey}
117
213
  labelProps={{ weight: 'semibold' }}
118
214
  onChange={onUserTabChange}
119
- tabs={filteredTabOptions}
215
+ tabs={tabsWithWalkthrough}
120
216
  value={currentTab}
121
217
  />
122
218
  <ScrollView>
@@ -153,12 +249,20 @@ const SmartBillSummary = ({
153
249
  <FabComponent onPress={openAIDrawer} />
154
250
  </View>
155
251
  ) : (
156
- <UTButton
157
- colorTheme="primary"
158
- Icon="EnergyIconChatSparkFilled"
159
- onPress={openAIDrawer}
160
- style={{ icon: styles.AIFloatButtonIcon, root: styles.AIFloatButton }}
161
- />
252
+ <View
253
+ onLayout={onLayoutAIButton}
254
+ style={[
255
+ styles.AIContainer,
256
+ isWalkthroughOn && styles.borderContainerButton,
257
+ isVisibleAIButton && styles.border
258
+ ]}>
259
+ <UTButton
260
+ colorTheme="primary"
261
+ Icon="EnergyIconChatSparkFilled"
262
+ onPress={openAIDrawer}
263
+ style={{ icon: styles.AIFloatButtonIcon, root: styles.AIFloatButton }}
264
+ />
265
+ </View>
162
266
  )}
163
267
 
164
268
  <AIDrawer
@@ -204,7 +308,8 @@ SmartBillSummary.propTypes = {
204
308
  ),
205
309
  translations: object,
206
310
  utils: object,
207
- periodSpan: string
311
+ periodSpan: string,
312
+ walkthroughStep: object
208
313
  };
209
314
 
210
315
  export default SmartBillSummary;
@@ -1,16 +1,35 @@
1
1
  import { StyleSheet } from 'react-native';
2
2
 
3
- export default StyleSheet.create({
4
- loading: {
5
- flex: 1
6
- },
7
- AIFloatButton: {
8
- borderRadius: 100,
9
- bottom: 16,
10
- position: 'absolute',
11
- right: 16
12
- },
13
- AIFloatButtonIcon: {
14
- padding: 8
15
- }
16
- });
3
+ export default Colors =>
4
+ StyleSheet.create({
5
+ loading: {
6
+ flex: 1
7
+ },
8
+ AIFloatButton: {
9
+ borderRadius: 100
10
+ },
11
+ AIContainer: {
12
+ bottom: 16,
13
+ position: 'absolute',
14
+ right: 16
15
+ },
16
+ AIFloatButtonIcon: {
17
+ padding: 8
18
+ },
19
+ tooltipContainer: {
20
+ bottom: '40%',
21
+ left: '15%'
22
+ },
23
+ borderContainer: {
24
+ borderWidth: 4,
25
+ borderColor: 'transparent'
26
+ },
27
+ borderContainerButton: {
28
+ borderWidth: 4,
29
+ borderColor: 'transparent',
30
+ padding: 8
31
+ },
32
+ border: {
33
+ borderColor: Colors.semanticSuccess03
34
+ }
35
+ });