Initial commit for intaleq_admin

This commit is contained in:
Hamza-Ayed
2026-01-20 23:39:59 +03:00
parent 0b17f93aaa
commit a367bc7e5c
53 changed files with 20383 additions and 14662 deletions

View File

@@ -1,238 +1,507 @@
import 'dart:convert';
import 'package:fl_chart/fl_chart.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../../constant/links.dart';
import '../../models/model/passengers_model.dart';
import '../../print.dart';
import '../functions/crud.dart';
class StaticController extends GetxController {
Map<String, dynamic> jsonData1 = {};
Map<String, dynamic> jsonData2 = {};
List staticList = [];
var chartDataPassengers;
var chartDataDrivers;
var chartDataDriversCalling;
var chartDataRides;
var chartDataEmployee;
var chartDataEmployeeMaryam;
var chartDataEmployeeRawda;
var chartDataEmployeeMena;
var chartDataEmployeeSefer4;
var chartDataDriversMatchingNotes;
// --- Date & State Management ---
DateTime? startDate = DateTime(DateTime.now().year, DateTime.now().month, 1);
DateTime? endDate =
DateTime(DateTime.now().year, DateTime.now().month + 1, 0);
DateTime? compareStartDate;
DateTime? compareEndDate;
bool isComparing = false;
bool isLoading = false;
String totalMonthlyPassengers = '';
String totalMonthlyRides = '';
String totalMonthlyEmployee = '';
String totalMonthlyDrivers = '';
late List<MonthlyPassengerInstall> passengersData;
late List<MonthlyRidesInstall> ridesData;
late List<MonthlyEmployeeData> employeeData;
late List<MonthlyDriverInstall> driversData;
Future<void> fetch() async {
isLoading = true;
update(); // Notify the observers about the loading state change
// --- Daily Notes State ---
bool isLoadingNotes = false;
List<dynamic> dailyNotesList = [];
var res = await CRUD().get(
link: AppLink.getPassengersStatic,
payload: {},
);
jsonData1 = jsonDecode(res);
var jsonResponse = jsonDecode(res) as Map<String, dynamic>;
isLoading = false;
final List<dynamic> jsonData = jsonResponse['message'];
totalMonthlyPassengers = jsonData[0]['totalMonthly'].toString();
passengersData = jsonData.map<MonthlyPassengerInstall>((item) {
return MonthlyPassengerInstall.fromJson(item);
}).toList();
final List<FlSpot> spots = passengersData
.map((data) => FlSpot(
data.day.toDouble(),
data.totalPassengers.toDouble(),
))
.toList();
chartDataPassengers = spots;
// --- Chart Data (Current Range) ---
List<FlSpot> chartDataPassengers = [];
List<FlSpot> chartDataDrivers = [];
List<FlSpot> chartDataRides = [];
List<FlSpot> chartDataDriversMatchingNotes = [];
update(); // Notify the observers about the data and loading state change
// Employee Data (Notes/General Stats)
List<FlSpot> chartDataEmployeerama1 = [];
List<FlSpot> chartDataEmployeeshahd = [];
List<FlSpot> chartDataEmployeeRama2 = [];
List<FlSpot> chartDataEmployeeSefer4 = [];
// Employee Data (Calls/Activations Stats)
List<FlSpot> chartDataCallsrama1 = [];
List<FlSpot> chartDataCallsShahd = [];
List<FlSpot> chartDataCallsRama2 = [];
List<FlSpot> chartDataCallsSefer4 = [];
// --- Chart Data (Comparison Range) ---
List<FlSpot> chartDataPassengersCompare = [];
List<FlSpot> chartDataDriversCompare = [];
List<FlSpot> chartDataRidesCompare = [];
List<FlSpot> chartDataDriversMatchingNotesCompare = [];
// Employee Comparison (Notes)
List<FlSpot> chartDataEmployeerama1Compare = [];
List<FlSpot> chartDataEmployeeshahdCompare = [];
List<FlSpot> chartDataEmployeeRama2Compare = [];
List<FlSpot> chartDataEmployeeSefer4Compare = [];
// Employee Comparison (Calls/Activations)
List<FlSpot> chartDataCallsrama1Compare = [];
List<FlSpot> chartDataCallsShahdCompare = [];
List<FlSpot> chartDataCallsRama2Compare = [];
List<FlSpot> chartDataCallsSefer4Compare = [];
// --- Totals ---
String totalMonthlyPassengers = '0';
String totalMonthlyRides = '0';
String totalMonthlyDrivers = '0';
// --- Raw Lists ---
List staticList = [];
// --- Employment Type Stats List (Simple Count) ---
List<Map<String, dynamic>> employmentStatsList = [];
@override
void onInit() {
super.onInit();
getAll();
}
Future<void> fetchRides() async {
isLoading = true;
update(); // Notify the observers about the loading state change
var res = await CRUD().get(
link: AppLink.getRidesStatic,
payload: {},
);
jsonData1 = jsonDecode(res);
var jsonResponse = jsonDecode(res) as Map<String, dynamic>;
isLoading = false;
final List<dynamic> jsonData = jsonResponse['message'];
totalMonthlyRides = jsonData[0]['totalMonthly'].toString();
ridesData = jsonData.map<MonthlyRidesInstall>((item) {
return MonthlyRidesInstall.fromJson(item);
}).toList();
final List<FlSpot> spots = ridesData
.map((data) => FlSpot(
data.day.toDouble(),
data.totalRides.toDouble(),
))
.toList();
chartDataRides = spots;
update(); // Notify the observers about the data and loading state change
// --- Helpers for View ---
double get daysInPeriod {
if (startDate == null || endDate == null) return 31;
return endDate!.difference(startDate!).inDays + 1.0;
}
Future<void> fetchEmployee() async {
try {
isLoading = true;
update();
String get currentDateString {
if (startDate == null || endDate == null) return "";
return "${DateFormat('yyyy-MM-dd').format(startDate!)} : ${DateFormat('yyyy-MM-dd').format(endDate!)}";
}
var res = await CRUD().get(link: AppLink.getEmployeeStatic, payload: {});
// --- Date Actions ---
void updateDateRange(DateTime start, DateTime end) {
startDate = start;
endDate = end;
if (isComparing) _calculateCompareDates();
getAll();
update();
}
// First check if the response is valid JSON
if (res == 'failure') {
throw FormatException('Invalid response: $res');
}
void _calculateCompareDates() {
if (startDate == null || endDate == null) return;
Duration duration = endDate!.difference(startDate!);
compareEndDate = startDate!.subtract(const Duration(days: 1));
compareStartDate = compareEndDate!.subtract(duration);
}
var jsonResponse = jsonDecode(res) as Map<String, dynamic>;
Future<void> toggleComparison() async {
isComparing = !isComparing;
if (isComparing) {
_calculateCompareDates();
} else {
compareStartDate = null;
compareEndDate = null;
_clearComparisonData();
}
await getAll();
}
// Initialize empty lists for all chart data
chartDataEmployeeMaryam = <FlSpot>[];
chartDataEmployeeRawda = <FlSpot>[];
chartDataEmployeeMena = <FlSpot>[];
chartDataEmployeeSefer4 = <FlSpot>[];
totalMonthlyRides = '0';
void _clearComparisonData() {
chartDataPassengersCompare.clear();
chartDataDriversCompare.clear();
chartDataRidesCompare.clear();
chartDataDriversMatchingNotesCompare.clear();
// Check for error response
if (jsonResponse['status'] == 'failure') {
isLoading = false;
update();
return;
}
chartDataEmployeerama1Compare.clear();
chartDataEmployeeshahdCompare.clear();
chartDataEmployeeRama2Compare.clear();
chartDataEmployeeSefer4Compare.clear();
final List<dynamic> jsonData = jsonResponse['message'];
if (jsonData.isEmpty) {
isLoading = false;
update();
return;
}
chartDataCallsrama1Compare.clear();
chartDataCallsShahdCompare.clear();
chartDataCallsRama2Compare.clear();
chartDataCallsSefer4Compare.clear();
}
totalMonthlyRides = jsonData[0]['totalMonthly']?.toString() ?? '0';
Map<String, dynamic> _getPayload(DateTime start, DateTime end) {
return {
"start_date": DateFormat('yyyy-MM-dd').format(start),
"end_date": DateFormat('yyyy-MM-dd').format(end),
"month": start.month.toString(),
"year": start.year.toString(),
};
}
// Group data by employee
Map<String, List<MonthlyEmployeeData>> employeeDataMap = {};
// --- Main Fetch Logic ---
Future getAll() async {
if (startDate == null || endDate == null) return;
for (var item in jsonData) {
var employeeData = MonthlyEmployeeData.fromJson(item);
if (!employeeDataMap.containsKey(employeeData.name)) {
employeeDataMap[employeeData.name] = [];
}
employeeDataMap[employeeData.name]!.add(employeeData);
}
isLoading = true;
update();
final today = DateTime.now().day;
await Future.wait([
fetchPassengers(isCompare: false),
fetchRides(isCompare: false),
fetchDrivers(isCompare: false),
fetchEmployee(isCompare: false),
fetchEditorCalls(isCompare: false),
fetchEmploymentStats(),
]);
// Create data for each employee
final employeeNames = {
'maryam': chartDataEmployeeMaryam,
'yasmine': chartDataEmployeeRawda,
'mena': chartDataEmployeeMena,
'ashjan': chartDataEmployeeSefer4,
};
if (isComparing && compareStartDate != null && compareEndDate != null) {
await Future.wait([
fetchPassengers(isCompare: true),
fetchRides(isCompare: true),
fetchDrivers(isCompare: true),
fetchEmployee(isCompare: true),
fetchEditorCalls(isCompare: true),
]);
}
employeeNames.forEach((name, chartData) {
var spots = <FlSpot>[];
for (int day = 1; day <= today; day++) {
spots.add(FlSpot(
day.toDouble(),
employeeDataMap[name]
?.firstWhere(
(e) => e.day == day,
orElse: () => MonthlyEmployeeData(
day: day,
totalEmployees: 0,
name: name,
),
)
.totalEmployees
.toDouble() ??
0,
));
}
isLoading = false;
update();
}
// Explicitly cast to List<FlSpot>
if (name == 'maryam')
chartDataEmployeeMaryam = List<FlSpot>.from(spots);
if (name == 'yasmine')
chartDataEmployeeRawda = List<FlSpot>.from(spots);
if (name == 'mena') chartDataEmployeeMena = List<FlSpot>.from(spots);
if (name == 'ashjan')
chartDataEmployeeSefer4 = List<FlSpot>.from(spots);
});
} catch (e) {
Log.print('Error in fetchEmployee: $e');
// Set empty FlSpot lists in case of error
chartDataEmployeeMaryam = <FlSpot>[];
chartDataEmployeeRawda = <FlSpot>[];
chartDataEmployeeMena = <FlSpot>[];
chartDataEmployeeSefer4 = <FlSpot>[];
totalMonthlyRides = '0';
} finally {
isLoading = false;
update();
// ... (Existing Functions _generateSpots, fetchPassengers, etc.) ...
List<FlSpot> _generateSpots(List<dynamic> data, String dateKey,
String valueKey, DateTime startOfRange) {
List<FlSpot> spots = [];
Map<String, double> dataMap = {};
for (var item in data) {
String dateStr = item[dateKey].toString();
double val = double.tryParse(item[valueKey].toString()) ?? 0.0;
dataMap[dateStr] = val;
}
DateTime rangeEnd =
(startOfRange == startDate) ? endDate! : compareEndDate!;
int totalDays = rangeEnd.difference(startOfRange).inDays + 1;
for (int i = 0; i < totalDays; i++) {
DateTime currentDate = startOfRange.add(Duration(days: i));
String dateKeyStr = DateFormat('yyyy-MM-dd').format(currentDate);
double value = dataMap[dateKeyStr] ?? 0.0;
spots.add(FlSpot((i + 1).toDouble(), value));
}
return spots;
}
Future<void> fetchPassengers({bool isCompare = false}) async {
DateTime start = isCompare ? compareStartDate! : startDate!;
DateTime end = isCompare ? compareEndDate! : endDate!;
var res = await CRUD().get(
link: AppLink.getPassengersStatic, payload: _getPayload(start, end));
var jsonResponse = jsonDecode(res);
if (jsonResponse['status'] == 'failure') return;
final List<dynamic> jsonData = jsonResponse['message'];
if (!isCompare &&
jsonData.isNotEmpty &&
jsonData[0]['totalMonthly'] != null) {
totalMonthlyPassengers = jsonData[0]['totalMonthly'].toString();
}
List<FlSpot> spots =
_generateSpots(jsonData, 'day', 'totalPassengers', start);
if (isCompare)
chartDataPassengersCompare = spots;
else
chartDataPassengers = spots;
}
Future<void> fetchRides({bool isCompare = false}) async {
DateTime start = isCompare ? compareStartDate! : startDate!;
DateTime end = isCompare ? compareEndDate! : endDate!;
var res = await CRUD()
.get(link: AppLink.getRidesStatic, payload: _getPayload(start, end));
var jsonResponse = jsonDecode(res);
if (jsonResponse['status'] == 'failure') return;
final List<dynamic> jsonData = jsonResponse['message'];
if (!isCompare &&
jsonData.isNotEmpty &&
jsonData[0]['totalMonthly'] != null) {
totalMonthlyRides = jsonData[0]['totalMonthly'].toString();
}
List<FlSpot> spots = _generateSpots(jsonData, 'day', 'totalRides', start);
if (isCompare)
chartDataRidesCompare = spots;
else
chartDataRides = spots;
}
Future<void> fetchDrivers({bool isCompare = false}) async {
DateTime start = isCompare ? compareStartDate! : startDate!;
DateTime end = isCompare ? compareEndDate! : endDate!;
var res = await CRUD().get(
link: AppLink.getdriverstotalMonthly, payload: _getPayload(start, end));
var jsonResponse = jsonDecode(res);
if (jsonResponse['status'] == 'failure') return;
final List<dynamic> jsonData = jsonResponse['message'];
if (!isCompare &&
jsonData.isNotEmpty &&
jsonData[0]['totalMonthlyDrivers'] != null) {
totalMonthlyDrivers = jsonData[0]['totalMonthlyDrivers'].toString();
}
if (!isCompare) {
staticList = jsonData;
}
List<FlSpot> spotsDrivers =
_generateSpots(jsonData, 'day', 'dailyTotalDrivers', start);
List<FlSpot> spotsNotes =
_generateSpots(jsonData, 'day', 'dailyMatchingNotes', start);
if (isCompare) {
chartDataDriversCompare = spotsDrivers;
chartDataDriversMatchingNotesCompare = spotsNotes;
} else {
chartDataDrivers = spotsDrivers;
chartDataDriversMatchingNotes = spotsNotes;
}
}
Future<void> fetchDrivers() async {
isLoading = true;
update(); // Notify the observers about the loading state change
Future<void> fetchEmployee({bool isCompare = false}) async {
try {
DateTime start = isCompare ? compareStartDate! : startDate!;
DateTime end = isCompare ? compareEndDate! : endDate!;
var res = await CRUD().get(
link: AppLink.getEmployeeStatic, payload: _getPayload(start, end));
var res = await CRUD().get(
link: AppLink.getdriverstotalMonthly,
payload: {},
);
jsonData2 = jsonDecode(res);
var jsonResponse = jsonDecode(res) as Map<String, dynamic>;
isLoading = false;
final List<dynamic> jsonData = jsonResponse['message'];
staticList = jsonData;
totalMonthlyDrivers = jsonData[0]['totalDrivers'].toString();
driversData = jsonData.map<MonthlyDriverInstall>((item) {
return MonthlyDriverInstall.fromJson(item);
}).toList();
final List<FlSpot> spots = driversData
.map((data) => FlSpot(
data.day.toDouble(),
data.dailyTotalDrivers.toDouble(),
))
.toList();
chartDataDrivers = spots;
final List<FlSpot> spotsCalling = driversData
.map((data) => FlSpot(
data.day.toDouble(),
data.dailyTotalCallingDrivers.toDouble(),
))
.toList();
chartDataDriversCalling = spotsCalling;
final List<FlSpot> spotsTotalMatchingNotes = driversData
.map((data) => FlSpot(
data.day.toDouble(),
data.dailyMatchingNotes.toDouble(),
))
.toList();
chartDataDriversMatchingNotes = spotsTotalMatchingNotes;
if (isCompare) {
chartDataEmployeerama1Compare = [];
chartDataEmployeeshahdCompare = [];
chartDataEmployeeRama2Compare = [];
chartDataEmployeeSefer4Compare = [];
} else {
chartDataEmployeerama1 = [];
chartDataEmployeeshahd = [];
chartDataEmployeeRama2 = [];
chartDataEmployeeSefer4 = [];
}
update(); // Notify the observers about the data and loading state change
if (res == 'failure') return;
var jsonResponse = jsonDecode(res) as Map<String, dynamic>;
if (jsonResponse['status'] == 'failure') return;
final List<dynamic> jsonData = jsonResponse['message'];
if (jsonData.isEmpty) return;
Map<String, Map<String, double>> dateNameMap = {};
for (var item in jsonData) {
String dateKeyStr = item['date'] ?? item['day'];
String name = item['NAME'].toString().toLowerCase().trim();
double count = double.tryParse(item['count'].toString()) ?? 0.0;
if (!dateNameMap.containsKey(dateKeyStr)) dateNameMap[dateKeyStr] = {};
if (dateNameMap[dateKeyStr]!.containsKey(name)) {
dateNameMap[dateKeyStr]![name] =
dateNameMap[dateKeyStr]![name]! + count;
} else {
dateNameMap[dateKeyStr]![name] = count;
}
}
final targetLists = isCompare
? {
'rama1': chartDataEmployeerama1Compare,
'shahd': chartDataEmployeeshahdCompare,
'rama2': chartDataEmployeeRama2Compare,
'mayar': chartDataEmployeeSefer4Compare
}
: {
'rama1': chartDataEmployeerama1,
'shahd': chartDataEmployeeshahd,
'rama2': chartDataEmployeeRama2,
'mayar': chartDataEmployeeSefer4
};
int totalDays = end.difference(start).inDays + 1;
targetLists.forEach((key, listToFill) {
for (int i = 0; i < totalDays; i++) {
DateTime currentDate = start.add(Duration(days: i));
String currentDateStr = DateFormat('yyyy-MM-dd').format(currentDate);
double value = 0;
Map<String, double>? dayData = dateNameMap[currentDateStr];
if (dayData != null) {
// if (key == 'mayar') {
// value = (dayData['mayar'] ?? 0) +
// (dayData['rama1'] ?? 0) +
// (dayData['sefer4'] ?? 0);
// } else {
value = dayData[key] ?? 0;
// }
}
listToFill.add(FlSpot((i + 1).toDouble(), value));
}
});
} catch (e) {
Log.print('Error in fetchEmployee: $e');
}
}
Future getAll() async {
await fetch();
await fetchRides();
await fetchDrivers();
await fetchEmployee();
Future<void> fetchEditorCalls({bool isCompare = false}) async {
try {
DateTime start = isCompare ? compareStartDate! : startDate!;
DateTime end = isCompare ? compareEndDate! : endDate!;
var res = await CRUD().get(
link: AppLink.getEditorStatsCalls, payload: _getPayload(start, end));
if (isCompare) {
chartDataCallsrama1Compare = [];
chartDataCallsShahdCompare = [];
chartDataCallsRama2Compare = [];
chartDataCallsSefer4Compare = [];
} else {
chartDataCallsrama1 = [];
chartDataCallsShahd = [];
chartDataCallsRama2 = [];
chartDataCallsSefer4 = [];
}
if (res == 'failure') return;
var jsonResponse = jsonDecode(res) as Map<String, dynamic>;
if (jsonResponse['status'] == 'failure') return;
final List<dynamic> jsonData = jsonResponse['message'];
if (jsonData.isEmpty) return;
Map<String, Map<String, double>> dateNameMap = {};
for (var item in jsonData) {
String dateKeyStr = item['date'] ?? item['day'];
String name = item['NAME'].toString().toLowerCase().trim();
double count = double.tryParse(item['count'].toString()) ?? 0.0;
if (!dateNameMap.containsKey(dateKeyStr)) {
dateNameMap[dateKeyStr] = {};
}
if (dateNameMap[dateKeyStr]!.containsKey(name)) {
dateNameMap[dateKeyStr]![name] =
dateNameMap[dateKeyStr]![name]! + count;
} else {
dateNameMap[dateKeyStr]![name] = count;
}
}
final targetLists = isCompare
? {
'rama1': chartDataCallsrama1Compare,
'shahd': chartDataCallsShahdCompare,
'rama2': chartDataCallsRama2Compare,
'mayar': chartDataCallsSefer4Compare,
}
: {
'rama1': chartDataCallsrama1,
'shahd': chartDataCallsShahd,
'rama2': chartDataCallsRama2,
'mayar': chartDataCallsSefer4,
};
int totalDays = end.difference(start).inDays + 1;
targetLists.forEach((key, listToFill) {
for (int i = 0; i < totalDays; i++) {
DateTime currentDate = start.add(Duration(days: i));
String currentDateStr = DateFormat('yyyy-MM-dd').format(currentDate);
double value = 0;
Map<String, double>? dayData = dateNameMap[currentDateStr];
if (dayData != null) {
// if (key == 'mayar_group') {
// value = (dayData['mayar'] ?? 0) +
// (dayData['rama1'] ?? 0) +
// (dayData['sefer4'] ?? 0);
// } else {
value = dayData[key] ?? 0;
// }
}
listToFill.add(FlSpot((i + 1).toDouble(), value));
}
});
} catch (e) {
Log.print('Error in fetchEditorCalls: $e');
}
}
// --- 🔴 FIXED: Fetch Employment Stats with Unique Check ---
Future<void> fetchEmploymentStats() async {
try {
// لا نستخدم .clear() هنا، سنقوم باستبدال القائمة بالكامل في النهاية
var res = await CRUD().get(
link: AppLink.getEmployeeDriverAfterCallingRegister,
payload: _getPayload(startDate!, endDate!));
if (res == 'failure') return;
var jsonResponse = jsonDecode(res);
if (jsonResponse['status'] == 'success') {
if (jsonResponse['message'] != null &&
jsonResponse['message']['data'] != null) {
List<dynamic> data = jsonResponse['message']['data'];
List<String> allowedNames = ['shahd', 'mayar', 'rama1', 'rama2'];
// استخدام Map لضمان عدم تكرار الأسماء (تجميع القيم)
Map<String, int> uniqueMap = {};
for (var item in data) {
String name =
item['employmentType'].toString().toLowerCase().trim();
int count = int.tryParse(item['count'].toString()) ?? 0;
if (allowedNames.contains(name)) {
if (uniqueMap.containsKey(name)) {
uniqueMap[name] = uniqueMap[name]! + count;
} else {
uniqueMap[name] = count;
}
}
}
// تحويل الـ Map إلى القائمة النهائية
List<Map<String, dynamic>> tempList = [];
uniqueMap.forEach((key, value) {
tempList.add({'name': key, 'count': value});
});
// استبدال القائمة القديمة بالقائمة الجديدة النظيفة
employmentStatsList = tempList;
}
}
} catch (e) {
Log.print("Error fetchEmploymentStats: $e");
}
}
// --- Fetch Daily Notes Log ---
Future<void> fetchDailyNotes(DateTime date) async {
try {
isLoadingNotes = true;
dailyNotesList.clear();
update();
var res = await CRUD().post(
link: AppLink.getNotesForEmployee,
payload: {"date": DateFormat('yyyy-MM-dd').format(date)});
if (res != 'failure') {
var jsonResponse = (res);
if (jsonResponse['status'] == 'success') {
dailyNotesList = jsonResponse['message'];
}
}
} catch (e) {
Log.print("Error fetchDailyNotes: $e");
} finally {
isLoadingNotes = false;
update();
}
}
}