Files
focusflow_api/lib/src/modules/streaks/streak_routes.dart
Oracle Public Cloud User 8958455a12 Initial scaffold: FocusFlow ADHD Task Manager backend
Dart Shelf API with modules: auth (JWT + PBKDF2), tasks (CRUD + dopamine scorer),
streaks (forgiveness + freeze), rewards (variable reward engine), time perception,
sync (offline-first push/pull), rooms (body doubling placeholder).
Includes DB migration (001_initial_schema.sql) and Docker Compose.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:53:40 +00:00

99 lines
3.2 KiB
Dart

import 'dart:convert';
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import '../../middleware/error_handler.dart';
import '../../shared/api_response.dart';
import 'streak_service.dart';
/// Streak module route definitions.
class StreakRoutes {
final StreakService _service;
StreakRoutes(this._service);
Router get router {
final router = Router();
router.get('/', _listStreaks);
router.post('/', _createStreak);
router.get('/<id>', _getStreak);
router.post('/<id>/complete', _completeToday);
router.post('/<id>/forgive', _forgive);
router.post('/<id>/freeze', _freeze);
router.get('/<id>/history', _getHistory);
return router;
}
// ── Handlers ────────────────────────────────────────────────────────
Future<Response> _listStreaks(Request request) async {
final userId = request.context['userId'] as String;
final streaks = await _service.listStreaks(userId);
return ApiResponse.success(streaks);
}
Future<Response> _createStreak(Request request) async {
final userId = request.context['userId'] as String;
final body =
jsonDecode(await request.readAsString()) as Map<String, dynamic>;
if (body['name'] == null || (body['name'] as String).isEmpty) {
throw ApiException.badRequest('Name is required');
}
final streak = await _service.createStreak(userId, body);
return ApiResponse.created(streak);
}
Future<Response> _getStreak(Request request, String id) async {
final userId = request.context['userId'] as String;
final streak = await _service.getStreak(id, userId);
return ApiResponse.success(streak);
}
Future<Response> _completeToday(Request request, String id) async {
final userId = request.context['userId'] as String;
final result = await _service.completeToday(id, userId);
return ApiResponse.success(result, message: result['message'] as String);
}
Future<Response> _forgive(Request request, String id) async {
final userId = request.context['userId'] as String;
String? note;
try {
final body =
jsonDecode(await request.readAsString()) as Map<String, dynamic>;
note = body['note'] as String?;
} catch (_) {
// body optional
}
final result = await _service.forgive(id, userId, note: note);
return ApiResponse.success(result, message: result['message'] as String);
}
Future<Response> _freeze(Request request, String id) async {
final userId = request.context['userId'] as String;
final body =
jsonDecode(await request.readAsString()) as Map<String, dynamic>;
final days = body['days'] as int?;
if (days == null) {
throw ApiException.badRequest('Field "days" is required');
}
final result = await _service.freeze(id, userId, days: days);
return ApiResponse.success(result, message: result['message'] as String);
}
Future<Response> _getHistory(Request request, String id) async {
final userId = request.context['userId'] as String;
final history = await _service.getHistory(id, userId);
return ApiResponse.success(history);
}
}