Files
network-app-mobile/lib/shared/services/api_client.dart

202 lines
5.9 KiB
Dart

import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../../config/env.dart';
final apiClientProvider = Provider<ApiClient>((ref) {
return ApiClient();
});
class ApiClient {
late final Dio _dio;
final _storage = const FlutterSecureStorage();
ApiClient() {
_dio = Dio(BaseOptions(
baseUrl: Env.apiBaseUrl,
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 30),
headers: {
'Content-Type': 'application/json',
},
));
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) async {
// Add auth token if available
final token = await _storage.read(key: 'session_token');
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
},
onError: (error, handler) {
if (error.response?.statusCode == 401) {
// Handle unauthorized - clear token and redirect to login
_storage.delete(key: 'session_token');
}
handler.next(error);
},
));
}
// Auth
Future<Map<String, dynamic>> signUp({
required String email,
required String password,
required String name,
}) async {
final response = await _dio.post('/api/auth/sign-up/email', data: {
'email': email,
'password': password,
'name': name,
});
// Store session token from header (BetterAuth auto-signs in after signup)
final authToken = response.headers.value('set-auth-token');
if (authToken != null) {
await _storage.write(key: 'session_token', value: authToken);
}
return response.data;
}
Future<Map<String, dynamic>> signIn({
required String email,
required String password,
}) async {
final response = await _dio.post('/api/auth/sign-in/email', data: {
'email': email,
'password': password,
});
// Store session token from header (BetterAuth bearer plugin)
final authToken = response.headers.value('set-auth-token');
if (authToken != null) {
await _storage.write(key: 'session_token', value: authToken);
}
return response.data;
}
Future<void> signOut() async {
await _dio.post('/api/auth/sign-out');
await _storage.delete(key: 'session_token');
}
Future<Map<String, dynamic>?> getSession() async {
try {
final response = await _dio.get('/api/auth/session');
return response.data;
} catch (_) {
return null;
}
}
// Clients
Future<List<Map<String, dynamic>>> getClients({String? search, String? tag}) async {
final response = await _dio.get('/api/clients', queryParameters: {
if (search != null) 'search': search,
if (tag != null) 'tag': tag,
});
return List<Map<String, dynamic>>.from(response.data);
}
Future<Map<String, dynamic>> getClient(String id) async {
final response = await _dio.get('/api/clients/$id');
return response.data;
}
Future<Map<String, dynamic>> createClient(Map<String, dynamic> data) async {
final response = await _dio.post('/api/clients', data: data);
return response.data;
}
Future<Map<String, dynamic>> updateClient(String id, Map<String, dynamic> data) async {
final response = await _dio.put('/api/clients/$id', data: data);
return response.data;
}
Future<void> deleteClient(String id) async {
await _dio.delete('/api/clients/$id');
}
Future<void> markClientContacted(String id) async {
await _dio.post('/api/clients/$id/contacted');
}
// Emails
Future<Map<String, dynamic>> generateEmail({
required String clientId,
required String purpose,
String? provider,
}) async {
final response = await _dio.post('/api/emails/generate', data: {
'clientId': clientId,
'purpose': purpose,
if (provider != null) 'provider': provider,
});
return response.data;
}
Future<List<Map<String, dynamic>>> getEmails({String? status, String? clientId}) async {
final response = await _dio.get('/api/emails', queryParameters: {
if (status != null) 'status': status,
if (clientId != null) 'clientId': clientId,
});
return List<Map<String, dynamic>>.from(response.data);
}
Future<Map<String, dynamic>> updateEmail(String id, Map<String, dynamic> data) async {
final response = await _dio.put('/api/emails/$id', data: data);
return response.data;
}
Future<Map<String, dynamic>> sendEmail(String id) async {
final response = await _dio.post('/api/emails/$id/send');
return response.data;
}
Future<void> deleteEmail(String id) async {
await _dio.delete('/api/emails/$id');
}
// Events
Future<List<Map<String, dynamic>>> getEvents({
String? clientId,
String? type,
int? upcomingDays,
}) async {
final response = await _dio.get('/api/events', queryParameters: {
if (clientId != null) 'clientId': clientId,
if (type != null) 'type': type,
if (upcomingDays != null) 'upcoming': upcomingDays.toString(),
});
return List<Map<String, dynamic>>.from(response.data);
}
Future<Map<String, dynamic>> createEvent(Map<String, dynamic> data) async {
final response = await _dio.post('/api/events', data: data);
return response.data;
}
Future<void> deleteEvent(String id) async {
await _dio.delete('/api/events/$id');
}
Future<void> syncClientEvents(String clientId) async {
await _dio.post('/api/events/sync/$clientId');
}
// Profile
Future<Map<String, dynamic>> getProfile() async {
final response = await _dio.get('/api/profile');
return response.data;
}
Future<Map<String, dynamic>> updateProfile(Map<String, dynamic> data) async {
final response = await _dio.put('/api/profile', data: data);
return response.data;
}
}