266 lines
8.4 KiB
Dart

import 'dart:convert';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:logger/logger.dart';
import 'package:marco/controller/permission_controller.dart';
import 'package:marco/controller/project_controller.dart';
import 'package:marco/helpers/services/api_endpoints.dart';
import 'package:marco/helpers/services/storage/local_storage.dart';
final Logger logger = Logger();
class AuthService {
static const String _baseUrl = ApiEndpoints.baseUrl;
static const Map<String, String> _headers = {
'Content-Type': 'application/json',
};
static bool isLoggedIn = false;
/// Login with email and password
static Future<Map<String, String>?> loginUser(Map<String, dynamic> data) async {
try {
final response = await http.post(
Uri.parse("$_baseUrl/auth/login-mobile"),
headers: _headers,
body: jsonEncode(data),
);
final responseData = jsonDecode(response.body);
if (response.statusCode == 200 && responseData['data'] != null) {
await _handleLoginSuccess(responseData['data']);
return null;
} else if (response.statusCode == 401) {
return {"password": "Invalid email or password"};
} else {
return {"error": responseData['message'] ?? "Unexpected error occurred"};
}
} catch (e) {
logger.e("Login error: $e");
return {"error": "Network error. Please check your connection."};
}
}
/// Refresh JWT token
static Future<bool> refreshToken() async {
final accessToken = await LocalStorage.getJwtToken();
final refreshToken = await LocalStorage.getRefreshToken();
if (accessToken == null || refreshToken == null || accessToken.isEmpty || refreshToken.isEmpty) {
logger.w("Missing access/refresh token.");
return false;
}
final requestBody = {
"token": accessToken,
"refreshToken": refreshToken,
};
try {
final response = await http.post(
Uri.parse("$_baseUrl/auth/refresh-token"),
headers: _headers,
body: jsonEncode(requestBody),
);
final data = jsonDecode(response.body);
if (response.statusCode == 200 && data['success'] == true) {
await LocalStorage.setJwtToken(data['data']['token']);
await LocalStorage.setRefreshToken(data['data']['refreshToken']);
await LocalStorage.setLoggedInUser(true);
logger.i("Token refreshed.");
return true;
} else {
logger.w("Refresh token failed: ${data['message']}");
return false;
}
} catch (e) {
logger.e("Token refresh error: $e");
return false;
}
}
/// Forgot password
static Future<Map<String, String>?> forgotPassword(String email) async {
try {
final response = await http.post(
Uri.parse("$_baseUrl/auth/forgot-password"),
headers: _headers,
body: jsonEncode({"email": email}),
);
final data = jsonDecode(response.body);
if (response.statusCode == 200 && data['success'] == true) return null;
return {"error": data['message'] ?? "Failed to send reset link."};
} catch (e) {
logger.e("Forgot password error: $e");
return {"error": "Network error. Please check your connection."};
}
}
/// Request demo
static Future<Map<String, String>?> requestDemo(Map<String, dynamic> demoData) async {
try {
final response = await http.post(
Uri.parse("$_baseUrl/market/inquiry"),
headers: _headers,
body: jsonEncode(demoData),
);
final data = jsonDecode(response.body);
if (response.statusCode == 200 && data['success'] == true) return null;
return {"error": data['message'] ?? "Failed to submit demo request."};
} catch (e) {
logger.e("Request demo error: $e");
return {"error": "Network error. Please check your connection."};
}
}
/// Get list of industries
static Future<List<Map<String, dynamic>>?> getIndustries() async {
try {
final response = await http.get(
Uri.parse("$_baseUrl/market/industries"),
headers: _headers,
);
final data = jsonDecode(response.body);
if (response.statusCode == 200 && data['success'] == true) {
return List<Map<String, dynamic>>.from(data['data']);
}
return null;
} catch (e) {
logger.e("Get industries error: $e");
return null;
}
}
/// Generate MPIN
static Future<Map<String, String>?> generateMpin({
required String employeeId,
required String mpin,
}) async {
final token = await LocalStorage.getJwtToken();
try {
final response = await http.post(
Uri.parse("$_baseUrl/auth/generate-mpin"),
headers: {
..._headers,
if (token != null && token.isNotEmpty) 'Authorization': 'Bearer $token',
},
body: jsonEncode({"employeeId": employeeId, "mpin": mpin}),
);
final data = jsonDecode(response.body);
if (response.statusCode == 200 && data['success'] == true) return null;
return {"error": data['message'] ?? "Failed to generate MPIN."};
} catch (e) {
logger.e("Generate MPIN error: $e");
return {"error": "Network error. Please check your connection."};
}
}
/// Verify MPIN
static Future<Map<String, String>?> verifyMpin({
required String mpin,
required String mpinToken,
}) async {
final employeeInfo = LocalStorage.getEmployeeInfo();
if (employeeInfo == null) return {"error": "Employee info not found."};
final token = await LocalStorage.getJwtToken();
try {
final response = await http.post(
Uri.parse("$_baseUrl/auth/login-mpin"),
headers: {
..._headers,
if (token != null && token.isNotEmpty) 'Authorization': 'Bearer $token',
},
body: jsonEncode({
"employeeId": employeeInfo.id,
"mpin": mpin,
"mpinToken": mpinToken,
}),
);
final data = jsonDecode(response.body);
if (response.statusCode == 200 && data['success'] == true) return null;
return {"error": data['message'] ?? "MPIN verification failed."};
} catch (e) {
logger.e("Verify MPIN error: $e");
return {"error": "Network error. Please check your connection."};
}
}
/// Generate OTP
static Future<Map<String, String>?> generateOtp(String email) async {
try {
final response = await http.post(
Uri.parse("$_baseUrl/auth/send-otp"),
headers: _headers,
body: jsonEncode({"email": email}),
);
final data = jsonDecode(response.body);
if (response.statusCode == 200 && data['success'] == true) return null;
return {"error": data['message'] ?? "Failed to generate OTP."};
} catch (e) {
logger.e("Generate OTP error: $e");
return {"error": "Network error. Please check your connection."};
}
}
/// Verify OTP and login
static Future<Map<String, String>?> verifyOtp({
required String email,
required String otp,
}) async {
try {
final response = await http.post(
Uri.parse("$_baseUrl/auth/login-otp"),
headers: _headers,
body: jsonEncode({"email": email, "otp": otp}),
);
final data = jsonDecode(response.body);
if (response.statusCode == 200 && data['data'] != null) {
await _handleLoginSuccess(data['data']);
return null;
}
return {"error": data['message'] ?? "OTP verification failed."};
} catch (e) {
logger.e("Verify OTP error: $e");
return {"error": "Network error. Please check your connection."};
}
}
/// Handle login success flow
static Future<void> _handleLoginSuccess(Map<String, dynamic> data) async {
final jwtToken = data['token'];
final refreshToken = data['refreshToken'];
final mpinToken = data['mpinToken'];
await LocalStorage.setJwtToken(jwtToken);
await LocalStorage.setLoggedInUser(true);
if (refreshToken != null) await LocalStorage.setRefreshToken(refreshToken);
if (mpinToken != null && mpinToken.isNotEmpty) {
await LocalStorage.setMpinToken(mpinToken);
await LocalStorage.setIsMpin(true);
} else {
await LocalStorage.setIsMpin(false);
await LocalStorage.removeMpinToken();
}
final permissionController = Get.put(PermissionController());
await permissionController.loadData(jwtToken);
await Get.find<ProjectController>().fetchProjects();
isLoggedIn = true;
logger.i("Login success initialized.");
}
}