@eohjsc/react-native-smart-city 0.7.41 → 0.7.43

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.
Files changed (35) hide show
  1. package/package.json +1 -1
  2. package/src/commons/Dashboard/MyDashboardDevice/index.js +14 -12
  3. package/src/commons/Dashboard/MyUnit/index.js +4 -3
  4. package/src/commons/DateTimeRangeChange/index.js +5 -5
  5. package/src/commons/Device/HorizontalBarChart.js +11 -24
  6. package/src/commons/Device/PowerConsumptionChart.js +224 -100
  7. package/src/commons/Form/CurrencyInput.js +9 -18
  8. package/src/commons/SubUnit/Favorites/index.js +35 -10
  9. package/src/commons/SubUnit/ShortDetail.js +17 -4
  10. package/src/commons/SubUnit/__test__/Favorites.test.js +90 -0
  11. package/src/commons/SubUnit/__test__/ShortDetail.test.js +45 -2
  12. package/src/configs/AccessibilityLabel.js +1 -0
  13. package/src/hooks/IoT/__test__/useValueEvaluation.test.js +12 -12
  14. package/src/iot/UpdateStates.js +37 -16
  15. package/src/iot/mqtt.js +26 -1
  16. package/src/navigations/UnitStack.js +2 -2
  17. package/src/screens/ActivityLog/ItemLog.js +69 -16
  18. package/src/screens/ActivityLog/__test__/ItemLog.test.js +169 -2
  19. package/src/screens/ActivityLog/index.js +2 -2
  20. package/src/screens/ActivityLog/styles/itemLogStyles.js +35 -0
  21. package/src/screens/Device/__test__/DeviceDetail-3rdparty.test.js +16 -5
  22. package/src/screens/Device/__test__/DeviceDetail-arduino.test.js +10 -0
  23. package/src/screens/Device/__test__/DeviceDetail-modbus.test.js +37 -8
  24. package/src/screens/Device/__test__/DeviceDetail-zigbee.test.js +16 -5
  25. package/src/screens/Device/__test__/DeviceDetail.test.js +17 -6
  26. package/src/screens/Device/__test__/sensorDisplayItem.test.js +47 -11
  27. package/src/screens/Device/components/SensorDisplayItem.js +24 -5
  28. package/src/screens/Device/styles.js +4 -0
  29. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +8 -49
  30. package/src/screens/UnitSummary/components/PowerConsumption/__test__/PowerConsumption.test.js +153 -6
  31. package/src/screens/UnitSummary/components/PowerConsumption/index.js +6 -47
  32. package/src/utils/I18n/translations/en.js +2 -0
  33. package/src/utils/I18n/translations/vi.js +2 -0
  34. package/src/utils/chartHelper/index.js +53 -0
  35. package/src/utils/chartHelper/getMaxValueIndex.js +0 -11
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eohjsc/react-native-smart-city",
3
3
  "title": "React Native Smart Home",
4
- "version": "0.7.41",
4
+ "version": "0.7.43",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -43,19 +43,21 @@ const MyDashboardDevice = ({ refreshing }) => {
43
43
  );
44
44
  const [myDashboardDevices, setMyDashboardDevices] = useState([]);
45
45
 
