Initial Flutter scaffold: Riverpod + GoRouter + Dio
This commit is contained in:
182
lib/shared/services/api_client.dart
Normal file
182
lib/shared/services/api_client.dart
Normal file
@@ -0,0 +1,182 @@
|
||||
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,
|
||||
});
|
||||
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
|
||||
if (response.data['token'] != null) {
|
||||
await _storage.write(key: 'session_token', value: response.data['token']);
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user