@controleonline/ui-common 1.2.71 → 1.2.76

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 (150) hide show
  1. package/.github/actions/workers/manager/action.yml +147 -0
  2. package/.github/actions/workers/qa/action.yml +44 -0
  3. package/.github/actions/workers/security/action.yml +44 -0
  4. package/.github/actions/workers/technical-documenter/action.yml +51 -0
  5. package/.github/workflows/manager-worker.yml +168 -0
  6. package/.github/workflows/publish-npm.yml +45 -0
  7. package/.gitmodules +3 -0
  8. package/AGENTS.md +6 -0
  9. package/README.md +14 -0
  10. package/package.json +3 -2
  11. package/src/api/fetch.js +1 -1
  12. package/src/api/index.js +92 -22
  13. package/src/react/components/AddImportModal.js +94 -110
  14. package/src/react/components/BottomNavigationBar.config.js +211 -231
  15. package/src/react/components/CategoryForm.js +52 -35
  16. package/src/react/components/DefaultProvider.native.js +131 -95
  17. package/src/react/components/DefaultProvider.web.js +148 -74
  18. package/src/react/components/NetworkPrinterPreviewModal.js +249 -0
  19. package/src/react/components/NetworkPrinterPreviewModal.styles.js +159 -0
  20. package/src/react/components/RuntimeInfoFooter.js +164 -104
  21. package/src/react/components/RuntimeInfoFooter.styles.js +3 -0
  22. package/src/react/components/UnifiedPaymentBar.js +7 -4
  23. package/src/react/components/UserAvatar.js +160 -0
  24. package/src/react/components/integrations/IntegrationHero/index.js +48 -0
  25. package/src/react/components/integrations/IntegrationHero/styles.js +57 -0
  26. package/src/react/components/integrations/IntegrationTabs/index.js +89 -0
  27. package/src/react/components/integrations/IntegrationTabs/styles.js +44 -0
  28. package/src/react/config/deviceConfigBootstrap.js +5 -3
  29. package/src/react/pages/Connections.js +229 -0
  30. package/src/react/pages/Connections.styles.js +222 -0
  31. package/src/react/pages/DeviceDetailPage.js +2865 -0
  32. package/src/react/pages/DeviceDetailPage.styles.js +308 -0
  33. package/src/react/pages/Devices/currentDevice.js +194 -0
  34. package/src/react/pages/Devices/deviceTypes/DeviceGroupCard.js +257 -0
  35. package/src/react/pages/Devices/deviceTypes/all.js +23 -0
  36. package/src/react/pages/Devices/deviceTypes/device.js +25 -0
  37. package/src/react/pages/Devices/deviceTypes/deviceListHelpers.js +178 -0
  38. package/src/react/pages/Devices/deviceTypes/display.js +26 -0
  39. package/src/react/pages/Devices/deviceTypes/index.js +145 -0
  40. package/src/react/pages/Devices/deviceTypes/ipCamera.js +35 -0
  41. package/src/react/pages/Devices/deviceTypes/pdv.js +88 -0
  42. package/src/react/pages/Devices/deviceTypes/printer.js +37 -0
  43. package/src/react/pages/Devices/deviceTypes/shared.js +453 -0
  44. package/src/react/pages/Devices/deviceTypes/useDeviceNetworkConnectivity.js +145 -0
  45. package/src/react/pages/Devices.js +183 -0
  46. package/src/react/pages/Devices.styles.js +353 -0
  47. package/src/react/pages/Food99IntegrationPage/components/Food99CatalogTab.js +219 -0
  48. package/src/react/pages/Food99IntegrationPage/components/Food99OverviewTab.js +134 -0
  49. package/src/react/pages/Food99IntegrationPage/components/Food99PreviewModal.js +173 -0
  50. package/src/react/pages/Food99IntegrationPage/components/Food99ProductCard.js +1 -0
  51. package/src/react/pages/Food99IntegrationPage/components/Food99QuickWalletModal.js +181 -0
  52. package/src/react/pages/Food99IntegrationPage/components/Food99SettingsTab.js +306 -0
  53. package/src/react/pages/Food99IntegrationPage/components/Food99StoreTab.js +417 -0
  54. package/src/react/pages/Food99IntegrationPage/index.js +1530 -0
  55. package/src/react/pages/Food99IntegrationPage/styles.js +792 -0
  56. package/src/react/pages/Food99IntegrationPage/utils.js +155 -0
  57. package/src/react/pages/Food99IntegrationPage.js +1 -0
  58. package/src/react/pages/Food99IntegrationPage.styles.js +1 -0
  59. package/src/react/pages/GenericLogPage.js +42 -167
  60. package/src/react/pages/IFoodIntegrationPage/components/IFoodCatalogTab.js +8 -0
  61. package/src/react/pages/IFoodIntegrationPage/components/IFoodOperationsTab.js +420 -0
  62. package/src/react/pages/IFoodIntegrationPage/components/IFoodOverviewTab.js +118 -0
  63. package/src/react/pages/IFoodIntegrationPage/components/IFoodPreviewModal.js +103 -0
  64. package/src/react/pages/IFoodIntegrationPage/components/IFoodProductCard.js +1 -0
  65. package/src/react/pages/IFoodIntegrationPage/components/IFoodStoreTab.js +150 -0
  66. package/src/react/pages/IFoodIntegrationPage/index.js +1298 -0
  67. package/src/react/pages/IFoodIntegrationPage/styles.js +764 -0
  68. package/src/react/pages/IFoodIntegrationPage/utils.js +91 -0
  69. package/src/react/pages/IFoodIntegrationPage.js +1 -0
  70. package/src/react/pages/IFoodIntegrationPage.styles.js +1 -0
  71. package/src/react/pages/Imports.js +214 -166
  72. package/src/react/pages/IntegrationConfigPage.js +744 -0
  73. package/src/react/pages/IntegrationConfigPage.styles.js +269 -0
  74. package/src/react/pages/Integrations.js +299 -0
  75. package/src/react/pages/Integrations.styles.js +130 -0
  76. package/src/react/pages/ManagerOrderNotificationsPage.js +642 -0
  77. package/src/react/pages/MarketplaceIntegrationPage/components/MarketplaceProductCard.js +205 -0
  78. package/src/react/pages/MarketplaceIntegrationPage/components/RemoteMarketplaceMenuTab.js +335 -0
  79. package/src/react/pages/MarketplaceIntegrationPage/index.js +60 -0
  80. package/src/react/pages/MarketplaceIntegrationPage/utils.js +137 -0
  81. package/src/react/pages/MercadoLivreIntegrationPage.js +538 -0
  82. package/src/react/pages/PrinterDeviceDetailPage.js +1916 -0
  83. package/src/react/pages/PrinterDeviceDetailPage.styles.js +223 -0
  84. package/src/react/pages/PrinterDeviceFormPage.js +521 -0
  85. package/src/react/pages/PrinterDeviceFormPage.styles.js +159 -0
  86. package/src/react/pages/WhatsAppConnectionPage.js +459 -0
  87. package/src/react/pages/WhatsAppConnectionPage.styles.js +284 -0
  88. package/src/react/pages/integrationsCatalog.js +399 -0
  89. package/src/react/services/Cielo/Cielo.js +193 -193
  90. package/src/react/utils/categoryContexts.js +46 -0
  91. package/src/react/utils/entityDisplay.js +222 -217
  92. package/src/react/utils/fileUrl.js +39 -20
  93. package/src/react/utils/integrationPage.js +16 -0
  94. package/src/react/utils/runtimeFooter.js +40 -22
  95. package/src/react/utils/runtimeLanguage.js +50 -9
  96. package/src/react/utils/runtimeMenu.js +191 -131
  97. package/src/react/utils/runtimeZoom.js +43 -0
  98. package/src/react/utils/shopConfig.js +27 -15
  99. package/src/react/utils/shopFranchises.js +126 -1
  100. package/src/react/utils/storeColumns.js +23 -4
  101. package/src/react/utils/userAvatar.js +104 -0
  102. package/src/store/categories/index.js +48 -20
  103. package/src/store/device_config/index.js +62 -21
  104. package/src/store/entity_log/index.js +22 -1
  105. package/src/store/imports/customActions.js +51 -0
  106. package/src/store/imports/index.js +89 -88
  107. package/src/store/status/index.js +11 -11
  108. package/src/store/themes/index.js +22 -0
  109. package/src/store/timezones/index.js +3 -1
  110. package/src/tests/browser/manager/connections.spec.js +143 -0
  111. package/src/tests/browser/manager/devices-current.spec.js +343 -0
  112. package/src/tests/browser/manager/mercado-livre-integration.spec.js +268 -0
  113. package/src/tests/react/api/deviceHeaders.test.js +114 -0
  114. package/src/tests/react/components/AddImportModal.test.js +166 -0
  115. package/src/tests/react/components/BottomNavigationBar.config.test.js +20 -0
  116. package/src/tests/react/components/UserAvatar.test.js +52 -0
  117. package/src/tests/react/pages/DevicePickerStyles.test.js +47 -0
  118. package/src/tests/react/pages/Devices/deviceListHelpers.test.js +39 -0
  119. package/src/tests/react/pages/DevicesCurrentDevice.test.js +198 -0
  120. package/src/tests/react/pages/connectionsHelpers.test.js +34 -0
  121. package/src/tests/react/pages/mercadoLivreIntegrationPageContract.test.mjs +16 -0
  122. package/src/tests/react/services/Cielo.test.js +190 -190
  123. package/src/tests/react/store/categoriesOrdering.test.js +26 -0
  124. package/src/tests/react/utils/appDomain.test.js +62 -0
  125. package/src/tests/react/utils/entityDisplay.test.js +2 -2
  126. package/src/tests/react/utils/fileUrl.test.js +3 -3
  127. package/src/tests/react/utils/formatter.test.mjs +33 -0
  128. package/src/tests/react/utils/runtimeFooter.test.js +29 -4
  129. package/src/tests/react/utils/runtimeLanguage.test.js +79 -9
  130. package/src/tests/react/utils/runtimeMenu.test.js +198 -134
  131. package/src/tests/react/utils/runtimeZoom.test.js +38 -0
  132. package/src/tests/react/utils/shopConfig.test.js +10 -9
  133. package/src/tests/react/utils/shopFranchises.test.js +43 -0
  134. package/src/tests/react/utils/translate.discovery.test.mjs +170 -0
  135. package/src/tests/react/utils/translate.test.helpers.mjs +152 -0
  136. package/src/tests/react/utils/translate.test.mjs +141 -349
  137. package/src/tests/react/utils/userAvatar.test.js +63 -0
  138. package/src/utils/appDomain.js +15 -4
  139. package/src/utils/formatter.js +104 -16
  140. package/src/utils/integrationConfigs.js +80 -80
  141. package/src/utils/translate.js +222 -438
  142. package/src/utils/translateDiscovery.js +96 -0
  143. package/src/utils/translateNormalize.js +33 -0
  144. package/src/utils/translatePending.js +92 -0
  145. package/src/utils/translateStorage.js +142 -0
  146. package/.github/agents/developer.agent.md +0 -30
  147. package/.github/agents/devops.agent.md +0 -30
  148. package/.github/agents/qa.agent.md +0 -30
  149. package/.github/agents/security.agent.md +0 -30
  150. package/.github/workflows/npmjs.yml +0 -35
