update api

This commit is contained in:
Phuoc Nguyen
2025-10-10 17:15:40 +07:00
parent b94c158004
commit 04f7042b8d
24 changed files with 3322 additions and 8 deletions

View File

@@ -5,11 +5,12 @@ class ApiConstants {
// ===== Base URL Configuration =====
/// Base URL for the API
/// TODO: Replace with actual production URL
static const String baseUrl = 'https://api.retailpos.example.com';
/// Development: http://localhost:3000
/// Production: TODO - Replace with actual production URL
static const String baseUrl = 'http://localhost:3000';
/// API version prefix
static const String apiVersion = '/api/v1';
static const String apiVersion = '/api';
/// Full base URL with version
static String get fullBaseUrl => '$baseUrl$apiVersion';
@@ -33,8 +34,21 @@ class ApiConstants {
// ===== Endpoint Paths =====
// Authentication Endpoints
/// POST - Login user
static const String login = '/auth/login';
/// POST - Register new user
static const String register = '/auth/register';
/// GET - Get current user profile (requires auth)
static const String profile = '/auth/profile';
/// POST - Refresh access token (requires auth)
static const String refreshToken = '/auth/refresh';
// Products Endpoints
/// GET - Fetch all products
/// GET - Fetch all products (with pagination and filters)
static const String products = '/products';
/// GET - Fetch single product by ID

View File

@@ -1,7 +1,11 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:get_it/get_it.dart';
import '../../features/auth/data/datasources/auth_remote_datasource.dart';
import '../../features/auth/data/repositories/auth_repository_impl.dart';
import '../../features/auth/domain/repositories/auth_repository.dart';
import '../network/dio_client.dart';
import '../network/network_info.dart';
import '../storage/secure_storage.dart';
/// Service locator instance
final sl = GetIt.instance;
@@ -28,12 +32,33 @@ Future<void> initDependencies() async {
() => DioClient(),
);
// Secure Storage
sl.registerLazySingleton<SecureStorage>(
() => SecureStorage(),
);
// ===== Authentication Feature =====
// Auth Remote Data Source
sl.registerLazySingleton<AuthRemoteDataSource>(
() => AuthRemoteDataSourceImpl(dioClient: sl()),
);
// Auth Repository
sl.registerLazySingleton<AuthRepository>(
() => AuthRepositoryImpl(
remoteDataSource: sl(),
secureStorage: sl(),
dioClient: sl(),
),
);
// ===== Data Sources =====
// Note: Data sources are managed by Riverpod providers
// Note: Other data sources are managed by Riverpod providers
// No direct registration needed here
// ===== Repositories =====
// TODO: Register repositories when they are implemented
// TODO: Register other repositories when they are implemented
// ===== Use Cases =====
// TODO: Register use cases when they are implemented

View File

@@ -28,3 +28,23 @@ class UnauthorizedException implements Exception {
final String message;
UnauthorizedException([this.message = 'Unauthorized access']);
}
class AuthenticationException implements Exception {
final String message;
AuthenticationException([this.message = 'Authentication failed']);
}
class InvalidCredentialsException implements Exception {
final String message;
InvalidCredentialsException([this.message = 'Invalid email or password']);
}
class TokenExpiredException implements Exception {
final String message;
TokenExpiredException([this.message = 'Token has expired']);
}
class ConflictException implements Exception {
final String message;
ConflictException([this.message = 'Resource already exists']);
}

View File

@@ -39,3 +39,23 @@ class NotFoundFailure extends Failure {
class UnauthorizedFailure extends Failure {
const UnauthorizedFailure([super.message = 'Unauthorized access']);
}
/// Authentication failure
class AuthenticationFailure extends Failure {
const AuthenticationFailure([super.message = 'Authentication failed']);
}
/// Invalid credentials failure
class InvalidCredentialsFailure extends Failure {
const InvalidCredentialsFailure([super.message = 'Invalid email or password']);
}
/// Token expired failure
class TokenExpiredFailure extends Failure {
const TokenExpiredFailure([super.message = 'Token has expired']);
}
/// Conflict failure (e.g., email already exists)
class ConflictFailure extends Failure {
const ConflictFailure([super.message = 'Resource already exists']);
}

View File

@@ -5,6 +5,7 @@ import 'api_interceptor.dart';
/// Dio HTTP client configuration
class DioClient {
late final Dio _dio;
String? _authToken;
DioClient() {
_dio = Dio(
@@ -21,10 +22,35 @@ class DioClient {
);
_dio.interceptors.add(ApiInterceptor());
// Add auth interceptor to inject token
_dio.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
if (_authToken != null) {
options.headers[ApiConstants.authorization] = 'Bearer $_authToken';
}
return handler.next(options);
},
),
);
}
Dio get dio => _dio;
/// Set authentication token for all future requests
void setAuthToken(String token) {
_authToken = token;
}
/// Clear authentication token
void clearAuthToken() {
_authToken = null;
}
/// Check if auth token is set
bool get hasAuthToken => _authToken != null;
/// GET request
Future<Response> get(
String path, {

View File

@@ -0,0 +1,60 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
/// Secure storage service for storing sensitive data like JWT tokens
class SecureStorage {
final FlutterSecureStorage _storage;
// Storage keys
static const String _accessTokenKey = 'access_token';
static const String _refreshTokenKey = 'refresh_token';
SecureStorage({FlutterSecureStorage? storage})
: _storage = storage ?? const FlutterSecureStorage();
/// Save access token
Future<void> saveAccessToken(String token) async {
await _storage.write(key: _accessTokenKey, value: token);
}
/// Get access token
Future<String?> getAccessToken() async {
return await _storage.read(key: _accessTokenKey);
}
/// Save refresh token (for future use)
Future<void> saveRefreshToken(String token) async {
await _storage.write(key: _refreshTokenKey, value: token);
}
/// Get refresh token (for future use)
Future<String?> getRefreshToken() async {
return await _storage.read(key: _refreshTokenKey);
}
/// Delete access token
Future<void> deleteAccessToken() async {
await _storage.delete(key: _accessTokenKey);
}
/// Delete refresh token
Future<void> deleteRefreshToken() async {
await _storage.delete(key: _refreshTokenKey);
}
/// Delete all tokens (logout)
Future<void> deleteAllTokens() async {
await _storage.delete(key: _accessTokenKey);
await _storage.delete(key: _refreshTokenKey);
}
/// Check if access token exists
Future<bool> hasAccessToken() async {
final token = await getAccessToken();
return token != null && token.isNotEmpty;
}
/// Clear all secure storage
Future<void> clearAll() async {
await _storage.deleteAll();
}
}