155 lines
4.9 KiB
Dart
155 lines
4.9 KiB
Dart
import 'package:supabase_flutter/supabase_flutter.dart' as supabase;
|
|
import 'package:dio/dio.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import '../models/user_model.dart';
|
|
import '../core/api_config.dart';
|
|
import 'auth_service.dart';
|
|
|
|
/// Implementasi AuthService menggunakan Supabase
|
|
class SupabaseAuthService implements AuthService {
|
|
final supabase.SupabaseClient _client = supabase.Supabase.instance.client;
|
|
final Dio _dio = Dio();
|
|
|
|
@override
|
|
Future<UserModel> login(String email, String password) async {
|
|
try {
|
|
final response = await _client.auth.signInWithPassword(
|
|
email: email,
|
|
password: password,
|
|
);
|
|
|
|
final user = response.user;
|
|
if (user == null) {
|
|
throw Exception('Login gagal: User tidak ditemukan');
|
|
}
|
|
|
|
// Ambil device_id dari backend
|
|
String? deviceId;
|
|
try {
|
|
final deviceRes = await _dio.get('${ApiConfig.baseUrl}/device/my-device/${user.id}');
|
|
if (deviceRes.statusCode == 200) {
|
|
deviceId = deviceRes.data['device_id'];
|
|
}
|
|
} catch (e) {
|
|
print('Gagal mengambil info device: $e');
|
|
// Tidak melempar error agar login tetap sukses meskipun belum ada device
|
|
}
|
|
|
|
// Simpan device_id ke cache lokal agar auto-login selanjutnya super cepat
|
|
if (deviceId != null) {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString('cached_device_id', deviceId);
|
|
}
|
|
|
|
return UserModel(
|
|
id: user.id,
|
|
name: user.userMetadata?['name'] ?? user.email?.split('@').first ?? 'User',
|
|
email: user.email ?? email,
|
|
token: response.session?.accessToken ?? '',
|
|
deviceId: deviceId,
|
|
);
|
|
} on supabase.AuthException catch (e) {
|
|
if (e.message.contains('Invalid login credentials')) {
|
|
throw Exception('Email atau password salah.');
|
|
} else if (e.message.contains('Email not confirmed')) {
|
|
throw Exception('Email belum diverifikasi.');
|
|
}
|
|
throw Exception(e.message);
|
|
} catch (e) {
|
|
throw Exception('Terjadi kesalahan koneksi atau server.');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<UserModel> register(String name, String email, String password, String claimCode) async {
|
|
try {
|
|
final response = await _client.auth.signUp(
|
|
email: email,
|
|
password: password,
|
|
data: {'name': name},
|
|
);
|
|
|
|
final user = response.user;
|
|
if (user == null) {
|
|
throw Exception('Registrasi gagal');
|
|
}
|
|
|
|
// Klaim device setelah berhasil mendaftar ke Supabase
|
|
String? deviceId;
|
|
try {
|
|
final claimRes = await _dio.post('${ApiConfig.baseUrl}/device/claim', data: {
|
|
'claim_code': claimCode,
|
|
'user_id': user.id,
|
|
});
|
|
|
|
if (claimRes.statusCode == 200) {
|
|
deviceId = claimRes.data['device']['device_id'];
|
|
// Simpan device_id ke cache lokal
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString('cached_device_id', deviceId!);
|
|
}
|
|
} catch (e) {
|
|
// Jika gagal klaim
|
|
String errorMsg = 'Gagal klaim perangkat.';
|
|
if (e is DioException && e.response?.data != null) {
|
|
errorMsg = e.response?.data['message'] ?? errorMsg;
|
|
}
|
|
throw Exception('Akun terbuat, tapi $errorMsg');
|
|
}
|
|
|
|
return UserModel(
|
|
id: user.id,
|
|
name: name,
|
|
email: email,
|
|
token: response.session?.accessToken ?? '',
|
|
deviceId: deviceId,
|
|
);
|
|
} on supabase.AuthException catch (e) {
|
|
if (e.message.contains('already registered')) {
|
|
throw Exception('Email sudah terdaftar.');
|
|
} else if (e.message.contains('weak')) {
|
|
throw Exception('Password terlalu lemah.');
|
|
}
|
|
throw Exception(e.message);
|
|
} catch (e) {
|
|
throw Exception('Terjadi kesalahan koneksi atau server.');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<void> logout() async {
|
|
// Hapus sesi Supabase
|
|
await _client.auth.signOut();
|
|
|
|
// Hapus cache device_id agar tidak terbawa jika user login pakai akun lain
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.remove('cached_device_id');
|
|
}
|
|
|
|
// Fungsi tambahan untuk memulihkan sesi
|
|
Future<UserModel?> checkSession() async {
|
|
final session = _client.auth.currentSession;
|
|
if (session != null) {
|
|
final user = session.user;
|
|
|
|
// Ambil device_id langsung dari cache lokal (cepat & offline-safe)
|
|
String? deviceId;
|
|
try {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
deviceId = prefs.getString('cached_device_id');
|
|
} catch (e) {
|
|
print('Gagal membaca cache device_id: $e');
|
|
}
|
|
|
|
return UserModel(
|
|
id: user.id,
|
|
name: user.userMetadata?['name'] ?? user.email?.split('@').first ?? 'User',
|
|
email: user.email ?? '',
|
|
token: session.accessToken,
|
|
deviceId: deviceId,
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
}
|