feat: Implement tenant selection logic and load saved tenant from local storage

This commit is contained in:
Vaibhav Surve 2025-09-25 11:27:03 +05:30
parent 53fefbba50
commit 1900e944e5
4 changed files with 130 additions and 71 deletions

View File

@ -1,6 +1,8 @@
import 'dart:convert';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/app_logger.dart';
import 'package:marco/helpers/services/tenant_service.dart'; import 'package:marco/helpers/services/tenant_service.dart';
import 'package:marco/helpers/services/storage/local_storage.dart';
import 'package:marco/model/tenant/tenant_list_model.dart'; import 'package:marco/model/tenant/tenant_list_model.dart';
import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart';
@ -13,18 +15,36 @@ class TenantSelectionController extends GetxController {
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
loadTenants(); _checkExistingTenant();
}
/// Check if a tenant was previously selected
Future<void> _checkExistingTenant() async {
try {
final savedTenant = await TenantService.loadSavedTenant();
if (savedTenant != null) {
// Tenant already selected go to dashboard
Get.offAllNamed('/dashboard');
} else {
// No tenant saved load from API
await loadTenants();
}
} catch (e, st) {
logSafe("❌ Error checking saved tenant",
level: LogLevel.error, error: e, stackTrace: st);
await loadTenants();
}
} }
/// Load tenants from API /// Load tenants from API
Future<void> loadTenants() async { Future<void> loadTenants() async {
try {
isLoading.value = true; isLoading.value = true;
try {
final data = await _tenantService.getTenants(); final data = await _tenantService.getTenants();
if (data != null) { if (data != null && data.isNotEmpty) {
tenants.value = data.map((e) => Tenant.fromJson(e)).toList(); tenants.value = data.map((e) => Tenant.fromJson(e)).toList();
// Automatically select if only one tenant // Auto-select if only one tenant
if (tenants.length == 1) { if (tenants.length == 1) {
await onTenantSelected(tenants.first.id); await onTenantSelected(tenants.first.id);
} }
@ -35,37 +55,34 @@ class TenantSelectionController extends GetxController {
} catch (e, st) { } catch (e, st) {
logSafe("❌ Exception in loadTenants", logSafe("❌ Exception in loadTenants",
level: LogLevel.error, error: e, stackTrace: st); level: LogLevel.error, error: e, stackTrace: st);
tenants.clear();
} finally { } finally {
isLoading.value = false; isLoading.value = false;
} }
} }
/// Select tenant /// Handle tenant selection
Future<void> onTenantSelected(String tenantId) async { Future<void> onTenantSelected(String tenantId) async {
try {
isLoading.value = true; isLoading.value = true;
try {
final success = await _tenantService.selectTenant(tenantId); final success = await _tenantService.selectTenant(tenantId);
if (success) { if (success) {
logSafe("✅ Tenant selection successful: $tenantId"); final tenant = tenants.firstWhere((t) => t.id == tenantId);
// Store selected tenant in memory // Save selected tenant in TenantService and LocalStorage
TenantService.setSelectedTenant( TenantService.setSelectedTenant(tenant);
tenants.firstWhere((t) => t.id == tenantId)); await LocalStorage.saveString(
'selectedTenant', jsonEncode(tenant.toJson()));
// Navigate to dashboard/home // Navigate to dashboard
Get.offAllNamed('/dashboard'); Get.offAllNamed('/dashboard');
// Optional: show success snackbar
showAppSnackbar( showAppSnackbar(
title: "Success", title: "Success",
message: "Organization selected successfully.", message: "Organization selected successfully.",
type: SnackbarType.success, type: SnackbarType.success,
); );
} else { } else {
logSafe("❌ Tenant selection failed for: $tenantId",
level: LogLevel.warning);
// Show error snackbar
showAppSnackbar( showAppSnackbar(
title: "Error", title: "Error",
message: "Unable to select organization. Please try again.", message: "Unable to select organization. Please try again.",
@ -76,7 +93,6 @@ class TenantSelectionController extends GetxController {
logSafe("❌ Exception in onTenantSelected", logSafe("❌ Exception in onTenantSelected",
level: LogLevel.error, error: e, stackTrace: st); level: LogLevel.error, error: e, stackTrace: st);
// Show error snackbar for exception
showAppSnackbar( showAppSnackbar(
title: "Error", title: "Error",
message: "An unexpected error occurred while selecting organization.", message: "An unexpected error occurred while selecting organization.",

View File

@ -97,6 +97,22 @@ class TenantService implements ITenantService {
} }
} }
/// Load previously selected tenant from local storage
static Future<Tenant?> loadSavedTenant() async {
final jsonString = LocalStorage.getString('selectedTenant');
if (jsonString == null) return null;
try {
final tenantMap = jsonDecode(jsonString) as Map<String, dynamic>;
final tenant = Tenant.fromJson(tenantMap);
currentTenant = tenant;
return tenant;
} catch (e) {
logSafe("❌ Failed to load saved tenant: $e", level: LogLevel.warning);
return null;
}
}
@override @override
Future<bool> selectTenant(String tenantId, {bool hasRetried = false}) async { Future<bool> selectTenant(String tenantId, {bool hasRetried = false}) async {
try { try {

View File

@ -32,8 +32,9 @@ class Tenant {
contactName: json['contactName'] ?? '', contactName: json['contactName'] ?? '',
contactNumber: json['contactNumber'] ?? '', contactNumber: json['contactNumber'] ?? '',
logoImage: json['logoImage'] is String ? json['logoImage'] : null, logoImage: json['logoImage'] is String ? json['logoImage'] : null,
organizationSize: organizationSize: json['organizationSize'] is String
json['organizationSize'] is String ? json['organizationSize'] : null, ? json['organizationSize']
: null,
industry: json['industry'] != null industry: json['industry'] != null
? Industry.fromJson(json['industry']) ? Industry.fromJson(json['industry'])
: null, : null,
@ -42,6 +43,21 @@ class Tenant {
: null, : null,
); );
} }
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
'domainName': domainName,
'contactName': contactName,
'contactNumber': contactNumber,
'logoImage': logoImage,
'organizationSize': organizationSize,
'industry': industry?.toJson(),
'tenantStatus': tenantStatus?.toJson(),
};
}
} }
class Industry { class Industry {
@ -59,6 +75,13 @@ class Industry {
name: json['name'] ?? '', name: json['name'] ?? '',
); );
} }
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
};
}
} }
class TenantStatus { class TenantStatus {
@ -76,4 +99,11 @@ class TenantStatus {
name: json['name'] ?? '', name: json['name'] ?? '',
); );
} }
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
};
}
} }

View File

@ -165,7 +165,7 @@ class _BetaBadge extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.orangeAccent, color: Colors.orangeAccent,
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(5),
), ),
child: MyText( child: MyText(
'BETA', 'BETA',
@ -246,10 +246,13 @@ class _TenantCard extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Card( return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(5),
child: Card(
elevation: 3, elevation: 3,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(5),
), ),
margin: const EdgeInsets.only(bottom: 20), margin: const EdgeInsets.only(bottom: 20),
child: Padding( child: Padding(
@ -258,7 +261,7 @@ class _TenantCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(5),
child: Container( child: Container(
width: 60, width: 60,
height: 60, height: 60,
@ -286,21 +289,15 @@ class _TenantCard extends StatelessWidget {
], ],
), ),
), ),
InkWell( Icon(
onTap: onTap,
child: Container(
height: 60,
alignment: Alignment.center,
child: Icon(
Icons.arrow_forward_ios, Icons.arrow_forward_ios,
size: 24, size: 24,
color: Colors.red, color: Colors.red,
), ),
),
),
], ],
), ),
), ),
),
); );
} }
} }