ordering-ui-react-native 0.22.1 → 0.22.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ordering-ui-react-native",
3
- "version": "0.22.01",
3
+ "version": "0.22.02",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -50,20 +50,17 @@ export const usePrinterCommands = () => {
50
50
  const generateCommands = (order: any) => {
51
51
  let commands: any = [];
52
52
 
53
- const textProps = {
54
- fontSize: 12,
55
- absolutePosition: 40
56
- }
53
+ const textProps = { fontSize: 12 }
57
54
 
58
55
  const generateProductsText = () => {
59
56
  const list: any = []
60
57
 
61
58
  if (order?.products.length) {
62
59
  order?.products.map((product: any) => {
63
- list.push(`${product?.quantity} ${product?.name} \t\t\t ${parsePrice(product.total ?? getProductPrice(product))}`)
60
+ list.push(`${product?.quantity} ${product?.name} \t\t ${parsePrice(product.total ?? getProductPrice(product))}`)
64
61
 
65
62
  product.options?.map((option: any) => {
66
- list.push(`\t ${option.name}`)
63
+ list.push({ text: `\t ${option.name}`, props: { fontSize: 10 } })
67
64
 
68
65
  option.suboptions?.map((suboption: any) => {
69
66
  const { quantity, name, position, price } = suboption
@@ -74,16 +71,16 @@ export const usePrinterCommands = () => {
74
71
  : `${quantity} x ${name} +${parsePrice(price)}`
75
72
  : 'No'
76
73
 
77
- list.push(`\t\t ${string}`)
74
+ list.push({ text: `\t\t ${string}`, props: { fontSize: 10 } })
78
75
  })
79
76
  })
80
77
 
81
78
  if (product.comment) {
82
- list.push(`\t ${t('COMMENT', 'Comment')}`)
83
- list.push(`\t\t ${product.comment}`)
79
+ list.push({ text: `\t ${t('COMMENT', 'Comment')}`, props: { fontSize: 10 } })
80
+ list.push({ text: `\t\t ${product.comment}`, props: { fontSize: 10 } })
84
81
  }
85
82
 
86
- list.push('------------------------------------------------',)
83
+ list.push('_separator_')
87
84
  })
88
85
  }
89
86
 
@@ -91,14 +88,14 @@ export const usePrinterCommands = () => {
91
88
  }
92
89
 
93
90
  const appends: any = [
94
- `${t('ORDER_NO', 'Order No.')} ${order.id}`,
95
- '\n', // need to replace with other break line command
91
+ { text: `${t('ORDER_NO', 'Order No.')} ${order.id}`, props: { fontSize: 16 } },
92
+ ' ',
96
93
  order.orderStatus,
97
- `${t('DELIVERY_TYPE', 'Delivery Type')}: ${deliveryStatus[order?.delivery_type]}`,
94
+ { text: `${t('DELIVERY_TYPE', 'Delivery Type')}: ${deliveryStatus[order?.delivery_type]}`, props: { fontSize: 14 } },
95
+ { text: `${t(`PAYMENT_METHOD${paymethodsLength(order) > 1 ? 'S' : ''}`, `Payment method${paymethodsLength(order) > 1 ? 's' : ''}`)}: ${handlePaymethodsListString(order)}`, props: { fontSize: 14 } },
98
96
  `${t('DELIVERY_DATE', 'Delivery Date')}: ${order?.delivery_datetime_utc ? parseDate(order?.delivery_datetime_utc) : parseDate(order?.delivery_datetime, { utc: false })}`,
99
- `${t(`PAYMENT_METHOD${paymethodsLength(order) > 1 ? 'S' : ''}`, `Payment method${paymethodsLength(order) > 1 ? 's' : ''}`)}: ${handlePaymethodsListString(order)}`,
100
- '\n', // need to replace with other break line command
101
- `${t('CUSTOMER_DETAILS', 'Customer details')}`,
97
+ '_separator_',
98
+ { text: `${t('CUSTOMER_DETAILS', 'Customer details')}`, props: { fontSize: 14 } },
102
99
  `${t('FULL_NAME', 'Full Name')}: ${customerName(order)}`,
103
100
  `${t('EMAIL', 'Email')}: ${order?.customer?.email}`,
104
101
  `${t('MOBILE_PHONE', 'Mobile Phone')}: ${order?.customer?.cellphone}`,
@@ -106,31 +103,41 @@ export const usePrinterCommands = () => {
106
103
  `${t('FULL_ADDRESS', 'Full Addres')}: ${order?.customer?.address}`,
107
104
  `${!!order?.customer?.internal_number ? `${t('INTERNAL_NUMBER', 'Internal Number')}: ${order?.customer?.internal_number}` : '\n'}`,
108
105
  `${!!order?.customer?.zipcode ? `${t('ZIPCODE', 'Zipcode')}: ${order?.customer?.zipcode}` : '\n'}`,
109
- '\n', // need to replace with other break line command
110
- `${t('BUSINESS_DETAILS', 'Business details')}`,
106
+ '_separator_',
107
+ { text: `${t('BUSINESS_DETAILS', 'Business details')}`, props: { fontSize: 14 } },
111
108
  order?.business?.name,
112
109
  order?.business?.email,
113
110
  `${t('BUSINESS_PHONE', 'Business Phone')}: ${order?.business?.cellphone}`,
114
111
  `${!!order?.business?.phone ? `${t('BUSINESS_PHONE', 'Business Phone')}: ${order?.business?.phone}` : '\n'}`,
115
112
  `${t('ADDRESS', 'Address')}: ${order?.business?.address}`,
116
113
  `${!!order?.business?.address_notes ? `${t('SPECIAL_ADDRESS', 'Special Address')}: ${order?.business?.address_notes}` : '\n'}`,
117
- '\n', // need to replace with other break line command
118
- `${t('ORDER_DETAILS', 'Order Details')}`,
114
+ '_separator_',
115
+ { text: `${t('ORDER_DETAILS', 'Order Details')}`, props: { fontSize: 14 } },
119
116
  ...generateProductsText(),
120
- '\n', // need to replace with other break line command
121
- `${t('SUBTOTAL', 'Subtotal')} \t\t\t ${parsePrice(order.tax_type === 1 ? (order?.summary?.subtotal + order?.summary?.tax) ?? 0 : order?.summary?.subtotal ?? 0)}`,
122
- `${order?.summary?.discount > 0 ? `${order?.offer_type === 1 ? `${t('DISCOUNT', 'Discount')} (${verifyDecimals(order?.offer_rate, parsePrice)}%)` : t('DISCOUNT', 'Discount')} \t\t\t ${parsePrice(order?.summary?.discount)}` : '\n'}`,
123
- `${order?.tax_type !== 1 ? `${t('TAX', 'Tax')} (${verifyDecimals(order?.summary?.tax_rate, parseNumber)}%) \t\t\t ${parsePrice(order?.summary?.tax ?? 0)}` : '\n'}`,
124
- `${order?.summary?.delivery_price > 0 ? `${t('DELIVERY_FEE', 'Delivery Fee')} \t\t\t ${parsePrice(order?.summary?.delivery_price ?? 0)}` : '\n'}`,
125
- `${t('DRIVER_TIP', 'Driver tip')} ${percentTip(order) ? `(${percentTip(order)}%)` : ''} \t\t\t ${parsePrice(order?.summary?.driver_tip ?? 0)}`,
126
- `${t('SERVICE_FEE', 'Service Fee')} (${verifyDecimals(order?.summary?.service_fee, parseNumber)}%) \t\t\t ${parsePrice(order?.summary?.service_fee ?? 0)}`,
127
- '------------------------------------------------',
128
- `${t('TOTAL', 'Total')} \t\t\t ${parsePrice(order?.summary?.total ?? 0)}`
117
+ ' ',
118
+ `${t('SUBTOTAL', 'Subtotal')} \t\t ${parsePrice(order.tax_type === 1 ? (order?.summary?.subtotal + order?.summary?.tax) ?? 0 : order?.summary?.subtotal ?? 0)}`,
119
+ `${order?.summary?.discount > 0 ? `${order?.offer_type === 1 ? `${t('DISCOUNT', 'Discount')} (${verifyDecimals(order?.offer_rate, parsePrice)}%)` : t('DISCOUNT', 'Discount')} \t\t ${parsePrice(order?.summary?.discount)}` : '\n'}`,
120
+ `${order?.tax_type !== 1 ? `${t('TAX', 'Tax')} (${verifyDecimals(order?.summary?.tax_rate, parseNumber)}%) \t\t ${parsePrice(order?.summary?.tax ?? 0)}` : '\n'}`,
121
+ `${order?.summary?.delivery_price > 0 ? `${t('DELIVERY_FEE', 'Delivery Fee')} \t\t ${parsePrice(order?.summary?.delivery_price ?? 0)}` : '\n'}`,
122
+ `${t('DRIVER_TIP', 'Driver tip')} ${percentTip(order) ? `(${percentTip(order)}%)` : ''} \t\t ${parsePrice(order?.summary?.driver_tip ?? 0)}`,
123
+ `${t('SERVICE_FEE', 'Service Fee')} (${verifyDecimals(order?.summary?.service_fee, parseNumber)}%) \t\t ${parsePrice(order?.summary?.service_fee ?? 0)}`,
124
+ '_separator_',
125
+ `${t('TOTAL', 'Total')} \t\t ${parsePrice(order?.summary?.total ?? 0)}`,
126
+ ' ',
127
+ ' ',
129
128
  ]
130
129
 
131
130
  commands = [
132
131
  ...commands,
133
- ...appends.map((append: any) => ({ appendBitmapText: append, ...textProps }))
132
+ ...appends.map((append: any) => {
133
+ return append === '_separator_'
134
+ ? { appendBitmapText: '---------------------------------------' }
135
+ : {
136
+ appendBitmapText: append?.text ?? append,
137
+ ...textProps,
138
+ ...append?.props
139
+ }
140
+ })
134
141
  ]
135
142
 
136
143
  return commands
@@ -1,21 +1,31 @@
1
1
  import React, { useEffect, useState } from 'react'
2
- import { ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native'
2
+ import { ScrollView, StyleSheet, TouchableOpacity, View, Dimensions } from 'react-native'
3
+ import { useForm, Controller } from 'react-hook-form';
3
4
  import SimpleLineIcons from 'react-native-vector-icons/SimpleLineIcons'
4
5
  import FeatherIcon from 'react-native-vector-icons/Feather'
6
+ import MCIcons from 'react-native-vector-icons/MaterialCommunityIcons'
7
+ import FAIcons from 'react-native-vector-icons/FontAwesome'
5
8
  import { useTheme } from 'styled-components/native'
6
9
  import { useLanguage } from 'ordering-components/native'
7
10
 
8
11
  import { _setStoreData, _retrieveStoreData } from '../../providers/StoreUtil'
9
12
  import { Container } from './styles'
10
- import { OText } from '../shared'
13
+ import { OText, OInput} from '../shared'
11
14
 
12
15
  export const PrinterSettings = (props: any) => {
13
16
  const { onClose } = props
14
17
 
15
18
  const [currentPrinter, setCurrentPrinter] = useState<any>(null)
19
+ const [layoutWidth, setLayoutWidth] = useState<any>({ actionsBtns: 0 })
20
+
21
+ const WIDTH_SCREEN = Dimensions.get('window').width
16
22
 
17
23
  const [, t] = useLanguage()
18
24
  const theme = useTheme()
25
+ const { handleSubmit, control, setValue, watch } = useForm();
26
+
27
+ const watchIp = watch('ip')
28
+ const isErrorIp = !/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i.test(watchIp)
19
29
 
20
30
  const styles = StyleSheet.create({
21
31
  icons: {
@@ -24,34 +34,80 @@ export const PrinterSettings = (props: any) => {
24
34
  padding: 10,
25
35
  alignItems: 'flex-end'
26
36
  },
37
+ optionIcons: {
38
+ padding: 8,
39
+ borderWidth: 1,
40
+ marginRight: 10,
41
+ borderRadius: 8,
42
+ },
43
+ wIconContainer: {
44
+ flexDirection: 'row',
45
+ alignItems: 'center',
46
+ width: WIDTH_SCREEN - 60 - 40
47
+ },
48
+ wrapperContainer: {
49
+ flexDirection: 'column',
50
+ },
51
+ wrapperIcons: {
52
+ flexDirection: 'row',
53
+ justifyContent: 'flex-start',
54
+ marginBottom: 5,
55
+ },
56
+ inputStyle: {
57
+ height: 40,
58
+ borderWidth: 1,
59
+ borderRadius: 8,
60
+ },
27
61
  })
28
62
 
29
63
  const printerList = [
30
- { model: 'mPOP', emulation: 'StarPRNT', portName: 'BT:TSP100' },
31
- { model: 'FVP10', emulation: 'StarLine', portName: 'BT:TSP100' },
32
- { model: 'TSP100', emulation: 'StarGraphic', portName: 'BT:TSP100' },
33
- { model: 'TSP65011', emulation: 'StarLine', portName: 'BT:TSP100' },
34
- { model: 'TSP7001', emulation: 'StarLine', portName: 'BT:TSP100' },
35
- { model: 'TSP80011', emulation: 'StarLine', portName: 'BT:TSP100' },
36
- { model: 'SP700', emulation: 'StarDotimpact', portName: 'BT:TSP100' },
37
- { model: 'SM-S210i', emulation: 'EscPosMobile', portName: 'BT:TSP100' },
38
- { model: 'SM-S220i', emulation: 'EscPosMobile', portName: 'BT:TSP100' },
39
- { model: 'SM-S230i', emulation: 'EscosMobile', portName: 'BT:TSP100' },
40
- { model: 'SM-T300i/T300', emulation: 'EscPosMobile', portName: 'BT:TSP100' },
41
- { model: 'SM-T400i', emulation: 'EscosMobile', portName: 'BT:TSP100' },
42
- { model: 'SM-L200', emulation: 'StarPRNT', portName: 'BT:TSP100' },
43
- { model: 'SM-L300', emulation: 'StarPRNT', portName: 'BT:TSP100' },
44
- { model: 'BSC10', emulation: 'EscPos', portName: 'BT:TSP100' },
45
- { model: 'SM-S210i StarPRNT', emulation: 'StarPRNT', portName: 'BT:TSP100' },
46
- { model: 'SM-S220i StarPRNT', emulation: 'StarPRNT', portName: 'BT:TSP100' },
47
- { model: 'SM-S230i StarPRNT', emulation: 'StarPRNT', portName: 'BT:TSP100' },
48
- { model: 'SM-T300i/T300 StarPRNT', emulation: 'StarPRNT', portName: 'BT:TSP100' },
49
- { model: 'SM-T400i StarPRNT', emulation: 'StarPRNT', portName: 'BT:TSP100' },
64
+ { model: 'mPOP', emulation: 'StarPRNT', portName1: 'BT:mPOP', type: 1, ip: '' },
65
+ { model: 'FVP10', emulation: 'StarLine', portName1: 'BT:FVP10', type: 1, ip: '' },
66
+ { model: 'TSP100', emulation: 'StarGraphic', portName1: 'BT:TSP100', type: 1, ip: '' },
67
+ { model: 'TSP65011', emulation: 'StarLine', portName1: 'BT:TSP65011', type: 1, ip: '' },
68
+ { model: 'TSP7001', emulation: 'StarLine', portName1: 'BT:TSP7001', type: 1, ip: '' },
69
+ { model: 'TSP80011', emulation: 'StarLine', portName1: 'BT:TSP80011', type: 1, ip: '' },
70
+ { model: 'SP700', emulation: 'StarDotimpact', portName1: 'BT:SP700', type: 1, ip: '' },
71
+ { model: 'SM-S210i', emulation: 'EscPosMobile', portName1: 'BT:SMS210i', type: 1, ip: '' },
72
+ { model: 'SM-S220i', emulation: 'EscPosMobile', portName1: 'BT:SMS220i', type: 1, ip: '' },
73
+ { model: 'SM-S230i', emulation: 'EscosMobile', portName1: 'BT:SMS230i', type: 1, ip: '' },
74
+ { model: 'SM-T300i/T300', emulation: 'EscPosMobile', portName1: 'BT:SMT300i/T300', type: 1, ip: '' },
75
+ { model: 'SM-T400i', emulation: 'EscosMobile', portName1: 'BT:SMT400i', type: 1, ip: '' },
76
+ { model: 'SM-L200', emulation: 'StarPRNT', portName1: 'BT:SML200', type: 1, ip: '' },
77
+ { model: 'SM-L300', emulation: 'StarPRNT', portName1: 'BT:SML300', type: 1, ip: '' },
78
+ { model: 'BSC10', emulation: 'EscPos', portName1: 'BT:BSC10', type: 1, ip: '' },
79
+ { model: 'SM-S210i StarPRNT', emulation: 'StarPRNT', portName1: 'BT:SMS210i', type: 1, ip: '' },
80
+ { model: 'SM-S220i StarPRNT', emulation: 'StarPRNT', portName1: 'BT:SMS220i', type: 1, ip: '' },
81
+ { model: 'SM-S230i StarPRNT', emulation: 'StarPRNT', portName1: 'BT:SMS230i', type: 1, ip: '' },
82
+ { model: 'SM-T300i/T300 StarPRNT', emulation: 'StarPRNT', portName1: 'BT:SMT300i', type: 1, ip: '' },
83
+ { model: 'SM-T400i StarPRNT', emulation: 'StarPRNT', portName1: 'BT:SMT400i', type: 1, ip: '' },
50
84
  ]
51
85
 
52
- const handleClick = async (item: any) => {
53
- setCurrentPrinter(item)
54
- await _setStoreData('printer', item)
86
+ const handleClick = async (item: any, type?: number, ip?: string) => {
87
+ let _item = item
88
+ if (_item) {
89
+ _item = {
90
+ ...currentPrinter,
91
+ ...item,
92
+ type: type ?? currentPrinter?.type,
93
+ ip: ip ?? currentPrinter?.ip,
94
+ portName: (type ?? currentPrinter?.type) === 1 || !ip
95
+ ? currentPrinter?.portName1 ?? item.portName1
96
+ : `TCP:${ip}`
97
+ }
98
+ }
99
+ setCurrentPrinter(_item)
100
+ await _setStoreData('printer', _item)
101
+ type === 1 && onClose && onClose()
102
+ }
103
+
104
+ const onLayout = (event: any, type: string) => {
105
+ const { width } = event.nativeEvent.layout;
106
+ setLayoutWidth({ ...layoutWidth, [type]: width })
107
+ };
108
+
109
+ const onSubmit = ({ ip }: any) => {
110
+ handleClick(currentPrinter, 2, ip)
55
111
  onClose && onClose()
56
112
  }
57
113
 
@@ -64,6 +120,10 @@ export const PrinterSettings = (props: any) => {
64
120
  getPrinterDefault()
65
121
  }, [])
66
122
 
123
+ useEffect(() => {
124
+ currentPrinter?.ip && !isErrorIp && setValue('ip', currentPrinter?.ip)
125
+ }, [currentPrinter?.type])
126
+
67
127
  return (
68
128
  <ScrollView
69
129
  showsVerticalScrollIndicator={false}
@@ -78,37 +138,108 @@ export const PrinterSettings = (props: any) => {
78
138
  activeOpacity={1}
79
139
  onPress={() => handleClick(item)}
80
140
  >
81
- <TouchableOpacity
82
- activeOpacity={1}
83
- style={{ flexDirection: 'row', alignItems: 'center' }}
84
- onPress={() => handleClick(item)}
85
- >
86
- <SimpleLineIcons
87
- name='printer'
88
- color={theme.colors.textGray}
89
- size={18}
90
- style={{ ...styles.icons, color: currentPrinter?.model === item.model ? theme.colors.primary : theme.colors.textGray }}
91
- />
92
- <OText
93
- size={18}
94
- color={currentPrinter?.model === item.model ? theme.colors.primary : theme.colors.textGray}
95
- >
96
- {item.model}
97
- </OText>
98
- </TouchableOpacity>
99
- {currentPrinter?.model === item.model && (
100
- <TouchableOpacity
101
- activeOpacity={1}
102
- onPress={() => handleClick(null)}
141
+ <View style={styles.wrapperContainer}>
142
+ <View style={{ flexDirection: 'row' }}>
143
+ <TouchableOpacity
144
+ activeOpacity={1}
145
+ style={styles.wIconContainer}
146
+ onPress={() => handleClick(item)}
147
+ >
148
+ <SimpleLineIcons
149
+ name='printer'
150
+ color={theme.colors.textGray}
151
+ size={18}
152
+ style={{ ...styles.icons, color: currentPrinter?.model === item.model ? theme.colors.primary : theme.colors.textGray }}
153
+ />
154
+ <OText
155
+ size={18}
156
+ color={currentPrinter?.model === item.model ? theme.colors.primary : theme.colors.textGray}
157
+ >
158
+ {item.model}
159
+ </OText>
160
+ </TouchableOpacity>
161
+ {currentPrinter?.model === item.model && (
162
+ <TouchableOpacity
163
+ activeOpacity={1}
164
+ onPress={() => handleClick(null)}
165
+ style={{ width: 40 }}
166
+ >
167
+ <FeatherIcon
168
+ name='x-circle'
169
+ color={theme.colors.danger500}
170
+ size={20}
171
+ style={styles.icons}
172
+ />
173
+ </TouchableOpacity>
174
+ )}
175
+ </View>
176
+ <View
177
+ style={styles.wrapperIcons}
103
178
  >
104
- <FeatherIcon
105
- name='x-circle'
106
- color={theme.colors.danger500}
107
- size={20}
108
- style={styles.icons}
109
- />
110
- </TouchableOpacity>
111
- )}
179
+ <View style={styles.wrapperIcons} onLayout={(e) => onLayout(e, 'actionsBtns')}>
180
+ <FAIcons
181
+ name='bluetooth'
182
+ size={20}
183
+ {...(currentPrinter?.type === 1 && currentPrinter?.model === item.model ? { color: theme.colors.primary } : {})}
184
+ style={{ ...styles.optionIcons, borderColor: currentPrinter?.type === 1 && currentPrinter?.model === item.model ? theme.colors.primary : theme.colors.textGray }}
185
+ onPress={() => handleClick(item, 1)}
186
+ />
187
+ <MCIcons
188
+ name='access-point-network'
189
+ size={20}
190
+ {...(currentPrinter?.type === 2 && currentPrinter?.model === item.model ? { color: theme.colors.primary } : {})}
191
+ style={{ ...styles.optionIcons, borderColor: currentPrinter?.type === 2 && currentPrinter?.model === item.model ? theme.colors.primary : theme.colors.textGray }}
192
+ onPress={() => handleClick(item, 2)}
193
+ />
194
+ </View>
195
+ {currentPrinter?.type === 2 && currentPrinter?.model === item.model && (
196
+ <View style={{ flexDirection: 'row', width: WIDTH_SCREEN - 60 - layoutWidth.actionsBtns }}>
197
+ <Controller
198
+ control={control}
199
+ name={'ip'}
200
+ rules={{
201
+ required: t('VALIDATION_ERROR_IP_ADDRESS_REQUIRED', 'Ip address is required'),
202
+ pattern: {
203
+ value: /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i,
204
+ message: t('INVALID_ERROR_IP_ADDRESS', 'Invalid ip address')
205
+ }
206
+ }}
207
+ defaultValue={currentPrinter?.ip ?? ''}
208
+ render={() => (
209
+ <OInput
210
+ placeholder={t('IP_ADDRESS', 'Ip address')}
211
+ placeholderTextColor={theme.colors.arrowColor}
212
+ style={{ ...styles.inputStyle, borderColor: isErrorIp ? theme.colors.danger500 : theme.colors.tabBar }}
213
+ value={currentPrinter?.ip ?? ''}
214
+ selectionColor={theme.colors.primary}
215
+ color={theme.colors.textGray}
216
+ onChange={(value: any) => {
217
+ setValue('ip', value)
218
+ setCurrentPrinter({
219
+ ...currentPrinter,
220
+ ip: value
221
+ })
222
+ }}
223
+ />
224
+ )}
225
+ />
226
+ <TouchableOpacity
227
+ activeOpacity={1}
228
+ disabled={isErrorIp}
229
+ onPress={handleSubmit(onSubmit)}
230
+ style={{ width: 40 }}
231
+ >
232
+ <FeatherIcon
233
+ name='save'
234
+ size={20}
235
+ color={isErrorIp ? theme.colors.tabBar : theme.colors.primary }
236
+ style={styles.icons}
237
+ />
238
+ </TouchableOpacity>
239
+ </View>
240
+ )}
241
+ </View>
242
+ </View>
112
243
  </Container>
113
244
  ))}
114
245
  </View>