@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,642 @@
1
+ import React, {useCallback, useEffect, useMemo, useState} from 'react';
2
+ import {
3
+ ActivityIndicator,
4
+ ScrollView,
5
+ StyleSheet,
6
+ Switch,
7
+ Text,
8
+ TextInput,
9
+ TouchableOpacity,
10
+ View,
11
+ } from 'react-native';
12
+ import {SafeAreaView} from 'react-native-safe-area-context';
13
+ import Icon from 'react-native-vector-icons/MaterialIcons';
14
+ import {useFocusEffect} from '@react-navigation/native';
15
+ import {useStore} from '@store';
16
+ import {useMessage} from '@controleonline/ui-common/src/react/components/MessageService';
17
+ import {
18
+ applyManagerOrderNotificationPreferences,
19
+ applyManagerFinancialNotificationPreferences,
20
+ buildManagerOrderNotificationContent,
21
+ getManagerOrderNotificationPermissionStatus,
22
+ resolveManagerFinancialNotificationPreferences,
23
+ resolveManagerOrderNotificationPreferences,
24
+ requestManagerOrderNotificationPermission,
25
+ } from '@controleonline/ui-common/src/react/utils/managerOrderNotifications';
26
+ import {
27
+ normalizeNotificationTargets,
28
+ useGeneralSettingsConfig,
29
+ } from '@controleonline/ui-crm/src/react/pages/settings/GeneralSettings.shared';
30
+ import {colors} from '@controleonline/../../src/styles/colors';
31
+
32
+ const permissionStatusLabels = {
33
+ granted: 'Permissão do sistema liberada.',
34
+ default: 'Permissão do sistema ainda não confirmada.',
35
+ denied: 'Permissão do sistema negada.',
36
+ unsupported: 'Este ambiente não expõe notificações locais.',
37
+ };
38
+
39
+ export default function ManagerOrderNotificationsPage() {
40
+ const authStore = useStore('auth');
41
+ const peopleStore = useStore('people');
42
+ const {showError, showSuccess} = useMessage() || {};
43
+ const authActions = authStore.actions;
44
+ const {user} = authStore.getters;
45
+ const {currentCompany} = peopleStore.getters;
46
+ const {effectiveCompanyConfigs, saveConfigs} = useGeneralSettingsConfig();
47
+
48
+ const currentPreferences = useMemo(
49
+ () => resolveManagerOrderNotificationPreferences(user),
50
+ [user],
51
+ );
52
+ const financialPreferences = useMemo(
53
+ () => resolveManagerFinancialNotificationPreferences(user),
54
+ [user],
55
+ );
56
+
57
+ const [pushEnabled, setPushEnabled] = useState(currentPreferences.pushEnabled);
58
+ const [cashClosePushEnabled, setCashClosePushEnabled] = useState(
59
+ financialPreferences.cashClosePushEnabled,
60
+ );
61
+ const [storeClosePushEnabled, setStoreClosePushEnabled] = useState(
62
+ financialPreferences.storeClosePushEnabled,
63
+ );
64
+ const [cashRegisterNumbers, setCashRegisterNumbers] = useState('');
65
+ const [storeCloseNumbers, setStoreCloseNumbers] = useState('');
66
+ const [permissionStatus, setPermissionStatus] = useState('default');
67
+ const [isSaving, setIsSaving] = useState(false);
68
+ const [isSavingFinancial, setIsSavingFinancial] = useState(false);
69
+ const isOwnerCompany = Boolean(currentCompany?.user?.owner_enabled);
70
+ const previewNotification = useMemo(
71
+ () =>
72
+ buildManagerOrderNotificationContent(
73
+ [
74
+ {
75
+ order: '12345',
76
+ notificationHeader: 'Pedido #12345',
77
+ notificationSubheader: 'Referencia interna #12345',
78
+ notificationStatusLabel: 'Fila',
79
+ },
80
+ ],
81
+ currentCompany,
82
+ ),
83
+ [currentCompany],
84
+ );
85
+
86
+ useEffect(() => {
87
+ setPushEnabled(currentPreferences.pushEnabled);
88
+ }, [currentPreferences]);
89
+
90
+ useEffect(() => {
91
+ setCashClosePushEnabled(financialPreferences.cashClosePushEnabled);
92
+ setStoreClosePushEnabled(financialPreferences.storeClosePushEnabled);
93
+ }, [financialPreferences]);
94
+
95
+ useEffect(() => {
96
+ setCashRegisterNumbers(
97
+ normalizeNotificationTargets(
98
+ effectiveCompanyConfigs?.['cash-register-notifications'],
99
+ ).join('\n'),
100
+ );
101
+ setStoreCloseNumbers(
102
+ normalizeNotificationTargets(
103
+ effectiveCompanyConfigs?.['store-close-notifications'],
104
+ ).join('\n'),
105
+ );
106
+ }, [effectiveCompanyConfigs]);
107
+
108
+ const loadPermissionStatus = useCallback(async () => {
109
+ setPermissionStatus(await getManagerOrderNotificationPermissionStatus());
110
+ }, []);
111
+
112
+ useFocusEffect(
113
+ useCallback(() => {
114
+ loadPermissionStatus();
115
+ }, [loadPermissionStatus]),
116
+ );
117
+
118
+ const handleSave = useCallback(async () => {
119
+ if (isSaving) {
120
+ return;
121
+ }
122
+
123
+ setIsSaving(true);
124
+
125
+ try {
126
+ let nextPermissionStatus = permissionStatus;
127
+
128
+ if (pushEnabled) {
129
+ nextPermissionStatus = await requestManagerOrderNotificationPermission();
130
+ setPermissionStatus(nextPermissionStatus);
131
+
132
+ if (nextPermissionStatus !== 'granted') {
133
+ throw new Error(
134
+ nextPermissionStatus === 'unsupported'
135
+ ? 'Este ambiente não permite notificações locais.'
136
+ : 'Permita as notificações do sistema para ativar o aviso push.',
137
+ );
138
+ }
139
+ }
140
+
141
+ authActions.logIn(
142
+ applyManagerOrderNotificationPreferences(user, {
143
+ pushEnabled,
144
+ }),
145
+ );
146
+
147
+ showSuccess?.(
148
+ pushEnabled
149
+ ? 'Notificações de pedidos atualizadas.'
150
+ : 'Notificações de pedidos desativadas.',
151
+ );
152
+ } catch (error) {
153
+ showError?.(
154
+ error?.message || 'Não foi possível salvar as notificações do gestor.',
155
+ );
156
+ } finally {
157
+ setIsSaving(false);
158
+ }
159
+ }, [
160
+ authActions,
161
+ isSaving,
162
+ permissionStatus,
163
+ pushEnabled,
164
+ showError,
165
+ showSuccess,
166
+ user,
167
+ ]);
168
+
169
+ const handleSaveFinancial = useCallback(async () => {
170
+ if (isSavingFinancial || !isOwnerCompany) {
171
+ return;
172
+ }
173
+
174
+ setIsSavingFinancial(true);
175
+
176
+ try {
177
+ authActions.logIn(
178
+ applyManagerFinancialNotificationPreferences(user, {
179
+ cashClosePushEnabled,
180
+ storeClosePushEnabled,
181
+ }),
182
+ );
183
+
184
+ const saved = await saveConfigs({
185
+ 'cash-register-notifications': normalizeNotificationTargets(
186
+ cashRegisterNumbers,
187
+ ),
188
+ 'store-close-notifications': normalizeNotificationTargets(
189
+ storeCloseNumbers,
190
+ ),
191
+ });
192
+
193
+ if (!saved) {
194
+ throw new Error('Nao foi possivel salvar as configuracoes financeiras.');
195
+ }
196
+
197
+ showSuccess?.('Notificacoes financeiras atualizadas.');
198
+ } catch (error) {
199
+ showError?.(
200
+ error?.message || 'Nao foi possivel salvar as notificacoes financeiras.',
201
+ );
202
+ } finally {
203
+ setIsSavingFinancial(false);
204
+ }
205
+ }, [
206
+ authActions,
207
+ cashClosePushEnabled,
208
+ cashRegisterNumbers,
209
+ isOwnerCompany,
210
+ isSavingFinancial,
211
+ saveConfigs,
212
+ showError,
213
+ showSuccess,
214
+ storeCloseNumbers,
215
+ storeClosePushEnabled,
216
+ user,
217
+ ]);
218
+
219
+ return (
220
+ <SafeAreaView style={styles.screen}>
221
+ <ScrollView
222
+ contentContainerStyle={styles.content}
223
+ showsVerticalScrollIndicator={false}>
224
+ <View style={styles.heroCard}>
225
+ <Text style={styles.heroEyebrow}>PERFIL DO GESTOR</Text>
226
+ <Text style={styles.heroTitle}>Notificações de pedidos</Text>
227
+ <Text style={styles.heroDescription}>
228
+ Os pedidos novos do Gestor chegam por push nativo do Firebase, com
229
+ som padrão do sistema e abertura direta da tela de detalhes.
230
+ </Text>
231
+ </View>
232
+
233
+ <View style={styles.section}>
234
+ <View style={styles.sectionHeader}>
235
+ <View style={styles.sectionIconWrap}>
236
+ <Icon name="receipt-long" size={20} color={colors.primary} />
237
+ </View>
238
+ <View style={styles.sectionHeaderCopy}>
239
+ <Text style={styles.sectionTitle}>Preview do pedido</Text>
240
+ <Text style={styles.sectionDescription}>
241
+ Esta tela usa o cabecalho do pedido e o status inicial em fila
242
+ para antecipar como o aviso aparece no Gestor.
243
+ </Text>
244
+ </View>
245
+ </View>
246
+
247
+ <View style={styles.previewCard}>
248
+ <View style={styles.previewHeader}>
249
+ <View style={styles.previewCopy}>
250
+ <Text style={styles.previewTitle}>{previewNotification.title}</Text>
251
+ <Text style={styles.previewBody}>{previewNotification.body}</Text>
252
+ </View>
253
+ <View style={styles.previewStatusBadge}>
254
+ <Text style={styles.previewStatusText}>
255
+ {previewNotification.statusLabel || 'Fila'}
256
+ </Text>
257
+ </View>
258
+ </View>
259
+ </View>
260
+ </View>
261
+
262
+ <View style={styles.section}>
263
+ <View style={styles.sectionHeader}>
264
+ <View style={styles.sectionIconWrap}>
265
+ <Icon name="notifications-active" size={20} color={colors.primary} />
266
+ </View>
267
+ <View style={styles.sectionHeaderCopy}>
268
+ <Text style={styles.sectionTitle}>Push de novos pedidos</Text>
269
+ <Text style={styles.sectionDescription}>
270
+ O push usa o som padrão do Android e abre a tela do pedido
271
+ quando você toca na notificação.
272
+ </Text>
273
+ </View>
274
+ </View>
275
+
276
+ <View style={styles.toggleCard}>
277
+ <View style={styles.toggleCopy}>
278
+ <Text style={styles.toggleLabel}>Receber notificações push</Text>
279
+ <Text style={styles.toggleHint}>
280
+ Status do sistema: {permissionStatusLabels[permissionStatus] || permissionStatus}
281
+ </Text>
282
+ </View>
283
+ <Switch value={pushEnabled} onValueChange={setPushEnabled} />
284
+ </View>
285
+ </View>
286
+
287
+ <View style={styles.section}>
288
+ <View style={styles.sectionHeader}>
289
+ <View style={styles.sectionIconWrap}>
290
+ <Icon name="savings" size={20} color={colors.primary} />
291
+ </View>
292
+ <View style={styles.sectionHeaderCopy}>
293
+ <Text style={styles.sectionTitle}>Fechamento financeiro</Text>
294
+ <Text style={styles.sectionDescription}>
295
+ Somente o owner da empresa pode ajustar estes alertas. O push
296
+ usa o mesmo websocket do Gestor e o WhatsApp sai pela tabela de
297
+ integrações do backend.
298
+ </Text>
299
+ </View>
300
+ </View>
301
+
302
+ {!isOwnerCompany ? (
303
+ <View style={styles.ownerHintCard}>
304
+ <Text style={styles.ownerHintText}>
305
+ Este perfil nao tem permissao de owner na empresa ativa.
306
+ </Text>
307
+ </View>
308
+ ) : (
309
+ <>
310
+ <View style={styles.toggleCard}>
311
+ <View style={styles.toggleCopy}>
312
+ <Text style={styles.toggleLabel}>
313
+ Push no fechamento de caixa
314
+ </Text>
315
+ <Text style={styles.toggleHint}>
316
+ Recebe o alerta quando o caixa for encerrado com o mesmo
317
+ resumo enviado ao WhatsApp.
318
+ </Text>
319
+ </View>
320
+ <Switch
321
+ value={cashClosePushEnabled}
322
+ onValueChange={setCashClosePushEnabled}
323
+ />
324
+ </View>
325
+
326
+ <View style={styles.toggleCard}>
327
+ <View style={styles.toggleCopy}>
328
+ <Text style={styles.toggleLabel}>
329
+ Push no fechamento de loja
330
+ </Text>
331
+ <Text style={styles.toggleHint}>
332
+ Recebe o resumo financeiro quando 99 ou iFood mudarem o
333
+ status da loja para fechada.
334
+ </Text>
335
+ </View>
336
+ <Switch
337
+ value={storeClosePushEnabled}
338
+ onValueChange={setStoreClosePushEnabled}
339
+ />
340
+ </View>
341
+
342
+ <View style={styles.soundCard}>
343
+ <Text style={styles.inputLabel}>
344
+ WhatsApp do fechamento de caixa
345
+ </Text>
346
+ <TextInput
347
+ value={cashRegisterNumbers}
348
+ onChangeText={setCashRegisterNumbers}
349
+ placeholder="5511999999999"
350
+ placeholderTextColor="#94A3B8"
351
+ autoCapitalize="none"
352
+ autoCorrect={false}
353
+ keyboardType="phone-pad"
354
+ multiline
355
+ style={styles.input}
356
+ />
357
+
358
+ <Text style={styles.inputLabel}>
359
+ WhatsApp do fechamento de loja
360
+ </Text>
361
+ <TextInput
362
+ value={storeCloseNumbers}
363
+ onChangeText={setStoreCloseNumbers}
364
+ placeholder="5511999999999"
365
+ placeholderTextColor="#94A3B8"
366
+ autoCapitalize="none"
367
+ autoCorrect={false}
368
+ keyboardType="phone-pad"
369
+ multiline
370
+ style={styles.input}
371
+ />
372
+ </View>
373
+ </>
374
+ )}
375
+ </View>
376
+
377
+ <TouchableOpacity
378
+ style={[styles.saveButton, isSaving && styles.saveButtonDisabled]}
379
+ onPress={handleSave}
380
+ activeOpacity={0.85}
381
+ disabled={isSaving}>
382
+ {isSaving ? (
383
+ <ActivityIndicator size="small" color={colors.white} />
384
+ ) : (
385
+ <>
386
+ <Icon
387
+ name="save"
388
+ size={18}
389
+ color={colors.white}
390
+ style={styles.saveIcon}
391
+ />
392
+ <Text style={styles.saveButtonText}>Salvar configuração</Text>
393
+ </>
394
+ )}
395
+ </TouchableOpacity>
396
+
397
+ {isOwnerCompany && (
398
+ <TouchableOpacity
399
+ style={[
400
+ styles.saveButton,
401
+ styles.secondarySaveButton,
402
+ isSavingFinancial && styles.saveButtonDisabled,
403
+ ]}
404
+ onPress={handleSaveFinancial}
405
+ activeOpacity={0.85}
406
+ disabled={isSavingFinancial}>
407
+ {isSavingFinancial ? (
408
+ <ActivityIndicator size="small" color={colors.white} />
409
+ ) : (
410
+ <>
411
+ <Icon
412
+ name="lock"
413
+ size={18}
414
+ color={colors.white}
415
+ style={styles.saveIcon}
416
+ />
417
+ <Text style={styles.saveButtonText}>
418
+ Salvar alertas financeiros
419
+ </Text>
420
+ </>
421
+ )}
422
+ </TouchableOpacity>
423
+ )}
424
+ </ScrollView>
425
+ </SafeAreaView>
426
+ );
427
+ }
428
+
429
+ const styles = StyleSheet.create({
430
+ screen: {
431
+ flex: 1,
432
+ backgroundColor: '#F8FAFC',
433
+ },
434
+ content: {
435
+ padding: 20,
436
+ paddingBottom: 40,
437
+ gap: 18,
438
+ },
439
+ heroCard: {
440
+ backgroundColor: '#0F172A',
441
+ borderRadius: 24,
442
+ padding: 22,
443
+ shadowColor: '#0F172A',
444
+ shadowOffset: {width: 0, height: 10},
445
+ shadowOpacity: 0.18,
446
+ shadowRadius: 18,
447
+ elevation: 4,
448
+ },
449
+ heroEyebrow: {
450
+ color: '#93C5FD',
451
+ fontSize: 11,
452
+ fontWeight: '800',
453
+ letterSpacing: 1.2,
454
+ marginBottom: 10,
455
+ },
456
+ heroTitle: {
457
+ color: colors.white,
458
+ fontSize: 28,
459
+ fontWeight: '800',
460
+ marginBottom: 8,
461
+ },
462
+ heroDescription: {
463
+ color: '#CBD5E1',
464
+ fontSize: 14,
465
+ lineHeight: 20,
466
+ },
467
+ section: {
468
+ gap: 12,
469
+ },
470
+ sectionHeader: {
471
+ flexDirection: 'row',
472
+ gap: 12,
473
+ alignItems: 'flex-start',
474
+ },
475
+ sectionIconWrap: {
476
+ width: 42,
477
+ height: 42,
478
+ borderRadius: 14,
479
+ backgroundColor: '#DBEAFE',
480
+ alignItems: 'center',
481
+ justifyContent: 'center',
482
+ },
483
+ sectionHeaderCopy: {
484
+ flex: 1,
485
+ },
486
+ sectionTitle: {
487
+ color: '#0F172A',
488
+ fontSize: 18,
489
+ fontWeight: '800',
490
+ marginBottom: 4,
491
+ },
492
+ sectionDescription: {
493
+ color: '#475569',
494
+ fontSize: 14,
495
+ lineHeight: 20,
496
+ },
497
+ toggleCard: {
498
+ backgroundColor: colors.white,
499
+ borderRadius: 20,
500
+ padding: 18,
501
+ flexDirection: 'row',
502
+ alignItems: 'center',
503
+ justifyContent: 'space-between',
504
+ gap: 16,
505
+ shadowColor: '#0F172A',
506
+ shadowOffset: {width: 0, height: 6},
507
+ shadowOpacity: 0.05,
508
+ shadowRadius: 14,
509
+ elevation: 2,
510
+ },
511
+ previewCard: {
512
+ backgroundColor: colors.white,
513
+ borderRadius: 20,
514
+ padding: 18,
515
+ shadowColor: '#0F172A',
516
+ shadowOffset: {width: 0, height: 6},
517
+ shadowOpacity: 0.05,
518
+ shadowRadius: 14,
519
+ elevation: 2,
520
+ },
521
+ previewHeader: {
522
+ flexDirection: 'row',
523
+ gap: 12,
524
+ alignItems: 'flex-start',
525
+ },
526
+ previewCopy: {
527
+ flex: 1,
528
+ },
529
+ previewTitle: {
530
+ color: '#0F172A',
531
+ fontSize: 18,
532
+ fontWeight: '800',
533
+ marginBottom: 6,
534
+ },
535
+ previewBody: {
536
+ color: '#475569',
537
+ fontSize: 14,
538
+ lineHeight: 20,
539
+ },
540
+ previewStatusBadge: {
541
+ borderRadius: 999,
542
+ backgroundColor: '#E0F2FE',
543
+ paddingHorizontal: 12,
544
+ paddingVertical: 7,
545
+ },
546
+ previewStatusText: {
547
+ color: '#0369A1',
548
+ fontSize: 12,
549
+ fontWeight: '800',
550
+ textTransform: 'uppercase',
551
+ },
552
+ toggleCopy: {
553
+ flex: 1,
554
+ },
555
+ toggleLabel: {
556
+ color: '#0F172A',
557
+ fontSize: 16,
558
+ fontWeight: '700',
559
+ marginBottom: 4,
560
+ },
561
+ toggleHint: {
562
+ color: '#64748B',
563
+ fontSize: 13,
564
+ lineHeight: 18,
565
+ },
566
+ soundCard: {
567
+ backgroundColor: colors.white,
568
+ borderRadius: 20,
569
+ padding: 18,
570
+ gap: 14,
571
+ shadowColor: '#0F172A',
572
+ shadowOffset: {width: 0, height: 6},
573
+ shadowOpacity: 0.05,
574
+ shadowRadius: 14,
575
+ elevation: 2,
576
+ },
577
+ soundCardDisabled: {
578
+ opacity: 0.7,
579
+ },
580
+ ownerHintCard: {
581
+ backgroundColor: '#FEF3C7',
582
+ borderRadius: 20,
583
+ padding: 18,
584
+ },
585
+ ownerHintText: {
586
+ color: '#92400E',
587
+ fontSize: 14,
588
+ lineHeight: 20,
589
+ fontWeight: '600',
590
+ },
591
+ inputLabel: {
592
+ color: '#0F172A',
593
+ fontSize: 14,
594
+ fontWeight: '700',
595
+ marginBottom: 8,
596
+ marginTop: 4,
597
+ },
598
+ input: {
599
+ borderWidth: 1,
600
+ borderColor: '#CBD5E1',
601
+ borderRadius: 14,
602
+ paddingHorizontal: 14,
603
+ paddingVertical: 13,
604
+ color: '#0F172A',
605
+ backgroundColor: '#F8FAFC',
606
+ minHeight: 52,
607
+ textAlignVertical: 'top',
608
+ },
609
+ inputDisabled: {
610
+ color: '#94A3B8',
611
+ backgroundColor: '#F1F5F9',
612
+ },
613
+ saveButton: {
614
+ marginTop: 8,
615
+ backgroundColor: colors.primary,
616
+ borderRadius: 16,
617
+ paddingVertical: 15,
618
+ alignItems: 'center',
619
+ justifyContent: 'center',
620
+ flexDirection: 'row',
621
+ shadowColor: '#0F172A',
622
+ shadowOffset: {width: 0, height: 8},
623
+ shadowOpacity: 0.12,
624
+ shadowRadius: 16,
625
+ elevation: 3,
626
+ },
627
+ saveButtonDisabled: {
628
+ opacity: 0.65,
629
+ },
630
+ secondarySaveButton: {
631
+ backgroundColor: '#0F766E',
632
+ marginTop: 0,
633
+ },
634
+ saveIcon: {
635
+ marginRight: 8,
636
+ },
637
+ saveButtonText: {
638
+ color: colors.white,
639
+ fontSize: 16,
640
+ fontWeight: '800',
641
+ },
642
+ });