first commit
This commit is contained in:
84
lib/app/data/models/aset_model.dart
Normal file
84
lib/app/data/models/aset_model.dart
Normal file
@ -0,0 +1,84 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AsetModel {
|
||||
final String id;
|
||||
final String nama;
|
||||
final String deskripsi;
|
||||
final String kategori;
|
||||
final int harga;
|
||||
final int? denda;
|
||||
final String status;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
final int? kuantitas;
|
||||
final int? kuantitasTerpakai;
|
||||
final String? satuanUkur;
|
||||
|
||||
// Untuk menampung URL gambar pertama dari tabel foto_aset
|
||||
String? imageUrl;
|
||||
|
||||
// Menggunakan RxList untuk membuatnya mutable dan reaktif
|
||||
RxList<Map<String, dynamic>> satuanWaktuSewa = <Map<String, dynamic>>[].obs;
|
||||
|
||||
AsetModel({
|
||||
required this.id,
|
||||
required this.nama,
|
||||
required this.deskripsi,
|
||||
required this.kategori,
|
||||
required this.harga,
|
||||
this.denda,
|
||||
required this.status,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.kuantitas,
|
||||
this.kuantitasTerpakai,
|
||||
this.satuanUkur,
|
||||
this.imageUrl,
|
||||
List<Map<String, dynamic>>? initialSatuanWaktuSewa,
|
||||
}) {
|
||||
// Inisialisasi satuanWaktuSewa jika ada data awal
|
||||
if (initialSatuanWaktuSewa != null) {
|
||||
satuanWaktuSewa.addAll(initialSatuanWaktuSewa);
|
||||
}
|
||||
}
|
||||
|
||||
factory AsetModel.fromJson(Map<String, dynamic> json) {
|
||||
return AsetModel(
|
||||
id: json['id'] ?? '',
|
||||
nama: json['nama'] ?? '',
|
||||
deskripsi: json['deskripsi'] ?? '',
|
||||
kategori: json['kategori'] ?? '',
|
||||
harga: json['harga'] ?? 0,
|
||||
denda: json['denda'],
|
||||
status: json['status'] ?? '',
|
||||
createdAt:
|
||||
json['created_at'] != null
|
||||
? DateTime.parse(json['created_at'])
|
||||
: null,
|
||||
updatedAt:
|
||||
json['updated_at'] != null
|
||||
? DateTime.parse(json['updated_at'])
|
||||
: null,
|
||||
kuantitas: json['kuantitas'],
|
||||
kuantitasTerpakai: json['kuantitas_terpakai'],
|
||||
satuanUkur: json['satuan_ukur'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'nama': nama,
|
||||
'deskripsi': deskripsi,
|
||||
'kategori': kategori,
|
||||
'harga': harga,
|
||||
'denda': denda,
|
||||
'status': status,
|
||||
'created_at': createdAt?.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
'kuantitas': kuantitas,
|
||||
'kuantitas_terpakai': kuantitasTerpakai,
|
||||
'satuan_ukur': satuanUkur,
|
||||
};
|
||||
}
|
||||
}
|
41
lib/app/data/models/foto_aset_model.dart
Normal file
41
lib/app/data/models/foto_aset_model.dart
Normal file
@ -0,0 +1,41 @@
|
||||
class FotoAsetModel {
|
||||
final String id;
|
||||
final String fotoAset; // URL foto
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
final String idAset;
|
||||
|
||||
FotoAsetModel({
|
||||
required this.id,
|
||||
required this.fotoAset,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
required this.idAset,
|
||||
});
|
||||
|
||||
factory FotoAsetModel.fromJson(Map<String, dynamic> json) {
|
||||
return FotoAsetModel(
|
||||
id: json['id'] ?? '',
|
||||
fotoAset: json['foto_aset'] ?? '',
|
||||
createdAt:
|
||||
json['created_at'] != null
|
||||
? DateTime.parse(json['created_at'])
|
||||
: null,
|
||||
updatedAt:
|
||||
json['updated_at'] != null
|
||||
? DateTime.parse(json['updated_at'])
|
||||
: null,
|
||||
idAset: json['id_aset'] ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'foto_aset': fotoAset,
|
||||
'created_at': createdAt?.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
'id_aset': idAset,
|
||||
};
|
||||
}
|
||||
}
|
54
lib/app/data/models/paket_model.dart
Normal file
54
lib/app/data/models/paket_model.dart
Normal file
@ -0,0 +1,54 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class PaketModel {
|
||||
final String? id;
|
||||
final String? nama;
|
||||
final String? deskripsi;
|
||||
final int? harga;
|
||||
final int? kuantitas;
|
||||
final String? foto_paket;
|
||||
final List<dynamic>? satuanWaktuSewa;
|
||||
|
||||
PaketModel({
|
||||
this.id,
|
||||
this.nama,
|
||||
this.deskripsi,
|
||||
this.harga,
|
||||
this.kuantitas,
|
||||
this.foto_paket,
|
||||
this.satuanWaktuSewa,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'nama': nama,
|
||||
'deskripsi': deskripsi,
|
||||
'harga': harga,
|
||||
'kuantitas': kuantitas,
|
||||
'foto_paket': foto_paket,
|
||||
'satuanWaktuSewa': satuanWaktuSewa,
|
||||
};
|
||||
}
|
||||
|
||||
factory PaketModel.fromMap(Map<String, dynamic> map) {
|
||||
return PaketModel(
|
||||
id: map['id'],
|
||||
nama: map['nama'],
|
||||
deskripsi: map['deskripsi'],
|
||||
harga: map['harga']?.toInt(),
|
||||
kuantitas: map['kuantitas']?.toInt(),
|
||||
foto_paket: map['foto_paket'],
|
||||
satuanWaktuSewa: map['satuanWaktuSewa'],
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory PaketModel.fromJson(String source) => PaketModel.fromMap(json.decode(source));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PaketModel(id: $id, nama: $nama, deskripsi: $deskripsi, harga: $harga, kuantitas: $kuantitas, foto_paket: $foto_paket, satuanWaktuSewa: $satuanWaktuSewa)';
|
||||
}
|
||||
}
|
79
lib/app/data/models/pesanan_model.dart
Normal file
79
lib/app/data/models/pesanan_model.dart
Normal file
@ -0,0 +1,79 @@
|
||||
class PesananModel {
|
||||
final String id;
|
||||
final String asetId;
|
||||
final String satuanWaktuId;
|
||||
final String userId;
|
||||
final String status;
|
||||
final DateTime tanggalPemesanan;
|
||||
final String jamPemesanan;
|
||||
final int durasi;
|
||||
final int totalHarga;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
|
||||
// Optional fields for joined data from other tables
|
||||
String? namaSatuanWaktu;
|
||||
String? namaAset;
|
||||
String? namaUser;
|
||||
|
||||
PesananModel({
|
||||
required this.id,
|
||||
required this.asetId,
|
||||
required this.satuanWaktuId,
|
||||
required this.userId,
|
||||
required this.status,
|
||||
required this.tanggalPemesanan,
|
||||
required this.jamPemesanan,
|
||||
required this.durasi,
|
||||
required this.totalHarga,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.namaSatuanWaktu,
|
||||
this.namaAset,
|
||||
this.namaUser,
|
||||
});
|
||||
|
||||
factory PesananModel.fromJson(Map<String, dynamic> json) {
|
||||
return PesananModel(
|
||||
id: json['id'] ?? '',
|
||||
asetId: json['aset_id'] ?? '',
|
||||
satuanWaktuId: json['satuan_waktu_id'] ?? '',
|
||||
userId: json['user_id'] ?? '',
|
||||
status: json['status'] ?? 'pending',
|
||||
tanggalPemesanan:
|
||||
json['tanggal_pemesanan'] != null
|
||||
? DateTime.parse(json['tanggal_pemesanan'])
|
||||
: DateTime.now(),
|
||||
jamPemesanan: json['jam_pemesanan'] ?? '00:00',
|
||||
durasi: json['durasi'] ?? 1,
|
||||
totalHarga: json['total_harga'] ?? 0,
|
||||
createdAt:
|
||||
json['created_at'] != null
|
||||
? DateTime.parse(json['created_at'])
|
||||
: null,
|
||||
updatedAt:
|
||||
json['updated_at'] != null
|
||||
? DateTime.parse(json['updated_at'])
|
||||
: null,
|
||||
namaSatuanWaktu: json['nama_satuan_waktu'],
|
||||
namaAset: json['nama_aset'],
|
||||
namaUser: json['nama_user'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'aset_id': asetId,
|
||||
'satuan_waktu_id': satuanWaktuId,
|
||||
'user_id': userId,
|
||||
'status': status,
|
||||
'tanggal_pemesanan': tanggalPemesanan.toIso8601String().split('T')[0],
|
||||
'jam_pemesanan': jamPemesanan,
|
||||
'durasi': durasi,
|
||||
'total_harga': totalHarga,
|
||||
'created_at': createdAt?.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
}
|
1
lib/app/data/models/rental_booking_model.dart
Normal file
1
lib/app/data/models/rental_booking_model.dart
Normal file
@ -0,0 +1 @@
|
||||
|
102
lib/app/data/models/rental_item_model.dart
Normal file
102
lib/app/data/models/rental_item_model.dart
Normal file
@ -0,0 +1,102 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class RentalItem {
|
||||
final String id;
|
||||
final String title;
|
||||
final String description;
|
||||
final double pricePerDay;
|
||||
final String? imageUrl;
|
||||
final String ownerId;
|
||||
final String category;
|
||||
final List<String>? features;
|
||||
final bool isAvailable;
|
||||
final String? location;
|
||||
final DateTime createdAt;
|
||||
final DateTime? updatedAt;
|
||||
|
||||
RentalItem({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.pricePerDay,
|
||||
this.imageUrl,
|
||||
required this.ownerId,
|
||||
required this.category,
|
||||
this.features,
|
||||
required this.isAvailable,
|
||||
this.location,
|
||||
required this.createdAt,
|
||||
this.updatedAt,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'title': title,
|
||||
'description': description,
|
||||
'price_per_day': pricePerDay,
|
||||
'image_url': imageUrl,
|
||||
'owner_id': ownerId,
|
||||
'category': category,
|
||||
'features': features,
|
||||
'is_available': isAvailable,
|
||||
'location': location,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
factory RentalItem.fromMap(Map<String, dynamic> map) {
|
||||
return RentalItem(
|
||||
id: map['id'] ?? '',
|
||||
title: map['title'] ?? '',
|
||||
description: map['description'] ?? '',
|
||||
pricePerDay: map['price_per_day']?.toDouble() ?? 0.0,
|
||||
imageUrl: map['image_url'],
|
||||
ownerId: map['owner_id'] ?? '',
|
||||
category: map['category'] ?? '',
|
||||
features:
|
||||
map['features'] != null ? List<String>.from(map['features']) : null,
|
||||
isAvailable: map['is_available'] ?? true,
|
||||
location: map['location'],
|
||||
createdAt: DateTime.parse(map['created_at']),
|
||||
updatedAt:
|
||||
map['updated_at'] != null ? DateTime.parse(map['updated_at']) : null,
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory RentalItem.fromJson(String source) =>
|
||||
RentalItem.fromMap(json.decode(source));
|
||||
|
||||
RentalItem copyWith({
|
||||
String? id,
|
||||
String? title,
|
||||
String? description,
|
||||
double? pricePerDay,
|
||||
String? imageUrl,
|
||||
String? ownerId,
|
||||
String? category,
|
||||
List<String>? features,
|
||||
bool? isAvailable,
|
||||
String? location,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
}) {
|
||||
return RentalItem(
|
||||
id: id ?? this.id,
|
||||
title: title ?? this.title,
|
||||
description: description ?? this.description,
|
||||
pricePerDay: pricePerDay ?? this.pricePerDay,
|
||||
imageUrl: imageUrl ?? this.imageUrl,
|
||||
ownerId: ownerId ?? this.ownerId,
|
||||
category: category ?? this.category,
|
||||
features: features ?? this.features,
|
||||
isAvailable: isAvailable ?? this.isAvailable,
|
||||
location: location ?? this.location,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
);
|
||||
}
|
||||
}
|
37
lib/app/data/models/satuan_waktu_model.dart
Normal file
37
lib/app/data/models/satuan_waktu_model.dart
Normal file
@ -0,0 +1,37 @@
|
||||
class SatuanWaktuModel {
|
||||
final String id;
|
||||
final String namaSatuanWaktu;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
|
||||
SatuanWaktuModel({
|
||||
required this.id,
|
||||
required this.namaSatuanWaktu,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
});
|
||||
|
||||
factory SatuanWaktuModel.fromJson(Map<String, dynamic> json) {
|
||||
return SatuanWaktuModel(
|
||||
id: json['id'] ?? '',
|
||||
namaSatuanWaktu: json['nama_satuan_waktu'] ?? '',
|
||||
createdAt:
|
||||
json['created_at'] != null
|
||||
? DateTime.parse(json['created_at'])
|
||||
: null,
|
||||
updatedAt:
|
||||
json['updated_at'] != null
|
||||
? DateTime.parse(json['updated_at'])
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'nama_satuan_waktu': namaSatuanWaktu,
|
||||
'created_at': createdAt?.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
}
|
53
lib/app/data/models/satuan_waktu_sewa_model.dart
Normal file
53
lib/app/data/models/satuan_waktu_sewa_model.dart
Normal file
@ -0,0 +1,53 @@
|
||||
class SatuanWaktuSewaModel {
|
||||
final String id;
|
||||
final String asetId;
|
||||
final String satuanWaktuId;
|
||||
final int harga;
|
||||
final int? denda;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
|
||||
// Untuk menyimpan nama satuan waktu (jam/hari) dari tabel satuan_waktu
|
||||
String? namaSatuanWaktu;
|
||||
|
||||
SatuanWaktuSewaModel({
|
||||
required this.id,
|
||||
required this.asetId,
|
||||
required this.satuanWaktuId,
|
||||
required this.harga,
|
||||
this.denda,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.namaSatuanWaktu,
|
||||
});
|
||||
|
||||
factory SatuanWaktuSewaModel.fromJson(Map<String, dynamic> json) {
|
||||
return SatuanWaktuSewaModel(
|
||||
id: json['id'] ?? '',
|
||||
asetId: json['aset_id'] ?? '',
|
||||
satuanWaktuId: json['satuan_waktu_id'] ?? '',
|
||||
harga: json['harga'] ?? 0,
|
||||
denda: json['denda'],
|
||||
createdAt:
|
||||
json['created_at'] != null
|
||||
? DateTime.parse(json['created_at'])
|
||||
: null,
|
||||
updatedAt:
|
||||
json['updated_at'] != null
|
||||
? DateTime.parse(json['updated_at'])
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'aset_id': asetId,
|
||||
'satuan_waktu_id': satuanWaktuId,
|
||||
'harga': harga,
|
||||
'denda': denda,
|
||||
'created_at': createdAt?.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
}
|
71
lib/app/data/models/user_model.dart
Normal file
71
lib/app/data/models/user_model.dart
Normal file
@ -0,0 +1,71 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class User {
|
||||
final String id;
|
||||
final String email;
|
||||
final String? name;
|
||||
final String? avatarUrl;
|
||||
final String? phoneNumber;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
|
||||
User({
|
||||
required this.id,
|
||||
required this.email,
|
||||
this.name,
|
||||
this.avatarUrl,
|
||||
this.phoneNumber,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'email': email,
|
||||
'name': name,
|
||||
'avatar_url': avatarUrl,
|
||||
'phone_number': phoneNumber,
|
||||
'created_at': createdAt?.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
factory User.fromMap(Map<String, dynamic> map) {
|
||||
return User(
|
||||
id: map['id'] ?? '',
|
||||
email: map['email'] ?? '',
|
||||
name: map['name'],
|
||||
avatarUrl: map['avatar_url'],
|
||||
phoneNumber: map['phone_number'],
|
||||
createdAt:
|
||||
map['created_at'] != null ? DateTime.parse(map['created_at']) : null,
|
||||
updatedAt:
|
||||
map['updated_at'] != null ? DateTime.parse(map['updated_at']) : null,
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory User.fromJson(String source) => User.fromMap(json.decode(source));
|
||||
|
||||
User copyWith({
|
||||
String? id,
|
||||
String? email,
|
||||
String? name,
|
||||
String? avatarUrl,
|
||||
String? phoneNumber,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
}) {
|
||||
return User(
|
||||
id: id ?? this.id,
|
||||
email: email ?? this.email,
|
||||
name: name ?? this.name,
|
||||
avatarUrl: avatarUrl ?? this.avatarUrl,
|
||||
phoneNumber: phoneNumber ?? this.phoneNumber,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
);
|
||||
}
|
||||
}
|
1099
lib/app/data/providers/aset_provider.dart
Normal file
1099
lib/app/data/providers/aset_provider.dart
Normal file
File diff suppressed because it is too large
Load Diff
535
lib/app/data/providers/auth_provider.dart
Normal file
535
lib/app/data/providers/auth_provider.dart
Normal file
@ -0,0 +1,535 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
|
||||
class AuthProvider extends GetxService {
|
||||
late final SupabaseClient client;
|
||||
bool _isInitialized = false;
|
||||
|
||||
Future<AuthProvider> init() async {
|
||||
// Cek jika sudah diinisialisasi sebelumnya
|
||||
if (_isInitialized) {
|
||||
debugPrint('Supabase already initialized');
|
||||
return this;
|
||||
}
|
||||
|
||||
try {
|
||||
// Cek jika dotenv sudah dimuat
|
||||
if (dotenv.env['SUPABASE_URL'] == null ||
|
||||
dotenv.env['SUPABASE_ANON_KEY'] == null) {
|
||||
await dotenv.load();
|
||||
}
|
||||
|
||||
final supabaseUrl = dotenv.env['SUPABASE_URL'];
|
||||
final supabaseKey = dotenv.env['SUPABASE_ANON_KEY'];
|
||||
|
||||
if (supabaseUrl == null || supabaseKey == null) {
|
||||
throw Exception('Supabase credentials not found in .env file');
|
||||
}
|
||||
|
||||
debugPrint(
|
||||
'Initializing Supabase with URL: ${supabaseUrl.substring(0, 15)}...',
|
||||
);
|
||||
|
||||
await Supabase.initialize(
|
||||
url: supabaseUrl,
|
||||
anonKey: supabaseKey,
|
||||
debug: true, // Aktifkan debugging untuk membantu troubleshooting
|
||||
);
|
||||
|
||||
client = Supabase.instance.client;
|
||||
_isInitialized = true;
|
||||
debugPrint('Supabase initialized successfully');
|
||||
return this;
|
||||
} catch (e) {
|
||||
debugPrint('Error initializing Supabase: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Authentication methods
|
||||
Future<AuthResponse> signUp({
|
||||
required String email,
|
||||
required String password,
|
||||
Map<String, dynamic>? data,
|
||||
}) async {
|
||||
return await client.auth.signUp(
|
||||
email: email,
|
||||
password: password,
|
||||
data: data,
|
||||
);
|
||||
}
|
||||
|
||||
Future<AuthResponse> signIn({
|
||||
required String email,
|
||||
required String password,
|
||||
}) async {
|
||||
return await client.auth.signInWithPassword(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> signOut() async {
|
||||
await client.auth.signOut();
|
||||
}
|
||||
|
||||
User? get currentUser => client.auth.currentUser;
|
||||
|
||||
Stream<AuthState> get authChanges => client.auth.onAuthStateChange;
|
||||
|
||||
String? getCurrentUserId() {
|
||||
try {
|
||||
final session = Supabase.instance.client.auth.currentSession;
|
||||
return session?.user.id;
|
||||
} catch (e) {
|
||||
print('Error getting current user ID: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Metode untuk mendapatkan role_id dari raw_user_meta_data
|
||||
Future<String?> getUserRoleId() async {
|
||||
final user = currentUser;
|
||||
if (user == null) {
|
||||
debugPrint('No current user found when getting role');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
debugPrint('Fetching role_id from user metadata for user ID: ${user.id}');
|
||||
|
||||
// Cek user metadata untuk role_id
|
||||
final userMetadata = user.userMetadata;
|
||||
debugPrint('User metadata: $userMetadata');
|
||||
|
||||
// Cek beberapa kemungkinan nama field untuk role_id
|
||||
if (userMetadata != null) {
|
||||
if (userMetadata.containsKey('role_id')) {
|
||||
final roleId = userMetadata['role_id'].toString();
|
||||
debugPrint('Found role_id in metadata: $roleId');
|
||||
return roleId;
|
||||
}
|
||||
|
||||
if (userMetadata.containsKey('role')) {
|
||||
final role = userMetadata['role'].toString();
|
||||
debugPrint('Found role in metadata: $role');
|
||||
|
||||
// Coba konversi nama role ke UUID (from hardcoded data)
|
||||
if (role.toUpperCase() == 'WARGA') {
|
||||
return 'bb5360d5-8fd0-404e-8f6f-71ec4d8ad0ae';
|
||||
}
|
||||
if (role.toUpperCase() == 'PETUGAS_BUMDES') {
|
||||
return '38a8a23c-1873-4033-b977-3293247903b';
|
||||
}
|
||||
if (role.toUpperCase() == 'PETUGAS_MITRA') {
|
||||
return '8b1af754-0866-4e12-a9d8-da8ed31bec15';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Jika tidak ada di metadata, coba cari di tabel roles dengan user_id
|
||||
debugPrint('Checking roles table for user ID: ${user.id}');
|
||||
|
||||
try {
|
||||
// Mencoba mengambil roles berdasarkan id user di auth
|
||||
final roleData =
|
||||
await client
|
||||
.from('roles')
|
||||
.select('id')
|
||||
.eq('user_id', user.id)
|
||||
.maybeSingle();
|
||||
|
||||
debugPrint('Role data by user_id: $roleData');
|
||||
|
||||
if (roleData != null && roleData.containsKey('id')) {
|
||||
final roleId = roleData['id'].toString();
|
||||
debugPrint('Found role ID in roles table: $roleId');
|
||||
return roleId;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error querying roles by user_id: $e');
|
||||
}
|
||||
|
||||
// Jika tidak ditemukan dengan user_id, coba lihat seluruh tabel roles
|
||||
// untuk debugging
|
||||
debugPrint('Getting all roles to debug matching issues');
|
||||
final allRoles = await client.from('roles').select('*').limit(10);
|
||||
|
||||
debugPrint('All roles in table: $allRoles');
|
||||
|
||||
// Fallback - tampaknya user belum di-assign role
|
||||
// Berikan hardcoded role berdasarkan email pattern
|
||||
final email = user.email?.toLowerCase();
|
||||
if (email != null) {
|
||||
if (email.contains('bumdes')) {
|
||||
return '38a8a23c-1873-4033-b977-3293247903b'; // PETUGAS_BUMDES
|
||||
} else if (email.contains('mitra')) {
|
||||
return '8b1af754-0866-4e12-a9d8-da8ed31bec15'; // PETUGAS_MITRA
|
||||
}
|
||||
}
|
||||
|
||||
// Default ke WARGA
|
||||
return 'bb5360d5-8fd0-404e-8f6f-71ec4d8ad0ae'; // WARGA
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching user role_id: $e');
|
||||
// Default ke WARGA sebagai fallback
|
||||
return 'bb5360d5-8fd0-404e-8f6f-71ec4d8ad0ae';
|
||||
}
|
||||
}
|
||||
|
||||
// Metode untuk mendapatkan nama role dari tabel roles berdasarkan role_id
|
||||
Future<String?> getRoleName(String roleId) async {
|
||||
try {
|
||||
debugPrint('Fetching role name for role_id: $roleId');
|
||||
|
||||
// Ambil nama role dari tabel roles
|
||||
// ID di tabel roles adalah tipe UUID, pastikan format roleId sesuai
|
||||
final roleData =
|
||||
await client
|
||||
.from('roles')
|
||||
.select('nama_role, id')
|
||||
.eq('id', roleId)
|
||||
.maybeSingle();
|
||||
|
||||
debugPrint('Query result for roles table: $roleData');
|
||||
|
||||
if (roleData != null) {
|
||||
// Cek berbagai kemungkinan nama kolom
|
||||
String? roleName;
|
||||
if (roleData.containsKey('nama_role')) {
|
||||
roleName = roleData['nama_role'].toString();
|
||||
} else if (roleData.containsKey('nama_role')) {
|
||||
roleName = roleData['nama_role'].toString();
|
||||
} else if (roleData.containsKey('role_name')) {
|
||||
roleName = roleData['role_name'].toString();
|
||||
}
|
||||
|
||||
if (roleName != null) {
|
||||
debugPrint('Found role name in roles table: $roleName');
|
||||
return roleName;
|
||||
}
|
||||
|
||||
// Jika tidak ada nama kolom yang cocok, tampilkan kolom yang tersedia
|
||||
debugPrint(
|
||||
'Available columns in roles table: ${roleData.keys.join(', ')}',
|
||||
);
|
||||
}
|
||||
|
||||
// Lihat data lengkap tabel untuk troubleshooting
|
||||
debugPrint('Getting all roles data for troubleshooting');
|
||||
final allRoles = await client.from('roles').select('*').limit(5);
|
||||
|
||||
debugPrint('All roles table data (up to 5 rows): $allRoles');
|
||||
|
||||
// Hardcoded fallback berdasarkan UUID roleId yang dilihat dari data
|
||||
debugPrint('Using hardcoded fallback for role_id: $roleId');
|
||||
if (roleId == 'bb5360d5-8fd0-404e-8f6f-71ec4d8ad0ae') return 'WARGA';
|
||||
if (roleId == '38a8a23c-1873-4033-b977-3293247903b') {
|
||||
return 'PETUGAS_BUMDES';
|
||||
}
|
||||
if (roleId == '8b1af754-0866-4e12-a9d8-da8ed31bec15') {
|
||||
return 'PETUGAS_MITRA';
|
||||
}
|
||||
|
||||
// Default fallback jika role_id tidak dikenali
|
||||
debugPrint('Unrecognized role_id: $roleId, defaulting to WARGA');
|
||||
return 'WARGA';
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching role name: $e');
|
||||
return 'WARGA'; // Default fallback
|
||||
}
|
||||
}
|
||||
|
||||
// Metode untuk mendapatkan nama lengkap dari tabel warga_desa berdasarkan user_id
|
||||
Future<String?> getUserFullName() async {
|
||||
final user = currentUser;
|
||||
if (user == null) {
|
||||
debugPrint('No current user found when getting full name');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
debugPrint('Fetching nama_lengkap for user_id: ${user.id}');
|
||||
|
||||
// Coba ambil nama lengkap dari tabel warga_desa
|
||||
final userData =
|
||||
await client
|
||||
.from('warga_desa')
|
||||
.select('nama_lengkap')
|
||||
.eq('user_id', user.id)
|
||||
.maybeSingle();
|
||||
|
||||
debugPrint('User data from warga_desa table: $userData');
|
||||
|
||||
// Jika berhasil mendapatkan data
|
||||
if (userData != null && userData.containsKey('nama_lengkap')) {
|
||||
final namaLengkap = userData['nama_lengkap']?.toString();
|
||||
if (namaLengkap != null && namaLengkap.isNotEmpty) {
|
||||
debugPrint('Found nama_lengkap: $namaLengkap');
|
||||
return namaLengkap;
|
||||
}
|
||||
}
|
||||
|
||||
// Jika tidak ada data di warga_desa, coba cek struktur tabel untuk troubleshooting
|
||||
debugPrint('Checking warga_desa table structure');
|
||||
final tableData =
|
||||
await client.from('warga_desa').select('*').limit(1).maybeSingle();
|
||||
|
||||
if (tableData != null) {
|
||||
debugPrint(
|
||||
'Available columns in warga_desa table: ${tableData.keys.join(', ')}',
|
||||
);
|
||||
} else {
|
||||
debugPrint('No data found in warga_desa table');
|
||||
}
|
||||
|
||||
// Fallback ke data dari Supabase Auth
|
||||
final userMetadata = user.userMetadata;
|
||||
if (userMetadata != null) {
|
||||
if (userMetadata.containsKey('full_name')) {
|
||||
return userMetadata['full_name']?.toString();
|
||||
}
|
||||
if (userMetadata.containsKey('name')) {
|
||||
return userMetadata['name']?.toString();
|
||||
}
|
||||
}
|
||||
|
||||
// Gunakan email jika nama tidak ditemukan
|
||||
return user.email?.split('@').first ?? 'Pengguna Warga';
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching user full name: $e');
|
||||
return 'Pengguna Warga'; // Default fallback
|
||||
}
|
||||
}
|
||||
|
||||
// Metode untuk mendapatkan avatar dari tabel warga_desa berdasarkan user_id
|
||||
Future<String?> getUserAvatar() async {
|
||||
final user = currentUser;
|
||||
if (user == null) {
|
||||
debugPrint('No current user found when getting avatar');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
debugPrint('Fetching avatar for user_id: ${user.id}');
|
||||
|
||||
// Coba ambil avatar dari tabel warga_desa
|
||||
final userData =
|
||||
await client
|
||||
.from('warga_desa')
|
||||
.select('avatar')
|
||||
.eq('user_id', user.id)
|
||||
.maybeSingle();
|
||||
|
||||
debugPrint('Avatar data from warga_desa table: $userData');
|
||||
|
||||
// Jika berhasil mendapatkan data
|
||||
if (userData != null && userData.containsKey('avatar')) {
|
||||
final avatarUrl = userData['avatar']?.toString();
|
||||
if (avatarUrl != null && avatarUrl.isNotEmpty) {
|
||||
debugPrint('Found avatar URL: $avatarUrl');
|
||||
return avatarUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback ke data dari Supabase Auth
|
||||
final userMetadata = user.userMetadata;
|
||||
if (userMetadata != null && userMetadata.containsKey('avatar_url')) {
|
||||
return userMetadata['avatar_url']?.toString();
|
||||
}
|
||||
|
||||
return null; // No avatar found
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching user avatar: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Metode untuk mendapatkan email pengguna
|
||||
Future<String?> getUserEmail() async {
|
||||
final user = currentUser;
|
||||
if (user == null) {
|
||||
debugPrint('No current user found when getting email');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Email ada di data user Supabase Auth
|
||||
return user.email;
|
||||
}
|
||||
|
||||
// Metode untuk mendapatkan NIK dari tabel warga_desa berdasarkan user_id
|
||||
Future<String?> getUserNIK() async {
|
||||
final user = currentUser;
|
||||
if (user == null) {
|
||||
debugPrint('No current user found when getting NIK');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
debugPrint('Fetching NIK for user_id: ${user.id}');
|
||||
|
||||
// Coba ambil NIK dari tabel warga_desa
|
||||
final userData =
|
||||
await client
|
||||
.from('warga_desa')
|
||||
.select('nik')
|
||||
.eq('user_id', user.id)
|
||||
.maybeSingle();
|
||||
|
||||
// Jika berhasil mendapatkan data
|
||||
if (userData != null && userData.containsKey('nik')) {
|
||||
final nik = userData['nik']?.toString();
|
||||
if (nik != null && nik.isNotEmpty) {
|
||||
debugPrint('Found NIK: $nik');
|
||||
return nik;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback ke data dari metadata
|
||||
final userMetadata = user.userMetadata;
|
||||
if (userMetadata != null && userMetadata.containsKey('nik')) {
|
||||
return userMetadata['nik']?.toString();
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching user NIK: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Metode untuk mendapatkan nomor telepon dari tabel warga_desa berdasarkan user_id
|
||||
Future<String?> getUserPhone() async {
|
||||
final user = currentUser;
|
||||
if (user == null) {
|
||||
debugPrint('No current user found when getting phone');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
debugPrint('Fetching phone for user_id: ${user.id}');
|
||||
|
||||
// Coba ambil nomor telepon dari tabel warga_desa
|
||||
final userData =
|
||||
await client
|
||||
.from('warga_desa')
|
||||
.select('nomor_telepon, no_telepon, phone')
|
||||
.eq('user_id', user.id)
|
||||
.maybeSingle();
|
||||
|
||||
// Jika berhasil mendapatkan data, cek beberapa kemungkinan nama kolom
|
||||
if (userData != null) {
|
||||
if (userData.containsKey('nomor_telepon')) {
|
||||
final phone = userData['nomor_telepon']?.toString();
|
||||
if (phone != null && phone.isNotEmpty) return phone;
|
||||
}
|
||||
|
||||
if (userData.containsKey('no_telepon')) {
|
||||
final phone = userData['no_telepon']?.toString();
|
||||
if (phone != null && phone.isNotEmpty) return phone;
|
||||
}
|
||||
|
||||
if (userData.containsKey('phone')) {
|
||||
final phone = userData['phone']?.toString();
|
||||
if (phone != null && phone.isNotEmpty) return phone;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback ke data dari Supabase Auth
|
||||
final userMetadata = user.userMetadata;
|
||||
if (userMetadata != null) {
|
||||
if (userMetadata.containsKey('phone')) {
|
||||
return userMetadata['phone']?.toString();
|
||||
}
|
||||
if (userMetadata.containsKey('phone_number')) {
|
||||
return userMetadata['phone_number']?.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching user phone: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Metode untuk mendapatkan alamat dari tabel warga_desa berdasarkan user_id
|
||||
Future<String?> getUserAddress() async {
|
||||
final user = currentUser;
|
||||
if (user == null) {
|
||||
debugPrint('No current user found when getting address');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
debugPrint('Fetching address for user_id: ${user.id}');
|
||||
|
||||
// Coba ambil alamat dari tabel warga_desa
|
||||
final userData =
|
||||
await client
|
||||
.from('warga_desa')
|
||||
.select('alamat')
|
||||
.eq('user_id', user.id)
|
||||
.maybeSingle();
|
||||
|
||||
// Jika berhasil mendapatkan data
|
||||
if (userData != null && userData.containsKey('alamat')) {
|
||||
final address = userData['alamat']?.toString();
|
||||
if (address != null && address.isNotEmpty) {
|
||||
debugPrint('Found address: $address');
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback ke data dari Supabase Auth
|
||||
final userMetadata = user.userMetadata;
|
||||
if (userMetadata != null && userMetadata.containsKey('address')) {
|
||||
return userMetadata['address']?.toString();
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching user address: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Mendapatkan data sewa_aset berdasarkan status (misal: MENUNGGU PEMBAYARAN, PEMBAYARANAN DENDA)
|
||||
Future<List<Map<String, dynamic>>> getSewaAsetByStatus(
|
||||
List<String> statuses,
|
||||
) async {
|
||||
final user = currentUser;
|
||||
if (user == null) {
|
||||
debugPrint('No current user found when getting sewa_aset by status');
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
debugPrint(
|
||||
'Fetching sewa_aset for user_id: \\${user.id} with statuses: \\${statuses.join(', ')}',
|
||||
);
|
||||
// Supabase expects the IN filter as a comma-separated string in parentheses
|
||||
final statusString = '(${statuses.map((s) => '"$s"').join(',')})';
|
||||
final response = await client
|
||||
.from('sewa_aset')
|
||||
.select('*')
|
||||
.eq('user_id', user.id)
|
||||
.filter('status', 'in', statusString);
|
||||
debugPrint('Fetched sewa_aset count: \\${response.length}');
|
||||
// Pastikan response adalah List
|
||||
if (response is List) {
|
||||
return response
|
||||
.map<Map<String, dynamic>>(
|
||||
(item) => Map<String, dynamic>.from(item),
|
||||
)
|
||||
.toList();
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching sewa_aset by status: \\${e.toString()}');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
187
lib/app/data/providers/pesanan_provider.dart
Normal file
187
lib/app/data/providers/pesanan_provider.dart
Normal file
@ -0,0 +1,187 @@
|
||||
import 'package:bumrent_app/app/data/models/aset_model.dart';
|
||||
import 'package:bumrent_app/app/data/models/pesanan_model.dart';
|
||||
import 'package:bumrent_app/app/data/models/satuan_waktu_model.dart';
|
||||
import 'package:bumrent_app/app/data/providers/auth_provider.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
class PesananProvider {
|
||||
final SupabaseClient _supabase = Supabase.instance.client;
|
||||
final _tableName = 'pesanan';
|
||||
|
||||
Future<List<PesananModel>> getPesananByUserId(String userId) async {
|
||||
try {
|
||||
final response = await _supabase
|
||||
.from(_tableName)
|
||||
.select('*, aset(nama)')
|
||||
.eq('user_id', userId)
|
||||
.order('created_at', ascending: false);
|
||||
|
||||
final List<PesananModel> pesananList = [];
|
||||
for (final item in response) {
|
||||
final pesanan = PesananModel.fromJson(item);
|
||||
|
||||
// Attach the asset name
|
||||
if (item['aset'] != null) {
|
||||
pesanan.namaAset = item['aset']['nama'];
|
||||
}
|
||||
|
||||
// Get and attach satuan waktu name
|
||||
final satuanWaktu = await getSatuanWaktuById(pesanan.satuanWaktuId);
|
||||
if (satuanWaktu != null) {
|
||||
pesanan.namaSatuanWaktu = satuanWaktu.namaSatuanWaktu;
|
||||
}
|
||||
|
||||
pesananList.add(pesanan);
|
||||
}
|
||||
|
||||
return pesananList;
|
||||
} catch (e) {
|
||||
print('Error getting pesanan by user ID: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<PesananModel>> getAllPesanan() async {
|
||||
try {
|
||||
final response = await _supabase
|
||||
.from(_tableName)
|
||||
.select('*, aset(nama), auth_users(full_name)')
|
||||
.order('created_at', ascending: false);
|
||||
|
||||
final List<PesananModel> pesananList = [];
|
||||
for (final item in response) {
|
||||
final pesanan = PesananModel.fromJson(item);
|
||||
|
||||
// Attach the asset name
|
||||
if (item['aset'] != null) {
|
||||
pesanan.namaAset = item['aset']['nama'];
|
||||
}
|
||||
|
||||
// Attach the user name
|
||||
if (item['auth_users'] != null) {
|
||||
pesanan.namaUser = item['auth_users']['full_name'];
|
||||
}
|
||||
|
||||
// Get and attach satuan waktu name
|
||||
final satuanWaktu = await getSatuanWaktuById(pesanan.satuanWaktuId);
|
||||
if (satuanWaktu != null) {
|
||||
pesanan.namaSatuanWaktu = satuanWaktu.namaSatuanWaktu;
|
||||
}
|
||||
|
||||
pesananList.add(pesanan);
|
||||
}
|
||||
|
||||
return pesananList;
|
||||
} catch (e) {
|
||||
print('Error getting all pesanan: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Future<PesananModel?> getPesananById(String id) async {
|
||||
try {
|
||||
final response =
|
||||
await _supabase
|
||||
.from(_tableName)
|
||||
.select('*, aset(nama), auth_users(full_name)')
|
||||
.eq('id', id)
|
||||
.single();
|
||||
|
||||
final pesanan = PesananModel.fromJson(response);
|
||||
|
||||
// Attach the asset name
|
||||
if (response['aset'] != null) {
|
||||
pesanan.namaAset = response['aset']['nama'];
|
||||
}
|
||||
|
||||
// Attach the user name
|
||||
if (response['auth_users'] != null) {
|
||||
pesanan.namaUser = response['auth_users']['full_name'];
|
||||
}
|
||||
|
||||
// Get and attach satuan waktu name
|
||||
final satuanWaktu = await getSatuanWaktuById(pesanan.satuanWaktuId);
|
||||
if (satuanWaktu != null) {
|
||||
pesanan.namaSatuanWaktu = satuanWaktu.namaSatuanWaktu;
|
||||
}
|
||||
|
||||
return pesanan;
|
||||
} catch (e) {
|
||||
print('Error getting pesanan by ID: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> createPesanan({
|
||||
required String asetId,
|
||||
required String satuanWaktuId,
|
||||
required String userId,
|
||||
required DateTime tanggalPemesanan,
|
||||
required String jamPemesanan,
|
||||
required int durasi,
|
||||
required int totalHarga,
|
||||
}) async {
|
||||
try {
|
||||
final response =
|
||||
await _supabase
|
||||
.from(_tableName)
|
||||
.insert({
|
||||
'aset_id': asetId,
|
||||
'satuan_waktu_id': satuanWaktuId,
|
||||
'user_id': userId,
|
||||
'status': 'pending',
|
||||
'tanggal_pemesanan':
|
||||
tanggalPemesanan.toIso8601String().split('T')[0],
|
||||
'jam_pemesanan': jamPemesanan,
|
||||
'durasi': durasi,
|
||||
'total_harga': totalHarga,
|
||||
})
|
||||
.select('id')
|
||||
.single();
|
||||
|
||||
return response['id'];
|
||||
} catch (e) {
|
||||
print('Error creating pesanan: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> updatePesananStatus(String id, String status) async {
|
||||
try {
|
||||
await _supabase
|
||||
.from(_tableName)
|
||||
.update({
|
||||
'status': status,
|
||||
'updated_at': DateTime.now().toIso8601String(),
|
||||
})
|
||||
.eq('id', id);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error updating pesanan status: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> deletePesanan(String id) async {
|
||||
try {
|
||||
await _supabase.from(_tableName).delete().eq('id', id);
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error deleting pesanan: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<SatuanWaktuModel?> getSatuanWaktuById(String id) async {
|
||||
try {
|
||||
final response =
|
||||
await _supabase.from('satuan_waktu').select().eq('id', id).single();
|
||||
return SatuanWaktuModel.fromJson(response);
|
||||
} catch (e) {
|
||||
print('Error getting satuan waktu by ID: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
1
lib/app/data/providers/supabase_provider.dart
Normal file
1
lib/app/data/providers/supabase_provider.dart
Normal file
@ -0,0 +1 @@
|
||||
|
1
lib/app/data/repositories/rental_booking_repository.dart
Normal file
1
lib/app/data/repositories/rental_booking_repository.dart
Normal file
@ -0,0 +1 @@
|
||||
|
1
lib/app/data/repositories/rental_item_repository.dart
Normal file
1
lib/app/data/repositories/rental_item_repository.dart
Normal file
@ -0,0 +1 @@
|
||||
|
1
lib/app/data/repositories/user_repository.dart
Normal file
1
lib/app/data/repositories/user_repository.dart
Normal file
@ -0,0 +1 @@
|
||||
|
Reference in New Issue
Block a user