46
- const listChipDashboard = useMemo(() => {
47
- return myDashboardDevices.flatMap((dashboard) =>
48
- dashboard.devices.map((device) => device.chip_id)
46
+ const chipIdsDashboardSet = useMemo(() => {
47
+ return new Set(
48
+ myDashboardDevices.flatMap((dashboard) =>
49
+ dashboard.devices.map((device) => device.chip_id)
50
+ )
49
51
  );
50
52
  }, [myDashboardDevices]);
51
53
 
52
54
  const { chips, isFetching } = useChipJsonConfiguration({
53
- ready: !!listChipDashboard.length,
55
+ ready: !!chipIdsDashboardSet.size,
54
56
  });
55
57
 
56
58
  const listChipsMqtt = useMemo(() => {
57
- return chips.filter((chip) => listChipDashboard.includes(chip.id));
58
- }, [chips, listChipDashboard]);
59
+ return chips.filter((chip) => chipIdsDashboardSet.has(chip.id));
60
+ }, [chips, chipIdsDashboardSet]);
59
61
 
60
62
  const { mqttConfigs } = useConnectChipMqtt(listChipsMqtt);
61
63
 
@@ -81,14 +83,14 @@ const MyDashboardDevice = ({ refreshing }) => {
81
83
 
82
84
  useWatchConfigs(isFetching ? [] : configsNeedWatching);
83
85
 
84
- const listSharedChips = useMemo(() => {
85
- const chipMqttIds = listChipsMqtt.map((chip) => chip.id);
86
- return listChipDashboard.filter((id) => !chipMqttIds.includes(id));
87
- }, [listChipsMqtt, listChipDashboard]);
86
+ const listSharedChipIds = useMemo(() => {
87
+ const chipMqttIdsSet = new Set(listChipsMqtt.map((chip) => chip.id));
88
+ return [...chipIdsDashboardSet].filter((id) => !chipMqttIdsSet.has(id));
89
+ }, [listChipsMqtt, chipIdsDashboardSet]);
88
90
 
89
91
  useWatchSharedChips({
90
- filterChipIds: listSharedChips,
91
- ready: !!listSharedChips.length,
92
+ filterChipIds: listSharedChipIds,
93
+ ready: !!listSharedChipIds.length,
92
94
  });
93
95
 
94
96
  const fetchMyDashboardDevices = useCallback(async () => {
@@ -157,9 +157,10 @@ const MyUnit = ({ refreshing }) => {
157
157
  });
158
158
 
159
159
  const listChipsMqtt = useMemo(() => {
160
- const listChipUnit =
161
- myUnitDetail?.abstract_devices.map((device) => device.chip_id) ?? [];
162
- return chips.filter((chip) => listChipUnit.includes(chip.id));
160
+ const chipIdsUnitSet = new Set(
161
+ myUnitDetail?.abstract_devices.map((device) => device.chip_id) ?? []
162
+ );
163
+ return chips.filter((chip) => chipIdsUnitSet.has(chip.id));
163
164
  }, [chips, myUnitDetail]);
164
165
 
165
166
  useConnectChipMqtt(listChipsMqtt);
@@ -1,13 +1,13 @@
1
- import React, { memo, useCallback, useEffect, useState } from 'react';
2
- import { StyleSheet, View } from 'react-native';
3
1
  import moment from 'moment/moment';
2
+ import { memo, useCallback, useEffect, useState } from 'react';
3
+ import { StyleSheet, View } from 'react-native';
4
4
  import DateTimePickerModal from 'react-native-modal-datetime-picker';
5
5
 
6
- import Text from '../Text';
7
6
  import { Colors } from '../../configs';
8
- import DateTimeButton from './DateTimeButton';
9
- import { useTranslations } from '../../hooks/Common/useTranslations';
10
7
  import { DATE_TIME_FORMAT } from '../../configs/Constants';
8
+ import { useTranslations } from '../../hooks/Common/useTranslations';
9
+ import Text from '../Text';
10
+ import DateTimeButton from './DateTimeButton';
11
11
 
12
12
  const DateTimeRangeChange = memo(
13
13
  ({
@@ -1,9 +1,12 @@
1
1
  import { isEmpty } from 'lodash';
2
- import React, { memo, useEffect, useMemo, useState } from 'react';
2
+ import { memo, useEffect, useMemo, useState } from 'react';
3
3
  import { StyleSheet, View } from 'react-native';
4
4
 
5
5
  import { Colors } from '../../configs';
6
- import { getMaxValueIndex } from '../../utils/chartHelper/getMaxValueIndex';
6
+ import {
7
+ createDataLabelFormatter,
8
+ getMaxValueIndex,
9
+ } from '../../utils/chartHelper';
7
10
  import Highcharts from '../Highcharts';
8
11
 
9
12
  // https://github.com/facebook/hermes/issues/114#issuecomment-887106990
@@ -41,7 +44,7 @@ import Highcharts from '../Highcharts';
41
44
  // );
42
45
  // }
43
46
 
44
- const HorizontalBarChart = memo(({ datas, config }) => {
47
+ const HorizontalBarChart = memo(({ datas, config, color = Colors.Primary }) => {
45
48
  const [chartOptions, setChartOptions] = useState({
46
49
  chart: {
47
50
  type: 'bar',
@@ -92,23 +95,7 @@ const HorizontalBarChart = memo(({ datas, config }) => {
92
95
  dataLabels: {
93
96
  enabled: true,
94
97
  useHTML: true,
95
- formatter: `function formatter() {
96
- var _JSON$parse = JSON.parse(this.series.name),
97
- unit = _JSON$parse.unit,
98
- price = _JSON$parse.price;
99
- var textColor = this.color === '#00979D' ? this.y === 0 ? '#262626' : '#FFFFFF' : '#262626';
100
- var valueStyle = "color:" + textColor + ";font-weight:normal;font-size:12px;";
101
- var costStyle = valueStyle + 'font-weight:bold;';
102
- var label = "<span style=\\"" + valueStyle + "\\">" + ("" + this.y + unit);
103
- if (price === '' || price === null || isNaN(price)) {
104
- return label + '</span>';
105
- }
106
- var formatMoney = function formatMoney(number) {
107
- var formatNumber = number.toFixed();
108
- return parseInt(formatNumber, 10).toFixed(0).toString().replace(/(\\d)(?=(\\d\\d\\d)+(?!\\d))/g, '$1.') + 'đ';
109
- };
110
- return label + ("/<span style=\\"" + costStyle + "\\">") + formatMoney(this.y * price) + '</span></span>';
111
- }`,
98
+ formatter: createDataLabelFormatter(),
112
99
  align: 'right',
113
100
  inside: false,
114
101
  },
@@ -139,14 +126,14 @@ const HorizontalBarChart = memo(({ datas, config }) => {
139
126
  useEffect(() => {
140
127
  const dataY = (datas[0]?.data || []).map((item, index) => {
141
128
  return {
142
- color: index % 2 === 0 ? Colors.Primary + '20' : Colors.Primary + '16',
129
+ color: index % 2 === 0 ? color + '50' : color + '30',
143
130
  y: item.y,
144
131
  };
145
132
  });
146
133
  const dataX = (datas[0]?.data || []).map((item) => item.x);
147
134
  const maxY = getMaxValueIndex(dataY);
148
135
  if (!isEmpty(maxY.max)) {
149
- dataY.splice(maxY._index, 1, { ...maxY.max, color: Colors.Primary });
136
+ dataY.splice(maxY._index, 1, { ...maxY.max, color: color });
150
137
  }
151
138
 
152
139
  const isAllZero = dataY.every((item) => item.y === 0);
@@ -166,12 +153,12 @@ const HorizontalBarChart = memo(({ datas, config }) => {
166
153
  },
167
154
  series: [
168
155
  {
169
- name: JSON.stringify(config),
156
+ name: JSON.stringify({ ...config, color }),
170
157
  data: dataY,
171
158
  },
172
159
  ],
173
160
  }));
174
- }, [datas, config]);
161
+ }, [datas, config, color]);
175
162
 
176
163
  return (
177
164
  <View style={[styles.container, { height: heightChart }]}>
@@ -1,159 +1,283 @@
1
- import React, { memo, useCallback, useState, useMemo, useEffect } from 'react';
2
- import { StyleSheet, View } from 'react-native';
3
1
  import moment from 'moment';
2
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
3
+ import { ActivityIndicator, StyleSheet, View } from 'react-native';
4
4
  import { useTranslations } from '../../hooks/Common/useTranslations';
5
5
 
6
- import { Colors } from '../../configs';
7
- import Text from '../Text';
6
+ import { API, Colors } from '../../configs';
7
+ import AccessibilityLabel from '../../configs/AccessibilityLabel';
8
+ import { axiosGet } from '../../utils/Apis/axios';
9
+ import { formatMoney } from '../../utils/Utils';
8
10
  import Button from '../Button';
9
- import CurrencyInput from '../Form/CurrencyInput';
11
+ import ChartAggregationOption from '../ChartAggregationOption';
10
12
  import DateTimeRangeChange from '../DateTimeRangeChange';
13
+ import CurrencyInput from '../Form/CurrencyInput';
14
+ import Text from '../Text';
11
15
  import HorizontalBarChart from './HorizontalBarChart';
12
- import ChartAggregationOption from '../ChartAggregationOption';
13
- import { formatMoney } from '../../utils/Utils';
14
- import AccessibilityLabel from '../../configs/AccessibilityLabel';
15
16
 
16
- const PowerConsumptionChart = memo(
17
- ({
18
- datas,
19
- chartConfig,
20
- setChartConfig,
21
- style,
22
- groupBy,
23
- setGroupBy,
24
- onChangeDate,
25
- }) => {
26
- const t = useTranslations();
27
- const [price, setPrice] = useState(null);
17
+ const PowerConsumptionChart = ({
18
+ label,
19
+ powerConfigId,
20
+ defaultPeriod = 'date',
21
+ color = Colors.Primary,
22
+ isWidgetOrder = false,
23
+ style,
24
+ }) => {
25
+ const t = useTranslations();
26
+ const [price, setPrice] = useState(null);
27
+ const [groupBy, setGroupBy] = useState(defaultPeriod);
28
+ const [datas, setDatas] = useState([]);
29
+ const [chartConfig, setChartConfig] = useState({
30
+ unit: 'kWh',
31
+ price: '',
32
+ });
33
+ const [value, setValue] = useState([moment().subtract(6, 'days'), moment()]);
34
+ const [isFetching, setIsFetching] = useState(false);
28
35
 
29
- const onCalculateCost = useCallback(() => {
30
- setChartConfig((config) => ({
31
- ...config,
32
- price,
33
- }));
34
- }, [setChartConfig, price]);
35
-
36
- const totalPrice = useMemo(() => {
37
- const { price: chartPrice } = chartConfig;
38
- if (chartPrice === '' || isNaN(chartPrice)) {
39
- return null;
36
+ const fetchData = useCallback(
37
+ async (startDate, endDate) => {
38
+ setIsFetching(true);
39
+ let params = new URLSearchParams();
40
+ params.append('config', powerConfigId);
41
+ params.append('group_by', groupBy);
42
+ if (groupBy === 'date') {
43
+ params.append('date_from', moment(startDate).format('YYYY-MM-DD'));
44
+ params.append('date_to', moment(endDate).format('YYYY-MM-DD'));
45
+ }
46
+ const { success, data } = await axiosGet(
47
+ API.VALUE_CONSUME.DISPLAY_HISTORY(),
48
+ {
49
+ params,
50
+ },
51
+ true
52
+ );
53
+ if (success) {
54
+ setDatas(data);
40
55
  }
41
- const sum = datas[0].data.reduce((a, b) => a + b.y, 0);
42
- const roundedSum = sum * chartPrice;
43
- return roundedSum.toFixed();
44
- }, [datas, chartConfig]);
56
+ setIsFetching(false);
57
+ },
58
+ [groupBy, powerConfigId]
59
+ );
45
60
 
46
- const renderChart = useMemo(() => {
47
- return <HorizontalBarChart datas={datas} config={chartConfig} />;
48
- }, [chartConfig, datas]);
61
+ useEffect(() => {
62
+ fetchData(value[0], value[1]);
63
+ }, [fetchData, value]);
49
64
 
50
- const [value, setValue] = useState([
51
- moment().subtract(6, 'days'),
52
- moment(),
53
- ]);
65
+ useEffect(() => {
66
+ setGroupBy(defaultPeriod);
67
+ }, [defaultPeriod]);
54
68
 
55
- useEffect(() => {
56
- onChangeDate(value[0], value[1]);
57
- }, [onChangeDate, value]);
69
+ const onCalculateCost = useCallback(() => {
70
+ setChartConfig((config) => ({
71
+ ...config,
72
+ price,
73
+ }));
74
+ }, [setChartConfig, price]);
58
75
 
59
- const selectStart = (date) => {
60
- setValue((state) => [date, state[1]]);
61
- };
62
- const selectEnd = (date) => {
63
- setValue((state) => [state[0], date]);
64
- };
76
+ const totalPrice = useMemo(() => {
77
+ const { price: chartPrice } = chartConfig;
78
+ if (chartPrice === '' || isNaN(chartPrice)) {
79
+ return null;
80
+ }
81
+ const sum =
82
+ datas[0] && datas[0].data
83
+ ? datas[0].data.reduce((a, b) => a + b.y, 0)
84
+ : 0;
85
+ const roundedSum = sum * chartPrice;
86
+ return roundedSum.toFixed();
87
+ }, [datas, chartConfig]);
65
88
 
89
+ const renderChart = useMemo(() => {
90
+ if (isFetching) {
91
+ return (
92
+ <View style={styles.loadingWrapper}>
93
+ <ActivityIndicator size="large" color={Colors.Primary} />
94
+ </View>
95
+ );
96
+ }
97
+ if (!datas || datas.length === 0) {
98
+ return null;
99
+ }
66
100
  return (
67
- <View style={style}>
68
- <View style={styles.historyView}>
69
- <View style={styles.titleHistory}>
70
- <Text size={20} semibold color={Colors.Gray9}>
71
- {t('history')}
72
- </Text>
101
+ <HorizontalBarChart datas={datas} config={chartConfig} color={color} />
102
+ );
103
+ }, [chartConfig, datas, color, isFetching]);
73
104
 
105
+ const selectStart = (date) => {
106
+ setValue((state) => [date, state[1]]);
107
+ };
108
+ const selectEnd = (date) => {
109
+ setValue((state) => [state[0], date]);
110
+ };
111
+
112
+ return (
113
+ <View style={[styles.wrapper, style]}>
114
+ <View style={styles.historyView}>
115
+ <View style={styles.titleHistory}>
116
+ <Text
117
+ style={styles.label}
118
+ bold
119
+ color={Colors.Gray9}
120
+ numberOfLines={1}
121
+ >
122
+ {label || t('power_consumption_chart')}
123
+ </Text>
124
+
125
+ {!isWidgetOrder && (
74
126
  <ChartAggregationOption groupBy={groupBy} setGroupBy={setGroupBy} />
75
- </View>
76
- {groupBy === 'date' && (
77
- <DateTimeRangeChange
78
- startTime={value[0]}
79
- endTime={value[1]}
80
- selectStart={selectStart}
81
- selectEnd={selectEnd}
82
- />
83
127
  )}
84
128
  </View>
129
+ {!isWidgetOrder && groupBy === 'date' && (
130
+ <DateTimeRangeChange
131
+ startTime={value[0]}
132
+ endTime={value[1]}
133
+ selectStart={selectStart}
134
+ selectEnd={selectEnd}
135
+ style={styles.dateTimeRange}
136
+ />
137
+ )}
138
+ </View>
85
139
 
86
- <View style={styles.wrapCalculateCost}>
87
- <Text type="H4">
140
+ {!isWidgetOrder && (
141
+ <View style={styles.calculateCostCard}>
142
+ <Text style={styles.title}>
88
143
  {t('input_price_to_calculate_electricity_cost')}
89
144
  </Text>
90
- <View style={styles.row}>
91
- <CurrencyInput
92
- value={price}
93
- onChange={setPrice}
94
- minValue={0}
95
- maxValue={100000000}
96
- placeholder={'0'}
97
- onSubmitEditing={onCalculateCost}
98
- />
145
+ <View style={styles.inputRow}>
146
+ <View style={styles.inputWrapper}>
147
+ <CurrencyInput
148
+ value={price}
149
+ onChange={setPrice}
150
+ minValue={0}
151
+ maxValue={100000000}
152
+ placeholder={'0'}
153
+ onSubmitEditing={onCalculateCost}
154
+ currency="đ/kWh"
155
+ wrapperStyle={styles.currencyInputNoBorder}
156
+ />
157
+ </View>
99
158
  <Button
100
159
  type="primary"
101
160
  title={t('calculate_cost')}
161
+ height={42}
102
162
  onPress={onCalculateCost}
103
163
  style={styles.buttonCalculate}
104
- textSemiBold={false}
164
+ textSemiBold={true}
105
165
  accessibilityLabel={AccessibilityLabel.BUTTON_CALCULATE_COST}
106
166
  />
107
167
  </View>
108
168
  </View>
169
+ )}
109
170
 
171
+ <View style={styles.chartCard}>
110
172
  {renderChart}
111
173
  {!!chartConfig.price && (
112
- <Text type="H4">
113
- {t('total_power_price')}{' '}
114
- <Text bold accessibilityLabel={AccessibilityLabel.TOTAL_PRICE}>
174
+ <View style={styles.totalPriceRow}>
175
+ <Text style={styles.totalLabel}>{t('total_power_price')}</Text>
176
+ <Text
177
+ style={styles.totalValue}
178
+ accessibilityLabel={AccessibilityLabel.TOTAL_PRICE}
179
+ >
115
180
  {formatMoney(totalPrice)}
116
181
  </Text>
117
- </Text>
182
+ </View>
118
183
  )}
119
184
  </View>
120
- );
121
- }
122
- );
185
+ </View>
186
+ );
187
+ };
123
188
 
124
- export default PowerConsumptionChart;
189
+ export default React.memo(PowerConsumptionChart);
125
190
 
126
191
  const styles = StyleSheet.create({
192
+ wrapper: {
193
+ flex: 1,
194
+ marginBottom: 8,
195
+ },
127
196
  historyView: {
128
- paddingTop: 16,
197
+ paddingTop: 0,
129
198
  },
130
199
  titleHistory: {
131
200
  flexDirection: 'row',
132
201
  alignItems: 'center',
133
202
  justifyContent: 'space-between',
134
203
  },
135
- chartInfo: {
136
- flexDirection: 'row',
137
- justifyContent: 'center',
138
- alignItems: 'center',
204
+ dateTimeRange: {
205
+ justifyContent: 'flex-end',
206
+ marginTop: 12,
207
+ marginLeft: 6,
208
+ flex: 1,
139
209
  },
140
- chartContainer: {
141
- marginLeft: -8,
210
+ calculateCostCard: {
211
+ backgroundColor: Colors.LightPrimary,
212
+ borderRadius: 8,
213
+ padding: 16,
214
+ marginTop: 16,
142
215
  },
143
- chart: {
144
- height: 300,
216
+ title: {
217
+ fontSize: 14,
218
+ fontWeight: 'normal',
219
+ color: Colors.Primary,
220
+ marginBottom: 12,
145
221
  },
146
- wrapCalculateCost: {
147
- marginTop: 12,
148
- },
149
- row: {
222
+ inputRow: {
150
223
  flexDirection: 'row',
151
224
  alignItems: 'center',
152
- marginTop: 8,
225
+ gap: 12,
226
+ },
227
+ inputWrapper: {
228
+ flex: 1,
229
+ backgroundColor: Colors.White,
230
+ borderWidth: 1,
231
+ borderColor: Colors.Cyan2,
232
+ borderRadius: 8,
233
+ height: 42,
234
+ justifyContent: 'center',
235
+ paddingHorizontal: 12,
236
+ },
237
+ currencyInputNoBorder: {
238
+ borderBottomWidth: 0,
153
239
  },
154
240
  buttonCalculate: {
155
241
  width: null,
156
242
  flex: null,
157
- paddingHorizontal: 12,
243
+ paddingHorizontal: 16,
244
+ borderRadius: 8,
245
+ },
246
+ chartCard: {
247
+ backgroundColor: Colors.White,
248
+ borderRadius: 12,
249
+ padding: 12,
250
+ marginTop: 16,
251
+ borderWidth: 1,
252
+ borderColor: Colors.Gray4,
253
+ },
254
+ totalPriceRow: {
255
+ flexDirection: 'row',
256
+ justifyContent: 'space-between',
257
+ alignItems: 'center',
258
+ paddingTop: 16,
259
+ marginTop: 12,
260
+ borderTopWidth: 1,
261
+ borderTopColor: Colors.Gray4,
262
+ },
263
+ totalLabel: {
264
+ fontSize: 14,
265
+ color: Colors.Gray8,
266
+ },
267
+ totalValue: {
268
+ fontSize: 18,
269
+ fontWeight: '700',
270
+ color: Colors.Primary,
271
+ },
272
+ label: {
273
+ fontSize: 18,
274
+ fontWeight: '700',
275
+ flex: 1,
276
+ marginRight: 8,
277
+ },
278
+ loadingWrapper: {
279
+ height: 150,
280
+ justifyContent: 'center',
281
+ alignItems: 'center',
158
282
  },
159
283
  });
@@ -1,14 +1,13 @@
1
- import React, { useState, useRef, useCallback, useMemo } from 'react';
1
+ import { useCallback, useMemo, useRef, useState } from 'react';
2
2
  import {
3
- View,
4
- TextInput,
5
3
  StyleSheet,
4
+ TextInput,
6
5
  TouchableWithoutFeedback,
7
- Platform,
6
+ View,
8
7
  } from 'react-native';
9
- import Text from '../Text';
10
8
  import { Colors } from '../../configs';
11
9
  import AccessibilityLabel from '../../configs/AccessibilityLabel';
10
+ import Text from '../Text';
12
11
 
13
12
  const formatNumber = (input, options) => {
14
13
  const {
@@ -44,12 +43,13 @@ const formatNumber = (input, options) => {
44
43
  const CurrencyInput = ({
45
44
  value,
46
45
  onChange,
47
- currency = 'đ',
46
+ currency,
48
47
  minValue,
49
48
  maxValue,
50
49
  precision = 0,
51
50
  placeholder,
52
51
  onSubmitEditing,
52
+ wrapperStyle,
53
53
  }) => {
54
54
  const [startingWithSign, setStartingWithSign] = useState();
55
55
  const noNegativeValues = typeof minValue === 'number' && minValue >= 0;
@@ -119,16 +119,9 @@ const CurrencyInput = ({
119
119
  : formattedValue;
120
120
  }, [formattedValue, startingWithSign]);
121
121
 
122
- const currencyMarginLeft = useMemo(() => {
123
- if (Platform.OS === 'ios') {
124
- return 5;
125
- }
126
- return textInputValue.toString().length < 2 ? -12 : 0;
127
- }, [textInputValue]);
128
-
129
122
  return (
130
123
  <TouchableWithoutFeedback onPress={focusInput}>
131
- <View style={styles.wrap}>
124
+ <View style={[styles.wrap, wrapperStyle]}>
132
125
  <TextInput
133
126
  ref={inputRef}
134
127
  value={textInputValue}
@@ -140,10 +133,7 @@ const CurrencyInput = ({
140
133
  maxLength={10}
141
134
  accessibilityLabel={AccessibilityLabel.INPUT_CALCULATE_COST}
142
135
  />
143
- <Text
144
- semibold
145
- style={[{ marginLeft: currencyMarginLeft }, styles.currency]}
146
- >
136
+ <Text semibold style={styles.currency}>
147
137
  {currency}
148
138
  </Text>
149
139
  </View>
@@ -164,6 +154,7 @@ const styles = StyleSheet.create({
164
154
  input: {
165
155
  fontSize: 16,
166
156
  lineHeight: 24,
157
+ flex: 1,
167
158
  },
168
159
  currency: {
169
160
  fontSize: 16,