Implement data sync and cleanup

This commit is contained in:
2026-01-09 13:48:38 -06:00
parent dc6bcad83f
commit d28898cb81
12 changed files with 596 additions and 50 deletions

View File

@@ -0,0 +1,135 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../models/cycle_entry.dart';
class SyncService {
static const String _baseUrl = 'http://localhost:8090';
// Push data to backend
Future<void> pushSyncData(String userId, List<CycleEntry> entries) async {
try {
final url = Uri.parse('$_baseUrl/sync/push');
final payload = {
'userId': userId,
'entries': entries.map((e) => _cycleEntryToJson(e)).toList(),
};
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
body: jsonEncode(payload),
);
if (response.statusCode == 200) {
debugPrint('Sync Push Successful');
} else {
debugPrint('Sync Push Failed: ${response.body}');
}
} catch (e) {
debugPrint('Sync Push Error: $e');
}
}
// Pull data from backend
Future<List<CycleEntry>> pullSyncData(String userId) async {
try {
final url = Uri.parse('$_baseUrl/sync/pull?userId=$userId');
final response = await http.get(url);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final List entriesJson = data['entries'] ?? [];
return entriesJson.map((json) => _jsonToCycleEntry(json)).toList();
}
} catch (e) {
debugPrint('Sync Pull Error: $e');
}
return [];
}
// Helpers (Adapters)
Map<String, dynamic> _cycleEntryToJson(CycleEntry entry) {
// Convert boolean symptoms to list of strings
final symptomsList = <String>[];
if (entry.hasHeadache) symptomsList.add('headache');
if (entry.hasBloating) symptomsList.add('bloating');
if (entry.hasBreastTenderness) symptomsList.add('breastTenderness');
if (entry.hasFatigue) symptomsList.add('fatigue');
if (entry.hasAcne) symptomsList.add('acne');
if (entry.hasLowerBackPain) symptomsList.add('lowerBackPain');
if (entry.hasConstipation) symptomsList.add('constipation');
if (entry.hasDiarrhea) symptomsList.add('diarrhea');
if (entry.hasInsomnia) symptomsList.add('insomnia');
return {
'id': entry.id,
'date': entry.date.toIso8601String(),
'flowIntensity': entry.flowIntensity?.name,
'isPeriodDay': entry.isPeriodDay,
'symptoms': jsonEncode(symptomsList),
'moods': jsonEncode(entry.mood != null ? [entry.mood!.name] : []),
'notes': entry.notes,
'createdAt': entry.createdAt.toIso8601String(),
'updatedAt': entry.updatedAt.toIso8601String(),
};
}
CycleEntry _jsonToCycleEntry(Map<String, dynamic> json) {
// FlowIntensity enum parsing
FlowIntensity? flow;
if (json['flowIntensity'] != null) {
flow = FlowIntensity.values.firstWhere(
(e) => e.name == json['flowIntensity'],
orElse: () => FlowIntensity.medium,
);
}
// Mood parsing
MoodLevel? mood;
final moodsList = _parseList(json['moods']);
if (moodsList.isNotEmpty) {
try {
mood = MoodLevel.values.firstWhere((e) => e.name == moodsList.first);
} catch (_) {}
}
final symptoms = _parseList(json['symptoms']);
return CycleEntry(
id: json['id'],
date: DateTime.parse(json['date']),
flowIntensity: flow,
isPeriodDay: json['isPeriodDay'] == true,
mood: mood,
hasHeadache: symptoms.contains('headache'),
hasBloating: symptoms.contains('bloating'),
hasBreastTenderness: symptoms.contains('breastTenderness'),
hasFatigue: symptoms.contains('fatigue'),
hasAcne: symptoms.contains('acne'),
hasLowerBackPain: symptoms.contains('lowerBackPain'),
hasConstipation: symptoms.contains('constipation'),
hasDiarrhea: symptoms.contains('diarrhea'),
hasInsomnia: symptoms.contains('insomnia'),
notes: json['notes'],
createdAt: json['createdAt'] != null
? DateTime.parse(json['createdAt'])
: DateTime.now(),
updatedAt: json['updatedAt'] != null
? DateTime.parse(json['updatedAt'])
: DateTime.now(),
);
}
List<String> _parseList(dynamic jsonVal) {
if (jsonVal == null) return [];
if (jsonVal is String) {
try {
return List<String>.from(jsonDecode(jsonVal));
} catch (_) {
return [];
}
}
return List<String>.from(jsonVal);
}
}