@controleonline/ui-common 1.2.70 → 1.2.75

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 (188) 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 +32 -28
  11. package/src/api/fetch.js +1 -1
  12. package/src/api/index.js +328 -58
  13. package/src/react/components/AddImportModal.js +95 -111
  14. package/src/react/components/AnimatedModal.js +171 -0
  15. package/src/react/components/AnimatedModal.styles.js +21 -0
  16. package/src/react/components/AppTypeSwitcher.js +164 -0
  17. package/src/react/components/AppTypeSwitcher.styles.js +109 -0
  18. package/src/react/components/BackgroundRuntimeBridge.js +5 -4
  19. package/src/react/components/BottomNavigationBar.config.js +211 -231
  20. package/src/react/components/BottomNavigationBar.js +86 -31
  21. package/src/react/components/BottomNavigationBar.styles.js +118 -110
  22. package/src/react/components/CategoryForm.js +52 -35
  23. package/src/react/components/DefaultProvider.native.js +194 -156
  24. package/src/react/components/DefaultProvider.web.js +188 -112
  25. package/src/react/components/DeliveryPushBridge.native.js +2 -2
  26. package/src/react/components/DeviceAlertSoundService.js +3 -3
  27. package/src/react/components/KioskModeBridge.js +2 -2
  28. package/src/react/components/LauncherModeBridge.js +2 -2
  29. package/src/react/components/ManagerPushBridge.native.js +2 -2
  30. package/src/react/components/NetworkPrinterPreviewModal.js +249 -0
  31. package/src/react/components/NetworkPrinterPreviewModal.styles.js +159 -0
  32. package/src/react/components/RemoteCheckoutService.js +28 -20
  33. package/src/react/components/RuntimeBottomNavigationBar.js +146 -119
  34. package/src/react/components/RuntimeInfoFooter.js +137 -45
  35. package/src/react/components/RuntimeInfoFooter.styles.js +3 -0
  36. package/src/react/components/StateStore.js +258 -0
  37. package/src/react/components/UnifiedPaymentBar.js +7 -4
  38. package/src/react/components/UserAvatar.js +160 -0
  39. package/src/react/components/WebsocketListener.native.js +11 -11
  40. package/src/react/components/integrations/IntegrationHero/index.js +48 -0
  41. package/src/react/components/integrations/IntegrationHero/styles.js +57 -0
  42. package/src/react/components/integrations/IntegrationTabs/index.js +89 -0
  43. package/src/react/components/integrations/IntegrationTabs/styles.js +44 -0
  44. package/src/react/config/deviceConfigBootstrap.js +71 -30
  45. package/src/react/css/orders.js +72 -0
  46. package/src/react/pages/Connections.js +229 -0
  47. package/src/react/pages/Connections.styles.js +222 -0
  48. package/src/react/pages/DeviceDetailPage.js +2814 -0
  49. package/src/react/pages/DeviceDetailPage.styles.js +308 -0
  50. package/src/react/pages/Devices/currentDevice.js +194 -0
  51. package/src/react/pages/Devices/deviceTypes/DeviceGroupCard.js +257 -0
  52. package/src/react/pages/Devices/deviceTypes/all.js +23 -0
  53. package/src/react/pages/Devices/deviceTypes/device.js +25 -0
  54. package/src/react/pages/Devices/deviceTypes/deviceListHelpers.js +178 -0
  55. package/src/react/pages/Devices/deviceTypes/display.js +26 -0
  56. package/src/react/pages/Devices/deviceTypes/index.js +145 -0
  57. package/src/react/pages/Devices/deviceTypes/ipCamera.js +35 -0
  58. package/src/react/pages/Devices/deviceTypes/pdv.js +88 -0
  59. package/src/react/pages/Devices/deviceTypes/printer.js +37 -0
  60. package/src/react/pages/Devices/deviceTypes/shared.js +453 -0
  61. package/src/react/pages/Devices/deviceTypes/useDeviceNetworkConnectivity.js +145 -0
  62. package/src/react/pages/Devices.js +183 -0
  63. package/src/react/pages/Devices.styles.js +353 -0
  64. package/src/react/pages/Food99IntegrationPage/components/Food99CatalogTab.js +219 -0
  65. package/src/react/pages/Food99IntegrationPage/components/Food99OverviewTab.js +134 -0
  66. package/src/react/pages/Food99IntegrationPage/components/Food99PreviewModal.js +173 -0
  67. package/src/react/pages/Food99IntegrationPage/components/Food99ProductCard.js +1 -0
  68. package/src/react/pages/Food99IntegrationPage/components/Food99QuickWalletModal.js +181 -0
  69. package/src/react/pages/Food99IntegrationPage/components/Food99SettingsTab.js +306 -0
  70. package/src/react/pages/Food99IntegrationPage/components/Food99StoreTab.js +417 -0
  71. package/src/react/pages/Food99IntegrationPage/index.js +1530 -0
  72. package/src/react/pages/Food99IntegrationPage/styles.js +792 -0
  73. package/src/react/pages/Food99IntegrationPage/utils.js +155 -0
  74. package/src/react/pages/Food99IntegrationPage.js +1 -0
  75. package/src/react/pages/Food99IntegrationPage.styles.js +1 -0
  76. package/src/react/pages/GenericLogPage.js +42 -167
  77. package/src/react/pages/IFoodIntegrationPage/components/IFoodCatalogTab.js +8 -0
  78. package/src/react/pages/IFoodIntegrationPage/components/IFoodOperationsTab.js +420 -0
  79. package/src/react/pages/IFoodIntegrationPage/components/IFoodOverviewTab.js +118 -0
  80. package/src/react/pages/IFoodIntegrationPage/components/IFoodPreviewModal.js +103 -0
  81. package/src/react/pages/IFoodIntegrationPage/components/IFoodProductCard.js +1 -0
  82. package/src/react/pages/IFoodIntegrationPage/components/IFoodStoreTab.js +150 -0
  83. package/src/react/pages/IFoodIntegrationPage/index.js +1298 -0
  84. package/src/react/pages/IFoodIntegrationPage/styles.js +764 -0
  85. package/src/react/pages/IFoodIntegrationPage/utils.js +91 -0
  86. package/src/react/pages/IFoodIntegrationPage.js +1 -0
  87. package/src/react/pages/IFoodIntegrationPage.styles.js +1 -0
  88. package/src/react/pages/Imports.js +214 -166
  89. package/src/react/pages/IntegrationConfigPage.js +744 -0
  90. package/src/react/pages/IntegrationConfigPage.styles.js +269 -0
  91. package/src/react/pages/Integrations.js +299 -0
  92. package/src/react/pages/Integrations.styles.js +130 -0
  93. package/src/react/pages/ManagerOrderNotificationsPage.js +642 -0
  94. package/src/react/pages/MarketplaceIntegrationPage/components/MarketplaceProductCard.js +205 -0
  95. package/src/react/pages/MarketplaceIntegrationPage/components/RemoteMarketplaceMenuTab.js +335 -0
  96. package/src/react/pages/MarketplaceIntegrationPage/index.js +60 -0
  97. package/src/react/pages/MarketplaceIntegrationPage/utils.js +137 -0
  98. package/src/react/pages/MercadoLivreIntegrationPage.js +538 -0
  99. package/src/react/pages/PrinterDeviceDetailPage.js +1916 -0
  100. package/src/react/pages/PrinterDeviceDetailPage.styles.js +223 -0
  101. package/src/react/pages/PrinterDeviceFormPage.js +521 -0
  102. package/src/react/pages/PrinterDeviceFormPage.styles.js +159 -0
  103. package/src/react/pages/SettingsPage/PaymentTypesByWalletTab.js +484 -454
  104. package/src/react/pages/SettingsPage/index.js +1266 -1167
  105. package/src/react/pages/WhatsAppConnectionPage.js +459 -0
  106. package/src/react/pages/WhatsAppConnectionPage.styles.js +284 -0
  107. package/src/react/pages/integrationsCatalog.js +399 -0
  108. package/src/react/print/providers/local.js +1 -1
  109. package/src/react/router/publicRoutes.js +25 -0
  110. package/src/react/services/Cielo/Checkout.js +39 -0
  111. package/src/react/services/Cielo/Cielo.js +193 -0
  112. package/src/react/services/Cielo/Print.js +7 -0
  113. package/src/react/services/InfinitePay/Checkout.js +33 -0
  114. package/src/react/services/InfinitePay/InfinitePay.js +24 -0
  115. package/src/react/{utils → services}/paymentGatewayExecution.js +91 -91
  116. package/src/react/styles/global.js +115 -0
  117. package/src/react/utils/categoryContexts.js +46 -0
  118. package/src/react/utils/entityDisplay.js +222 -217
  119. package/src/react/utils/fileUrl.js +201 -16
  120. package/src/react/utils/integrationPage.js +16 -0
  121. package/src/react/utils/menuNavigation.js +31 -0
  122. package/src/react/utils/orderIdentity.js +277 -0
  123. package/src/react/utils/remotePayment.js +115 -61
  124. package/src/react/utils/runtimeFooter.js +40 -22
  125. package/src/react/utils/runtimeLanguage.js +50 -9
  126. package/src/react/utils/runtimeMenu.js +190 -98
  127. package/src/react/utils/runtimeZoom.js +43 -0
  128. package/src/react/utils/shopConfig.js +72 -34
  129. package/src/react/utils/shopFranchises.js +182 -23
  130. package/src/react/utils/socketRuntimePipeline.js +14 -14
  131. package/src/react/utils/storeColumns.js +23 -4
  132. package/src/react/utils/userAvatar.js +104 -0
  133. package/src/store/categories/index.js +48 -20
  134. package/src/store/configs/index.js +2 -2
  135. package/src/store/device_config/index.js +62 -21
  136. package/src/store/entity_log/index.js +22 -1
  137. package/src/store/imports/customActions.js +51 -0
  138. package/src/store/imports/index.js +89 -88
  139. package/src/store/status/index.js +11 -11
  140. package/src/store/themes/index.js +22 -0
  141. package/src/store/timezones/index.js +3 -1
  142. package/src/tests/browser/manager/connections.spec.js +143 -0
  143. package/src/tests/browser/manager/devices-current.spec.js +343 -0
  144. package/src/tests/browser/manager/mercado-livre-integration.spec.js +268 -0
  145. package/src/tests/react/api/deviceHeaders.test.js +114 -0
  146. package/src/tests/react/api/loadSmokeIndex.test.js +75 -0
  147. package/src/tests/react/components/AddImportModal.test.js +166 -0
  148. package/src/tests/react/components/BottomNavigationBar.config.test.js +20 -0
  149. package/src/tests/react/components/UserAvatar.test.js +52 -0
  150. package/src/tests/react/config/deviceConfigBootstrap.test.js +47 -0
  151. package/src/tests/react/pages/DevicePickerStyles.test.js +47 -0
  152. package/src/tests/react/pages/Devices/deviceListHelpers.test.js +39 -0
  153. package/src/tests/react/pages/DevicesCurrentDevice.test.js +198 -0
  154. package/src/tests/react/pages/connectionsHelpers.test.js +34 -0
  155. package/src/tests/react/pages/mercadoLivreIntegrationPageContract.test.mjs +16 -0
  156. package/src/tests/react/print/localPrintProvider.test.js +1 -1
  157. package/src/tests/react/services/Cielo.test.js +190 -0
  158. package/src/tests/react/store/categoriesOrdering.test.js +26 -0
  159. package/src/tests/react/utils/appDomain.test.js +62 -0
  160. package/src/tests/react/utils/entityDisplay.test.js +2 -2
  161. package/src/tests/react/utils/fileUrl.test.js +62 -0
  162. package/src/tests/react/utils/formatter.test.mjs +33 -0
  163. package/src/tests/react/utils/importStatus.test.js +2 -2
  164. package/src/tests/react/utils/orderIdentity.test.js +139 -0
  165. package/src/tests/react/utils/remotePayment.test.js +62 -0
  166. package/src/tests/react/utils/runtimeFooter.test.js +32 -9
  167. package/src/tests/react/utils/runtimeLanguage.test.js +80 -10
  168. package/src/tests/react/utils/runtimeMenu.test.js +195 -111
  169. package/src/tests/react/utils/runtimeZoom.test.js +38 -0
  170. package/src/tests/react/utils/shopConfig.test.js +75 -0
  171. package/src/tests/react/utils/shopFranchises.test.js +122 -12
  172. package/src/tests/react/utils/translate.discovery.test.mjs +170 -0
  173. package/src/tests/react/utils/translate.test.helpers.mjs +152 -0
  174. package/src/tests/react/utils/translate.test.mjs +252 -396
  175. package/src/tests/react/utils/userAvatar.test.js +63 -0
  176. package/src/utils/appDomain.js +15 -4
  177. package/src/utils/formatter.js +122 -16
  178. package/src/utils/integrationConfigs.js +1 -0
  179. package/src/utils/translate.js +277 -398
  180. package/src/utils/translateDiscovery.js +96 -0
  181. package/src/utils/translateNormalize.js +33 -0
  182. package/src/utils/translatePending.js +92 -0
  183. package/src/utils/translateStorage.js +142 -0
  184. package/.github/agents/developer.agent.md +0 -30
  185. package/.github/agents/devops.agent.md +0 -30
  186. package/.github/agents/qa.agent.md +0 -30
  187. package/.github/agents/security.agent.md +0 -30
  188. 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
+ });