460 lines
12 KiB
Markdown
460 lines
12 KiB
Markdown
|
|
# Validação de Sinal Mobile e Armazenamento Offline
|
||
|
|
|
||
|
|
## Visão Geral
|
||
|
|
|
||
|
|
Sistema inteligente que monitora a qualidade do sinal de conexão mobile (4G/5G) e automaticamente ativa o modo offline quando o sinal está abaixo de 30%, garantindo que os dados sejam salvos localmente e sincronizados quando a conexão melhorar.
|
||
|
|
|
||
|
|
## 🎯 **Funcionalidades Principais**
|
||
|
|
|
||
|
|
### 1. **Monitoramento de Sinal em Tempo Real**
|
||
|
|
- Detecção automática do tipo de conexão (WiFi, 4G, 5G, 3G, 2G)
|
||
|
|
- Estimativa da intensidade do sinal baseada na geração da rede
|
||
|
|
- Atualização contínua do status de conexão
|
||
|
|
|
||
|
|
### 2. **Ativação Automática do Modo Offline**
|
||
|
|
- **Trigger**: Sinal abaixo de 30% ou sem conexão
|
||
|
|
- **Comportamento**: Salva dados localmente em vez de enviar para API
|
||
|
|
- **Notificação**: Alerta o usuário sobre a mudança de modo
|
||
|
|
|
||
|
|
### 3. **Armazenamento Local Inteligente**
|
||
|
|
- Dados organizados por tipo (entregas, fotos, assinaturas, status)
|
||
|
|
- Fila de sincronização para operações pendentes
|
||
|
|
- Sistema de retry com limite de tentativas
|
||
|
|
|
||
|
|
### 4. **Sincronização Automática**
|
||
|
|
- Detecta quando a conexão melhora
|
||
|
|
- Sincroniza dados pendentes automaticamente
|
||
|
|
- Limpa dados locais após sincronização bem-sucedida
|
||
|
|
|
||
|
|
## 🏗️ **Arquitetura do Sistema**
|
||
|
|
|
||
|
|
### **Componentes Principais**
|
||
|
|
|
||
|
|
#### 1. **useMobileSignal Hook**
|
||
|
|
```typescript
|
||
|
|
// Monitora conexão e estima força do sinal
|
||
|
|
const { signalInfo, checkConnection } = useMobileSignal();
|
||
|
|
|
||
|
|
// signalInfo contém:
|
||
|
|
{
|
||
|
|
isConnected: boolean;
|
||
|
|
connectionType: 'wifi' | 'cellular' | 'none' | 'unknown';
|
||
|
|
isMobile: boolean;
|
||
|
|
signalStrength: number; // 0-100%
|
||
|
|
shouldUseOffline: boolean;
|
||
|
|
carrier?: string;
|
||
|
|
details?: {
|
||
|
|
cellularGeneration?: '2g' | '3g' | '4g' | '5g';
|
||
|
|
isConnectionExpensive?: boolean;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. **MobileSignalIndicator Component**
|
||
|
|
```typescript
|
||
|
|
// Interface visual do status de conexão
|
||
|
|
<MobileSignalIndicator
|
||
|
|
showDetails={true} // Mostrar detalhes completos
|
||
|
|
compact={false} // Modo compacto ou expandido
|
||
|
|
onPress={() => {}} // Ação ao tocar
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. **OfflineStorage Service**
|
||
|
|
```typescript
|
||
|
|
// Gerencia armazenamento local
|
||
|
|
const offlineStorage = new OfflineStorageService();
|
||
|
|
|
||
|
|
// Salvar dados offline
|
||
|
|
await offlineStorage.saveOfflineData('delivery', deliveryData);
|
||
|
|
|
||
|
|
// Adicionar à fila de sincronização
|
||
|
|
await offlineStorage.addToSyncQueue({
|
||
|
|
action: 'create',
|
||
|
|
endpoint: '/v1/delivery/create',
|
||
|
|
data: deliveryData
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4. **OfflineContext**
|
||
|
|
```typescript
|
||
|
|
// Contexto global para estado offline
|
||
|
|
const {
|
||
|
|
isOfflineMode,
|
||
|
|
offlineStats,
|
||
|
|
saveOfflineData,
|
||
|
|
syncOfflineData
|
||
|
|
} = useOffline();
|
||
|
|
```
|
||
|
|
|
||
|
|
## 📱 **Interface Visual**
|
||
|
|
|
||
|
|
### **Indicador de Sinal Mobile**
|
||
|
|
|
||
|
|
#### **Modo Expandido (showDetails={true})**
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────┐
|
||
|
|
│ 📶 WiFi 80% 🔄 │
|
||
|
|
│ ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
|
||
|
|
│ ● Modo Online │
|
||
|
|
│ Rede: 5G │
|
||
|
|
│ Conexão cara │
|
||
|
|
└─────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
#### **Modo Compacto (compact={true})**
|
||
|
|
```
|
||
|
|
📶 ████
|
||
|
|
```
|
||
|
|
|
||
|
|
### **Cores e Estados**
|
||
|
|
|
||
|
|
| Estado | Cor | Descrição |
|
||
|
|
|--------|-----|-----------|
|
||
|
|
| **Excelente** (70-100%) | 🟢 Verde | Conexão estável, modo online |
|
||
|
|
| **Bom** (40-69%) | 🟡 Amarelo | Conexão aceitável, modo online |
|
||
|
|
| **Fraco** (0-39%) | 🔴 Vermelho | Modo offline ativado |
|
||
|
|
|
||
|
|
## 🔄 **Fluxo de Funcionamento**
|
||
|
|
|
||
|
|
### **1. Monitoramento Contínuo**
|
||
|
|
```
|
||
|
|
App Inicia → useMobileSignal → NetInfo Listener → Atualiza signalInfo
|
||
|
|
```
|
||
|
|
|
||
|
|
### **2. Decisão de Modo**
|
||
|
|
```
|
||
|
|
signalInfo.signalStrength < 30% → shouldUseOffline = true → Modo Offline
|
||
|
|
signalInfo.signalStrength >= 30% → shouldUseOffline = false → Modo Online
|
||
|
|
```
|
||
|
|
|
||
|
|
### **3. Armazenamento Offline**
|
||
|
|
```
|
||
|
|
Dados → Validação → Salva Localmente → Adiciona à Fila de Sync
|
||
|
|
```
|
||
|
|
|
||
|
|
### **4. Sincronização**
|
||
|
|
```
|
||
|
|
Conexão Melhora → Detecta Mudança → Sincroniza Dados → Limpa Local
|
||
|
|
```
|
||
|
|
|
||
|
|
## 💾 **Tipos de Dados Armazenados**
|
||
|
|
|
||
|
|
### **1. Entregas (delivery)**
|
||
|
|
```typescript
|
||
|
|
{
|
||
|
|
outId: number;
|
||
|
|
transactionId: number;
|
||
|
|
deliveryDate: string;
|
||
|
|
receiverDoc: string;
|
||
|
|
receiverName: string;
|
||
|
|
lat: number | null;
|
||
|
|
lng: number | null;
|
||
|
|
broken: boolean;
|
||
|
|
devolution: boolean;
|
||
|
|
reasonDevolution: string;
|
||
|
|
deliveryImages: Array<{ type: string; url: string }>;
|
||
|
|
userId: number;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **2. Fotos (photo)**
|
||
|
|
```typescript
|
||
|
|
{
|
||
|
|
file: string; // URI local da foto
|
||
|
|
transactionId: number;
|
||
|
|
timestamp: number;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **3. Assinaturas (signature)**
|
||
|
|
```typescript
|
||
|
|
{
|
||
|
|
file: string; // URI local da assinatura
|
||
|
|
transactionId: number;
|
||
|
|
timestamp: number;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **4. Status (status)**
|
||
|
|
```typescript
|
||
|
|
{
|
||
|
|
outId: number;
|
||
|
|
customerId: number;
|
||
|
|
status: 'pending' | 'in_progress' | 'delivered' | 'failed';
|
||
|
|
lat: number | null;
|
||
|
|
lng: number | null;
|
||
|
|
notes?: string;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🚀 **Como Usar**
|
||
|
|
|
||
|
|
### **1. Implementação Básica**
|
||
|
|
```typescript
|
||
|
|
import { useMobileSignal } from '../hooks/useMobileSignal';
|
||
|
|
import { useOffline } from '../contexts/OfflineContext';
|
||
|
|
|
||
|
|
const MyComponent = () => {
|
||
|
|
const { signalInfo } = useMobileSignal();
|
||
|
|
const { isOfflineMode, saveOfflineData } = useOffline();
|
||
|
|
|
||
|
|
const handleSaveData = async (data: any) => {
|
||
|
|
if (isOfflineMode) {
|
||
|
|
// Salvar offline
|
||
|
|
await saveOfflineData('delivery', data);
|
||
|
|
} else {
|
||
|
|
// Enviar para API
|
||
|
|
await api.createDelivery(data);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<View>
|
||
|
|
<MobileSignalIndicator showDetails={true} />
|
||
|
|
{/* Resto da interface */}
|
||
|
|
</View>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### **2. Integração com CompleteDeliveryScreen**
|
||
|
|
```typescript
|
||
|
|
const handleSubmit = async () => {
|
||
|
|
try {
|
||
|
|
if (isOfflineMode) {
|
||
|
|
// Salvar dados offline
|
||
|
|
const offlineId = await saveOfflineData('delivery', deliveryData);
|
||
|
|
await addToSyncQueue({
|
||
|
|
action: 'create',
|
||
|
|
endpoint: '/v1/delivery/create',
|
||
|
|
data: deliveryData
|
||
|
|
});
|
||
|
|
|
||
|
|
Alert.alert(
|
||
|
|
'Dados Salvos Offline',
|
||
|
|
'Os dados foram salvos localmente e serão sincronizados quando a conexão melhorar.'
|
||
|
|
);
|
||
|
|
} else {
|
||
|
|
// Enviar para API normalmente
|
||
|
|
await api.createMultipleDeliveries([deliveryData]);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Erro ao salvar dados:', error);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### **3. Verificação de Status**
|
||
|
|
```typescript
|
||
|
|
const checkOfflineStatus = async () => {
|
||
|
|
const stats = await offlineStorage.getOfflineStats();
|
||
|
|
|
||
|
|
if (stats.totalSize > 0) {
|
||
|
|
console.log('Dados pendentes para sincronização:', stats);
|
||
|
|
|
||
|
|
// Mostrar indicador visual
|
||
|
|
setHasOfflineData(true);
|
||
|
|
setOfflineDataCount(stats.totalSize);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
## 📊 **Estatísticas e Monitoramento**
|
||
|
|
|
||
|
|
### **Estatísticas Offline**
|
||
|
|
```typescript
|
||
|
|
const stats = await offlineStorage.getOfflineStats();
|
||
|
|
|
||
|
|
// Retorna:
|
||
|
|
{
|
||
|
|
deliveries: 5, // Entregas pendentes
|
||
|
|
photos: 12, // Fotos pendentes
|
||
|
|
signatures: 3, // Assinaturas pendentes
|
||
|
|
status: 2, // Status pendentes
|
||
|
|
syncQueue: 8, // Itens na fila de sync
|
||
|
|
totalSize: 30 // Total de itens pendentes
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **Logs de Debug**
|
||
|
|
```
|
||
|
|
=== DEBUG: INFORMAÇÕES DE SINAL MOBILE ===
|
||
|
|
Tipo de conexão: cellular
|
||
|
|
Conectado: true
|
||
|
|
Força do sinal estimada: 25%
|
||
|
|
Deve usar offline: true
|
||
|
|
Detalhes: { cellularGeneration: '4g', isConnectionExpensive: false }
|
||
|
|
|
||
|
|
=== DEBUG: MODO OFFLINE ATUALIZADO ===
|
||
|
|
Sinal: 25%
|
||
|
|
Tipo de conexão: cellular
|
||
|
|
Deve usar offline: true
|
||
|
|
Modo offline ativo: true
|
||
|
|
|
||
|
|
=== DEBUG: DADOS SALVOS OFFLINE ===
|
||
|
|
Tipo: delivery
|
||
|
|
ID: delivery_1703123456789_abc123
|
||
|
|
Timestamp: 2023-12-21T10:30:56.789Z
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🔧 **Configuração e Personalização**
|
||
|
|
|
||
|
|
### **1. Threshold de Sinal**
|
||
|
|
```typescript
|
||
|
|
// Em useMobileSignal.ts
|
||
|
|
const shouldUseOfflineMode = (strength: number, connectionType: string): boolean => {
|
||
|
|
// Personalizar threshold (padrão: 30%)
|
||
|
|
const OFFLINE_THRESHOLD = 30;
|
||
|
|
|
||
|
|
return strength < OFFLINE_THRESHOLD || connectionType === 'none';
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### **2. Estimativa de Força de Sinal**
|
||
|
|
```typescript
|
||
|
|
// Personalizar estimativas por tipo de rede
|
||
|
|
const estimateSignalStrength = (netInfo: NetInfoState): number => {
|
||
|
|
if (netInfo.type === 'cellular' && netInfo.details?.cellularGeneration) {
|
||
|
|
switch (netInfo.details.cellularGeneration) {
|
||
|
|
case '5g': return 95; // Ajustar valores
|
||
|
|
case '4g': return 80; // Ajustar valores
|
||
|
|
case '3g': return 60; // Ajustar valores
|
||
|
|
case '2g': return 30; // Ajustar valores
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 60;
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### **3. Tempo de Retry**
|
||
|
|
```typescript
|
||
|
|
// Em OfflineStorageService
|
||
|
|
const MAX_RETRIES = 5; // Aumentar tentativas
|
||
|
|
const RETRY_DELAY = 5000; // Delay entre tentativas (ms)
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🧪 **Testes e Validação**
|
||
|
|
|
||
|
|
### **1. Teste de Conexão Fraca**
|
||
|
|
```bash
|
||
|
|
# Simular sinal fraco
|
||
|
|
# Verificar ativação do modo offline
|
||
|
|
# Confirmar salvamento local
|
||
|
|
# Verificar notificação ao usuário
|
||
|
|
```
|
||
|
|
|
||
|
|
### **2. Teste de Sincronização**
|
||
|
|
```bash
|
||
|
|
# Salvar dados offline
|
||
|
|
# Melhorar conexão
|
||
|
|
# Verificar sincronização automática
|
||
|
|
# Confirmar limpeza dos dados locais
|
||
|
|
```
|
||
|
|
|
||
|
|
### **3. Teste de Recuperação**
|
||
|
|
```bash
|
||
|
|
# Simular falha na sincronização
|
||
|
|
# Verificar sistema de retry
|
||
|
|
# Confirmar limite de tentativas
|
||
|
|
# Verificar tratamento de erro
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🚨 **Tratamento de Erros**
|
||
|
|
|
||
|
|
### **1. Erro de Armazenamento**
|
||
|
|
```typescript
|
||
|
|
try {
|
||
|
|
await saveOfflineData('delivery', data);
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Erro ao salvar offline:', error);
|
||
|
|
|
||
|
|
// Fallback: tentar enviar para API mesmo com sinal fraco
|
||
|
|
try {
|
||
|
|
await api.createDelivery(data);
|
||
|
|
} catch (apiError) {
|
||
|
|
Alert.alert('Erro', 'Não foi possível salvar os dados. Tente novamente.');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **2. Erro de Sincronização**
|
||
|
|
```typescript
|
||
|
|
try {
|
||
|
|
await syncOfflineData();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Erro na sincronização:', error);
|
||
|
|
|
||
|
|
// Manter dados offline para próxima tentativa
|
||
|
|
Alert.alert(
|
||
|
|
'Erro na Sincronização',
|
||
|
|
'Alguns dados não puderam ser sincronizados. Eles permanecerão salvos localmente.'
|
||
|
|
);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 📈 **Métricas e Performance**
|
||
|
|
|
||
|
|
### **Indicadores de Performance**
|
||
|
|
- **Tempo de resposta**: < 100ms para detecção de mudança de sinal
|
||
|
|
- **Uso de memória**: < 50MB para dados offline
|
||
|
|
- **Tempo de sincronização**: < 5s para 100 itens
|
||
|
|
- **Taxa de sucesso**: > 95% para operações offline
|
||
|
|
|
||
|
|
### **Monitoramento**
|
||
|
|
- Logs detalhados para debug
|
||
|
|
- Estatísticas de uso offline
|
||
|
|
- Métricas de sincronização
|
||
|
|
- Alertas de erro em tempo real
|
||
|
|
|
||
|
|
## 🔮 **Melhorias Futuras**
|
||
|
|
|
||
|
|
### **1. Cache Inteligente**
|
||
|
|
- Compressão de dados offline
|
||
|
|
- Limpeza automática de dados antigos
|
||
|
|
- Priorização de dados críticos
|
||
|
|
|
||
|
|
### **2. Sincronização Incremental**
|
||
|
|
- Sync apenas de dados modificados
|
||
|
|
- Resolução de conflitos automática
|
||
|
|
- Merge inteligente de dados
|
||
|
|
|
||
|
|
### **3. Análise de Padrões**
|
||
|
|
- Machine learning para prever qualidade de sinal
|
||
|
|
- Otimização automática de threshold
|
||
|
|
- Recomendações de sincronização
|
||
|
|
|
||
|
|
### **4. Backup em Nuvem**
|
||
|
|
- Backup automático de dados críticos
|
||
|
|
- Sincronização cross-device
|
||
|
|
- Recuperação de dados perdidos
|
||
|
|
|
||
|
|
## 📚 **Referências Técnicas**
|
||
|
|
|
||
|
|
### **Bibliotecas Utilizadas**
|
||
|
|
- **@react-native-community/netinfo**: Monitoramento de rede
|
||
|
|
- **@react-native-async-storage/async-storage**: Armazenamento local
|
||
|
|
- **React Context API**: Gerenciamento de estado global
|
||
|
|
|
||
|
|
### **APIs Nativas**
|
||
|
|
- **NetInfo**: Informações de conectividade
|
||
|
|
- **AsyncStorage**: Armazenamento persistente
|
||
|
|
- **FileSystem**: Gerenciamento de arquivos
|
||
|
|
|
||
|
|
### **Padrões de Design**
|
||
|
|
- **Observer Pattern**: Monitoramento de mudanças de rede
|
||
|
|
- **Strategy Pattern**: Alternância entre modos online/offline
|
||
|
|
- **Queue Pattern**: Fila de sincronização
|
||
|
|
- **Retry Pattern**: Tentativas de sincronização
|
||
|
|
|
||
|
|
## ✅ **Conclusão**
|
||
|
|
|
||
|
|
O sistema de validação de sinal mobile e armazenamento offline oferece:
|
||
|
|
|
||
|
|
1. **Confiabilidade**: Dados nunca são perdidos, mesmo com conexão instável
|
||
|
|
2. **Transparência**: Usuário sempre sabe o status da conexão
|
||
|
|
3. **Automação**: Mudança de modo transparente e automática
|
||
|
|
4. **Performance**: Operações offline são instantâneas
|
||
|
|
5. **Escalabilidade**: Sistema preparado para crescimento futuro
|
||
|
|
|
||
|
|
Este sistema garante que o aplicativo funcione perfeitamente em qualquer condição de rede, proporcionando uma experiência consistente para o usuário final.
|