Files
mcbeno-app/lib/services/auth_service.dart

110 lines
3.5 KiB
Dart

import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:http/http.dart' as http;
class AuthService extends ChangeNotifier {
final _storage = const FlutterSecureStorage();
String? token;
Map<String, dynamic>? profile;
final _base = 'https://menuapi.devbeni.lol/api';
AuthService() {
_loadToken();
}
/// Convenience wrapper that returns the Data array for schedule or empty list
Future<List<dynamic>> fetchSchedule(int year, int month) async {
final resp = await _httpGet('/@me/schedule?year=$year&month=$month');
if (resp == null) return [];
try {
if (resp['data'] != null && resp['data']['Data'] is List) {
return List<dynamic>.from(resp['data']['Data']);
}
} catch (e) {
return [];
}
return [];
}
Future<void> loadProfile() async {
if (token == null) return;
try {
final res = await http.get(
Uri.parse('https://menuapi.devbeni.lol/api/me'),
headers: {'Authorization': 'Bearer $token'},
);
if (res.statusCode == 200) {
final body = jsonDecode(res.body);
// Try common shapes: { data: {...} } or { user: {...} } or the whole body
if (body is Map && body['data'] is Map) profile = Map<String, dynamic>.from(body['data']);
else if (body is Map && body['user'] is Map) profile = Map<String, dynamic>.from(body['user']);
else if (body is Map && body['FullName'] != null) profile = Map<String, dynamic>.from(body);
else profile = {'raw': body};
notifyListeners();
} else {
if (kDebugMode) print('[AuthService] loadProfile failed ${res.statusCode}: ${res.body}');
}
} catch (e) {
if (kDebugMode) print('[AuthService] loadProfile error: $e');
}
}
Future<bool> login(String username, String password) async {
try {
final res = await http.post(
Uri.parse('$_base/login'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'username': username, 'password': password}),
);
if (res.statusCode != 200) return false;
final data = jsonDecode(res.body);
// token might be in different places; try common keys
token = data['token'] ?? data['access_token'] ?? (data['data'] != null ? data['data']['token'] : null);
if (token == null) return false;
await _storage.write(key: 'token', value: token);
await loadProfile();
notifyListeners();
return true;
} catch (e) {
return false;
}
}
Future<void> logout() async {
token = null;
profile = null;
await _storage.delete(key: 'token');
notifyListeners();
}
Future<dynamic> _httpGet(String path) async {
if (token == null) {
if (kDebugMode) print('[AuthService] _httpGet called without token for $path');
return null;
}
try {
final res = await http.get(Uri.parse('$_base$path'), headers: {'Authorization': 'Bearer $token'});
if (res.statusCode == 200) {
return jsonDecode(res.body);
} else {
if (kDebugMode) {
print('[AuthService] GET $path -> ${res.statusCode}');
print('[AuthService] response body: ${res.body}');
}
throw Exception('HTTP ${res.statusCode}');
}
} catch (e) {
if (kDebugMode) print('[AuthService] _httpGet error: $e');
rethrow;
}
}
Future<void> _loadToken() async {
token = await _storage.read(key: 'token');
if (token != null) await loadProfile();
notifyListeners();
}
}