TKK_E32230206/lib/services/supabase_auth_service.dart

165 lines
5.6 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 layanan **Supabase Auth** untuk autentikasi user
/// dan **SharedPreferences** untuk menyimpan cache lokal data `device_id` IoT.
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 {
// 1. Melakukan sign in ke Supabase Auth
final response = await _client.auth.signInWithPassword(
email: email,
password: password,
);
final user = response.user;
if (user == null) {
throw Exception('Login gagal: User tidak ditemukan');
}
// 2. Mengambil informasi device_id yang terhubung ke pengguna dari database 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 user belum menghubungkan device
}
// 3. Menyimpan device_id ke cache lokal (SharedPreferences) agar auto-login selanjutnya lebih cepat dan offline-safe
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) {
// Pemetaan pesan error dari Supabase ke bahasa Indonesia yang ramah pengguna
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) async {
try {
// Melakukan pendaftaran akun ke Supabase Auth beserta meta data nama lengkap
final response = await _client.auth.signUp(
email: email,
password: password,
data: {'name': name},
);
final user = response.user;
if (user == null) {
throw Exception('Registrasi gagal');
}
return UserModel(
id: user.id,
name: name,
email: email,
token: response.session?.accessToken ?? '',
deviceId: null,
);
} 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<String> claimDevice(String userId, String claimCode) async {
try {
// Mengirim request klaim alat ke REST API backend
final claimRes = await _dio.post('${ApiConfig.baseUrl}/device/claim', data: {
'claim_code': claimCode.trim(),
'user_id': userId,
});
if (claimRes.statusCode == 200) {
final deviceId = claimRes.data['device']['device_id'] as String;
// Menyimpan ID perangkat yang berhasil diklaim ke SharedPreferences
final prefs = await SharedPreferences.getInstance();
await prefs.setString('cached_device_id', deviceId);
return deviceId;
} else {
throw Exception('Gagal klaim perangkat: ${claimRes.statusCode}');
}
} catch (e) {
String errorMsg = 'Gagal klaim perangkat.';
if (e is DioException && e.response?.data != null) {
errorMsg = e.response?.data['message'] ?? errorMsg;
}
throw Exception(errorMsg);
}
}
@override
Future<void> logout() async {
// 1. Membersihkan sesi Supabase Auth di server
await _client.auth.signOut();
// 2. Menghapus cache lokal device_id agar bersih saat login pengguna lain
final prefs = await SharedPreferences.getInstance();
await prefs.remove('cached_device_id');
}
/// Memulihkan sesi login yang tersimpan di internal storage untuk Auto-Login.
/// Mengambil data user dari sesi aktif Supabase, dan device_id dari SharedPreferences.
@override
Future<UserModel?> checkSession() async {
final session = _client.auth.currentSession;
if (session != null) {
final user = session.user;
// Mengambil device_id dari cache lokal (cepat & aman saat offline)
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;
}
}