dashbaord login page changes
This commit is contained in:
parent
a52b8d6c04
commit
9cbb1d8cd5
File diff suppressed because one or more lines are too long
@ -133,7 +133,6 @@ class ApiService {
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
Future<Map<String, dynamic>> logoutUsingAPI(agentId) async {
|
||||
// print(_token);
|
||||
if (_token == null) {
|
||||
@ -177,8 +176,8 @@ class ApiService {
|
||||
}
|
||||
|
||||
// 3. UNAUTHORIZED / FORBIDDEN (The 401/403 Fix)
|
||||
if ((response.statusCode == 401 && body['status'] == 401) || (response.statusCode == 403 && body['status'] == 403)) {
|
||||
|
||||
if ((response.statusCode == 401 && body['status'] == 401) ||
|
||||
(response.statusCode == 403 && body['status'] == 403)) {
|
||||
// Perform cleanup
|
||||
await AuthService.clearToken();
|
||||
|
||||
@ -196,10 +195,8 @@ class ApiService {
|
||||
|
||||
// 4. ALL OTHER ERRORS
|
||||
throw Exception('Server Error: ${response.statusCode}');
|
||||
|
||||
}
|
||||
|
||||
|
||||
Future<Map<String, dynamic>> CheckDuplicate(
|
||||
BuildContext context,
|
||||
String value,
|
||||
@ -454,6 +451,8 @@ class ApiService {
|
||||
} else if (path == 'PerformingTop50') {
|
||||
pathVal =
|
||||
'dashboard/downloadAgentMonthlyPoliciesExcel?manager_id=$managerId&agent_id=$id';
|
||||
} else if (path == 'PerformingAgentAll50') {
|
||||
pathVal = 'dashboard/downloadT50AgentPoliciesExcel?manager_id=$managerId';
|
||||
} else if (path == 'NonPerformingBelow50K') {
|
||||
pathVal = 'dashboard/downloadLowPremiumAgentExcel?manager_id=$managerId';
|
||||
} else {
|
||||
@ -1972,10 +1971,10 @@ class ApiService {
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
Future<void> generatePolicyExcel(managerId,fromDate,toDate) async {
|
||||
|
||||
final url = Uri.parse('${Env.apiUrl}reports/policy-excel?manager_id=$managerId&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}',);
|
||||
Future<void> generatePolicyExcel(managerId, fromDate, toDate) async {
|
||||
final url = Uri.parse(
|
||||
'${Env.apiUrl}reports/policy-excel?manager_id=$managerId&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}',
|
||||
);
|
||||
|
||||
print('getPdfDownload policy-excel - $url');
|
||||
await _initializeToken();
|
||||
@ -2042,14 +2041,15 @@ class ApiService {
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchAuditHistory(id) async {
|
||||
|
||||
print( "fetchAuditHistory - $id " );
|
||||
print("fetchAuditHistory - $id ");
|
||||
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
// final url = Uri.parse('${Env.apiUrl}audit/history?table_name=partner_policy&pk=80',);
|
||||
final url = Uri.parse('${Env.apiUrl}audit/history?table_name=partner_policy&pk=${id ?? ''}',);
|
||||
final url = Uri.parse(
|
||||
'${Env.apiUrl}audit/history?table_name=partner_policy&pk=${id ?? ''}',
|
||||
);
|
||||
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token' ?? '',
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:easy_loading_button/easy_loading_button.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
class CommonButton extends StatelessWidget {
|
||||
final String text;
|
||||
@ -25,10 +26,10 @@ class CommonButton extends StatelessWidget {
|
||||
type: EasyButtonType.elevated,
|
||||
idleStateWidget: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
style: GoogleFonts.poppins(
|
||||
color: textColor,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
loadingStateWidget: const CircularProgressIndicator(
|
||||
|
||||
@ -239,11 +239,7 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 26),
|
||||
if (profileData?['mobile'] != null ||
|
||||
profileData!['mobile']
|
||||
.toString()
|
||||
.trim()
|
||||
.isNotEmpty) ...[
|
||||
if (hasValidValue(profileData?['mobile'])) ...[
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
@ -260,11 +256,7 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
if (profileData?['email'] != null ||
|
||||
profileData!['email']
|
||||
.toString()
|
||||
.trim()
|
||||
.isNotEmpty) ...[
|
||||
if (hasValidValue(profileData?['email'])) ...[
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
@ -282,11 +274,7 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
|
||||
if (profileData?['address'] != null &&
|
||||
profileData!['address']
|
||||
.toString()
|
||||
.trim()
|
||||
.isNotEmpty) ...[
|
||||
if (hasValidValue(profileData?['address'])) ...[
|
||||
if ((roleId != 1) &&
|
||||
(roleId != 2) &&
|
||||
(roleId != 3)) ...[
|
||||
@ -431,6 +419,12 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
|
||||
);
|
||||
}
|
||||
|
||||
bool hasValidValue(dynamic value) {
|
||||
if (value == null) return false;
|
||||
if (value is String) return value.trim().isNotEmpty;
|
||||
return true; // for numbers, bool, etc.
|
||||
}
|
||||
|
||||
static final _dataBold = TextStyle(
|
||||
fontSize: 11.8,
|
||||
fontWeight: FontWeight.w400,
|
||||
|
||||
@ -10,6 +10,7 @@ import '../../../../core/services/api_service.dart';
|
||||
import '../../../../data/models/bar_data.dart';
|
||||
import '../../../providers/userRoleProvider.dart';
|
||||
import '../../../themes/charts/barChart.dart';
|
||||
import '../../../themes/charts/barChart_horizontal.dart';
|
||||
import '../../../themes/indicators/input_field_decoration.dart';
|
||||
|
||||
class BussinessDashboard extends ConsumerStatefulWidget {
|
||||
@ -163,7 +164,7 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
}
|
||||
}
|
||||
|
||||
List<BarData> buildInsurerBarData() {
|
||||
List<Map<String, dynamic>> getSortedInsurerWise() {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
if (value is num) return value.toDouble();
|
||||
@ -171,12 +172,45 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return filteredInsurerWise.map((item) {
|
||||
print('policies_current - ${item['total_policies_current_month']}');
|
||||
print('policies_PREV - ${item['total_policies_pre_month']}');
|
||||
final List<Map<String, dynamic>> sorted = List<Map<String, dynamic>>.from(
|
||||
filteredInsurerWise,
|
||||
);
|
||||
|
||||
print('premium_current - ${item['total_premium_current_month']}');
|
||||
print('premium_PREV - ${item['total_premium_pre_month']}');
|
||||
sorted.sort((a, b) {
|
||||
final aCurrent = isInsureWisePolicy
|
||||
? parseDouble(a['total_policies_current_month'])
|
||||
: parseDouble(a['total_premium_current_month']);
|
||||
|
||||
final aPrev = isInsureWisePolicy
|
||||
? parseDouble(a['total_policies_pre_month'])
|
||||
: parseDouble(a['total_premium_pre_month']);
|
||||
|
||||
final bCurrent = isInsureWisePolicy
|
||||
? parseDouble(b['total_policies_current_month'])
|
||||
: parseDouble(b['total_premium_current_month']);
|
||||
|
||||
final bPrev = isInsureWisePolicy
|
||||
? parseDouble(b['total_policies_pre_month'])
|
||||
: parseDouble(b['total_premium_pre_month']);
|
||||
|
||||
final aMax = aCurrent > aPrev ? aCurrent : aPrev;
|
||||
final bMax = bCurrent > bPrev ? bCurrent : bPrev;
|
||||
|
||||
return bMax.compareTo(aMax); // DESC
|
||||
});
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
List<BarData> buildInsurerBarData(List<Map<String, dynamic>> sortedList) {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
if (value is num) return value.toDouble();
|
||||
if (value is String) return double.tryParse(value) ?? 0.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return sortedList.map((item) {
|
||||
return BarData(
|
||||
Colors.blue,
|
||||
isInsureWisePolicy
|
||||
@ -185,25 +219,23 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
isInsureWisePolicy
|
||||
? parseDouble(item['total_policies_pre_month'])
|
||||
: parseDouble(item['total_premium_pre_month']),
|
||||
item['insurer_id'] != null ? item['insurer_id'] : '0',
|
||||
item['insurer_id'] ?? '0',
|
||||
'Insurer',
|
||||
5,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<String> buildInsurerLabels() {
|
||||
return filteredInsurerWise.map<String>((item) {
|
||||
List<String> buildInsurerLabels(List<Map<String, dynamic>> sortedList) {
|
||||
return sortedList.map<String>((item) {
|
||||
final name = item['short_name'];
|
||||
if (name != null && name.toString().trim().isNotEmpty) {
|
||||
return name.toString();
|
||||
} else {
|
||||
return item['short_name']?.toString() ?? '';
|
||||
}
|
||||
return (name != null && name.toString().trim().isNotEmpty)
|
||||
? name.toString()
|
||||
: '';
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<BarData> buildBrokerBarData() {
|
||||
List<Map<String, dynamic>> getSortedBrokerWise() {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
if (value is num) return value.toDouble();
|
||||
@ -211,12 +243,45 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return filteredBrokerWise.map((item) {
|
||||
print('policies_current - ${item['total_policies_current_month']}');
|
||||
print('policies_PREV - ${item['total_policies_pre_month']}');
|
||||
final List<Map<String, dynamic>> sorted = List<Map<String, dynamic>>.from(
|
||||
filteredBrokerWise,
|
||||
);
|
||||
|
||||
print('premium_current - ${item['total_premium_current_month']}');
|
||||
print('premium_PREV - ${item['total_premium_pre_month']}');
|
||||
sorted.sort((a, b) {
|
||||
final aCurrent = isBrokerWisePolicy
|
||||
? parseDouble(a['total_policies_current_month'])
|
||||
: parseDouble(a['total_premium_current_month']);
|
||||
|
||||
final aPrev = isBrokerWisePolicy
|
||||
? parseDouble(a['total_policies_pre_month'])
|
||||
: parseDouble(a['total_premium_pre_month']);
|
||||
|
||||
final bCurrent = isBrokerWisePolicy
|
||||
? parseDouble(b['total_policies_current_month'])
|
||||
: parseDouble(b['total_premium_current_month']);
|
||||
|
||||
final bPrev = isBrokerWisePolicy
|
||||
? parseDouble(b['total_policies_pre_month'])
|
||||
: parseDouble(b['total_premium_pre_month']);
|
||||
|
||||
final aMax = aCurrent > aPrev ? aCurrent : aPrev;
|
||||
final bMax = bCurrent > bPrev ? bCurrent : bPrev;
|
||||
|
||||
return bMax.compareTo(aMax); // 🔥 DESC
|
||||
});
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
List<BarData> buildBrokerBarData(List<Map<String, dynamic>> sortedList) {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
if (value is num) return value.toDouble();
|
||||
if (value is String) return double.tryParse(value) ?? 0.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return sortedList.map((item) {
|
||||
return BarData(
|
||||
Colors.blue,
|
||||
isBrokerWisePolicy
|
||||
@ -225,31 +290,97 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
isBrokerWisePolicy
|
||||
? parseDouble(item['total_policies_pre_month'])
|
||||
: parseDouble(item['total_premium_pre_month']),
|
||||
item['broker_id'] != null ? item['broker_id'] : '0',
|
||||
item['broker_id'] ?? '0',
|
||||
'Broker',
|
||||
5,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<String> buildBrokerLabels() {
|
||||
return filteredBrokerWise.map<String>((item) {
|
||||
List<String> buildBrokerLabels(List<Map<String, dynamic>> sortedList) {
|
||||
return sortedList.map<String>((item) {
|
||||
final name = item['broker_name'];
|
||||
if (name != null && name.toString().trim().isNotEmpty) {
|
||||
return name.toString();
|
||||
} else {
|
||||
return item['broker_name']?.toString() ?? '';
|
||||
}
|
||||
return (name != null && name.toString().trim().isNotEmpty)
|
||||
? name.toString()
|
||||
: '';
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<String> buildBrokerShortNames() {
|
||||
return filteredBrokerWise.map<String>((item) {
|
||||
List<String> buildBrokerShortNames(List<Map<String, dynamic>> sortedList) {
|
||||
return sortedList.map<String>((item) {
|
||||
return item['broker_short_name']?.toString() ?? '';
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<BarData> buildProductBarData() {
|
||||
List<Map<String, dynamic>> getSortedProductWise() {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
if (value is num) return value.toDouble();
|
||||
if (value is String) return double.tryParse(value) ?? 0.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
final List<Map<String, dynamic>> sorted = List<Map<String, dynamic>>.from(
|
||||
filteredProductWise,
|
||||
);
|
||||
|
||||
sorted.sort((a, b) {
|
||||
final aCurrent = isProductWisePolicy
|
||||
? parseDouble(a['total_policies_current_month'])
|
||||
: parseDouble(a['total_premium_current_month']);
|
||||
|
||||
final aPrev = isProductWisePolicy
|
||||
? parseDouble(a['total_policies_pre_month'])
|
||||
: parseDouble(a['total_premium_pre_month']);
|
||||
|
||||
final bCurrent = isProductWisePolicy
|
||||
? parseDouble(b['total_policies_current_month'])
|
||||
: parseDouble(b['total_premium_current_month']);
|
||||
|
||||
final bPrev = isProductWisePolicy
|
||||
? parseDouble(b['total_policies_pre_month'])
|
||||
: parseDouble(b['total_premium_pre_month']);
|
||||
|
||||
final aMax = aCurrent > aPrev ? aCurrent : aPrev;
|
||||
final bMax = bCurrent > bPrev ? bCurrent : bPrev;
|
||||
|
||||
return bMax.compareTo(aMax); // DESC
|
||||
});
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
List<BarData> buildProductBarData(List<Map<String, dynamic>> sortedList) {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
if (value is num) return value.toDouble();
|
||||
if (value is String) return double.tryParse(value) ?? 0.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return sortedList.map((item) {
|
||||
return BarData(
|
||||
Colors.blue,
|
||||
isProductWisePolicy
|
||||
? parseDouble(item['total_policies_current_month'])
|
||||
: parseDouble(item['total_premium_current_month']),
|
||||
isProductWisePolicy
|
||||
? parseDouble(item['total_policies_pre_month'])
|
||||
: parseDouble(item['total_premium_pre_month']),
|
||||
item['vehicle_type']?.toString() ?? '',
|
||||
'Product',
|
||||
10,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<String> buildProductLabels(List<Map<String, dynamic>> sortedList) {
|
||||
return sortedList.map<String>((item) {
|
||||
return item['vehicle_type']?.toString() ?? '';
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<BarData> buildProductBarData1() {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
if (value is num) return value.toDouble();
|
||||
@ -278,7 +409,7 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<String> buildProductLabels() {
|
||||
List<String> buildProductLabels1() {
|
||||
return filteredProductWise.map<String>((item) {
|
||||
final name = item['vehicle_type'];
|
||||
if (name != null && name.toString().trim().isNotEmpty) {
|
||||
@ -366,47 +497,96 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
legendWidget(),
|
||||
],
|
||||
),
|
||||
(showInsurer || showBroker)
|
||||
? Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// if (showInsurer) Expanded(child: insurerContainer()),
|
||||
// if (showBroker) Expanded(child: brokerContainer()),
|
||||
showInsurer
|
||||
? Expanded(child: insurerContainer())
|
||||
: SizedBox(),
|
||||
showBroker
|
||||
? Expanded(child: brokerContainer())
|
||||
: SizedBox(),
|
||||
// showProduct ? Expanded(child: productContainer()) : SizedBox(),
|
||||
],
|
||||
),
|
||||
)
|
||||
: SizedBox(),
|
||||
if (showProduct) ...[
|
||||
SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
showProduct
|
||||
? Expanded(child: productContainer())
|
||||
: SizedBox(),
|
||||
],
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
(showInsurer || showBroker)
|
||||
? Expanded(
|
||||
flex: 2,
|
||||
child: Column(
|
||||
children: [
|
||||
showInsurer
|
||||
? Expanded(child: insurerContainer())
|
||||
: SizedBox(),
|
||||
showInsurer ? SizedBox(height: 10) : SizedBox(),
|
||||
|
||||
showBroker
|
||||
? Expanded(child: brokerContainer())
|
||||
: SizedBox(),
|
||||
],
|
||||
),
|
||||
)
|
||||
: SizedBox(),
|
||||
|
||||
showProduct
|
||||
? Expanded(flex: 1, child: productContainer())
|
||||
: SizedBox(),
|
||||
],
|
||||
),
|
||||
] else ...[
|
||||
SizedBox.shrink(),
|
||||
],
|
||||
),
|
||||
|
||||
// (showInsurer || showBroker)
|
||||
// ? Expanded(
|
||||
// child: Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// // if (showInsurer) Expanded(child: insurerContainer()),
|
||||
// // if (showBroker) Expanded(child: brokerContainer()),
|
||||
// showInsurer
|
||||
// ? Expanded(child: insurerContainer())
|
||||
// : SizedBox(),
|
||||
// showBroker
|
||||
// ? Expanded(child: brokerContainer())
|
||||
// : SizedBox(),
|
||||
// // showProduct ? Expanded(child: productContainer()) : SizedBox(),
|
||||
// ],
|
||||
// ),
|
||||
// )
|
||||
// : SizedBox(),
|
||||
|
||||
// if (showBroker) ...[
|
||||
// SizedBox(height: 10),
|
||||
// Expanded(
|
||||
// child: Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// showBroker ? Expanded(child: brokerContainer()) : SizedBox(),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ] else ...[
|
||||
// SizedBox.shrink(),
|
||||
// ],
|
||||
// if (showProduct) ...[
|
||||
// SizedBox(height: 10),
|
||||
// Expanded(
|
||||
// child: Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// showProduct
|
||||
// ? Expanded(child: productContainer())
|
||||
// : SizedBox(),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ] else ...[
|
||||
// SizedBox.shrink(),
|
||||
// ],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget insurerContainer() {
|
||||
final chartInsurerData = buildInsurerBarData();
|
||||
final chartInsurerLabels = buildInsurerLabels();
|
||||
// final chartInsurerData = buildInsurerBarData();
|
||||
// final chartInsurerLabels = buildInsurerLabels();
|
||||
|
||||
final sortedInsurer = getSortedInsurerWise();
|
||||
|
||||
final chartInsurerData = buildInsurerBarData(sortedInsurer);
|
||||
final chartInsurerLabels = buildInsurerLabels(sortedInsurer);
|
||||
|
||||
print('chartInsurerData - $chartInsurerData');
|
||||
print('chartInsurerLabels - $chartInsurerLabels');
|
||||
return Card(
|
||||
@ -460,9 +640,15 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
}
|
||||
|
||||
Widget brokerContainer() {
|
||||
final chartBrokerData = buildBrokerBarData();
|
||||
final chartBrokerLabels = buildBrokerLabels();
|
||||
final chartBrokerShortName = buildBrokerShortNames();
|
||||
// final chartBrokerData = buildBrokerBarData();
|
||||
// final chartBrokerLabels = buildBrokerLabels();
|
||||
// final chartBrokerShortName = buildBrokerShortNames();
|
||||
|
||||
final sortedBroker = getSortedBrokerWise();
|
||||
|
||||
final chartBrokerData = buildBrokerBarData(sortedBroker);
|
||||
final chartBrokerLabels = buildBrokerLabels(sortedBroker);
|
||||
final chartBrokerShortNames = buildBrokerShortNames(sortedBroker);
|
||||
print('chartBrokerData - $chartBrokerData');
|
||||
print('chartBrokerLabels - $chartBrokerLabels');
|
||||
return Card(
|
||||
@ -498,7 +684,7 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
Expanded(
|
||||
child: CustomBarChart(
|
||||
dataList: chartBrokerData,
|
||||
labels: chartBrokerShortName,
|
||||
labels: chartBrokerShortNames,
|
||||
shortName: chartBrokerLabels,
|
||||
|
||||
// labels: chartBrokerLabels,
|
||||
@ -513,8 +699,12 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
}
|
||||
|
||||
Widget productContainer() {
|
||||
final chartProductData = buildProductBarData();
|
||||
final chartProductLabels = buildProductLabels();
|
||||
final sortedList = getSortedProductWise();
|
||||
|
||||
final chartProductData = buildProductBarData(sortedList);
|
||||
final chartProductLabels = buildProductLabels(sortedList);
|
||||
// final chartProductData = buildProductBarData();
|
||||
// final chartProductLabels = buildProductLabels();
|
||||
print('chartProductData - $chartProductData');
|
||||
print('chartProductLabels - $chartProductLabels');
|
||||
return Card(
|
||||
@ -547,7 +737,7 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: CustomBarChart(
|
||||
child: CustomBarChartHorizontal(
|
||||
dataList: chartProductData,
|
||||
labels: chartProductLabels,
|
||||
),
|
||||
@ -563,11 +753,21 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.circle, size: 10, color: Colors.cyan.shade300),
|
||||
Icon(
|
||||
Icons.circle,
|
||||
size: 10,
|
||||
color: Color(0xFF34a9a8),
|
||||
// color: Colors.cyan.shade300
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
Text('Current Month', style: _styleSmall1),
|
||||
SizedBox(width: 5),
|
||||
Icon(Icons.circle, size: 10, color: Colors.orange.shade300),
|
||||
Icon(
|
||||
Icons.circle,
|
||||
size: 10,
|
||||
// color: Colors.orange.shade300
|
||||
color: const Color(0xFFA5E4E1),
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
Text('Previous Month', style: _styleSmall1),
|
||||
],
|
||||
|
||||
@ -332,9 +332,57 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Performing Partner ( Top 50 )',
|
||||
style: _chartHeader,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Performing Partner ( Top 50 )',
|
||||
style: _chartHeader,
|
||||
),
|
||||
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
final path =
|
||||
"PerformingAgentAll50";
|
||||
final id = '';
|
||||
final month = 'current';
|
||||
|
||||
await apiService
|
||||
.generateChartExcel(
|
||||
path,
|
||||
id,
|
||||
month,
|
||||
managerId,
|
||||
);
|
||||
},
|
||||
child: Tooltip(
|
||||
message: 'Export Excel',
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(
|
||||
5.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(
|
||||
0xFF2E7D6E,
|
||||
),
|
||||
// color: const Color(0xFF425B5B),
|
||||
borderRadius:
|
||||
BorderRadius.circular(
|
||||
2.0,
|
||||
),
|
||||
),
|
||||
child: Image.asset(
|
||||
"assets/miscellaneous/export.png",
|
||||
height: 11,
|
||||
width: 11,
|
||||
// color: Colors.green,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -406,6 +454,8 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(width: 10),
|
||||
|
||||
Text(
|
||||
isNonPerfomingAgntPolicy
|
||||
? "No Business"
|
||||
@ -429,6 +479,42 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
final path = isNonPerfomingAgntPolicy
|
||||
? "NoBusiness"
|
||||
: "NonPerformingBelow50K";
|
||||
final id = '';
|
||||
final month = 'current';
|
||||
|
||||
await apiService.generateChartExcel(
|
||||
path,
|
||||
id,
|
||||
month,
|
||||
managerId,
|
||||
);
|
||||
},
|
||||
child: Tooltip(
|
||||
message: 'Export Excel',
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF2E7D6E),
|
||||
// color: const Color(0xFF425B5B),
|
||||
borderRadius: BorderRadius.circular(
|
||||
2.0,
|
||||
),
|
||||
),
|
||||
child: Image.asset(
|
||||
"assets/miscellaneous/export.png",
|
||||
height: 11,
|
||||
width: 11,
|
||||
// color: Colors.green,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
@ -624,39 +710,43 @@ class _PerformanceState extends State<Performance> {
|
||||
),
|
||||
],
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
final path1 = 'PerformingTop50';
|
||||
final path2 = widget.isPerfomingAgntPolicy
|
||||
? "NoBusiness"
|
||||
: "NonPerformingBelow50K";
|
||||
final path = (widget.title == 'Performing Partner')
|
||||
? path1
|
||||
: path2;
|
||||
|
||||
final id =
|
||||
((widget.title == 'Performing Partner') &&
|
||||
(row['agent_id'] != null))
|
||||
? row['agent_id']
|
||||
: '';
|
||||
final month = 'current';
|
||||
if (widget.title == 'Performing Partner') ...[
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
final path1 = 'PerformingTop50';
|
||||
final path2 = widget.isPerfomingAgntPolicy
|
||||
? "NoBusiness"
|
||||
: "NonPerformingBelow50K";
|
||||
final path =
|
||||
(widget.title == 'Performing Partner')
|
||||
? path1
|
||||
: path2;
|
||||
|
||||
await widget.apiService.generateChartExcel(
|
||||
path,
|
||||
id,
|
||||
month,
|
||||
widget.managerId,
|
||||
);
|
||||
},
|
||||
child: Tooltip(
|
||||
message: 'Click To Download Excel',
|
||||
child: Icon(
|
||||
Icons.download,
|
||||
size: 14,
|
||||
color: Colors.green.shade300,
|
||||
final id =
|
||||
((widget.title == 'Performing Partner') &&
|
||||
(row['agent_id'] != null))
|
||||
? row['agent_id']
|
||||
: '';
|
||||
final month = 'current';
|
||||
|
||||
await widget.apiService.generateChartExcel(
|
||||
path,
|
||||
id,
|
||||
month,
|
||||
widget.managerId,
|
||||
);
|
||||
},
|
||||
child: Tooltip(
|
||||
message: 'Click To Download Excel',
|
||||
child: Icon(
|
||||
Icons.download,
|
||||
size: 14,
|
||||
color: Colors.green.shade300,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -64,266 +64,347 @@ class _CustomBarChartState extends ConsumerState<CustomBarChart> {
|
||||
x: x,
|
||||
groupVertically: false,
|
||||
|
||||
// showingTooltipIndicators: [0],
|
||||
// showingTooltipIndicators: [x],
|
||||
showingTooltipIndicators: const [1, 2],
|
||||
|
||||
// barsSpace: 30,
|
||||
barRods: [
|
||||
BarChartRodData(toY: 0, color: Colors.transparent, width: 10),
|
||||
BarChartRodData(
|
||||
toY: value1,
|
||||
color: Colors.cyan.shade300,
|
||||
color: const Color(0xFF34a9a8),
|
||||
// color: Color(0xFF0FB9B1),
|
||||
width: 20,
|
||||
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
// BarChartRodData(toY: 2, color: Colors.orange.shade300, width: 6),
|
||||
BarChartRodData(
|
||||
toY: value2,
|
||||
color: Colors.orange.shade300,
|
||||
color: const Color(0xFFA5E4E1),
|
||||
// color: const Color(0xFF64748B),
|
||||
// color: Colors.orange.shade300,
|
||||
// color: Color(0xFF2F3640),
|
||||
width: 20,
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
],
|
||||
showingTooltipIndicators: touchedGroupIndex == x ? [0] : [],
|
||||
// showingTooltipIndicators: touchedGroupIndex == x ? [0] : [],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String compactNumber(num value) {
|
||||
if (value >= 10000000) {
|
||||
return '${(value / 10000000).toStringAsFixed(1).replaceAll('.0', '')}Cr';
|
||||
} else if (value >= 1000000) {
|
||||
return '${(value / 1000000).toStringAsFixed(1).replaceAll('.0', '')}M';
|
||||
} else if (value >= 1000) {
|
||||
return '${(value / 1000).toStringAsFixed(1).replaceAll('.0', '')}K';
|
||||
} else {
|
||||
return value.toInt().toString();
|
||||
}
|
||||
}
|
||||
|
||||
// Widget build(BuildContext context) {
|
||||
// return AspectRatio(
|
||||
// aspectRatio: 1.4,
|
||||
//
|
||||
// );
|
||||
// }
|
||||
|
||||
double getChartWidth() {
|
||||
const double barWidth = 40; // bar + spacing
|
||||
double minWidth =
|
||||
MediaQuery.of(context).size.width * 0.9; // minimum chart width
|
||||
|
||||
final calculatedWidth = widget.dataList.length * barWidth;
|
||||
return calculatedWidth < minWidth ? minWidth : calculatedWidth;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return SizedBox(
|
||||
width: constraints.maxWidth,
|
||||
height: constraints.maxHeight,
|
||||
child: BarChart(
|
||||
BarChartData(
|
||||
// alignment: BarChartAlignment.spaceBetween,
|
||||
alignment: BarChartAlignment.start,
|
||||
// verticalAxis: Axis.horizontal,
|
||||
// rotationQuarterTurns: rotationTurns,
|
||||
barTouchData: BarTouchData(
|
||||
enabled: true,
|
||||
handleBuiltInTouches: true,
|
||||
touchTooltipData: BarTouchTooltipData(
|
||||
tooltipMargin: 6,
|
||||
tooltipRoundedRadius: 6,
|
||||
tooltipPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
// ask fl_chart to fit tooltip inside available space
|
||||
fitInsideVertically:
|
||||
true, // if your fl_chart version supports it
|
||||
fitInsideHorizontally:
|
||||
true, // if your fl_chart version supports it
|
||||
getTooltipItem:
|
||||
(
|
||||
BarChartGroupData group,
|
||||
int groupIndex,
|
||||
BarChartRodData rod,
|
||||
int rodIndex,
|
||||
) {
|
||||
final textColor = rodIndex == 1
|
||||
? Colors.cyan.shade300
|
||||
: Colors.orange.shade300;
|
||||
final textStyle = TextStyle(
|
||||
color: textColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
|
||||
final formattedValue = indianFormatter.format(
|
||||
rod.toY.round(),
|
||||
);
|
||||
|
||||
return BarTooltipItem(formattedValue, textStyle);
|
||||
// return BarTooltipItem('${rod.toY.round()}', textStyle);
|
||||
},
|
||||
),
|
||||
|
||||
touchCallback: (FlTouchEvent e, BarTouchResponse? r) async {
|
||||
// optional: change state to highlight tapped group
|
||||
if (r == null || r.spot == null) {
|
||||
setState(() => touchedGroupIndex = -1);
|
||||
return;
|
||||
}
|
||||
setState(
|
||||
() => touchedGroupIndex = r.spot!.touchedBarGroupIndex,
|
||||
);
|
||||
|
||||
final spot = r.spot!;
|
||||
final groupIndex = spot.touchedBarGroupIndex;
|
||||
final rodIndex = spot.touchedRodDataIndex;
|
||||
|
||||
final barData = widget.dataList[groupIndex];
|
||||
|
||||
final name = barData.chartName;
|
||||
final val = barData.id;
|
||||
final month = rodIndex == 1 ? 'current' : 'previous';
|
||||
print('name - $name');
|
||||
print('val - $val');
|
||||
print('month - $month');
|
||||
print('managerId - $managerId');
|
||||
if (e is FlTapUpEvent) {
|
||||
debugPrint(
|
||||
'Tapped value → ${rodIndex == 1 ? barData.value1 : barData.value2} -> ${barData.id}-'
|
||||
' ${rodIndex == 1 ? 'current' : 'previous'} -> ${barData.chartName}',
|
||||
);
|
||||
if (managerId != null) {
|
||||
print('managerId - $managerId');
|
||||
await apiService.generateChartExcel(
|
||||
name,
|
||||
val,
|
||||
month,
|
||||
managerId,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
borderData: FlBorderData(
|
||||
show: true,
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppColors.contentColorBlack,
|
||||
width: 0.1,
|
||||
),
|
||||
left: BorderSide(
|
||||
color: AppColors.contentColorBlack,
|
||||
width: 0.1,
|
||||
),
|
||||
),
|
||||
),
|
||||
gridData: FlGridData(
|
||||
show: true,
|
||||
// drawVerticalLine: true,
|
||||
drawVerticalLine: false,
|
||||
getDrawingHorizontalLine: (value) => FlLine(
|
||||
// color: AppColors.gridLinesColor.withValues(alpha: 0.2),
|
||||
color: Colors.blueGrey.shade100,
|
||||
// color: Colors.black,
|
||||
// color: AppColors.borderColor,
|
||||
strokeWidth: 0.3,
|
||||
),
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
bottomTitles: AxisTitles(
|
||||
axisNameWidget: widget.btnName != null
|
||||
? Text(widget.btnName!)
|
||||
: Text(''),
|
||||
axisNameSize: 10,
|
||||
sideTitles: SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
getTitlesWidget: (value, meta) {
|
||||
final i = value.toInt();
|
||||
if (i >= widget.labels.length) return const SizedBox();
|
||||
final hasShortName =
|
||||
widget.shortName != null &&
|
||||
widget.shortName!.length > i &&
|
||||
widget.shortName![i].trim().isNotEmpty;
|
||||
|
||||
return SideTitleWidget(
|
||||
meta: meta,
|
||||
child: hasShortName
|
||||
? Tooltip(
|
||||
message: widget.shortName![i],
|
||||
child: Text(
|
||||
widget.labels[i],
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 9.5,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
widget.labels[i],
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 9.5,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
);
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
// width: constraints.maxWidth,
|
||||
// height: constraints.maxHeight,
|
||||
width: getChartWidth(), // 👈 IMPORTANT
|
||||
height: constraints.maxHeight,
|
||||
child: BarChart(
|
||||
BarChartData(
|
||||
// alignment: BarChartAlignment.spaceBetween,
|
||||
alignment: BarChartAlignment.start,
|
||||
// verticalAxis: Axis.horizontal,
|
||||
// rotationQuarterTurns: rotationTurns,
|
||||
barTouchData: BarTouchData(
|
||||
enabled: true,
|
||||
handleBuiltInTouches: true,
|
||||
touchTooltipData: BarTouchTooltipData(
|
||||
tooltipMargin: 20,
|
||||
tooltipRoundedRadius: 6,
|
||||
getTooltipColor: (group) {
|
||||
return Colors.transparent; // 👈 tooltip background color
|
||||
},
|
||||
tooltipPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 7,
|
||||
vertical: 2,
|
||||
),
|
||||
// rotateAngle: -85,
|
||||
// ask fl_chart to fit tooltip inside available space
|
||||
fitInsideVertically:
|
||||
true, // if your fl_chart version supports it
|
||||
fitInsideHorizontally:
|
||||
true, // if your fl_chart version supports it
|
||||
|
||||
getTooltipItem:
|
||||
(
|
||||
BarChartGroupData group,
|
||||
int groupIndex,
|
||||
BarChartRodData rod,
|
||||
int rodIndex,
|
||||
) {
|
||||
if (rod.toY == 0) {
|
||||
return null;
|
||||
}
|
||||
final textColor = rodIndex == 1
|
||||
? Color(0xFF34a9a8)
|
||||
: Color(0xFF020050);
|
||||
|
||||
// final textColor = Colors.black87;
|
||||
// final textColor = Color(0xFF020050);
|
||||
// final textColor =;
|
||||
final textStyle = GoogleFonts.poppins(
|
||||
color: textColor,
|
||||
fontSize: 8,
|
||||
fontWeight: rodIndex == 1
|
||||
? FontWeight.w600
|
||||
: FontWeight.w400,
|
||||
);
|
||||
|
||||
// final formattedValue = indianFormatter.format(
|
||||
// rod.toY.round(),
|
||||
// );
|
||||
|
||||
final formattedValue = compactNumber(rod.toY);
|
||||
return BarTooltipItem(formattedValue, textStyle);
|
||||
// return BarTooltipItem('${rod.toY.round()}', textStyle);
|
||||
},
|
||||
),
|
||||
|
||||
touchCallback: (FlTouchEvent e, BarTouchResponse? r) async {
|
||||
// optional: change state to highlight tapped group
|
||||
if (r == null || r.spot == null) {
|
||||
setState(() => touchedGroupIndex = -1);
|
||||
return;
|
||||
}
|
||||
setState(
|
||||
() => touchedGroupIndex = r.spot!.touchedBarGroupIndex,
|
||||
);
|
||||
|
||||
final spot = r.spot!;
|
||||
final groupIndex = spot.touchedBarGroupIndex;
|
||||
final rodIndex = spot.touchedRodDataIndex;
|
||||
|
||||
final barData = widget.dataList[groupIndex];
|
||||
|
||||
final name = barData.chartName;
|
||||
final val = barData.id;
|
||||
final month = rodIndex == 1 ? 'current' : 'previous';
|
||||
print('name - $name');
|
||||
print('val - $val');
|
||||
print('month - $month');
|
||||
print('managerId - $managerId');
|
||||
if (e is FlTapUpEvent) {
|
||||
debugPrint(
|
||||
'Tapped value → ${rodIndex == 1 ? barData.value1 : barData.value2} -> ${barData.id}-'
|
||||
' ${rodIndex == 1 ? 'current' : 'previous'} -> ${barData.chartName}',
|
||||
);
|
||||
if (managerId != null) {
|
||||
print('managerId - $managerId');
|
||||
await apiService.generateChartExcel(
|
||||
name,
|
||||
val,
|
||||
month,
|
||||
managerId,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
leftTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
// interval: 10,
|
||||
getTitlesWidget: (value, meta) {
|
||||
// print("valuevalue - $value");
|
||||
borderData: FlBorderData(
|
||||
show: true,
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppColors.contentColorBlack,
|
||||
width: 0.1,
|
||||
),
|
||||
left: BorderSide(
|
||||
color: AppColors.contentColorBlack,
|
||||
width: 0.1,
|
||||
),
|
||||
),
|
||||
),
|
||||
gridData: FlGridData(
|
||||
show: true,
|
||||
// drawVerticalLine: true,
|
||||
drawVerticalLine: false,
|
||||
getDrawingHorizontalLine: (value) => FlLine(
|
||||
// color: AppColors.gridLinesColor.withValues(alpha: 0.2),
|
||||
color: Colors.blueGrey.shade100,
|
||||
// color: Colors.black,
|
||||
// color: AppColors.borderColor,
|
||||
strokeWidth: 0.3,
|
||||
),
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
bottomTitles: AxisTitles(
|
||||
axisNameWidget: widget.btnName != null
|
||||
? Text(widget.btnName!)
|
||||
: Text(''),
|
||||
axisNameSize: 10,
|
||||
sideTitles: SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
getTitlesWidget: (value, meta) {
|
||||
if (value == 0) {
|
||||
return const SizedBox.shrink(); // 👈 hide 0
|
||||
}
|
||||
final i = value.toInt();
|
||||
if (i >= widget.labels.length) return const SizedBox();
|
||||
final hasShortName =
|
||||
widget.shortName != null &&
|
||||
widget.shortName!.length > i &&
|
||||
widget.shortName![i].trim().isNotEmpty;
|
||||
|
||||
final text = value.toInt().toString();
|
||||
return SideTitleWidget(
|
||||
meta: meta,
|
||||
child: hasShortName
|
||||
? Tooltip(
|
||||
message: widget.shortName![i],
|
||||
child: Transform.rotate(
|
||||
angle: -1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 3.0,
|
||||
),
|
||||
child: Text(
|
||||
truncate(widget.labels[i], max: 5),
|
||||
// widget.labels[i],
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF1E293B),
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Tooltip(
|
||||
message: widget.labels[i],
|
||||
child: Transform.rotate(
|
||||
angle: -1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 3.0,
|
||||
),
|
||||
child: Text(
|
||||
truncate(widget.labels[i], max: 5),
|
||||
// widget.[i],
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFF1E293B),
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
final bool isLast = value == meta.max;
|
||||
// if (isLast) {
|
||||
// return const SizedBox.shrink(); // 👈 hide last label
|
||||
// }
|
||||
// print('value: $value');
|
||||
// print('text: $text');
|
||||
// print('length: ${text.length}');
|
||||
// print('isLast: $isLast');
|
||||
return Transform.rotate(
|
||||
// angle: -3,
|
||||
angle: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 3.0),
|
||||
child: Text(
|
||||
isLast ? '0' : value.toInt().toString(),
|
||||
textAlign: TextAlign.end,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 9,
|
||||
color: isLast ? Colors.white : Colors.black,
|
||||
fontWeight: isLast
|
||||
? FontWeight.w100
|
||||
: FontWeight.w400,
|
||||
leftTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
// interval: 10,
|
||||
getTitlesWidget: (value, meta) {
|
||||
// print("valuevalue - $value");
|
||||
|
||||
final text = value.toInt().toString();
|
||||
|
||||
final bool isLast = value == meta.max;
|
||||
// if (isLast) {
|
||||
// return const SizedBox.shrink(); // 👈 hide last label
|
||||
// }
|
||||
// print('value: $value');
|
||||
// print('text: $text');
|
||||
// print('length: ${text.length}');
|
||||
// print('isLast: $isLast');
|
||||
return Transform.rotate(
|
||||
// angle: -3,
|
||||
angle: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 3.0),
|
||||
child: Text(
|
||||
// isLast ? '0' : value.toInt().toString(),
|
||||
isLast ? '0' : compactNumber(value),
|
||||
textAlign: TextAlign.end,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 9,
|
||||
color: isLast ? Colors.white : Colors.black,
|
||||
fontWeight: isLast
|
||||
? FontWeight.w100
|
||||
: FontWeight.w300,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
reservedSize: 45,
|
||||
);
|
||||
},
|
||||
reservedSize: 45,
|
||||
),
|
||||
),
|
||||
rightTitles: const AxisTitles(),
|
||||
topTitles: const AxisTitles(),
|
||||
),
|
||||
rightTitles: const AxisTitles(),
|
||||
topTitles: const AxisTitles(),
|
||||
barGroups: widget.dataList.asMap().entries.map((e) {
|
||||
final index = e.key;
|
||||
final data = e.value;
|
||||
print('generateBarGroupBAR - $data');
|
||||
return generateBarGroup(
|
||||
index,
|
||||
data.color,
|
||||
data.value1,
|
||||
data.value2,
|
||||
data.shadowValue,
|
||||
);
|
||||
}).toList(),
|
||||
groupsSpace: 12,
|
||||
// maxY: widget.maxY,
|
||||
maxY: (widget.dataList != null && widget.dataList!.isNotEmpty)
|
||||
? widget.dataList!
|
||||
.map(
|
||||
(e) =>
|
||||
e.value1 > e.value2 ? e.value1 : e.value2,
|
||||
)
|
||||
.reduce((a, b) => a > b ? a : b) *
|
||||
1.15
|
||||
: 20,
|
||||
),
|
||||
barGroups: widget.dataList.asMap().entries.map((e) {
|
||||
final index = e.key;
|
||||
final data = e.value;
|
||||
print('generateBarGroupBAR - $data');
|
||||
return generateBarGroup(
|
||||
index,
|
||||
data.color,
|
||||
data.value1,
|
||||
data.value2,
|
||||
data.shadowValue,
|
||||
);
|
||||
}).toList(),
|
||||
|
||||
// maxY: widget.maxY,
|
||||
maxY: (widget.dataList != null && widget.dataList!.isNotEmpty)
|
||||
? widget.dataList!
|
||||
.map(
|
||||
(e) => e.value1 > e.value2 ? e.value1 : e.value2,
|
||||
)
|
||||
.reduce((a, b) => a > b ? a : b) +
|
||||
15
|
||||
: 20,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
String truncate(String text, {int max = 6}) {
|
||||
if (text.length <= max) return text;
|
||||
return text.substring(0, max);
|
||||
}
|
||||
}
|
||||
|
||||
401
lib/presentation/themes/charts/barChart_horizontal.dart
Normal file
401
lib/presentation/themes/charts/barChart_horizontal.dart
Normal file
@ -0,0 +1,401 @@
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../../core/services/api_service.dart';
|
||||
import '../../../data/models/bar_data.dart';
|
||||
import '../../providers/manager_provider.dart';
|
||||
import 'appChartColors.dart';
|
||||
|
||||
class CustomBarChartHorizontal extends ConsumerStatefulWidget {
|
||||
final List<BarData> dataList;
|
||||
final List<String> labels;
|
||||
final List<String>? shortName;
|
||||
final String title;
|
||||
final String? btnName;
|
||||
final double maxY;
|
||||
final int initialRotation;
|
||||
|
||||
const CustomBarChartHorizontal({
|
||||
super.key,
|
||||
required this.dataList,
|
||||
required this.labels,
|
||||
this.shortName,
|
||||
this.btnName,
|
||||
this.title = "Horizontal Bar Chart",
|
||||
this.maxY = 20,
|
||||
this.initialRotation = 1,
|
||||
});
|
||||
|
||||
final shadowColor = const Color(0xFFCCCCCC);
|
||||
|
||||
@override
|
||||
// State<CustomBarChartHorizontal> createState() => _CustomBarChartState();
|
||||
ConsumerState<CustomBarChartHorizontal> createState() =>
|
||||
_CustomBarChartState();
|
||||
}
|
||||
|
||||
class _CustomBarChartState extends ConsumerState<CustomBarChartHorizontal> {
|
||||
int touchedGroupIndex = -1;
|
||||
late int rotationTurns;
|
||||
dynamic managerId;
|
||||
late ApiService apiService;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
apiService = ApiService();
|
||||
rotationTurns = widget.initialRotation;
|
||||
Future.microtask(() {
|
||||
managerId = ref.read(managerIdProvider);
|
||||
});
|
||||
}
|
||||
|
||||
final indianFormatter = NumberFormat('#,##,##0', 'en_IN');
|
||||
BarChartGroupData generateBarGroup(
|
||||
int x,
|
||||
Color color,
|
||||
double value1,
|
||||
double value2,
|
||||
double shadowValue,
|
||||
) {
|
||||
return BarChartGroupData(
|
||||
x: x,
|
||||
groupVertically: false,
|
||||
|
||||
// showingTooltipIndicators: [x],
|
||||
showingTooltipIndicators: const [1, 2],
|
||||
|
||||
// barsSpace: 30,
|
||||
barRods: [
|
||||
BarChartRodData(toY: 0, color: Colors.transparent, width: 10),
|
||||
BarChartRodData(
|
||||
toY: value1,
|
||||
color: const Color(0xFF34a9a8),
|
||||
// color: Colors.cyan.shade300,
|
||||
width: 10,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(5),
|
||||
topRight: Radius.circular(5),
|
||||
),
|
||||
// borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
// BarChartRodData(toY: 2, color: Colors.orange.shade300, width: 6),
|
||||
BarChartRodData(
|
||||
toY: value2,
|
||||
color: const Color(0xFFA5E4E1),
|
||||
// color: Colors.orange.shade300,
|
||||
width: 10,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(5),
|
||||
topRight: Radius.circular(5),
|
||||
),
|
||||
// borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
],
|
||||
// showingTooltipIndicators: touchedGroupIndex == x ? [0] : [],
|
||||
);
|
||||
}
|
||||
|
||||
String compactNumber(num value) {
|
||||
if (value >= 10000000) {
|
||||
return '${(value / 10000000).toStringAsFixed(1).replaceAll('.0', '')}Cr';
|
||||
} else if (value >= 1000000) {
|
||||
return '${(value / 1000000).toStringAsFixed(1).replaceAll('.0', '')}M';
|
||||
} else if (value >= 1000) {
|
||||
return '${(value / 1000).toStringAsFixed(1).replaceAll('.0', '')}K';
|
||||
} else {
|
||||
return value.toInt().toString();
|
||||
}
|
||||
}
|
||||
|
||||
// Widget build(BuildContext context) {
|
||||
// return AspectRatio(
|
||||
// aspectRatio: 1.4,
|
||||
//
|
||||
// );
|
||||
// }
|
||||
|
||||
double getChartWidth() {
|
||||
const double barWidth = 40; // bar + spacing
|
||||
double minWidth =
|
||||
MediaQuery.of(context).size.width * 0.9; // minimum chart width
|
||||
|
||||
final calculatedWidth = widget.dataList.length * barWidth;
|
||||
return calculatedWidth < minWidth ? minWidth : calculatedWidth;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return SizedBox(
|
||||
// width: constraints.maxWidth,
|
||||
// height: constraints.maxHeight,
|
||||
width: getChartWidth(), // 👈 IMPORTANT
|
||||
height: constraints.maxHeight,
|
||||
child: BarChart(
|
||||
BarChartData(
|
||||
// alignment: BarChartAlignment.spaceBetween,
|
||||
alignment: BarChartAlignment.start,
|
||||
// verticalAxis: Axis.horizontal,
|
||||
rotationQuarterTurns: rotationTurns,
|
||||
barTouchData: BarTouchData(
|
||||
enabled: true,
|
||||
handleBuiltInTouches: true,
|
||||
touchTooltipData: BarTouchTooltipData(
|
||||
tooltipMargin: 6,
|
||||
tooltipRoundedRadius: 6,
|
||||
getTooltipColor: (group) {
|
||||
return Colors.transparent; // 👈 tooltip background color
|
||||
},
|
||||
tooltipPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 7,
|
||||
vertical: 2,
|
||||
),
|
||||
// rotateAngle: -85,
|
||||
// ask fl_chart to fit tooltip inside available space
|
||||
fitInsideVertically:
|
||||
true, // if your fl_chart version supports it
|
||||
fitInsideHorizontally:
|
||||
true, // if your fl_chart version supports it
|
||||
|
||||
getTooltipItem:
|
||||
(
|
||||
BarChartGroupData group,
|
||||
int groupIndex,
|
||||
BarChartRodData rod,
|
||||
int rodIndex,
|
||||
) {
|
||||
if (rod.toY == 0) {
|
||||
return null;
|
||||
}
|
||||
// final textColor = rodIndex == 1
|
||||
// ? Colors.cyan.shade500
|
||||
// : Colors.orange.shade500;
|
||||
|
||||
// final textColor = Colors.black;
|
||||
|
||||
final textColor = rodIndex == 1
|
||||
? Color(0xFF34a9a8)
|
||||
: Color(0xFF020050);
|
||||
final textStyle = GoogleFonts.poppins(
|
||||
color: textColor,
|
||||
fontSize: 8,
|
||||
fontWeight: rodIndex == 1
|
||||
? FontWeight.w600
|
||||
: FontWeight.w400,
|
||||
);
|
||||
|
||||
// final formattedValue = indianFormatter.format(
|
||||
// rod.toY.round(),
|
||||
// );
|
||||
|
||||
final formattedValue = compactNumber(rod.toY);
|
||||
return BarTooltipItem(formattedValue, textStyle);
|
||||
// return BarTooltipItem('${rod.toY.round()}', textStyle);
|
||||
},
|
||||
),
|
||||
|
||||
touchCallback: (FlTouchEvent e, BarTouchResponse? r) async {
|
||||
// optional: change state to highlight tapped group
|
||||
if (r == null || r.spot == null) {
|
||||
setState(() => touchedGroupIndex = -1);
|
||||
return;
|
||||
}
|
||||
setState(
|
||||
() => touchedGroupIndex = r.spot!.touchedBarGroupIndex,
|
||||
);
|
||||
|
||||
final spot = r.spot!;
|
||||
final groupIndex = spot.touchedBarGroupIndex;
|
||||
final rodIndex = spot.touchedRodDataIndex;
|
||||
|
||||
final barData = widget.dataList[groupIndex];
|
||||
|
||||
final name = barData.chartName;
|
||||
final val = barData.id;
|
||||
final month = rodIndex == 1 ? 'current' : 'previous';
|
||||
print('name - $name');
|
||||
print('val - $val');
|
||||
print('month - $month');
|
||||
print('managerId - $managerId');
|
||||
if (e is FlTapUpEvent) {
|
||||
debugPrint(
|
||||
'Tapped value → ${rodIndex == 1 ? barData.value1 : barData.value2} -> ${barData.id}-'
|
||||
' ${rodIndex == 1 ? 'current' : 'previous'} -> ${barData.chartName}',
|
||||
);
|
||||
if (managerId != null) {
|
||||
print('managerId - $managerId');
|
||||
await apiService.generateChartExcel(
|
||||
name,
|
||||
val,
|
||||
month,
|
||||
managerId,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
borderData: FlBorderData(
|
||||
show: true,
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppColors.gridLinesColor,
|
||||
// color: AppColors.contentColorBlack,
|
||||
width: 0.1,
|
||||
),
|
||||
right: BorderSide(
|
||||
color: AppColors.gridLinesColor,
|
||||
// color: AppColors.contentColorBlack,
|
||||
width: 0.1,
|
||||
),
|
||||
),
|
||||
),
|
||||
gridData: FlGridData(
|
||||
show: true,
|
||||
// drawVerticalLine: true,
|
||||
drawVerticalLine: false,
|
||||
getDrawingHorizontalLine: (value) => FlLine(
|
||||
// color: AppColors.gridLinesColor.withValues(alpha: 0.2),
|
||||
color: Colors.blueGrey.shade100,
|
||||
// color: Colors.black,
|
||||
// color: AppColors.borderColor,
|
||||
strokeWidth: 0.3,
|
||||
),
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
bottomTitles: AxisTitles(
|
||||
axisNameWidget: widget.btnName != null
|
||||
? Text(widget.btnName!)
|
||||
: Text(''),
|
||||
axisNameSize: 10,
|
||||
sideTitles: SideTitles(
|
||||
// reservedSize: 90,
|
||||
reservedSize: MediaQuery.of(context).size.width * 0.1,
|
||||
showTitles: true,
|
||||
getTitlesWidget: (value, meta) {
|
||||
final i = value.toInt();
|
||||
if (i >= widget.labels.length) return const SizedBox();
|
||||
final hasShortName =
|
||||
widget.shortName != null &&
|
||||
widget.shortName!.length > i &&
|
||||
widget.shortName![i].trim().isNotEmpty;
|
||||
|
||||
return SideTitleWidget(
|
||||
meta: meta,
|
||||
child: hasShortName
|
||||
? Tooltip(
|
||||
message: widget.shortName![i],
|
||||
child: Transform.rotate(
|
||||
angle: 0,
|
||||
child: Text(
|
||||
// widget.labels[i],
|
||||
truncate(widget.labels[i], max: 5),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF1E293B),
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Transform.rotate(
|
||||
angle: 0,
|
||||
child: Text(
|
||||
widget.labels[i],
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF1E293B),
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
rightTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
// interval: 10,
|
||||
getTitlesWidget: (value, meta) {
|
||||
// print("valuevalue - $value");
|
||||
|
||||
final text = value.toInt().toString();
|
||||
|
||||
final bool isLast = value == meta.max;
|
||||
// if (isLast) {
|
||||
// return const SizedBox.shrink(); // 👈 hide last label
|
||||
// }
|
||||
// print('value: $value');
|
||||
// print('text: $text');
|
||||
// print('length: ${text.length}');
|
||||
// print('isLast: $isLast');
|
||||
return Transform.rotate(
|
||||
angle: -3,
|
||||
// angle: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 3.0),
|
||||
child: Text(
|
||||
// isLast ? '0' : value.toInt().toString(),
|
||||
isLast ? '0' : compactNumber(value),
|
||||
textAlign: TextAlign.end,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 9,
|
||||
// color: isLast ? Colors.white : Colors.black,
|
||||
color: Colors.white,
|
||||
fontWeight: isLast
|
||||
? FontWeight.w100
|
||||
: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
reservedSize: 5,
|
||||
),
|
||||
),
|
||||
leftTitles: const AxisTitles(),
|
||||
topTitles: const AxisTitles(),
|
||||
),
|
||||
barGroups: widget.dataList.asMap().entries.map((e) {
|
||||
final index = e.key;
|
||||
final data = e.value;
|
||||
print('generateBarGroupBAR - $data');
|
||||
return generateBarGroup(
|
||||
index,
|
||||
data.color,
|
||||
data.value1,
|
||||
data.value2,
|
||||
data.shadowValue,
|
||||
);
|
||||
}).toList(),
|
||||
groupsSpace: 12,
|
||||
// maxY: widget.maxY,
|
||||
maxY: (widget.dataList != null && widget.dataList!.isNotEmpty)
|
||||
? widget.dataList!
|
||||
.map(
|
||||
(e) => e.value1 > e.value2 ? e.value1 : e.value2,
|
||||
)
|
||||
.reduce((a, b) => a > b ? a : b) *
|
||||
1.15
|
||||
: 20,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
String truncate(String text, {int max = 6}) {
|
||||
if (text.length <= max) return text;
|
||||
return text.substring(0, max);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user