@@ -0,0 +1,181 @@
1
+ import React from 'react';
2
+ import { ActivityIndicator, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
3
+ import Icon from 'react-native-vector-icons/Feather';
4
+ import { colors } from '@controleonline/../../src/styles/colors';
5
+
6
+ import AnimatedModal from '@controleonline/ui-common/src/react/components/AnimatedModal';
7
+
8
+ import styles from '../styles';
9
+
10
+ const resolveButtonPalette = (palette, accentColor) => {
11
+ const primaryBackground =
12
+ palette.buttonBackground || accentColor || palette.primary;
13
+ const primaryBorder = palette.buttonBorder || primaryBackground;
14
+ const primaryText = palette.buttonText || palette.white;
15
+ const primaryIcon = palette.buttonIcon || primaryText;
16
+ const secondaryBackground =
17
+ palette.buttonBackgroundSecondary || palette.white;
18
+ const secondaryBorder = palette.buttonBorderSecondary || palette.border;
19
+ const secondaryText = palette.buttonTextSecondary || palette.textSecondary;
20
+ const disabledBackground =
21
+ palette.buttonDisabledBackground || secondaryBorder;
22
+ const disabledBorder = palette.buttonBorderSecondary || secondaryBorder;
23
+ const disabledText = palette.buttonDisabledText || secondaryText;
24
+
25
+ return {
26
+ primaryBackground,
27
+ primaryBorder,
28
+ primaryText,
29
+ primaryIcon,
30
+ secondaryBackground,
31
+ secondaryBorder,
32
+ secondaryText,
33
+ disabledBackground,
34
+ disabledBorder,
35
+ disabledText,
36
+ };
37
+ };
38
+
39
+ const createModalStyles = (palette = colors) =>
40
+ StyleSheet.create({
41
+ form: {
42
+ gap: 8,
43
+ marginBottom: 14,
44
+ },
45
+ label: {
46
+ fontSize: 12,
47
+ fontWeight: '700',
48
+ color: palette.textSecondary,
49
+ textTransform: 'uppercase',
50
+ letterSpacing: 0.3,
51
+ },
52
+ input: {
53
+ borderWidth: 1,
54
+ borderColor: palette.border,
55
+ borderRadius: 12,
56
+ minHeight: 44,
57
+ backgroundColor: palette.background,
58
+ paddingHorizontal: 12,
59
+ paddingVertical: 10,
60
+ fontSize: 14,
61
+ fontWeight: '600',
62
+ color: palette.text,
63
+ },
64
+ hint: {
65
+ fontSize: 12,
66
+ lineHeight: 18,
67
+ color: palette.textSecondary,
68
+ },
69
+ });
70
+
71
+ // Modal leve para cadastrar uma carteira da empresa ativa sem sair da integração.
72
+ export default function Food99QuickWalletModal({
73
+ visible,
74
+ walletName,
75
+ setWalletName,
76
+ actionLoading,
77
+ accentColor,
78
+ palette = colors,
79
+ onClose,
80
+ onCreate,
81
+ }) {
82
+ const modalStyles = createModalStyles(palette);
83
+ const buttonPalette = resolveButtonPalette(palette, accentColor);
84
+ const isCreating = actionLoading === 'create-wallet';
85
+
86
+ return (
87
+ <AnimatedModal visible={visible} onRequestClose={onClose}>
88
+ <View style={styles.modalShell}>
89
+ <View style={styles.modalCard}>
90
+ <View style={styles.modalHeader}>
91
+ <View>
92
+ <Text style={styles.modalTitle}>Cadastro rapido de carteira</Text>
93
+ <Text style={styles.modalSubtitle}>
94
+ Crie a carteira da empresa ativa para usá-la como carteira de repasse do 99Food.
95
+ </Text>
96
+ </View>
97
+ <TouchableOpacity onPress={onClose} style={styles.modalCloseButton}>
98
+ <Icon name="x" size={18} color={palette.textSecondary} />
99
+ </TouchableOpacity>
100
+ </View>
101
+
102
+ <View style={modalStyles.form}>
103
+ <Text style={modalStyles.label}>Nome da carteira</Text>
104
+ <TextInput
105
+ value={walletName}
106
+ onChangeText={setWalletName}
107
+ placeholder="Ex.: Pic Pay"
108
+ placeholderTextColor={palette.textSecondary}
109
+ autoFocus
110
+ style={modalStyles.input}
111
+ returnKeyType="done"
112
+ onSubmitEditing={onCreate}
113
+ />
114
+ <Text style={modalStyles.hint}>
115
+ O cadastro rápido cria a carteira na empresa ativa. Depois disso, ela fica disponível para seleção
116
+ no campo de repasse.
117
+ </Text>
118
+ </View>
119
+
120
+ <View style={styles.modalActions}>
121
+ <TouchableOpacity
122
+ style={[
123
+ styles.secondaryButton,
124
+ {
125
+ borderColor: buttonPalette.secondaryBorder,
126
+ backgroundColor: buttonPalette.secondaryBackground,
127
+ },
128
+ ]}
129
+ onPress={onClose}>
130
+ <Text
131
+ style={[
132
+ styles.secondaryButtonText,
133
+ { color: buttonPalette.secondaryText },
134
+ ]}>
135
+ Cancelar
136
+ </Text>
137
+ </TouchableOpacity>
138
+ <TouchableOpacity
139
+ style={[
140
+ styles.primaryButton,
141
+ styles.modalPrimaryButton,
142
+ {
143
+ borderWidth: 1,
144
+ borderColor: isCreating
145
+ ? buttonPalette.disabledBorder
146
+ : buttonPalette.primaryBorder,
147
+ backgroundColor: isCreating
148
+ ? buttonPalette.disabledBackground
149
+ : buttonPalette.primaryBackground,
150
+ },
151
+ ]}
152
+ onPress={onCreate}
153
+ disabled={isCreating}>
154
+ {isCreating ? (
155
+ <ActivityIndicator
156
+ size="small"
157
+ color={buttonPalette.disabledText}
158
+ />
159
+ ) : (
160
+ <>
161
+ <Icon
162
+ name="plus"
163
+ size={16}
164
+ color={buttonPalette.primaryIcon}
165
+ />
166
+ <Text
167
+ style={[
168
+ styles.primaryButtonText,
169
+ { color: buttonPalette.primaryText },
170
+ ]}>
171
+ Criar carteira
172
+ </Text>
173
+ </>
174
+ )}
175
+ </TouchableOpacity>
176
+ </View>
177
+ </View>
178
+ </View>
179
+ </AnimatedModal>
180
+ );
181
+ }
@@ -0,0 +1,306 @@
1
+ import React from 'react';
2
+ import { ActivityIndicator, Platform, Text, TextInput, TouchableOpacity, View } from 'react-native';
3
+ import { Picker } from '@react-native-picker/picker';
4
+ import Icon from 'react-native-vector-icons/Feather';
5
+ import { colors } from '@controleonline/../../src/styles/colors';
6
+
7
+ import { withOpacity } from '@controleonline/../../src/styles/branding';
8
+
9
+ import styles from '../styles';
10
+ import {
11
+ deliveryMethodOptions,
12
+ sanitizeConfirmMethodInput,
13
+ sanitizeRadiusInput,
14
+ sanitizeTimeInput,
15
+ } from '../utils';
16
+
17
+ const resolveButtonPalette = (palette, accentColor) => {
18
+ const primaryBackground =
19
+ palette.buttonBackground || accentColor || palette.primary;
20
+ const primaryBorder = palette.buttonBorder || primaryBackground;
21
+ const primaryText = palette.buttonText || palette.white;
22
+ const primaryIcon = palette.buttonIcon || primaryText;
23
+ const secondaryBackground =
24
+ palette.buttonBackgroundSecondary || palette.white;
25
+ const secondaryBorder = palette.buttonBorderSecondary || palette.border;
26
+ const secondaryText = palette.buttonTextSecondary || palette.textSecondary;
27
+ const secondaryIcon = palette.buttonIconSecondary || secondaryText;
28
+ const disabledBackground =
29
+ palette.buttonDisabledBackground || secondaryBorder;
30
+ const disabledText = palette.buttonDisabledText || secondaryText;
31
+
32
+ return {
33
+ primaryBackground,
34
+ primaryBorder,
35
+ primaryText,
36
+ primaryIcon,
37
+ secondaryBackground,
38
+ secondaryBorder,
39
+ secondaryText,
40
+ secondaryIcon,
41
+ disabledBackground,
42
+ disabledText,
43
+ };
44
+ };
45
+
46
+ // Aba isolada para configurações operacionais da loja.
47
+ export default function Food99SettingsTab({
48
+ shadowStyle,
49
+ accentColor,
50
+ settingsSummaryRows,
51
+ storeSettingsDraft,
52
+ setStoreSettingsDraft,
53
+ wallets,
54
+ walletLoading,
55
+ actionLoading,
56
+ onQuickCreateWallet,
57
+ onSave,
58
+ palette = colors,
59
+ }) {
60
+ const buttonPalette = resolveButtonPalette(palette, accentColor);
61
+
62
+ return (
63
+ <View style={[styles.panel, shadowStyle]}>
64
+ <View style={styles.panelHeader}>
65
+ <View>
66
+ <Text style={styles.panelTitle}>Configuracoes operacionais</Text>
67
+ <Text style={styles.panelSubtitle}>
68
+ Ajuste raio, horario, metodo de entrega, confirmacao e carteira de repasse sem misturar isso com a conexão da loja.
69
+ </Text>
70
+ </View>
71
+ </View>
72
+
73
+ <View style={styles.statusRows}>
74
+ {settingsSummaryRows.map(row => (
75
+ <View
76
+ key={row.label}
77
+ style={[
78
+ styles.statusRowItem,
79
+ row.wide && styles.statusRowItemWide,
80
+ ]}>
81
+ <Text style={styles.statusRowLabel}>{row.label}</Text>
82
+ <Text style={row.small ? styles.statusRowValueSmall : styles.statusRowValue}>{row.value}</Text>
83
+ </View>
84
+ ))}
85
+ </View>
86
+
87
+ <View style={styles.settingsForm}>
88
+ <View style={styles.formField}>
89
+ <Text style={styles.formLabel}>Raio de atendimento (km)</Text>
90
+ <TextInput
91
+ value={storeSettingsDraft.deliveryRadiusKm}
92
+ onChangeText={value =>
93
+ setStoreSettingsDraft(current => ({ ...current, deliveryRadiusKm: sanitizeRadiusInput(value) }))
94
+ }
95
+ placeholder="Ex.: 5"
96
+ keyboardType="decimal-pad"
97
+ style={styles.formInput}
98
+ placeholderTextColor={palette.textSecondary}
99
+ />
100
+ </View>
101
+
102
+ <View style={styles.formRow}>
103
+ <View style={[styles.formField, styles.formFieldHalf]}>
104
+ <Text style={styles.formLabel}>Abertura (HH:mm)</Text>
105
+ <TextInput
106
+ value={storeSettingsDraft.openTime}
107
+ onChangeText={value =>
108
+ setStoreSettingsDraft(current => ({ ...current, openTime: sanitizeTimeInput(value) }))
109
+ }
110
+ placeholder="08:00"
111
+ keyboardType="number-pad"
112
+ maxLength={5}
113
+ style={styles.formInput}
114
+ placeholderTextColor={palette.textSecondary}
115
+ />
116
+ </View>
117
+
118
+ <View style={[styles.formField, styles.formFieldHalf]}>
119
+ <Text style={styles.formLabel}>Fechamento (HH:mm)</Text>
120
+ <TextInput
121
+ value={storeSettingsDraft.closeTime}
122
+ onChangeText={value =>
123
+ setStoreSettingsDraft(current => ({ ...current, closeTime: sanitizeTimeInput(value) }))
124
+ }
125
+ placeholder="22:00"
126
+ keyboardType="number-pad"
127
+ maxLength={5}
128
+ style={styles.formInput}
129
+ placeholderTextColor={palette.textSecondary}
130
+ />
131
+ </View>
132
+ </View>
133
+
134
+ <View style={styles.formRow}>
135
+ <View style={[styles.formField, styles.formFieldHalf]}>
136
+ <Text style={styles.formLabel}>Metodo de entrega</Text>
137
+ <View style={styles.optionGroup}>
138
+ {deliveryMethodOptions.map(option => {
139
+ const selected = String(storeSettingsDraft.deliveryMethod) === String(option.value);
140
+
141
+ return (
142
+ <TouchableOpacity
143
+ key={option.value}
144
+ onPress={() =>
145
+ setStoreSettingsDraft(current => ({ ...current, deliveryMethod: option.value }))
146
+ }
147
+ style={[
148
+ styles.optionChip,
149
+ {
150
+ borderColor: selected
151
+ ? buttonPalette.primaryBorder
152
+ : buttonPalette.secondaryBorder,
153
+ backgroundColor: selected
154
+ ? buttonPalette.primaryBackground
155
+ : buttonPalette.secondaryBackground,
156
+ },
157
+ ]}>
158
+ <Text
159
+ style={[
160
+ styles.optionChipText,
161
+ {
162
+ color: selected
163
+ ? buttonPalette.primaryText
164
+ : buttonPalette.secondaryText,
165
+ },
166
+ ]}>
167
+ {option.label}
168
+ </Text>
169
+ </TouchableOpacity>
170
+ );
171
+ })}
172
+ </View>
173
+ </View>
174
+
175
+ <View style={[styles.formField, styles.formFieldHalf]}>
176
+ <Text style={styles.formLabel}>Metodo de confirmacao</Text>
177
+ <TextInput
178
+ value={storeSettingsDraft.confirmMethod}
179
+ onChangeText={value =>
180
+ setStoreSettingsDraft(current => ({ ...current, confirmMethod: sanitizeConfirmMethodInput(value) }))
181
+ }
182
+ placeholder="Ex.: 1"
183
+ keyboardType="number-pad"
184
+ maxLength={3}
185
+ style={styles.formInput}
186
+ placeholderTextColor={palette.textSecondary}
187
+ />
188
+ </View>
189
+ </View>
190
+
191
+ <View style={styles.formField}>
192
+ <Text style={styles.formLabel}>ID da area de entrega (opcional)</Text>
193
+ <TextInput
194
+ value={storeSettingsDraft.deliveryAreaId}
195
+ onChangeText={value =>
196
+ setStoreSettingsDraft(current => ({ ...current, deliveryAreaId: value }))
197
+ }
198
+ placeholder="Usa automaticamente a primeira area quando vazio"
199
+ style={styles.formInput}
200
+ placeholderTextColor={palette.textSecondary}
201
+ />
202
+ </View>
203
+
204
+ <View style={styles.formField}>
205
+ <View style={styles.formFieldHeaderRow}>
206
+ <Text style={styles.formLabel}>Carteira de repasse</Text>
207
+ <TouchableOpacity
208
+ onPress={onQuickCreateWallet}
209
+ style={[
210
+ styles.inlineAction,
211
+ {
212
+ borderWidth: 1,
213
+ borderColor: buttonPalette.secondaryBorder,
214
+ backgroundColor: buttonPalette.secondaryBackground,
215
+ },
216
+ ]}>
217
+ <Icon
218
+ name="plus"
219
+ size={14}
220
+ color={buttonPalette.secondaryIcon}
221
+ />
222
+ <Text
223
+ style={[
224
+ styles.inlineActionText,
225
+ { color: buttonPalette.secondaryText },
226
+ ]}>
227
+ Cadastro rapido
228
+ </Text>
229
+ </TouchableOpacity>
230
+ </View>
231
+ <View style={styles.pickerWrap}>
232
+ <Picker
233
+ selectedValue={storeSettingsDraft.settlementWalletId}
234
+ mode={Platform.OS === 'android' ? 'dropdown' : undefined}
235
+ onValueChange={value =>
236
+ setStoreSettingsDraft(current => ({ ...current, settlementWalletId: String(value || '') }))
237
+ }
238
+ enabled={!walletLoading && Array.isArray(wallets) && wallets.length > 0}
239
+ style={styles.picker}>
240
+ <Picker.Item
241
+ label={
242
+ walletLoading
243
+ ? 'Carregando carteiras...'
244
+ : Array.isArray(wallets) && wallets.length === 0
245
+ ? 'Nenhuma carteira cadastrada'
246
+ : 'Selecione uma carteira'
247
+ }
248
+ value=""
249
+ />
250
+ {(Array.isArray(wallets) ? wallets : []).map(wallet => (
251
+ <Picker.Item
252
+ key={wallet.id}
253
+ label={`${wallet.wallet || 'Carteira'} (#${wallet.id})`}
254
+ value={String(wallet.id)}
255
+ />
256
+ ))}
257
+ </Picker>
258
+ </View>
259
+ <Text style={styles.formHint}>
260
+ A carteira selecionada recebe o repasse semanal do 99Food e precisa pertencer a empresa ativa.
261
+ </Text>
262
+ </View>
263
+ </View>
264
+
265
+ <View style={styles.actionRow}>
266
+ <TouchableOpacity
267
+ style={[
268
+ styles.primaryButton,
269
+ {
270
+ borderWidth: 1,
271
+ borderColor: buttonPalette.primaryBorder,
272
+ backgroundColor: buttonPalette.primaryBackground,
273
+ },
274
+ actionLoading === 'save-settings' && {
275
+ borderColor: buttonPalette.secondaryBorder,
276
+ backgroundColor: buttonPalette.disabledBackground,
277
+ },
278
+ ]}
279
+ onPress={onSave}
280
+ disabled={actionLoading === 'save-settings'}>
281
+ {actionLoading === 'save-settings' ? (
282
+ <ActivityIndicator
283
+ size="small"
284
+ color={buttonPalette.disabledText}
285
+ />
286
+ ) : (
287
+ <>
288
+ <Icon
289
+ name="save"
290
+ size={16}
291
+ color={buttonPalette.primaryIcon}
292
+ />
293
+ <Text
294
+ style={[
295
+ styles.primaryButtonText,
296
+ { color: buttonPalette.primaryText },
297
+ ]}>
298
+ Salvar configuracoes
299
+ </Text>
300
+ </>
301
+ )}
302
+ </TouchableOpacity>
303
+ </View>
304
+ </View>
305
+ );
306
+ }