@@ -223,94 +102,53 @@ export default function Contribuir() {
Iniciar Criação de Rota
-
- {/* Indicador de scan em andamento (apenas APK) */}
- {wifiScanner.isNative && wifiScanner.isScanning && !showWifiCard && selectedLineId && !wifiValidated && (
-
-
-
-
Escaneando redes Wi-Fi...
-
- Aguarde enquanto procuramos o Wi-Fi do ônibus
-
-
-
- )}
-
- {/* Indicador de Wi-Fi Validado (apenas APK) */}
- {wifiScanner.isNative && wifiValidated && selectedWifi && (
-
-
-
-
Wi-Fi selecionado!
-
- {selectedWifi.ssid} - Pronto para criar rota
-
-
-
- )}
-
-
-
- {/* Botão para escanear WiFi manualmente (apenas APK) */}
- {wifiScanner.isNative && selectedLineId && !wifiValidated && (
-
- )}
-
- {/* Botão para pular WiFi (apenas APK) */}
- {wifiScanner.isNative && selectedLineId && !wifiValidated && (
-
- )}
-
-
+
+
+
+
+
+ {!wifiScanner.isNative && selectedLineId && (
+
+ 📱 Contribuição disponível apenas no aplicativo Android
+
+ )}
- {wifiScanner.isNative && !wifiValidated && selectedLineId && (
-
- ⚠️ WiFi não validado - rota sem validação oficial
-
- )}
-
- {!wifiScanner.isNative && selectedLineId && (
-
- 📱 Contribuição disponível apenas no aplicativo Android
-
- )}
+ {/* Informações sobre validação */}
+
+
+
+
+
Como funciona a validação:
+
+ - Sua rota será gravada e armazenada
+ - O sistema compara com outras gravações
+ - Quando 3+ rotas forem 90% similares, vira rota oficial
+ - Paradas também passam por validação colaborativa
+
+
+
+
{geolocation.error && (
@@ -320,169 +158,35 @@ export default function Contribuir() {
)}
- {/* Card de Seleção de WiFi (apenas APK) */}
- {wifiScanner.isNative && showWifiCard && (
-
-
-
-
Escolha o Wi-Fi do Ônibus
-
-
- {wifiScanner.isScanning ? (
-
-
-
Escaneando redes Wi-Fi...
-
- ) : wifiScanner.networks.length > 0 ? (
- <>
-
- Selecione a rede Wi-Fi do ônibus para ajudar a identificar esta linha:
-
-
-
- {wifiScanner.networks.map((network, index) => (
-
- ))}
-
- >
- ) : (
-
-
-
Nenhuma rede Wi-Fi detectada
-
-
- )}
-
- {wifiScanner.error && (
-
- )}
-
- {!selectedLineId && (
-
- Selecione uma linha primeiro
-
- )}
-
-
+ {/* Card informativo */}
+
+
+
+
Sua contribuição importa!
- )}
-
- {/* Como Funciona */}
-
-
Como Funciona?
-
-
-
-
- 1️⃣
-
-
-
Entre no Ônibus
-
- {wifiScanner.isNative
- ? 'Escolha o Wi-Fi do ônibus quando solicitado'
- : 'Selecione a linha do ônibus que você está'
- }
-
-
-
-
-
-
- 2️⃣
-
-
-
Inicie a Criação da Rota
-
- Clique em "Iniciar Criação de Rota" e mantenha o app aberto durante a viagem
-
-
-
-
-
-
- 3️⃣
-
-
-
Marque os Pontos de Ônibus
-
- Quando o ônibus parar em um ponto, clique em "Marcar Ponto de Ônibus Aqui"
-
-
-
-
-
-
- 4️⃣
-
-
-
Finalize ao Descer
-
- Quando chegar ao seu destino, clique em "Finalizar e Salvar Rota"
-
-
-
-
-
-
-
- 💡 Dica: Seus dados são anônimos e ajudam a criar um mapa preciso
- das rotas de ônibus para toda a comunidade!
-
+
+ Ao gravar rotas, você ajuda a melhorar o aplicativo para todos os usuários.
+
+
+
+ Mesmo com o app fechado, o GPS continua coletando dados
-
- {/* Link para Ranking */}
-
-
-
-
-
Ver Ranking
-
Confira os top contribuidores
-
-
-
→
-
- {/* Modal para baixar app */}
+ {/* Modal de Aviso */}
+
setShowWarningModal(false)}
+ onConfirm={handleConfirmStart}
+ title="Importante: Validação de Rotas"
+ description="As rotas gravadas por você serão verificadas antes de fazer parte da rota oficial. O sistema compara múltiplas gravações para garantir precisão."
+ warningText="⚠️ Feche o aplicativo assim que descer do ônibus para finalizar a gravação."
+ confirmText="Entendi, começar gravação"
+ cancelText="Cancelar"
+ />
+
+ {/* Modal Download App */}
setShowDownloadModal(false)}
diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx
index 1a88eef..abef766 100644
--- a/src/pages/Home.tsx
+++ b/src/pages/Home.tsx
@@ -112,18 +112,22 @@ export default function Home() {
useEffect(() => {
if (isRecording && geolocation.latitude && geolocation.longitude && recordingSessionId && recordingLineId) {
const sendTrackingData = async () => {
- const result = await trackingService.submitTrackingData({
- lineId: recordingLineId,
- latitude: geolocation.latitude!,
- longitude: geolocation.longitude!,
- accuracy: geolocation.accuracy,
- speed: geolocation.speed,
- heading: geolocation.heading,
- sessionId: recordingSessionId,
- });
-
- if (result.success) {
+ try {
+ await fetch('/api/trajectories/point', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ sessionId: recordingSessionId,
+ lat: geolocation.latitude!,
+ lng: geolocation.longitude!,
+ speed: geolocation.speed,
+ accuracy: geolocation.accuracy,
+ heading: geolocation.heading,
+ }),
+ });
setPointsCollected(prev => prev + 1);
+ } catch (error) {
+ console.error('Erro ao enviar ponto:', error);
}
};
@@ -166,24 +170,36 @@ export default function Home() {
geolocation.stopTracking();
// Finalizar sessão no backend com dados de validação
- const result = await trackingService.stopSession(recordingSessionId, {
- validationMeta: {
- clientConfidence: validationResult?.confidence ?? 0.5,
- estimatedStops: validationResult?.estimatedStops ?? 0,
- reasons: validationResult?.reasons ?? [],
- avgSpeed: validationResult?.avgSpeed ?? 0,
- maxSpeed: validationResult?.maxSpeed ?? 0,
- distance: validationResult?.distance ?? 0,
- duration: validationResult?.duration ?? 0
+ try {
+ const response = await fetch('/api/trajectories/stop', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ sessionId: recordingSessionId,
+ metadata: {
+ clientConfidence: validationResult?.confidence ?? 0.5,
+ estimatedStops: validationResult?.estimatedStops ?? 0,
+ reasons: validationResult?.reasons ?? [],
+ avgSpeed: validationResult?.avgSpeed ?? 0,
+ maxSpeed: validationResult?.maxSpeed ?? 0,
+ distance: validationResult?.distance ?? 0,
+ duration: validationResult?.duration ?? 0
+ }
+ }),
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ const confidenceEmoji = validationResult && validationResult.confidence >= 0.7 ? '✅' : '⚠️';
+ toast.success(
+ `${confidenceEmoji} Rota salva! ${result.data?.pointsCount} pontos coletados. Aguardando validação colaborativa! 🎉`,
+ { duration: 5000 }
+ );
}
- });
-
- if (result.success) {
- const confidenceEmoji = validationResult && validationResult.confidence >= 0.7 ? '✅' : '⚠️';
- toast.success(
- `${confidenceEmoji} Rota salva! ${result.data?.pointsCollected} pontos coletados. Obrigado! 🎉`,
- { duration: 5000 }
- );
+ } catch (error) {
+ console.error('Erro ao finalizar gravação:', error);
+ toast.error('Erro ao finalizar gravação');
}
// Redirecionar para página Contribuir
@@ -192,20 +208,19 @@ export default function Home() {
// Função para marcar parada
const handleMarkStop = async (stopName: string) => {
- if (!isRecording || !geolocation.latitude || !geolocation.longitude || !recordingLineId) {
+ if (!isRecording || !geolocation.latitude || !geolocation.longitude || !recordingLineId || !recordingSessionId) {
toast.error('Erro ao marcar parada');
return;
}
try {
- await fetch('/api/stops/mark', {
+ await fetch('/api/trajectories/stop-mark', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
- lineId: recordingLineId,
+ sessionId: recordingSessionId,
lat: geolocation.latitude,
lng: geolocation.longitude,
- sessionId: recordingSessionId,
name: stopName
})
});
@@ -641,24 +656,29 @@ export default function Home() {
posicoes={posicoesFiltradas}
activeUsers={activeUsers}
isMobile={false}
+ recordingPath={recordingPath}
+ recordingLineColor={recordingLineColor || '#EF4444'}
+ showRecordingPath={isRecording}
/>
+ {/* Botão Criar Parada - largura total na parte inferior (só visível em modo gravação) */}
+ {isRecording && (
+
+ )}
+
{/* Botões flutuantes quando gravando */}
{isRecording && (
<>
- {/* Botão Marcar Parada */}
-
-
{/* Botão Finalizar */}