FIX_RATE
This commit is contained in:
parent
b3884f32c4
commit
650536745d
File diff suppressed because one or more lines are too long
@ -5,8 +5,8 @@ class Env {
|
||||
);
|
||||
static const String apiUrl = String.fromEnvironment(
|
||||
'API_URL',
|
||||
// defaultValue: 'https://partner.nhanceindia.in/partner_api/api/', /* Live build (enable index.html line 18) */
|
||||
defaultValue: 'https://venbait.in/nhance/partner/dev/api/', /* Test build (enable index.html line 19) */
|
||||
//defaultValue: 'https://partner.nhanceindia.in/partner_api/api/', /* Live build (enable index.html line 18) */
|
||||
defaultValue: 'https://venbait.in/nhance/partner/dev/api/', /* Test build (enable index.html line 19) */
|
||||
// defaultValue: 'http://localhost/nhance_partner_be/', /* localhost build (enable index.html line 19) */
|
||||
);
|
||||
// static const String baseUrl = String.fromEnvironment(
|
||||
|
||||
@ -918,6 +918,12 @@ class ApiService {
|
||||
Future<Map<String, dynamic>> loadPayoutGrid({
|
||||
String? role,
|
||||
String? fileId,
|
||||
String? insurer,
|
||||
String? vehicleType,
|
||||
String? segment,
|
||||
String? rto,
|
||||
String? planType,
|
||||
String? search,
|
||||
String? loggedId,
|
||||
}) async {
|
||||
if (_token == null) {
|
||||
@ -926,21 +932,47 @@ class ApiService {
|
||||
|
||||
final roleTrimmed = role?.trim();
|
||||
final fileIdTrimmed = fileId?.trim();
|
||||
final insurerTrimmed = insurer?.trim();
|
||||
final vehicleTypeTrimmed = vehicleType?.trim();
|
||||
final segmentTrimmed = segment?.trim();
|
||||
final rtoTrimmed = rto?.trim();
|
||||
final planTypeTrimmed = planType?.trim();
|
||||
final searchTrimmed = search?.trim();
|
||||
final loggedIdTrimmed = loggedId?.trim();
|
||||
final endpoint = Uri.parse('${Env.apiUrl}grid');
|
||||
final roleLower = roleTrimmed?.toLowerCase();
|
||||
|
||||
final queryParameters = <String, String>{};
|
||||
if (roleTrimmed != null && roleTrimmed.isNotEmpty) {
|
||||
queryParameters['role'] = roleTrimmed;
|
||||
}
|
||||
if (fileIdTrimmed != null && fileIdTrimmed.isNotEmpty) {
|
||||
if (roleLower != 'agent' &&
|
||||
fileIdTrimmed != null &&
|
||||
fileIdTrimmed.isNotEmpty) {
|
||||
queryParameters['file_id'] = fileIdTrimmed;
|
||||
}
|
||||
if (insurerTrimmed != null && insurerTrimmed.isNotEmpty) {
|
||||
queryParameters['insurer'] = insurerTrimmed;
|
||||
}
|
||||
if (vehicleTypeTrimmed != null && vehicleTypeTrimmed.isNotEmpty) {
|
||||
queryParameters['vehicle_type'] = vehicleTypeTrimmed;
|
||||
}
|
||||
if (segmentTrimmed != null && segmentTrimmed.isNotEmpty) {
|
||||
queryParameters['segment'] = segmentTrimmed;
|
||||
}
|
||||
if (rtoTrimmed != null && rtoTrimmed.isNotEmpty) {
|
||||
queryParameters['rto'] = rtoTrimmed;
|
||||
}
|
||||
if (planTypeTrimmed != null && planTypeTrimmed.isNotEmpty) {
|
||||
queryParameters['plan_type'] = planTypeTrimmed;
|
||||
}
|
||||
if (searchTrimmed != null && searchTrimmed.isNotEmpty) {
|
||||
queryParameters['search'] = searchTrimmed;
|
||||
}
|
||||
if (loggedIdTrimmed != null && loggedIdTrimmed.isNotEmpty) {
|
||||
queryParameters['logged_id'] = loggedIdTrimmed;
|
||||
}
|
||||
final url = endpoint.replace(queryParameters: queryParameters);
|
||||
|
||||
final headers = {
|
||||
'Authorization': 'Bearer ${_token ?? ''}',
|
||||
'app-signature': Env.App_Signature,
|
||||
@ -1050,6 +1082,96 @@ class ApiService {
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<void> downloadAgentRetentionRateExcel() async {
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
|
||||
final url = Uri.parse('${Env.apiUrl}agent/exportRetentionRateExcel');
|
||||
// final url = Uri.parse('http://localhost/nhance_partner_be/agent/exportRetentionRateExcel');
|
||||
final headers = {
|
||||
'Authorization': 'Bearer ${_token ?? ''}',
|
||||
'app-signature': Env.App_Signature,
|
||||
};
|
||||
|
||||
final response = await _makeGethttpRequest(url, headers);
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Failed to download retention rate excel');
|
||||
}
|
||||
|
||||
final contentType = response.headers['content-type'] ?? '';
|
||||
if (contentType.contains('application/json')) {
|
||||
throw Exception('No export data available');
|
||||
}
|
||||
|
||||
final blob = html.Blob([response.bodyBytes]);
|
||||
final blobUrl = html.Url.createObjectUrlFromBlob(blob);
|
||||
final fileName = extractFileName(
|
||||
response.headers['content-disposition'],
|
||||
'RentationRate.xlsx',
|
||||
);
|
||||
html.AnchorElement(href: blobUrl)
|
||||
..setAttribute('download', fileName)
|
||||
..click();
|
||||
html.Url.revokeObjectUrl(blobUrl);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> importAgentRetentionRateExcel({
|
||||
required PlatformFile file,
|
||||
}) async {
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
|
||||
final url = Uri.parse('${Env.apiUrl}agent/importRetentionRateExcel');
|
||||
// final url = Uri.parse('http://localhost/nhance_partner_be/agent/importRetentionRateExcel');
|
||||
try {
|
||||
final request = http.MultipartRequest('POST', url);
|
||||
request.headers.addAll({
|
||||
'Authorization': 'Bearer ${_token ?? ''}',
|
||||
'app-signature': Env.App_Signature,
|
||||
});
|
||||
|
||||
if (file.bytes == null) {
|
||||
throw Exception('Could not read selected file');
|
||||
}
|
||||
|
||||
request.files.add(
|
||||
http.MultipartFile.fromBytes(
|
||||
'retention_excel',
|
||||
file.bytes!,
|
||||
filename: file.name,
|
||||
),
|
||||
);
|
||||
|
||||
final streamedResponse = await request.send();
|
||||
final responseBody = await streamedResponse.stream.bytesToString();
|
||||
|
||||
if (streamedResponse.statusCode == 401 ||
|
||||
streamedResponse.statusCode == 403) {
|
||||
await clearLocalStorageAndRedirect();
|
||||
return {'status': 'error', 'message': 'Session expired'};
|
||||
}
|
||||
|
||||
if (responseBody.trim().isEmpty) {
|
||||
return {
|
||||
'status': 'error',
|
||||
'message': 'Empty response from server',
|
||||
'code': streamedResponse.statusCode,
|
||||
};
|
||||
}
|
||||
|
||||
final decoded = jsonDecode(responseBody);
|
||||
if (decoded is Map<String, dynamic>) {
|
||||
return decoded;
|
||||
}
|
||||
|
||||
return {'status': 'error', 'message': 'Unexpected response format'};
|
||||
} catch (e) {
|
||||
return {'status': 'error', 'message': e.toString()};
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> findSingleAgentData(id) async {
|
||||
// print(_token);
|
||||
if (_token == null) {
|
||||
|
||||
@ -24,13 +24,19 @@ Future<void> _restoreManagerId(WidgetRef ref) async {
|
||||
'attendanceIndvStaffName',
|
||||
);
|
||||
|
||||
if (savedManagerId != null && savedUserId != null) {
|
||||
ref.read(managerIdProvider.notifier).state = savedManagerId;
|
||||
// Partners (agents) often have no manager_id in JWT, so never gate role/userId
|
||||
// restore on managerId — without role, grid `?role=Agent&logged_id=` is omitted and
|
||||
// the payout grid endpoint misbehaves for agent logins after app restart.
|
||||
if (savedUserId != null) {
|
||||
ref.read(userIdProvider.notifier).state = savedUserId;
|
||||
ref.read(userRoleProvider.notifier).state = savedUserRole;
|
||||
|
||||
print("Manager ID restored: $savedManagerId");
|
||||
print("User ID restored: $savedUserId");
|
||||
}
|
||||
if (savedManagerId != null) {
|
||||
ref.read(managerIdProvider.notifier).state = savedManagerId;
|
||||
print("Manager ID restored: $savedManagerId");
|
||||
}
|
||||
if (savedUserRole != null && savedUserRole.trim().isNotEmpty) {
|
||||
ref.read(userRoleProvider.notifier).state = savedUserRole;
|
||||
print("Role restored: $savedUserRole");
|
||||
}
|
||||
|
||||
|
||||
@ -554,9 +554,9 @@ class _gridViewScreenState extends ConsumerState<gridViewScreen> {
|
||||
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'];
|
||||
next['partner_comp'] = next['oa'] ?? next['comp'];
|
||||
next['partner_tp'] = next['ob'] ?? next['tp'];
|
||||
next['partner_od'] = next['oc'] ?? next['od'];
|
||||
return next;
|
||||
}).toList();
|
||||
}
|
||||
@ -1611,9 +1611,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(
|
||||
@ -2443,9 +2447,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') {
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
import '../../../../core/routing/routes.dart';
|
||||
import '../../../../core/services/api_service.dart';
|
||||
import '../../../../data/utils/Pagination.dart';
|
||||
import '../../../../data/utils/toastNotification.dart';
|
||||
import '../../../layouts/main_layout.dart';
|
||||
import '../../../layouts/responsive_layout.dart';
|
||||
import '../../../providers/manager_provider.dart';
|
||||
@ -34,6 +36,7 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
List<Map<String, dynamic>> originalData = [];
|
||||
List<Map<String, dynamic>> filteredData = [];
|
||||
bool isLoading = false;
|
||||
bool isRetentionImportLoading = false;
|
||||
dynamic sortedData;
|
||||
dynamic managerID;
|
||||
@override
|
||||
@ -110,9 +113,6 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
(item['sales_executive_name'] ?? '-').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['retention_rate'] ?? '-').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(isActiveStatus.contains(query.toLowerCase()));
|
||||
}).toList();
|
||||
});
|
||||
@ -155,6 +155,232 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _exportRetentionRateExcel() async {
|
||||
final proceed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (ctx) {
|
||||
return AlertDialog(
|
||||
title: const Text('Export Rentation Rate'),
|
||||
content: const Text(
|
||||
'The downloaded Excel will include input validation.\n\n'
|
||||
'Allowed values: only numbers from 0 to 100.\n'
|
||||
'Not allowed: negative values, values above 100, text/special characters.',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, false),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.pop(ctx, true),
|
||||
child: const Text('Download'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
if (proceed != true) return;
|
||||
|
||||
try {
|
||||
await apiService.downloadAgentRetentionRateExcel();
|
||||
if (mounted) {
|
||||
ToastHelper.showSuccessToast(
|
||||
context,
|
||||
'Rentation rate Excel downloaded',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ToastHelper.showErrorToast(
|
||||
context,
|
||||
'Failed to export rentation rate Excel',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _importRetentionRateExcel() async {
|
||||
final picked = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: const ['xls', 'xlsx'],
|
||||
withData: true,
|
||||
);
|
||||
|
||||
if (picked == null || picked.files.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final file = picked.files.first;
|
||||
if (file.bytes == null) {
|
||||
if (mounted) {
|
||||
ToastHelper.showErrorToast(context, 'Could not read selected file');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
isRetentionImportLoading = true;
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await apiService.importAgentRetentionRateExcel(file: file);
|
||||
final status = (response['status'] ?? '').toString().toLowerCase();
|
||||
if (status == 'success') {
|
||||
final data = (response['data'] is Map<String, dynamic>)
|
||||
? response['data'] as Map<String, dynamic>
|
||||
: <String, dynamic>{};
|
||||
final report = (response['report'] is Map<String, dynamic>)
|
||||
? response['report'] as Map<String, dynamic>
|
||||
: <String, dynamic>{};
|
||||
|
||||
final inserted = (data['inserted_cells'] ?? 0).toString();
|
||||
final updated = (data['updated_cells'] ?? 0).toString();
|
||||
if (mounted) {
|
||||
ToastHelper.showSuccessToast(
|
||||
context,
|
||||
'Import done',
|
||||
);
|
||||
}
|
||||
await _showRetentionImportReportDialog(data, report);
|
||||
refresh();
|
||||
} else {
|
||||
if (mounted) {
|
||||
ToastHelper.showErrorToast(context, 'Import failed');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ToastHelper.showErrorToast(context, 'Failed to import rentation rate');
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
isRetentionImportLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showRetentionImportReportDialog(
|
||||
Map<String, dynamic> data,
|
||||
Map<String, dynamic> report,
|
||||
) async {
|
||||
if (!mounted) return;
|
||||
|
||||
final inserted = data['inserted_cells'] ?? 0;
|
||||
final updated = data['updated_cells'] ?? 0;
|
||||
final skippedZero = data['skipped_zero'] ?? 0;
|
||||
final skippedSame = data['skipped_same'] ?? 0;
|
||||
final skippedEmptyRow = data['skipped_empty_row'] ?? 0;
|
||||
final skippedEmptyCell = data['skipped_empty_cell'] ?? 0;
|
||||
final skippedUnknownAgent = data['skipped_unknown_agent'] ?? 0;
|
||||
final invalidRange = data['invalid_range'] ?? 0;
|
||||
final invalidNumber = data['invalid_number'] ?? 0;
|
||||
|
||||
final unknownAgents = (report['unknown_agent_codes'] as List?)
|
||||
?.map((e) => e.toString())
|
||||
.where((e) => e.trim().isNotEmpty)
|
||||
.toList() ??
|
||||
<String>[];
|
||||
final unknownVehicleTypes = (report['unknown_vehicle_types'] as List?)
|
||||
?.map((e) => e.toString())
|
||||
.where((e) => e.trim().isNotEmpty)
|
||||
.toList() ??
|
||||
<String>[];
|
||||
final invalidCells = (report['invalid_cells'] as List?)
|
||||
?.map((e) => e.toString())
|
||||
.where((e) => e.trim().isNotEmpty)
|
||||
.toList() ??
|
||||
<String>[];
|
||||
final agentWiseSkippedRaw = (report['agent_wise_skipped_counts'] is Map)
|
||||
? Map<String, dynamic>.from(report['agent_wise_skipped_counts'] as Map)
|
||||
: <String, dynamic>{};
|
||||
|
||||
final lines = <String>[
|
||||
'Inserted: $inserted',
|
||||
'Updated: $updated',
|
||||
// 'Skipped (value = 0): $skippedZero',
|
||||
// 'Skipped (Excel value equals DB value): $skippedSame',
|
||||
// 'Skipped (empty first column / agent code): $skippedEmptyRow',
|
||||
// 'Skipped (empty cell): $skippedEmptyCell',
|
||||
// 'Skipped (unknown agent code): $skippedUnknownAgent',
|
||||
'Skipped (out of range 0-100): $invalidRange',
|
||||
'Skipped (non-numeric value): $invalidNumber',
|
||||
];
|
||||
|
||||
if (unknownAgents.isNotEmpty) {
|
||||
lines.add('');
|
||||
lines.add('Unknown Agent Codes:');
|
||||
lines.addAll(unknownAgents.take(10).map((e) => '- $e'));
|
||||
if (unknownAgents.length > 10) {
|
||||
lines.add('- ...and ${unknownAgents.length - 10} more');
|
||||
}
|
||||
}
|
||||
|
||||
if (unknownVehicleTypes.isNotEmpty) {
|
||||
lines.add('');
|
||||
lines.add('Unknown Vehicle Types (header):');
|
||||
lines.addAll(unknownVehicleTypes.take(10).map((e) => '- $e'));
|
||||
if (unknownVehicleTypes.length > 10) {
|
||||
lines.add('- ...and ${unknownVehicleTypes.length - 10} more');
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidCells.isNotEmpty) {
|
||||
lines.add('');
|
||||
lines.add('Invalid Cell Samples:');
|
||||
lines.addAll(invalidCells.take(10).map((e) => '- $e'));
|
||||
if (invalidCells.length > 10) {
|
||||
lines.add('- ...and ${invalidCells.length - 10} more');
|
||||
}
|
||||
}
|
||||
|
||||
if (agentWiseSkippedRaw.isNotEmpty) {
|
||||
final sorted = agentWiseSkippedRaw.entries.toList()
|
||||
..sort((a, b) {
|
||||
final av = int.tryParse(a.value.toString()) ?? 0;
|
||||
final bv = int.tryParse(b.value.toString()) ?? 0;
|
||||
return bv.compareTo(av);
|
||||
});
|
||||
final nonZero = sorted
|
||||
.where((e) => (int.tryParse(e.value.toString()) ?? 0) > 0)
|
||||
.toList();
|
||||
if (nonZero.isNotEmpty) {
|
||||
lines.add('');
|
||||
lines.add('Skipped Count (Agent Wise):');
|
||||
lines.addAll(
|
||||
nonZero
|
||||
.take(20)
|
||||
.map((e) => '- ${e.key}: ${int.tryParse(e.value.toString()) ?? 0}'),
|
||||
);
|
||||
if (nonZero.length > 20) {
|
||||
lines.add('- ...and ${nonZero.length - 20} more');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (ctx) {
|
||||
return AlertDialog(
|
||||
title: const Text('Rentation Rate Import Report'),
|
||||
content: SizedBox(
|
||||
width: 520,
|
||||
child: SingleChildScrollView(
|
||||
child: SelectableText(lines.join('\n')),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
child: const Text('OK'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
|
||||
return [
|
||||
GestureDetector(
|
||||
@ -266,6 +492,81 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.15,
|
||||
),
|
||||
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: _exportRetentionRateExcel,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF2E7D6E),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.file_download_outlined,
|
||||
color: Colors.white,
|
||||
size: 16,
|
||||
),
|
||||
SizedBox(width: 6),
|
||||
Text(
|
||||
'Export Rentation Rate',
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.white,
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: isRetentionImportLoading
|
||||
? null
|
||||
: _importRetentionRateExcel,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF2E7D6E),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
isRetentionImportLoading
|
||||
? SizedBox(
|
||||
width: 14,
|
||||
height: 14,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: Icon(
|
||||
Icons.file_upload_outlined,
|
||||
color: Colors.white,
|
||||
size: 16,
|
||||
),
|
||||
SizedBox(width: 6),
|
||||
Text(
|
||||
'Import Rentation Rate',
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.white,
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
@ -317,7 +618,6 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
'Email',
|
||||
'Sales Executive Name',
|
||||
'Phone Number',
|
||||
'Retention Rate',
|
||||
'Address',
|
||||
'Status',
|
||||
],
|
||||
@ -328,7 +628,6 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
"email",
|
||||
"sales_executive_name",
|
||||
"mobile",
|
||||
"retention_rate",
|
||||
"address",
|
||||
"is_active",
|
||||
],
|
||||
@ -414,13 +713,6 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
flex: 2,
|
||||
child: Text('Sales Executive Name', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
'Retention Rate ',
|
||||
style: _headerStyle,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text('Address', style: _headerStyle),
|
||||
@ -542,10 +834,6 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
flex: 2,
|
||||
child: Text(item['sales_executive_name'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(item['retention_rate'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
the `--base-href` argument provided to `flutter build`.
|
||||
-->
|
||||
<!-- <base href="$FLUTTER_BASE_HREF"> -->
|
||||
<!-- <base href="/partner/"> --> <!-- Live build: also check env.dart (line 8) -->
|
||||
<base href="/nhance/partner/app/">
|
||||
<!-- <base href="/partner/"> --> <!-- Live build: also check env.dart (line 8) -->
|
||||
<base href="/nhance/partner/app/">
|
||||
<!-- <base href="{Env.baseHref}">-->
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user