128 lines
3.7 KiB
Dart
128 lines
3.7 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import '../config/api_config.dart';
|
|
import '../models/incoming_question.dart';
|
|
import 'auth_service.dart';
|
|
|
|
/// HTTP client for question queue, answers, and deferrals.
|
|
class QuestionsApiService {
|
|
QuestionsApiService({http.Client? client}) : _client = client ?? http.Client();
|
|
|
|
final http.Client _client;
|
|
|
|
/// Ensures a starter question exists for the signed-in user (login only).
|
|
Future<IncomingQuestion?> bootstrapOnLogin() async {
|
|
final String? token = await AuthService.instance.getIdToken();
|
|
if (token == null) {
|
|
return null;
|
|
}
|
|
|
|
final http.Response response = await _client.post(
|
|
Uri.parse('$apiBaseUrl/v1/me/questions/bootstrap'),
|
|
headers: _authHeaders(token),
|
|
);
|
|
if (response.statusCode != 200) {
|
|
debugPrint(
|
|
'bootstrapOnLogin failed: ${response.statusCode} ${response.body}',
|
|
);
|
|
return null;
|
|
}
|
|
|
|
final Map<String, dynamic> body =
|
|
jsonDecode(response.body) as Map<String, dynamic>;
|
|
final Map<String, dynamic>? questionJson =
|
|
body['question'] as Map<String, dynamic>?;
|
|
if (questionJson == null) {
|
|
return null;
|
|
}
|
|
return IncomingQuestion.fromJson(questionJson);
|
|
}
|
|
|
|
Future<List<IncomingQuestion>> fetchUnanswered() async {
|
|
final String? token = await AuthService.instance.getIdToken();
|
|
if (token == null) {
|
|
return <IncomingQuestion>[];
|
|
}
|
|
|
|
final http.Response response = await _client.get(
|
|
Uri.parse('$apiBaseUrl/v1/me/questions'),
|
|
headers: _authHeaders(token),
|
|
);
|
|
if (response.statusCode != 200) {
|
|
debugPrint(
|
|
'fetchUnanswered failed: ${response.statusCode} ${response.body}',
|
|
);
|
|
return <IncomingQuestion>[];
|
|
}
|
|
|
|
final Map<String, dynamic> body =
|
|
jsonDecode(response.body) as Map<String, dynamic>;
|
|
final List<dynamic> raw = body['questions'] as List<dynamic>? ?? <dynamic>[];
|
|
return raw
|
|
.map(
|
|
(dynamic item) =>
|
|
IncomingQuestion.fromJson(item as Map<String, dynamic>),
|
|
)
|
|
.toList();
|
|
}
|
|
|
|
Future<int?> submitAnswer({
|
|
required String questionId,
|
|
num answer = 0,
|
|
}) async {
|
|
final String? token = await AuthService.instance.getIdToken();
|
|
if (token == null) {
|
|
return null;
|
|
}
|
|
|
|
final http.Response response = await _client.post(
|
|
Uri.parse('$apiBaseUrl/v1/me/questions/$questionId/answer'),
|
|
headers: _authHeaders(token),
|
|
body: jsonEncode(<String, num>{'answer': answer}),
|
|
);
|
|
if (response.statusCode != 200) {
|
|
debugPrint(
|
|
'submitAnswer failed: ${response.statusCode} ${response.body}',
|
|
);
|
|
return null;
|
|
}
|
|
|
|
final Map<String, dynamic> body =
|
|
jsonDecode(response.body) as Map<String, dynamic>;
|
|
return (body['unansweredCount'] as num?)?.toInt();
|
|
}
|
|
|
|
Future<int?> deferQuestion({required String questionId}) async {
|
|
final String? token = await AuthService.instance.getIdToken();
|
|
if (token == null) {
|
|
return null;
|
|
}
|
|
|
|
final http.Response response = await _client.post(
|
|
Uri.parse('$apiBaseUrl/v1/me/questions/$questionId/defer'),
|
|
headers: _authHeaders(token),
|
|
);
|
|
if (response.statusCode != 200) {
|
|
debugPrint(
|
|
'deferQuestion failed: ${response.statusCode} ${response.body}',
|
|
);
|
|
return null;
|
|
}
|
|
|
|
final Map<String, dynamic> body =
|
|
jsonDecode(response.body) as Map<String, dynamic>;
|
|
return (body['unansweredCount'] as num?)?.toInt();
|
|
}
|
|
|
|
Map<String, String> _authHeaders(String token) {
|
|
return <String, String>{
|
|
'Authorization': 'Bearer $token',
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
};
|
|
}
|
|
}
|