import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:http/http.dart' as http; import 'package:prosapp_web_app/services/local_storage.dart'; class ApiService { ApiService._(); static final instance = ApiService._(); static String get baseUrl => dotenv.env['API_BASE_URL'] ?? 'https://backend.prosapp.co/api/v1'; Future getToken() => Future.value(LocalStorage.prefs.getString('jwt_token')); Future saveToken(String token) => LocalStorage.prefs.setString('jwt_token', token); Future deleteToken() => LocalStorage.prefs.remove('jwt_token'); Future> _headers() async { final token = await getToken(); return { 'Content-Type': 'application/json', if (token != null) 'Authorization': 'Bearer $token', }; } dynamic _parse(http.Response res) { final body = jsonDecode(res.body); if (res.statusCode >= 200 && res.statusCode < 300) return body; throw Exception(body['message'] ?? 'Error ${res.statusCode}'); } Future get(String path) async { final res = await http.get(Uri.parse('$baseUrl$path'), headers: await _headers()); return _parse(res); } Future post(String path, Map body) async { final res = await http.post( Uri.parse('$baseUrl$path'), headers: await _headers(), body: jsonEncode(body), ); return _parse(res); } Future patch(String path, Map body) async { final res = await http.patch( Uri.parse('$baseUrl$path'), headers: await _headers(), body: jsonEncode(body), ); return _parse(res); } Future delete(String path) async { final res = await http.delete(Uri.parse('$baseUrl$path'), headers: await _headers()); return _parse(res); } Future upload(Uint8List bytes, String filename) async { final token = await getToken(); final req = http.MultipartRequest('POST', Uri.parse('$baseUrl/storage/upload')); if (token != null) req.headers['Authorization'] = 'Bearer $token'; req.files.add(http.MultipartFile.fromBytes('file', bytes, filename: filename)); final streamed = await req.send(); final res = await http.Response.fromStream(streamed); if (res.statusCode >= 200 && res.statusCode < 300) { return (jsonDecode(res.body) as Map)['url'] as String?; } return null; } }