219 lines
6.1 KiB
Dart
219 lines
6.1 KiB
Dart
import 'dart:convert';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:qyuota/config/api_config.dart';
|
|
import 'dart:io';
|
|
import 'package:flutter/material.dart';
|
|
|
|
class AuthService {
|
|
static const String tokenKey = 'auth_token';
|
|
static const String userKey = 'user_data';
|
|
|
|
static final AuthService _instance = AuthService._internal();
|
|
factory AuthService() => _instance;
|
|
AuthService._internal();
|
|
|
|
Future<Map<String, dynamic>?> login(String email, String password) async {
|
|
try {
|
|
print('Login attempt with: $email'); // Debug log
|
|
|
|
final response = await http.post(
|
|
Uri.parse(ApiConfig.login),
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: jsonEncode({
|
|
'email': email,
|
|
'password': password,
|
|
}),
|
|
);
|
|
|
|
print('Response status: ${response.statusCode}');
|
|
print('Response body: ${response.body}');
|
|
|
|
if (response.statusCode == 200) {
|
|
final data = jsonDecode(response.body);
|
|
await _saveAuthData(
|
|
data['access_token'],
|
|
data['user'],
|
|
);
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString('user_id', data['user']['id'].toString());
|
|
return data;
|
|
}
|
|
|
|
final errorData = jsonDecode(response.body);
|
|
throw Exception(errorData['message'] ?? errorData['error'] ?? 'Login failed');
|
|
} catch (e) {
|
|
print('Login error details: $e');
|
|
if (e is HandshakeException) {
|
|
throw Exception('Tidak dapat terhubung ke server. Pastikan server berjalan.');
|
|
}
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> logout() async {
|
|
try {
|
|
final token = await getToken();
|
|
if (token != null) {
|
|
await http.post(
|
|
Uri.parse(ApiConfig.logout),
|
|
headers: ApiConfig.authHeaders(token),
|
|
);
|
|
}
|
|
} catch (e) {
|
|
print('Logout error: $e');
|
|
} finally {
|
|
await _clearAuthData();
|
|
}
|
|
}
|
|
|
|
Future<Map<String, dynamic>?> refreshToken() async {
|
|
try {
|
|
final token = await getToken();
|
|
if (token == null) throw Exception('No token found');
|
|
|
|
final response = await http.post(
|
|
Uri.parse(ApiConfig.refresh),
|
|
headers: ApiConfig.authHeaders(token),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final data = jsonDecode(response.body);
|
|
await _saveAuthData(
|
|
data['access_token'],
|
|
data['user'],
|
|
);
|
|
return data;
|
|
}
|
|
throw Exception('Token refresh failed');
|
|
} catch (e) {
|
|
print('Refresh token error: $e');
|
|
await _clearAuthData();
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> _saveAuthData(
|
|
String token,
|
|
Map<String, dynamic> userData,
|
|
) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString(tokenKey, token);
|
|
await prefs.setString(userKey, jsonEncode(userData));
|
|
}
|
|
|
|
Future<void> _clearAuthData() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.remove(tokenKey);
|
|
await prefs.remove(userKey);
|
|
}
|
|
|
|
Future<String?> getToken() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
return prefs.getString(tokenKey);
|
|
}
|
|
|
|
Future<String?> getUserId() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
return prefs.getString('user_id');
|
|
}
|
|
|
|
Future<Map<String, dynamic>?> getUserData() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userStr = prefs.getString(userKey);
|
|
if (userStr != null) {
|
|
return jsonDecode(userStr);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
Future<bool> isLoggedIn() async {
|
|
final token = await getToken();
|
|
return token != null;
|
|
}
|
|
|
|
Future<bool> checkSession(BuildContext context) async {
|
|
final token = await getToken();
|
|
if (token == null) {
|
|
// Jika tidak ada token, arahkan ke halaman login
|
|
Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false);
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
final response = await http.get(
|
|
Uri.parse(ApiConfig.profile),
|
|
headers: ApiConfig.authHeaders(token),
|
|
);
|
|
|
|
if (response.statusCode == 401) {
|
|
// Token tidak valid atau expired
|
|
await _clearAuthData();
|
|
Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
} catch (e) {
|
|
print('Error checking session: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<void> changePassword({
|
|
required String currentPassword,
|
|
required String newPassword,
|
|
required String confirmPassword,
|
|
}) async {
|
|
try {
|
|
final token = await getToken();
|
|
if (token == null) {
|
|
throw Exception('Token tidak ditemukan');
|
|
}
|
|
|
|
print('Attempting to change password...');
|
|
print('Endpoint: ${ApiConfig.changePassword}');
|
|
|
|
final response = await http.post(
|
|
Uri.parse(ApiConfig.changePassword),
|
|
headers: {
|
|
'Authorization': 'Bearer $token',
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: jsonEncode({
|
|
'current_password': currentPassword,
|
|
'new_password': newPassword,
|
|
'confirm_password': confirmPassword,
|
|
}),
|
|
);
|
|
|
|
print('Response status: ${response.statusCode}');
|
|
print('Response body: ${response.body}');
|
|
|
|
if (response.statusCode == 200) {
|
|
return;
|
|
}
|
|
|
|
final data = jsonDecode(response.body);
|
|
if (data['errors'] != null) {
|
|
final errors = data['errors'] as Map<String, dynamic>;
|
|
final firstError = errors.values.first;
|
|
if (firstError is List && firstError.isNotEmpty) {
|
|
throw Exception(firstError[0]);
|
|
}
|
|
throw Exception(firstError.toString());
|
|
}
|
|
throw Exception(data['message'] ?? 'Gagal mengubah password');
|
|
} catch (e) {
|
|
print('Change password error: $e');
|
|
if (e is SocketException) {
|
|
throw Exception('Tidak dapat terhubung ke server. Periksa koneksi internet Anda.');
|
|
}
|
|
rethrow;
|
|
}
|
|
}
|
|
} |