@ledvance/group-ui-biz-bundle 1.0.160 → 1.0.161

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.
@@ -0,0 +1,461 @@
1
+ import { useCallback, useMemo } from "react"
2
+ import { parseMinutes, PriceSegment, UnitList } from "./component/EnergyModal"
3
+ import { SetSegmentedPricesParams } from "./SetSegmentedPricesScreen"
4
+ import { useReactive } from "ahooks"
5
+ import { showDialog } from "@ledvance/base/src/utils/common";
6
+ import I18n from "@ledvance/base/src/i18n";
7
+ import { StyleSheet, FlatList, Image, TouchableOpacity, View, Text } from "react-native";
8
+ import { Utils, Popup } from "tuya-panel-kit";
9
+ import ThemeType from "@ledvance/base/src/config/themeType";
10
+ import res from "@ledvance/base/src/res";
11
+ import Card from "@ledvance/base/src/components/Card";
12
+ import Spacer from "@ledvance/base/src/components/Spacer";
13
+ import React from "react";
14
+
15
+ interface EditingPopupState {
16
+ isShow: boolean
17
+ editingSegmentPrice: PriceSegment | undefined
18
+ }
19
+ export interface SetSegmentedPricesUiState {
20
+ editingSegmentPrice: EditingPopupState,
21
+ segments: PriceSegment[],
22
+ priceUnit: string,
23
+ selectedSegmentprice?: PriceSegment,
24
+ isLoading: boolean,
25
+ isDataChanged: boolean,
26
+ }
27
+
28
+ export const useSetSegmentPrice = (params: SetSegmentedPricesParams, theme?: ThemeType) => {
29
+ const cx = Utils.RatioUtils.convertX
30
+ const initialSegments = useMemo(() => {
31
+ const rawSegments = (params.isGenerate ? params.dynamicData.generatePrices : params.dynamicData.intervalPrices) ?? [];
32
+ return rawSegments.map(item => ({ ...item }));
33
+ }, [params]);
34
+
35
+ const uiState = useReactive<SetSegmentedPricesUiState>({
36
+ editingSegmentPrice: {
37
+ isShow: false,
38
+ editingSegmentPrice: undefined,
39
+ },
40
+ segments: initialSegments,
41
+ priceUnit: params.priceUnit,
42
+ selectedSegmentprice: undefined,
43
+ isLoading: false,
44
+ isDataChanged: false,
45
+ });
46
+ const findEmptySegment = useCallback(() => {
47
+ let ptr = 0;
48
+ const TOTAL_MINUTES = 1439; // (0 ~ 1439)
49
+ for (const segment of uiState.segments) {
50
+ if (segment.startMinute > ptr) {
51
+ return {
52
+ startMinute: ptr,
53
+ endMinute: segment.startMinute,
54
+ price: 0,
55
+ }
56
+ }
57
+ ptr = segment.endMinute;
58
+ }
59
+ //优化项:如果指针是0,表示没有设置过时间段,这个时候不需要帮用户自动填充成00:00 - 23:59增加用户的麻烦,因为至少要两段才可以保存,
60
+ if (ptr > 0 && ptr < TOTAL_MINUTES) {
61
+ return {
62
+ startMinute: ptr,
63
+ endMinute: TOTAL_MINUTES,
64
+ price: 0,
65
+ }
66
+ }
67
+ return undefined
68
+ }, [uiState.segments])
69
+ const showAddPopup = useCallback(() => {
70
+ uiState.editingSegmentPrice = {
71
+ isShow: true,
72
+ editingSegmentPrice: findEmptySegment(),
73
+ }
74
+ }, [uiState]);
75
+ const showEditPopup = useCallback((item: PriceSegment) => {
76
+ uiState.editingSegmentPrice = {
77
+ isShow: true,
78
+ editingSegmentPrice: item,
79
+ };
80
+ }, [uiState]);
81
+ const hidePopup = useCallback(() => {
82
+ uiState.editingSegmentPrice = {
83
+ isShow: false,
84
+ editingSegmentPrice: undefined,
85
+ };
86
+ }, [uiState]);
87
+ const insertPriceSegment = useCallback((newInterval: PriceSegment, originalInterval?: PriceSegment) => {
88
+ const result: PriceSegment[] = [];
89
+ const isEditing = originalInterval && uiState.segments.some(
90
+ item => item.startMinute === originalInterval.startMinute && item.endMinute === originalInterval.endMinute
91
+ );
92
+ const intervals = isEditing
93
+ ? uiState.segments.filter(item => !(item.startMinute === originalInterval.startMinute && item.endMinute === originalInterval.endMinute))
94
+ : uiState.segments;
95
+ for (const old of intervals) {
96
+ // 无交集
97
+ if (
98
+ old.endMinute <= newInterval.startMinute ||
99
+ old.startMinute >= newInterval.endMinute
100
+ ) {
101
+ result.push(old)
102
+ continue
103
+ }
104
+
105
+ // 保留左边未覆盖部分
106
+ if (old.startMinute < newInterval.startMinute) {
107
+ result.push({
108
+ startMinute: old.startMinute,
109
+ endMinute: newInterval.startMinute,
110
+ price: old.price,
111
+ })
112
+ }
113
+
114
+ // 保留右边未覆盖部分
115
+ if (old.endMinute > newInterval.endMinute) {
116
+ result.push({
117
+ startMinute: newInterval.endMinute,
118
+ endMinute: old.endMinute,
119
+ price: old.price,
120
+ })
121
+ }
122
+ }
123
+
124
+ // 插入新区间
125
+ result.push(newInterval)
126
+
127
+ // 排序
128
+ result.sort((a, b) => a.startMinute - b.startMinute)
129
+
130
+ // 合并相邻且价格相同区间
131
+ const merged: PriceSegment[] = []
132
+
133
+ for (const seg of result) {
134
+ const last = merged[merged.length - 1]
135
+
136
+ if (
137
+ last &&
138
+ last.price === seg.price &&
139
+ last.endMinute === seg.startMinute
140
+ ) {
141
+ last.endMinute = seg.endMinute
142
+ } else {
143
+ merged.push({ ...seg })
144
+ }
145
+ }
146
+ uiState.segments = merged
147
+ uiState.isDataChanged = true
148
+ }, [uiState])
149
+ const parsePriceSegmentText = useCallback((startMinutes: number, endMinutes: number, price: number, currency: string) => {
150
+ const { hour: sh, minute: sm } = parseMinutes(startMinutes)
151
+ const { hour: eh, minute: em } = parseMinutes(endMinutes)
152
+ return `${sh}:${sm} - ${eh}:${em} ${price}${currency}/kWh`;
153
+ }, [])
154
+ const showAlerDialog = useCallback((content: string) => {
155
+ showDialog({
156
+ method: 'alert',
157
+ title: I18n.getLang('title_tips'),
158
+ subTitle: content,
159
+ onConfirm: async (_, { close }) => {
160
+ close()
161
+ }
162
+ })
163
+ }, [])
164
+
165
+ const verifyEditingPriceSegment = useCallback((item: PriceSegment | undefined) => {
166
+ if (!item) {
167
+ showAlerDialog(I18n.getLang('error_end_timer_must_greater'))
168
+ return false
169
+ }
170
+ const { startMinute, endMinute, price } = item
171
+ if (price == undefined || price == 0) {
172
+ //toast price must be greater than 0
173
+ // uiState.toastMessage = "price must be greater than 0"
174
+ showAlerDialog(I18n.getLang('error_price_must_greater_than_z'))
175
+ return false
176
+ }
177
+ if (endMinute <= startMinute) {
178
+ //toast end timer must be greater than the start timer
179
+ // uiState.toastMessage = "end timer must be greater than the start timer"
180
+ showAlerDialog(I18n.getLang('error_end_timer_must_greater'))
181
+ return false
182
+ }
183
+ return true
184
+ }, [])
185
+ const checkFullDayCoverage = (segments: PriceSegment[]): boolean => {
186
+ if (!segments || segments.length === 0) {
187
+ return false;
188
+ }
189
+
190
+ const sorted = [...segments].sort((a, b) => a.startMinute - b.startMinute);
191
+
192
+ if (sorted[0].startMinute !== 0) {
193
+ return false;
194
+ }
195
+
196
+ let currentEnd = sorted[0].endMinute;
197
+
198
+ for (let i = 1; i < sorted.length; i++) {
199
+ const nextSegment = sorted[i];
200
+
201
+ if (nextSegment.startMinute !== currentEnd) {
202
+ return false;
203
+ }
204
+
205
+ currentEnd = nextSegment.endMinute;
206
+ }
207
+
208
+ return currentEnd >= 1439;
209
+ }
210
+ const verifySegmentsResult = useCallback(() => {
211
+ const segments = uiState.segments
212
+ if (!checkFullDayCoverage(segments)) {
213
+ showAlerDialog(I18n.getLang('error_time_period_not_full_day'))
214
+ return false
215
+ }
216
+ if (segments.length < 2) {
217
+ showAlerDialog(I18n.getLang('error_time_period_single'))
218
+ return false
219
+ }
220
+ return true
221
+ }, [])
222
+ const handleSaveClick = async (onSuccess: () => void) => {
223
+ if (!verifySegmentsResult()) {
224
+ return
225
+ }
226
+ uiState.isLoading = true
227
+ // uiState.segments is a useReactive proxy; passing it straight through would let the
228
+ // proxy leak into redux (RTK/immer freezes it) and trigger a Proxy invariant crash
229
+ // ('get' on proxy: property '0' is read-only...) on the next re-render. Clone to plain data.
230
+ const plainSegments: PriceSegment[] = uiState.segments.map(s => ({
231
+ startMinute: s.startMinute,
232
+ endMinute: s.endMinute,
233
+ price: s.price,
234
+ }))
235
+ const isSuccess = await params.onSetPriceSements(plainSegments, uiState.priceUnit)
236
+ uiState.isLoading = false
237
+ if (isSuccess) {
238
+ onSuccess()
239
+ } else {
240
+ showAlerDialog(I18n.getLang('common_server_api_error'))
241
+ }
242
+ }
243
+ const colorMapRef = React.useRef<Map<number, string>>(new Map())
244
+ const colors = [
245
+ '#00D084', // green
246
+ '#4A90E2', // blue
247
+ '#F5A623', // orange
248
+ '#BD10E0', // purple
249
+ '#7ED321', // light green
250
+ '#F8E71C', // yellow
251
+ '#FF6B6B', // red
252
+ '#50E3C2', // teal
253
+ ]
254
+
255
+ useMemo(() => {
256
+ initialSegments.forEach((seg, index) => {
257
+ if (!colorMapRef.current.has(seg.startMinute)) {
258
+ colorMapRef.current.set(seg.startMinute, colors[index % colors.length]);
259
+ }
260
+ });
261
+ }, [initialSegments]);
262
+
263
+ //取颜色 使用map 确保颜色的一致性与连续性
264
+ const getSegmentColor = useCallback((startMinute: number, _price: number): string => {
265
+ let color = colorMapRef.current.get(startMinute);
266
+ if (!color) {
267
+ //找出当前未被使用的颜色,保证颜色列表充分利用且不重复
268
+ const usedColors = new Set(
269
+ uiState.segments
270
+ .map(seg => colorMapRef.current.get(seg.startMinute))
271
+ .filter(Boolean)
272
+ );
273
+ color = colors.find(c => !usedColors.has(c)) || colors[colorMapRef.current.size % colors.length];
274
+ colorMapRef.current.set(startMinute, color);
275
+ }
276
+ return color;
277
+ }, [uiState.segments]);
278
+
279
+ const showCurrencyPopup = () => {
280
+ const { height, statusBarHeight } = Utils.RatioUtils
281
+ Popup.custom({
282
+ title: (
283
+ <View style={{ backgroundColor: theme?.card.head, flexDirection: 'row', height: cx(60), justifyContent: 'space-between', alignItems: 'center', borderTopLeftRadius: cx(10), borderTopRightRadius: cx(10), paddingHorizontal: cx(8) }}>
284
+ <TouchableOpacity onPress={() => Popup.close()}>
285
+ <Text style={{ color: theme?.global.secondBrand, fontSize: cx(16) }}>{I18n.getLang('auto_scan_system_cancel')}</Text>
286
+ </TouchableOpacity>
287
+ </View>
288
+ ),
289
+ wrapperStyle: {
290
+ height: height - statusBarHeight - cx(40),
291
+ backgroundColor: theme?.global.background
292
+ },
293
+ footer: (<View style={{ backgroundColor: theme?.global.background }}></View>),
294
+ onMaskPress: () => { },
295
+ motionType: 'none',
296
+ useKeyboardView: true,
297
+ content: (
298
+ <View
299
+ style={{ backgroundColor: theme?.global.background, paddingHorizontal: cx(16) }}>
300
+ <Spacer />
301
+ <Card>
302
+ <FlatList
303
+ data={UnitList}
304
+ initialNumToRender={15}
305
+ renderItem={({ item }) => (
306
+ <TouchableOpacity
307
+ onPress={() => {
308
+ uiState.priceUnit = item
309
+ uiState.isDataChanged = true
310
+ Popup.close()
311
+ }}
312
+ >
313
+ <View style={styles.unitItem}>
314
+ <Text style={{ fontSize: cx(16), color: theme?.global.fontColor }}>{item}</Text>
315
+ {uiState.priceUnit === item && <Image
316
+ style={{ width: cx(16), height: cx(16) }}
317
+ source={{ uri: res.app_music_check }}
318
+ resizeMode="contain"
319
+ />}
320
+ </View>
321
+ </TouchableOpacity>
322
+ )}
323
+ ItemSeparatorComponent={() => (
324
+ <View style={{ flex: 1, height: 1, backgroundColor: theme?.card.background }}></View>
325
+ )}
326
+ keyExtractor={item => item}
327
+ />
328
+ </Card>
329
+ <Spacer />
330
+ </View>
331
+ )
332
+ })
333
+ }
334
+
335
+ const deletePriceSegment = useCallback((itemToDelete: PriceSegment) => {
336
+ showDialog({
337
+ method: 'confirm',
338
+ title: I18n.getLang('title_tips'),
339
+ subTitle: I18n.getLang('consumption_confirm_delete_period'),
340
+ onConfirm: (_, { close }) => {
341
+ close()
342
+ uiState.isDataChanged = true
343
+ uiState.segments = uiState.segments.filter(item =>
344
+ !(item.startMinute === itemToDelete.startMinute && item.endMinute === itemToDelete.endMinute)
345
+ )
346
+ if (uiState.selectedSegmentprice?.startMinute === itemToDelete.startMinute &&
347
+ uiState.selectedSegmentprice?.endMinute === itemToDelete.endMinute) {
348
+ uiState.selectedSegmentprice = undefined;
349
+ }
350
+ }
351
+ })
352
+ }, [uiState])
353
+
354
+ const styles = StyleSheet.create(
355
+ {
356
+ cardStyle: {
357
+ paddingHorizontal: cx(16),
358
+ paddingVertical: cx(8),
359
+ elevation: 1
360
+ },
361
+ addPeriodCircle: {
362
+ justifyContent: 'center',
363
+ alignItems: 'center',
364
+ width: cx(16),
365
+ height: cx(16),
366
+ borderRadius: cx(8),
367
+ backgroundColor: theme?.global.brand
368
+ },
369
+ addPeriodImg: {
370
+ width: cx(14),
371
+ height: cx(14),
372
+ tintColor: theme?.container.background
373
+ },
374
+ scrollContainer: {
375
+ paddingHorizontal: cx(16),
376
+ },
377
+ currencyCardContainer: {
378
+ flexDirection: 'row',
379
+ paddingHorizontal: cx(16),
380
+ paddingVertical: cx(8),
381
+ alignItems: 'center',
382
+ justifyContent: 'space-between',
383
+ },
384
+ cardTitle: {
385
+ fontSize: cx(16),
386
+ fontWeight: 'bold',
387
+ color: theme?.global.fontColor,
388
+ },
389
+ line: {
390
+ height: 1,
391
+ position: 'absolute',
392
+ start: cx(4),
393
+ end: cx(4),
394
+ bottom: 0,
395
+ backgroundColor: theme?.textInput.line,
396
+ },
397
+ textGroup: {
398
+ flexDirection: 'row',
399
+ borderRadius: cx(4),
400
+ backgroundColor: theme?.textInput.background,
401
+ alignItems: 'center',
402
+ flex: 1,
403
+ },
404
+ textParent: {
405
+ flex: 1,
406
+ height: cx(44),
407
+ justifyContent: 'center',
408
+ },
409
+ text: {
410
+ marginStart: cx(16),
411
+ marginEnd: cx(6),
412
+ fontSize: cx(16),
413
+ color: theme?.textInput.fontColor,
414
+ fontFamily: 'helvetica_neue_lt_std_roman',
415
+ },
416
+ unitItem: {
417
+ flexDirection: 'row',
418
+ justifyContent: 'space-between',
419
+ paddingHorizontal: cx(10),
420
+ alignItems: 'center',
421
+ height: cx(40),
422
+ },
423
+ verticalIndicator: {
424
+ position: 'absolute',
425
+ top: cx(8),
426
+ bottom: 0,
427
+ left: 0,
428
+ width: cx(40),
429
+ minHeight: cx(320),
430
+ },
431
+ segmentItem: {
432
+ position: 'relative',
433
+ marginTop: cx(8),
434
+ marginLeft: cx(24),
435
+ marginRight: cx(24),
436
+ },
437
+ editSegmentIndicator: {
438
+ width: cx(18),
439
+ height: cx(18),
440
+ marginHorizontal: cx(6),
441
+ },
442
+ deleteSegmentIndicator: {
443
+ position: 'absolute',
444
+ top: -cx(6),
445
+ right: -cx(6),
446
+ width: cx(14),
447
+ height: cx(14),
448
+ zIndex: 99,
449
+ elevation: 5,
450
+ backgroundColor: '#ffffff',
451
+ borderRadius: cx(12),
452
+ },
453
+ }
454
+ )
455
+
456
+ return {
457
+ uiState, showAddPopup, showEditPopup, hidePopup, insertPriceSegment, parsePriceSegmentText,
458
+ verifyEditingPriceSegment, handleSaveClick, getSegmentColor, styles, showCurrencyPopup, deletePriceSegment
459
+ }
460
+
461
+ }
@@ -0,0 +1,201 @@
1
+ import React, { } from "react";
2
+ import { Image, ScrollView, StyleSheet, Text, TouchableOpacity, View, TouchableWithoutFeedback } from "react-native";
3
+ import { Utils } from 'tuya-panel-kit'
4
+ import Card from "@ledvance/base/src/components/Card";
5
+ import ThemeType from "@ledvance/base/src/config/themeType";
6
+ import res from "@ledvance/base/src/res";
7
+ import Spacer from "@ledvance/base/src/components/Spacer";
8
+ import Page from "@ledvance/base/src/components/Page";
9
+ import I18n from "@ledvance/base/src/i18n";
10
+ import { useRoute } from '@react-navigation/core';
11
+ import EnergyPopup, { DynamicEnergyData, PriceSegment } from './component/EnergyModal';
12
+ import { useSetSegmentPrice } from "./SetSegmentPricesContract";
13
+ import VerticalDailyPricesIndicator from "./component/VerticalDailyPricesIndicator";
14
+ import { useNavigation } from '@react-navigation/core'
15
+
16
+ const { withTheme } = Utils.ThemeUtils
17
+ const { convertX: cx } = Utils.RatioUtils
18
+
19
+ const SetSegmentedPricesScreen = (props: { theme?: ThemeType }) => {
20
+ const params = useRoute().params as SetSegmentedPricesParams
21
+ const navigation = useNavigation()
22
+ const {
23
+ uiState, showAddPopup, showEditPopup, hidePopup, insertPriceSegment, parsePriceSegmentText,
24
+ verifyEditingPriceSegment, handleSaveClick, getSegmentColor, styles, showCurrencyPopup, deletePriceSegment
25
+ } = useSetSegmentPrice(params, props.theme)
26
+
27
+ return (
28
+ <Page
29
+ style={{ position: 'relative' }}
30
+ backText={params.backTitle}
31
+ headlineText={I18n.getLang('consumption_data_field_dynamic_money')}
32
+ rightButtonIcon={res.ic_check}
33
+ rightButtonIconClick={() => {
34
+ handleSaveClick(() => {
35
+ navigation.goBack()
36
+ })
37
+ }}
38
+ loading={uiState.isLoading}
39
+ showBackDialog={uiState.isDataChanged}
40
+ backDialogTitle={I18n.getLang('manage_user_unsaved_changes_dialog_headline')}
41
+ backDialogContent={I18n.getLang('motion_detection_change_activity_dialog_description_text')}
42
+ >
43
+ <ScrollView style={styles.scrollContainer}
44
+ contentContainerStyle={{ flexGrow: 1, paddingBottom: cx(20) }}>
45
+ <TouchableWithoutFeedback onPress={() => {
46
+ uiState.selectedSegmentprice = undefined
47
+ }}>
48
+ <View style={{ flex: 1 }}>
49
+ {/* currency field*/}
50
+ <Card style={{ elevation: cx(2) }}
51
+ containerStyle={styles.currencyCardContainer}>
52
+ <Text
53
+ style={styles.cardTitle}>{I18n.getLang('consumption_data_price_per_kwh_currency_headline_text')}</Text>
54
+ <TouchableOpacity style={{ flex: 0.4 }} accessibilityLabel={"TextFieldStyleButton"}
55
+ onPress={() => {
56
+ uiState.selectedSegmentprice = undefined
57
+ showCurrencyPopup()
58
+ }}>
59
+ <View style={styles.textGroup}>
60
+ <View style={styles.textParent}>
61
+ <Text style={styles.text}>{uiState.priceUnit}</Text>
62
+ </View>
63
+ <View style={styles.line} />
64
+ </View>
65
+ </TouchableOpacity>
66
+ </Card>
67
+ {/* segmented prices field*/}
68
+ <View style={{ width: '100%', marginTop: cx(10) }}>
69
+ <View style={{ flexDirection: 'row', width: '100%', position: 'relative', marginTop: cx(10) }}>
70
+ {/*Vertical indicator*/}
71
+ <View style={styles.verticalIndicator}>
72
+ <VerticalDailyPricesIndicator
73
+ style={{ height: '100%' }}
74
+ data={uiState.segments}
75
+ selectingData={uiState.selectedSegmentprice}
76
+ getSegmentColor={getSegmentColor}
77
+ />
78
+ </View>
79
+
80
+
81
+ <View style={{ flex: 1, marginLeft: cx(45) }}>
82
+ {/* Add Time period */}
83
+ <Card
84
+ style={[styles.cardStyle, { marginTop: cx(8), marginLeft: cx(24), marginRight: cx(24) }]}
85
+ onPress={() => {
86
+ uiState.selectedSegmentprice = undefined
87
+ showAddPopup()
88
+ }}>
89
+ <View style={{ flexDirection: 'row', alignItems: 'center' }}>
90
+ <View style={styles.addPeriodCircle}>
91
+ <Image source={{ uri: res.ic_plus }} style={styles.addPeriodImg}></Image>
92
+ </View>
93
+ <Spacer style={{ width: cx(8) }}></Spacer>
94
+ <Text
95
+ style={{ color: props.theme?.global.fontColor }}>{I18n.getLang('consumption_add_time_period')}</Text>
96
+ </View>
97
+ </Card>
98
+ {/** Time and Price segments */}
99
+ <Spacer />
100
+ {
101
+ (uiState.segments.map((item) => {
102
+ const { startMinute, endMinute, price } = item
103
+ const content = parsePriceSegmentText(startMinute, endMinute, price, uiState.priceUnit)
104
+ const backgroundColor = getSegmentColor(item.startMinute, item.price)
105
+ return (
106
+ <View
107
+ key={`${item.startMinute}-${item.endMinute}`}
108
+ style={styles.segmentItem}
109
+ >
110
+ {/* Segment Card*/}
111
+ <Card
112
+ style={[styles.cardStyle, {
113
+ backgroundColor: backgroundColor,
114
+ marginTop: 0,
115
+ marginLeft: 0,
116
+ marginRight: 0,
117
+ width: '100%',
118
+ }]}
119
+ onPress={() => {
120
+ console.log("outside set selectedItem ->", JSON.stringify(item))
121
+ uiState.selectedSegmentprice = item
122
+ }}>
123
+ <View
124
+ style={{ flexDirection: 'row', justifyContent: 'space-between', }}>
125
+ <Text
126
+ style={{ color: props.theme?.button.fontColor }}>{content}</Text>
127
+ <TouchableOpacity
128
+ style={styles.editSegmentIndicator}
129
+ onPress={() => {
130
+ showEditPopup(item)
131
+ }}>
132
+ <Image
133
+ style={{
134
+ width: '100%',
135
+ height: '100%',
136
+ tintColor: props.theme?.button.fontColor
137
+ }} source={{ uri: res.ic_more }} />
138
+ </TouchableOpacity>
139
+ </View>
140
+
141
+ </Card>
142
+ {/* Delete icon*/}
143
+ {uiState.selectedSegmentprice?.startMinute === item.startMinute &&
144
+ uiState.selectedSegmentprice?.endMinute === item.endMinute && (
145
+ <TouchableOpacity
146
+ style={styles.deleteSegmentIndicator}
147
+ onPress={() => {
148
+ deletePriceSegment(item)
149
+ }}>
150
+ <Image style={{
151
+ width: '100%',
152
+ height: '100%',
153
+ }} source={res.icon_delete} />
154
+ </TouchableOpacity>
155
+ )}
156
+
157
+ </View>
158
+ )
159
+ }
160
+ ))
161
+ }
162
+ </View>
163
+ </View>
164
+
165
+ </View>
166
+ </View>
167
+ </TouchableWithoutFeedback>
168
+ </ScrollView>
169
+ <EnergyPopup
170
+ visible={uiState.editingSegmentPrice.isShow}
171
+ popupType={'segment_price'}
172
+ title={I18n.getLang('contact_sensor_specific_settings')}
173
+ cancelText={I18n.getLang('auto_scan_system_cancel')}
174
+ confirmText={I18n.getLang('auto_scan_system_wifi_confirm')}
175
+ editingPriceSegment={uiState.editingSegmentPrice.editingSegmentPrice}
176
+ onCancel={() => {
177
+ hidePopup()
178
+ }}
179
+ onPriceSegmentConfirm={(segment) => {
180
+ if (verifyEditingPriceSegment(segment)) {
181
+ if (segment) {
182
+ console.log("wayne_check onPriceSegmentConfirm ->", JSON.stringify(segment))
183
+ insertPriceSegment(segment, uiState.editingSegmentPrice.editingSegmentPrice)
184
+ }
185
+ hidePopup()
186
+ }
187
+ }}
188
+ />
189
+ </Page>
190
+ )
191
+ }
192
+
193
+ export interface SetSegmentedPricesParams {
194
+ backTitle: string,
195
+ dynamicData: DynamicEnergyData,
196
+ priceUnit: string,
197
+ isGenerate: boolean,
198
+ onSetPriceSements: (segments: PriceSegment[], currency: string) => Promise<boolean>,
199
+ }
200
+
201
+ export default withTheme(SetSegmentedPricesScreen)