Fix
This commit is contained in:
parent
31914224ba
commit
a1711cc0e0
File diff suppressed because one or more lines are too long
@ -21,7 +21,7 @@ import '../../presentation/screens/Masters/EndorsementType/endorsementList.dart'
|
||||
import '../../presentation/screens/Masters/VehicleType/vehicleList.dart';
|
||||
import '../../presentation/screens/StaffAttendance/attendanceAllDetails.dart';
|
||||
import '../../presentation/screens/StaffAttendance/individual_Attendance.dart';
|
||||
import '../../presentation/screens/UserManagement/Agent/agent.dart';
|
||||
import '../../presentation/screens/UserManagement/Agent/agent_details.dart';
|
||||
import '../../presentation/screens/UserManagement/Agent/agentList.dart';
|
||||
import '../../presentation/screens/UserManagement/POS/pos_list.dart';
|
||||
import '../../presentation/screens/UserManagement/Profile/profile_mobile.dart';
|
||||
@ -134,6 +134,14 @@ final GoRouter appRouter = GoRouter(
|
||||
builder: (context, state) => const AgentList(),
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
path: AppRoutes.agentDetailsParam,
|
||||
builder: (context, state) {
|
||||
final agentId = state.pathParameters['agentId'] ?? 'new';
|
||||
return AgentDetailsScreen(agentId: agentId);
|
||||
},
|
||||
),
|
||||
|
||||
// GoRoute(
|
||||
// path: '/agent/:id',
|
||||
// builder: (context, state) {
|
||||
|
||||
@ -22,6 +22,11 @@ class AppRoutes {
|
||||
static const String profile = '/profile';
|
||||
static const String agentLst = '/agentLst';
|
||||
static const agent = '/agent/:id';
|
||||
/// Partner details page: use [agentDetailsFor] with `'new'` or agent id.
|
||||
static const String agentDetailsParam = '/agentDetails/:agentId';
|
||||
|
||||
static String agentDetailsFor(String agentId) =>
|
||||
'/agentDetails/${Uri.encodeComponent(agentId)}';
|
||||
static const String staffLst = '/staffLst';
|
||||
static const staff = '/staff/:id';
|
||||
static const String salesExecutiveLst = '/salesExecutiveLst';
|
||||
|
||||
@ -915,13 +915,18 @@ class ApiService {
|
||||
}
|
||||
|
||||
// ----------------------------------- PAYOUT GRID ----------------------------------------------
|
||||
Future<Map<String, dynamic>> loadPayoutGrid({String? role, String? fileId}) async {
|
||||
Future<Map<String, dynamic>> loadPayoutGrid({
|
||||
String? role,
|
||||
String? fileId,
|
||||
String? loggedId,
|
||||
}) async {
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
|
||||
final roleTrimmed = role?.trim();
|
||||
final fileIdTrimmed = fileId?.trim();
|
||||
final loggedIdTrimmed = loggedId?.trim();
|
||||
final endpoint = Uri.parse('${Env.apiUrl}grid');
|
||||
|
||||
final queryParameters = <String, String>{};
|
||||
@ -931,6 +936,9 @@ class ApiService {
|
||||
if (fileIdTrimmed != null && fileIdTrimmed.isNotEmpty) {
|
||||
queryParameters['file_id'] = fileIdTrimmed;
|
||||
}
|
||||
if (loggedIdTrimmed != null && loggedIdTrimmed.isNotEmpty) {
|
||||
queryParameters['logged_id'] = loggedIdTrimmed;
|
||||
}
|
||||
final url = endpoint.replace(queryParameters: queryParameters);
|
||||
|
||||
final headers = {
|
||||
@ -1059,6 +1067,65 @@ class ApiService {
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchPartnerVehicleTypes() async {
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
final url = Uri.parse('${Env.apiUrl}agent/partnerVehicleTypeList');
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token' ?? '',
|
||||
'app-signature': Env.App_Signature,
|
||||
};
|
||||
return _makeGetRequest(url, headers);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> updateAgentVehicleRetention({
|
||||
required String agentId,
|
||||
required String vehicleTypeId,
|
||||
required String retentionRate,
|
||||
required String updatedBy,
|
||||
}) async {
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
final url = Uri.parse('${Env.apiUrl}agent/updateAgentVehicleRetention');
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token' ?? '',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': Env.App_Signature,
|
||||
};
|
||||
final body = {
|
||||
'agent_id': agentId,
|
||||
'vehicle_type_id': vehicleTypeId,
|
||||
'retention_rate': retentionRate,
|
||||
'updated_by': updatedBy,
|
||||
};
|
||||
return _makePostRequestJson(url, body, headers);
|
||||
}
|
||||
|
||||
/// Bulk upsert retention rows for an agent (Save all in retention table).
|
||||
Future<Map<String, dynamic>> saveAgentRetentionRatesBulk({
|
||||
required String agentId,
|
||||
required List<Map<String, dynamic>> retentionRates,
|
||||
required String updatedBy,
|
||||
}) async {
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
final url = Uri.parse('${Env.apiUrl}agent/saveAgentRetentionRatesBulk');
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token' ?? '',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': Env.App_Signature,
|
||||
};
|
||||
final body = {
|
||||
'agent_id': agentId,
|
||||
'updated_by': updatedBy,
|
||||
'retention_rates': retentionRates,
|
||||
};
|
||||
return _makePostRequestJson(url, body, headers);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> deleteAgentIncentiveFile(id) async {
|
||||
// print(_token);
|
||||
if (_token == null) {
|
||||
|
||||
@ -34,10 +34,12 @@ class Validators {
|
||||
return "Required";
|
||||
}
|
||||
|
||||
final emailRegex = r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$';
|
||||
final trimmed = value.trim();
|
||||
final emailRegex =
|
||||
r'^[a-zA-Z0-9](?:[a-zA-Z0-9._%+-]*[a-zA-Z0-9])?@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$';
|
||||
|
||||
if (!RegExp(emailRegex).hasMatch(value)) {
|
||||
return "Invalid $label"; // 👈 will show: "Invalid Email"
|
||||
if (!RegExp(emailRegex).hasMatch(trimmed)) {
|
||||
return "Invalid $label";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -83,6 +83,10 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
bool _isUpdating = false;
|
||||
String _retentionRate = '-';
|
||||
|
||||
/// Normalized vehicle type key → retention % from [partner_retention_rate] (via findAgent `retention_by_vehicle`).
|
||||
/// Also keys `id:<vehicle_type_id>` when the API returns `vehicle_type_id`.
|
||||
final Map<String, num> _retentionByVehicleKey = {};
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.dispose();
|
||||
@ -107,8 +111,16 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadRetentionRateFromToken();
|
||||
_fetch();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _bootstrapGrid());
|
||||
}
|
||||
|
||||
Future<void> _bootstrapGrid() async {
|
||||
await Future.wait([
|
||||
_loadRetentionRateFromToken(),
|
||||
_loadPartnerRetentionByVehicle(),
|
||||
]);
|
||||
if (!mounted) return;
|
||||
await _fetch();
|
||||
}
|
||||
|
||||
Future<void> _loadRetentionRateFromToken() async {
|
||||
@ -122,14 +134,17 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
|
||||
final retentionRate = data['retention_rate']?.toString();
|
||||
final loggedId = data['id']?.toString();
|
||||
if (retentionRate == null || retentionRate.trim().isEmpty) return;
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_loggedId = (loggedId == null || loggedId.trim().isEmpty)
|
||||
? null
|
||||
: loggedId.trim();
|
||||
_retentionRate = retentionRate.trim();
|
||||
if (retentionRate != null && retentionRate.trim().isNotEmpty) {
|
||||
_retentionRate = retentionRate.trim();
|
||||
} else {
|
||||
_retentionRate = '-';
|
||||
}
|
||||
_grid = _applyRetentionToGridRows(_grid);
|
||||
_filteredGrid = _applyRetentionToGridRows(_filteredGrid);
|
||||
});
|
||||
@ -139,6 +154,88 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
String _normalizeVehicleTypeKey(String raw) {
|
||||
return raw.toLowerCase().trim().replaceAll(RegExp(r'\s+'), ' ');
|
||||
}
|
||||
|
||||
/// Loads per–vehicle-type retention for the logged-in agent, or for Accounts with `?agent_id=` on grid URL.
|
||||
Future<void> _loadPartnerRetentionByVehicle() async {
|
||||
final appRole =
|
||||
(ref.read(userRoleProvider) ?? '').toString().trim().toLowerCase();
|
||||
String? agentPk;
|
||||
if (appRole == 'agent') {
|
||||
try {
|
||||
final token = await AuthService.getToken();
|
||||
if (token == null || token.isEmpty) return;
|
||||
final data = Jwt.parseJwt(token)['data'];
|
||||
if (data is Map) {
|
||||
agentPk = (data['id']?.toString() ?? '').trim();
|
||||
if (agentPk.isEmpty) agentPk = null;
|
||||
}
|
||||
} catch (_) {
|
||||
return;
|
||||
}
|
||||
} else if (appRole == 'accounts') {
|
||||
agentPk = Uri.base.queryParameters['agent_id']?.trim();
|
||||
if (agentPk != null && agentPk.isEmpty) agentPk = null;
|
||||
}
|
||||
|
||||
if (agentPk == null || agentPk.isEmpty) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_retentionByVehicleKey.clear();
|
||||
_grid = _applyRetentionToGridRows(_grid);
|
||||
_filteredGrid = _applyRetentionToGridRows(_filteredGrid);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final res = await _apiService.findSingleAgentData(agentPk);
|
||||
if ((res['status'] ?? '').toString().toLowerCase() != 'success' ||
|
||||
res['data'] == null) {
|
||||
return;
|
||||
}
|
||||
final data = Map<String, dynamic>.from(res['data'] as Map);
|
||||
final raw = data['retention_by_vehicle'] ?? data['retentionByVehicle'];
|
||||
final next = <String, num>{};
|
||||
if (raw is List) {
|
||||
for (final item in raw) {
|
||||
if (item is! Map) continue;
|
||||
final m = Map<String, dynamic>.from(item);
|
||||
final rate = _toNum(m['retention_rate'] ?? m['retentionRate']);
|
||||
if (rate == null) continue;
|
||||
final name = (m['vehicle_type'] ?? '').toString().trim();
|
||||
if (name.isNotEmpty) {
|
||||
next[_normalizeVehicleTypeKey(name)] = rate;
|
||||
}
|
||||
final vid =
|
||||
int.tryParse((m['vehicle_type_id'] ?? m['vehicleTypeId'] ?? '')
|
||||
.toString());
|
||||
if (vid != null) {
|
||||
next['id:$vid'] = rate;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_retentionByVehicleKey
|
||||
..clear()
|
||||
..addAll(next);
|
||||
_grid = _applyRetentionToGridRows(_grid);
|
||||
_filteredGrid = _applyRetentionToGridRows(_filteredGrid);
|
||||
});
|
||||
}
|
||||
} catch (_) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_retentionByVehicleKey.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String? _apiRoleFromAppRole(String? role) {
|
||||
if (role == null) return null;
|
||||
final r = role.trim();
|
||||
@ -194,9 +291,13 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
final loggedIdForGrid =
|
||||
(effectiveRole ?? '').toLowerCase() == 'agent' ? _loggedId : null;
|
||||
|
||||
final res = await _apiService.loadPayoutGrid(
|
||||
role: effectiveRole,
|
||||
fileId: effectiveFileId,
|
||||
loggedId: loggedIdForGrid,
|
||||
);
|
||||
if ((res['status'] ?? '').toString().toLowerCase() != 'success') {
|
||||
ToastHelper.showErrorToast(
|
||||
@ -352,7 +453,7 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
|
||||
setState(() {
|
||||
_filteredGrid = next;
|
||||
if (_showAddButton && !_hasAnyFilterSelection) {
|
||||
if (_showPartnerRetentionValues && !_hasAnyFilterSelection) {
|
||||
_filteredGrid = [];
|
||||
}
|
||||
_currentPage = 1;
|
||||
@ -398,33 +499,73 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
return num.tryParse(normalized);
|
||||
}
|
||||
|
||||
String _partnerValueFrom(dynamic baseValue) {
|
||||
num? _retentionPercentForGridRowPreview(Map<String, dynamic> row) {
|
||||
final vt = row['vehicle_type']?.toString().trim() ?? '';
|
||||
if (vt.isNotEmpty) {
|
||||
final byName = _retentionByVehicleKey[_normalizeVehicleTypeKey(vt)];
|
||||
if (byName != null) return byName;
|
||||
}
|
||||
final vid =
|
||||
int.tryParse(row['vehicle_type_id']?.toString() ?? '');
|
||||
if (vid != null) {
|
||||
final byId = _retentionByVehicleKey['id:$vid'];
|
||||
if (byId != null) return byId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Accounts preview: subtract loaded per–vehicle retention; ≤0 → '-'; no match → show base.
|
||||
String _partnerValueForRowPreview(Map<String, dynamic> row, dynamic baseValue) {
|
||||
final base = _toNum(baseValue);
|
||||
final retention = _toNum(_retentionRate);
|
||||
if (base == null || retention == null) return '-';
|
||||
if (base == null) return '-';
|
||||
final retention = _retentionPercentForGridRowPreview(row);
|
||||
if (retention == null) {
|
||||
if (base == base.roundToDouble()) return base.toInt().toString();
|
||||
return base
|
||||
.toStringAsFixed(2)
|
||||
.replaceFirst(RegExp(r'0+$'), '')
|
||||
.replaceFirst(RegExp(r'\.$'), '');
|
||||
}
|
||||
final result = base - retention;
|
||||
if (result <= 0) return '-';
|
||||
if (result == result.roundToDouble()) {
|
||||
return result.toInt().toString();
|
||||
}
|
||||
return result.toStringAsFixed(2).replaceFirst(RegExp(r'0+$'), '').replaceFirst(RegExp(r'\.$'), '');
|
||||
return result
|
||||
.toStringAsFixed(2)
|
||||
.replaceFirst(RegExp(r'0+$'), '')
|
||||
.replaceFirst(RegExp(r'\.$'), '');
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _applyRetentionToGridRows(
|
||||
List<Map<String, dynamic>> rows,
|
||||
) {
|
||||
if (!_showAddButton) {
|
||||
if (!_showPartnerRetentionValues) {
|
||||
return rows
|
||||
.map((row) => Map<String, dynamic>.from(row)
|
||||
..remove('partner_comp')
|
||||
..remove('partner_tp')
|
||||
..remove('partner_od'))
|
||||
.map(
|
||||
(row) => Map<String, dynamic>.from(row)
|
||||
..remove('partner_comp')
|
||||
..remove('partner_tp')
|
||||
..remove('partner_od'),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
// Partner (agent): API already applies retention on comp/tp/od when logged_id is sent.
|
||||
if (_showAddButton) {
|
||||
return rows.map((row) {
|
||||
final next = Map<String, dynamic>.from(row);
|
||||
next['partner_comp'] = next['comp'];
|
||||
next['partner_tp'] = next['tp'];
|
||||
next['partner_od'] = next['od'];
|
||||
return next;
|
||||
}).toList();
|
||||
}
|
||||
// Accounts + ?agent_id= preview: client-side using findAgent retention map.
|
||||
return rows.map((row) {
|
||||
final next = Map<String, dynamic>.from(row);
|
||||
next['partner_comp'] = _partnerValueFrom(next['comp']);
|
||||
next['partner_tp'] = _partnerValueFrom(next['tp']);
|
||||
next['partner_od'] = _partnerValueFrom(next['od']);
|
||||
next['partner_comp'] = _partnerValueForRowPreview(next, next['comp']);
|
||||
next['partner_tp'] = _partnerValueForRowPreview(next, next['tp']);
|
||||
next['partner_od'] = _partnerValueForRowPreview(next, next['od']);
|
||||
return next;
|
||||
}).toList();
|
||||
}
|
||||
@ -440,7 +581,16 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
return role == 'agent';
|
||||
}
|
||||
|
||||
bool get _showPartnerRetentionValues => _showAddButton;
|
||||
/// Partner (agent) login, or Accounts opening grid with `?agent_id=` to preview that partner’s payouts.
|
||||
bool get _accountsAgentPreview {
|
||||
final role = (ref.watch(userRoleProvider) ?? '').toString().trim().toLowerCase();
|
||||
if (role != 'accounts') return false;
|
||||
final aid = Uri.base.queryParameters['agent_id']?.trim();
|
||||
return aid != null && aid.isNotEmpty;
|
||||
}
|
||||
|
||||
bool get _showPartnerRetentionValues =>
|
||||
_showAddButton || _accountsAgentPreview;
|
||||
bool get _showCompColumnForAgent =>
|
||||
!_showAddButton ||
|
||||
_selectedPlanTypeValue == 'comp';
|
||||
@ -807,7 +957,7 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
icon: Icons.search,
|
||||
message: 'Search',
|
||||
onTap: () {
|
||||
if (_showAddButton && !_hasAnyFilterSelection) {
|
||||
if (_showPartnerRetentionValues && !_hasAnyFilterSelection) {
|
||||
ToastHelper.showInfoToast(
|
||||
context,
|
||||
'Please select at least one filter to view/export data.',
|
||||
@ -975,7 +1125,7 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
showCompColumn: _showCompColumnForAgent,
|
||||
showTpColumn: _showTpColumnForAgent,
|
||||
showOdColumn: _showOdColumnForAgent,
|
||||
showPartnerCompValue: _showAddButton,
|
||||
showPartnerCompValue: _showPartnerRetentionValues,
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -1139,7 +1289,7 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
onTap: _isLoading
|
||||
? () {}
|
||||
: () async {
|
||||
if (_showAddButton && !_hasAnyFilterSelection) {
|
||||
if (_showPartnerRetentionValues && !_hasAnyFilterSelection) {
|
||||
if (mounted) {
|
||||
ToastHelper.showInfoToast(
|
||||
context,
|
||||
@ -1157,6 +1307,8 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
(roleLc == 'manager' || roleLc == 'accounts')
|
||||
? fileIdFromQuery
|
||||
: null;
|
||||
final previewAgentId =
|
||||
queryParams['agent_id']?.trim();
|
||||
await _apiService.downloadGridExcel(
|
||||
role: role,
|
||||
fileId: fileIdToSend,
|
||||
@ -1166,7 +1318,9 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
rto: _selectedRto,
|
||||
planType: _selectedPlanTypeValue,
|
||||
search: _searchController.text.trim(),
|
||||
loggedId: _loggedId,
|
||||
loggedId: previewAgentId != null && previewAgentId.isNotEmpty
|
||||
? previewAgentId
|
||||
: _loggedId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
|
||||
@ -15,7 +15,6 @@ import '../../../themes/indicators/filter_btn.dart';
|
||||
import '../../../themes/indicators/search_field_theme.dart';
|
||||
import '../../../themes/indicators/text_field_theme.dart';
|
||||
import '../../../widgets/custom_action_popup.dart';
|
||||
import 'agent.dart';
|
||||
import 'agentIncentiveFile.dart';
|
||||
|
||||
class AgentList extends ConsumerStatefulWidget {
|
||||
@ -163,7 +162,7 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
Navigator.pop(context);
|
||||
print('EDIT - ${data['id']}');
|
||||
dynamic id = data['id'];
|
||||
context.go('/agent/$id');
|
||||
context.go(AppRoutes.agentDetailsFor(id.toString()));
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -177,20 +176,6 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
];
|
||||
}
|
||||
|
||||
Future<void> showAgent({required String id}) {
|
||||
print('showAgent : $id');
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => Agent(
|
||||
id: id,
|
||||
onSubmit: (value) {
|
||||
debugPrint("New Claims: $value");
|
||||
refresh();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
managerId = ref.watch(managerIdProvider);
|
||||
@ -352,8 +337,7 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
// context.go('/agent/create');
|
||||
showAgent(id: 'Create');
|
||||
context.go(AppRoutes.agentDetailsFor('new'));
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
@ -620,8 +604,7 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
print('EDITStaff - ${item['id']}');
|
||||
selected_id = item['id'];
|
||||
|
||||
showAgent(id: selected_id);
|
||||
// context.go('/agent/$selected_id');
|
||||
context.go(AppRoutes.agentDetailsFor(selected_id.toString()));
|
||||
},
|
||||
splashRadius: 28,
|
||||
hoverColor: Colors.black12,
|
||||
|
||||
1261
lib/presentation/screens/UserManagement/Agent/agent_details.dart
Normal file
1261
lib/presentation/screens/UserManagement/Agent/agent_details.dart
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user