From 7cf3e80d46fc90fdaebba07f3275fba4a53e1b66 Mon Sep 17 00:00:00 2001 From: lahirulakruwan Date: Thu, 21 Nov 2024 14:50:22 +0530 Subject: [PATCH] Batch select changes added to frontend late attendance report and monthly payment report --- .../widgets/assign_duty_for_participant.dart | 1662 +++++++++-------- .../lib/widgets/daily_attendance_report.dart | 565 +++--- .../lib/widgets/late_attendance_report.dart | 384 ++-- .../lib/widgets/monthly_payment_report.dart | 616 +++--- 4 files changed, 1843 insertions(+), 1384 deletions(-) diff --git a/campus/frontend/lib/avinya/attendance/lib/widgets/assign_duty_for_participant.dart b/campus/frontend/lib/avinya/attendance/lib/widgets/assign_duty_for_participant.dart index d1fcfd81..dc49a191 100644 --- a/campus/frontend/lib/avinya/attendance/lib/widgets/assign_duty_for_participant.dart +++ b/campus/frontend/lib/avinya/attendance/lib/widgets/assign_duty_for_participant.dart @@ -7,48 +7,57 @@ import 'package:gallery/constants.dart'; import 'package:gallery/layout/adaptive.dart'; import 'package:intl/intl.dart'; - class AssignDutyForParticipant extends StatefulWidget { const AssignDutyForParticipant({super.key}); @override - State createState() => _AssignDutyForParticipantState(); + State createState() => + _AssignDutyForParticipantState(); } class _AssignDutyForParticipantState extends State { - var _selectedClassValue; var _selectedPersonValue; Organization? _fetchedOrganization; late List> _dropDownPersonList; + late List _selectedBatchValues; + late List> _dropDownClassList; late List _selectedClassValues; late List _selectedPersonValues; late List _selectedRoleValues; + late Future> _fetchBatchData; + List _batchData = []; List _dutyParticipants = []; - List _activitiesByAvinyaType = []; + List _activitiesByAvinyaType = []; List _activitiesNames = []; - List _dutyRelatedParticipantsFilterAndStore = []; //filter And Store duty Relavant Participants - List _dropDownRoleList = ['leader','assistant-leader','member']; + List _dutyRelatedParticipantsFilterAndStore = + []; //filter And Store duty Relavant Participants + List _dropDownRoleList = ['leader', 'assistant-leader', 'member']; late DutyRotationMetaDetails _rotationMetaDetails; - late TextEditingController _startDate; + late TextEditingController _startDate; late TextEditingController _endDate; bool _startDateSelected = true; bool _endDateSelected = true; - @override - void initState(){ - super.initState(); - loadActivitiesByAvinyaType(); - loadRotationMetadetails(); + void initState() { + super.initState(); + _fetchBatchData = _loadBatchData(); + loadActivitiesByAvinyaType(); + loadRotationMetadetails(); _startDate = TextEditingController(); _endDate = TextEditingController(); } + Future> _loadBatchData() async { + _batchData = await fetchActiveOrganizationsByAvinyaType(86); + return _batchData; + } + @override void dispose() { _startDate.dispose(); @@ -56,879 +65,1012 @@ class _AssignDutyForParticipantState extends State { super.dispose(); } - bool hasLeaderRoleWithActivity(String? activityName,String? allocatedRole){ - - if(allocatedRole == "leader" || allocatedRole == "assistant-leader"){ - int count = 0; + bool hasLeaderRoleWithActivity(String? activityName, String? allocatedRole) { + if (allocatedRole == "leader" || allocatedRole == "assistant-leader") { + int count = 0; - for(var participant in _dutyParticipants){ - - if(participant.activity?.name == activityName){ - if(participant.role == allocatedRole){ - count++; + for (var participant in _dutyParticipants) { + if (participant.activity?.name == activityName) { + if (participant.role == allocatedRole) { + count++; + } } } - } return count == 1; - }else{ - return false; + } else { + return false; } } - Future> loadDutyParticipantsData(int organization_id) async{ - + Future> loadDutyParticipantsData( + int organization_id) async { return await fetchDutyParticipants(organization_id); } - Future loadRotationMetadetails() async{ - _rotationMetaDetails = await fetchDutyRotationMetadataByOrganization(campusAppsPortalInstance.getUserPerson().organization!.id!); - - if(_rotationMetaDetails.start_date!=null && _rotationMetaDetails.end_date !=null){ - - DateTime parsedStartDate = DateTime.parse(_rotationMetaDetails.start_date!).toLocal(); - DateTime parsedEndDate = DateTime.parse(_rotationMetaDetails.end_date!).toLocal(); - _startDate.text = DateFormat('yyyy-MM-dd').format(parsedStartDate); - _endDate.text = DateFormat('yyyy-MM-dd').format(parsedEndDate); - - }else{ + Future loadRotationMetadetails() async { + _rotationMetaDetails = await fetchDutyRotationMetadataByOrganization( + campusAppsPortalInstance.getUserPerson().organization!.id!); + + if (_rotationMetaDetails.start_date != null && + _rotationMetaDetails.end_date != null) { + DateTime parsedStartDate = + DateTime.parse(_rotationMetaDetails.start_date!).toLocal(); + DateTime parsedEndDate = + DateTime.parse(_rotationMetaDetails.end_date!).toLocal(); + _startDate.text = DateFormat('yyyy-MM-dd').format(parsedStartDate); + _endDate.text = DateFormat('yyyy-MM-dd').format(parsedEndDate); + } else { setState(() { _startDateSelected = false; - _endDateSelected = false; + _endDateSelected = false; }); - } - + } } - Future loadActivitiesByAvinyaType() async{ - - _activitiesByAvinyaType = await fetchActivitiesByAvinyaType(91); //load avinya type =91(work) related activities + Future loadActivitiesByAvinyaType() async { + _activitiesByAvinyaType = await fetchActivitiesByAvinyaType( + 91); //load avinya type =91(work) related activities _activitiesByAvinyaType.removeWhere((activity) => activity.name == 'work'); - _activitiesNames = _activitiesByAvinyaType.map((activities) => activities.name).toList(); + _activitiesNames = + _activitiesByAvinyaType.map((activities) => activities.name).toList(); - _dropDownPersonList = List.generate(_activitiesNames.length,(index) =>[]); - _selectedClassValues = List.generate(_activitiesNames.length, (index) => null); - _selectedPersonValues = List.generate(_activitiesNames.length, (index) => null); - _selectedRoleValues = List.generate(_activitiesNames.length,(index)=>null); - + _dropDownPersonList = List.generate(_activitiesNames.length, (index) => []); + _dropDownClassList = List.generate(_activitiesNames.length, (index) => []); + _selectedBatchValues = + List.generate(_activitiesNames.length, (index) => null); + _selectedClassValues = + List.generate(_activitiesNames.length, (index) => null); + _selectedPersonValues = + List.generate(_activitiesNames.length, (index) => null); + _selectedRoleValues = + List.generate(_activitiesNames.length, (index) => null); } - - - @override - void didChangeDependencies(){ + @override + void didChangeDependencies() { super.didChangeDependencies(); } @override Widget build(BuildContext context) { - final isDesktop = isDisplayDesktop(context); return Container( child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if(isDesktop) - Container( - margin: EdgeInsets.only(left: 17.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - - Row( - children:[ - Container( - width: 300, - child: TextField( - enabled: false, - controller: _startDate, - decoration: InputDecoration( - icon: Icon(Icons.calendar_today), - labelText: "Rotation Start Date" - ), - readOnly: true, - onTap: () => _selectStartDate(context), - ), - ), - SizedBox( - width: 10, - ), - Container( - width: 300, - child: TextField( - enabled: false, - controller: _endDate, - decoration: InputDecoration( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (isDesktop) + Container( + margin: EdgeInsets.only(left: 17.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + width: 300, + child: TextField( + enabled: false, + controller: _startDate, + decoration: InputDecoration( icon: Icon(Icons.calendar_today), - labelText: "Rotation End Date" - ), - readOnly: true, - onTap: () => _selectEndDate(context), - ), - ), - ], + labelText: "Rotation Start Date"), + readOnly: true, + onTap: () => _selectStartDate(context), ), + ), SizedBox( - height: 10, + width: 10, ), - Container( - margin: EdgeInsets.only(left: 200), - child: _startDateSelected && _endDateSelected - ? SizedBox() - : Text( - 'Please select both start and end dates', - style: TextStyle(color: Colors.red), - ), - ), - ],), - ) - else - Container( - margin: EdgeInsets.only(left: 17.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SizedBox( - height: 10, - ), - Container( - width: 300, - child: TextField( - enabled: false, - controller: _startDate, - decoration: InputDecoration( - icon: Icon(Icons.calendar_today), - labelText: "Rotation Start Date" - ), - readOnly: true, - onTap: () => _selectStartDate(context), - ), - ), - SizedBox( - width: 10, - ), - Container( - width: 300, - child: TextField( - enabled: false, - controller: _endDate, - decoration: InputDecoration( + Container( + width: 300, + child: TextField( + enabled: false, + controller: _endDate, + decoration: InputDecoration( icon: Icon(Icons.calendar_today), - labelText: "Rotation End Date" - ), - readOnly: true, - onTap: () => _selectEndDate(context), - ), + labelText: "Rotation End Date"), + readOnly: true, + onTap: () => _selectEndDate(context), + ), + ), + ], + ), + SizedBox( + height: 10, + ), + Container( + margin: EdgeInsets.only(left: 200), + child: _startDateSelected && _endDateSelected + ? SizedBox() + : Text( + 'Please select both start and end dates', + style: TextStyle(color: Colors.red), ), - SizedBox( - height: 20, + ), + ], + ), + ) + else + Container( + margin: EdgeInsets.only(left: 17.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + height: 10, + ), + Container( + width: 300, + child: TextField( + enabled: false, + controller: _startDate, + decoration: InputDecoration( + icon: Icon(Icons.calendar_today), + labelText: "Rotation Start Date"), + readOnly: true, + onTap: () => _selectStartDate(context), + ), + ), + SizedBox( + width: 10, + ), + Container( + width: 300, + child: TextField( + enabled: false, + controller: _endDate, + decoration: InputDecoration( + icon: Icon(Icons.calendar_today), + labelText: "Rotation End Date"), + readOnly: true, + onTap: () => _selectEndDate(context), + ), + ), + SizedBox( + height: 20, + ), + Container( + margin: EdgeInsets.only(left: 30), + child: _startDateSelected && _endDateSelected + ? SizedBox() + : Text( + 'Please select both start and end dates', + style: TextStyle(color: Colors.red), ), - Container( - margin: EdgeInsets.only(left: 30), - child: _startDateSelected && _endDateSelected - ? SizedBox() - : Text( - 'Please select both start and end dates', - style: TextStyle(color: Colors.red), - ), - ), - ], - ), - ), - SizedBox( - height: 30, - ), - FutureBuilder( - future:loadDutyParticipantsData(campusAppsPortalInstance.getUserPerson().organization!.id!), - builder:(BuildContext context,snapshot){ - - if(snapshot.hasData){ - - return SingleChildScrollView( - child: ListView.builder( - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: _activitiesNames.length, - itemBuilder: (context,tableIndex){ - // print('table index:{$tableIndex}'); - _dutyRelatedParticipantsFilterAndStore.clear(); - _dutyParticipants = (snapshot.data as List); - _dutyRelatedParticipantsFilterAndStore = _dutyParticipants.where((filterParticipant)=>filterParticipant.activity!.name == _activitiesNames[tableIndex]).toList(); - return Container( - width: 1200, - margin: EdgeInsets.only(left: 10.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - for (var org in campusAppsPortalInstance - .getUserPerson() - .organization! - .child_organizations) - - if (org.child_organizations.length > 0) - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - - Container( - child: Row( - children: [ - SizedBox( - width: 10, - ), - const Icon( - IconData(0xe6f2, fontFamily: 'MaterialIcons'), - size: 25, - color: Colors.deepPurpleAccent, - ), - SizedBox( - width: 10, - ), - Flexible( - flex: 2, - child: Container( - width: 200, - child: Text( - '${_activitiesNames[tableIndex]}', - overflow: TextOverflow.clip, - style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold) - ) - ), - ), - ], - ), - ), - SizedBox( - height: 20, - ), - - if(isDesktop) - Row( - mainAxisAlignment: MainAxisAlignment.start, - children:[ - SizedBox( - child: - Row( - mainAxisAlignment: MainAxisAlignment.start, - children:[ - SizedBox( - width: 10, - ), - Text( - 'Select a class :', - overflow: TextOverflow.clip, - style: TextStyle(fontSize: 15,fontWeight: FontWeight.normal) - ), - - Container( - margin: EdgeInsets.only(left: 10.0), - width: 120, - child: buildClassDropDownButton(org,tableIndex,_dutyParticipants) - ), - ] - ), - ), - SizedBox( - width: 10, - ), - SizedBox( - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SizedBox( - width: 10, - ), - Text( - 'Select a person :', - overflow: TextOverflow.clip, - style: TextStyle(fontSize: 15,fontWeight: FontWeight.normal) - ), - SizedBox( - width: 20, - ), - - ConstrainedBox( - constraints: BoxConstraints( - minWidth: 120, - maxWidth: 240, - ), - child: buildPersonDropDownButton(tableIndex), - ) - - ] - ), - ), - SizedBox( - width: 5, - ), - SizedBox( - child: - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SizedBox( - width: 10, - ), - Text( - 'Select a role :', - overflow: TextOverflow.clip, - style: TextStyle(fontSize: 15,fontWeight: FontWeight.normal) - ), - - Container( - margin: EdgeInsets.only(left: 10.0), - width: 140, - child: buildRoleDropDownButton(tableIndex) - ), - ], - ), - ), - - ] - ) - else - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children:[ - SizedBox( - child: - Row( - mainAxisAlignment: MainAxisAlignment.start, - children:[ - SizedBox( - width: 10, - ), - Flexible( - flex: 1, - child: Container( - width: 100, - child: Text( - 'Select a class :', - overflow: TextOverflow.clip, - style: TextStyle(fontSize: 15,fontWeight: FontWeight.normal) - ), - ), - ), - SizedBox( - width: 20, - ), - Container( - margin: EdgeInsets.only(left: 10.0), - width: 120, - child: buildClassDropDownButton(org,tableIndex,_dutyParticipants) - ), - ] - ), - ), - SizedBox( - width: 10, - ), - SizedBox( - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SizedBox( - width: 10, - ), - Flexible( - flex: 1, - child: Container( - width: 100, - child: Text( - 'Select a person :', - overflow: TextOverflow.clip, - style: TextStyle(fontSize: 15,fontWeight: FontWeight.normal) - ), - ), - ), - SizedBox( - width: 30, - ), - - ConstrainedBox( - constraints: BoxConstraints( - minWidth: 120, - maxWidth: 240, - ), - child: buildPersonDropDownButton(tableIndex) - ), - ] - ), - ), - SizedBox( - width: 5, - ), - SizedBox( - child: - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SizedBox( - width: 10, - ), - Flexible( - flex: 1, - child: Container( - width: 100, - child: Text( - 'Select a role :', - overflow: TextOverflow.clip, - style: TextStyle(fontSize: 15,fontWeight: FontWeight.normal) - ), - ), - ), - SizedBox( - width: 20, - ), - Container( - margin: EdgeInsets.only(left: 10.0), - width: 140, - child: buildRoleDropDownButton(tableIndex) - ), - ], - ), - ), - - ] - ), - - ], + ), + ], + ), + ), + SizedBox( + height: 30, + ), + FutureBuilder( + future: loadDutyParticipantsData( + campusAppsPortalInstance.getUserPerson().organization!.id!), + builder: (BuildContext context, snapshot) { + if (snapshot.hasData) { + return SingleChildScrollView( + child: ListView.builder( + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: _activitiesNames.length, + itemBuilder: (context, tableIndex) { + // print('table index:{$tableIndex}'); + _dutyRelatedParticipantsFilterAndStore.clear(); + _dutyParticipants = + (snapshot.data as List); + _dutyRelatedParticipantsFilterAndStore = _dutyParticipants + .where((filterParticipant) => + filterParticipant.activity!.name == + _activitiesNames[tableIndex]) + .toList(); + return Container( + width: 1200, + margin: EdgeInsets.only(left: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Row( + children: [ + SizedBox( + width: 10, + ), + const Icon( + IconData(0xe6f2, + fontFamily: 'MaterialIcons'), + size: 25, + color: Colors.deepPurpleAccent, + ), + SizedBox( + width: 10, + ), + Flexible( + flex: 2, + child: Container( + width: 200, + child: Text( + '${_activitiesNames[tableIndex]}', + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 16, + fontWeight: + FontWeight.bold))), + ), + ], + ), + ), + SizedBox( + height: 20, + ), + if (isDesktop) + Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + SizedBox( + child: Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + SizedBox( + width: 10, + ), + Text('Select a Batch:'), + SizedBox(width: 10), + buildBatchDropDownButton( + tableIndex), + SizedBox( + width: 10, + ), + Text('Select a class :', + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 15, + fontWeight: + FontWeight.normal)), + Container( + margin: EdgeInsets.only( + left: 10.0), + width: 120, + child: + buildClassDropDownButton( + tableIndex, + _dutyParticipants)), + ]), + ), + SizedBox( + width: 10, + ), + SizedBox( + child: Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + SizedBox( + width: 10, + ), + Text('Select a person :', + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 15, + fontWeight: + FontWeight.normal)), + SizedBox( + width: 20, + ), + ConstrainedBox( + constraints: BoxConstraints( + minWidth: 120, + maxWidth: 240, ), - ), - - SingleChildScrollView( - scrollDirection: Axis.horizontal, + child: + buildPersonDropDownButton( + tableIndex), + ) + ]), + ), + SizedBox( + width: 5, + ), + SizedBox( child: Row( + mainAxisAlignment: + MainAxisAlignment.start, children: [ - buildTable(_dutyRelatedParticipantsFilterAndStore,tableIndex,_dutyParticipants) + SizedBox( + width: 10, + ), + Text('Select a role :', + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 15, + fontWeight: + FontWeight.normal)), + Container( + margin: EdgeInsets.only( + left: 10.0), + width: 140, + child: + buildRoleDropDownButton( + tableIndex)), ], - ), - ), - SizedBox( - height: 30, - ) - ], - - ), - ); - }, - ), - ); - } - - return Container( - margin: EdgeInsets.only(top: 10), - child: SpinKitCircle( - color: (Colors.deepPurpleAccent), - size: 70, + ), + ), + ]) + else + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + SizedBox( + child: Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + SizedBox( + width: 10, + ), + Flexible( + child: Container( + width: 100, + child: Text('Select a Batch:', + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 15, + fontWeight: + FontWeight.normal)), + )), + SizedBox(width: 20), + Container( + margin: + EdgeInsets.only(left: 10.0), + width: 150, + child: buildBatchDropDownButton( + tableIndex), + ), + ], + ), + ), + SizedBox( + width: 10, + ), + SizedBox( + child: Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + SizedBox( + width: 10, + ), + Flexible( + flex: 1, + child: Container( + width: 100, + child: Text( + 'Select a class :', + overflow: + TextOverflow.clip, + style: TextStyle( + fontSize: 15, + fontWeight: + FontWeight + .normal)), + ), + ), + SizedBox( + width: 20, + ), + Container( + margin: EdgeInsets.only( + left: 10.0), + width: 150, + child: + buildClassDropDownButton( + tableIndex, + _dutyParticipants)), + ]), + ), + SizedBox( + width: 10, + ), + SizedBox( + child: Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + SizedBox( + width: 10, + ), + Flexible( + flex: 1, + child: Container( + width: 100, + child: Text( + 'Select a person :', + overflow: + TextOverflow.clip, + style: TextStyle( + fontSize: 15, + fontWeight: + FontWeight + .normal)), + ), + ), + SizedBox( + width: 30, + ), + ConstrainedBox( + constraints: BoxConstraints( + minWidth: 120, + maxWidth: 240, + ), + child: + buildPersonDropDownButton( + tableIndex)), + ]), + ), + SizedBox( + width: 5, + ), + SizedBox( + child: Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + SizedBox( + width: 10, + ), + Flexible( + flex: 1, + child: Container( + width: 100, + child: Text('Select a role :', + overflow: + TextOverflow.clip, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight + .normal)), + ), + ), + SizedBox( + width: 20, + ), + Container( + margin: EdgeInsets.only( + left: 10.0), + width: 150, + child: + buildRoleDropDownButton( + tableIndex)), + ], + ), + ), + ]), + ], ), - ); - }, - ), - ], - ) - ); + ), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + buildTable( + _dutyRelatedParticipantsFilterAndStore, + tableIndex, + _dutyParticipants) + ], + ), + ), + SizedBox( + height: 30, + ) + ], + ), + ); + }, + ), + ); + } + + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Colors.deepPurpleAccent), + size: 70, + ), + ); + }, + ), + ], + )); } - Widget buildTable(List dutyRelatedParticipantsFilterAndStore,int tableIndex,List dutyParticipants){ + Widget buildTable(List dutyRelatedParticipantsFilterAndStore, + int tableIndex, List dutyParticipants) { return Card( - child: Padding( - padding:const EdgeInsets.all(17.0), - child: Column( + child: Padding( + padding: const EdgeInsets.all(17.0), + child: Column( children: [ - - SingleChildScrollView( - child: Container( - width: 950, - child: DataTable( - columns: [ - DataColumn( - label: Text( - "Student Name", - style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), - ), - ), - DataColumn( - label: Text( - "Digital Id", - style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), - ), - ), - DataColumn( - label: Text( - "Class", - style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), - ), - ), - DataColumn( - label: Text( - "Role", - style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), - ), - ), - DataColumn( - label: Text( - "Remove", - style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), - ), - ), - ], - rows: dutyRelatedParticipantsFilterAndStore.map((participant){ - + SingleChildScrollView( + child: Container( + width: 950, + child: DataTable( + columns: [ + DataColumn( + label: Text( + "Student Name", + style: TextStyle( + fontSize: 12, fontWeight: FontWeight.bold), + ), + ), + DataColumn( + label: Text( + "Digital Id", + style: TextStyle( + fontSize: 12, fontWeight: FontWeight.bold), + ), + ), + DataColumn( + label: Text( + "Class", + style: TextStyle( + fontSize: 12, fontWeight: FontWeight.bold), + ), + ), + DataColumn( + label: Text( + "Role", + style: TextStyle( + fontSize: 12, fontWeight: FontWeight.bold), + ), + ), + DataColumn( + label: Text( + "Remove", + style: TextStyle( + fontSize: 12, fontWeight: FontWeight.bold), + ), + ), + ], + rows: + dutyRelatedParticipantsFilterAndStore.map((participant) { bool isLeader = participant.role == 'leader'; - bool isAssistantLeader = participant.role == 'assistant-leader'; + bool isAssistantLeader = + participant.role == 'assistant-leader'; - return DataRow( - cells:[ - DataCell(Text( - participant.person!.preferred_name ?? 'N/A', - ) - ), - DataCell(Text( - participant.person!.digital_id ?? 'N/A', - ) - ), - DataCell(Text( - participant.person!.organization?.description ?? 'N/A', - ) - ), - DataCell(Row( - children: [ - if(isLeader) - Icon(Icons.star,color: Colors.orange,) - else if(isAssistantLeader) - Icon(Icons.star,color: Colors.green,), - SizedBox(width: 1,), - Text( participant.role ?? 'N/A',), - ], - ) - ), - DataCell(IconButton( - icon: Icon(Icons.delete), - onPressed: () async{ - var result = await deleteDutyForParticipant(participant.id!); - print(result); - setState(() { - - }); - }, + return DataRow( + cells: [ + DataCell(Text( + participant.person!.preferred_name ?? 'N/A', + )), + DataCell(Text( + participant.person!.digital_id ?? 'N/A', + )), + DataCell(Text( + participant.person!.organization?.description ?? + 'N/A', + )), + DataCell(Row( + children: [ + if (isLeader) + Icon( + Icons.star, + color: Colors.orange, ) - ) - ], - ); - }).toList(), + else if (isAssistantLeader) + Icon( + Icons.star, + color: Colors.green, + ), + SizedBox( + width: 1, + ), + Text( + participant.role ?? 'N/A', + ), + ], + )), + DataCell(IconButton( + icon: Icon(Icons.delete), + onPressed: () async { + var result = + await deleteDutyForParticipant(participant.id!); + print(result); + setState(() {}); + }, + )) + ], + ); + }).toList(), + ), ), ), - ), - ], + ], + ), ), - ), ); } - Widget buildClassDropDownButton(Organization org,int tableIndex,List dutyParticipants){ - - return DropdownButton( - value: _selectedClassValues[tableIndex], - items: org.child_organizations.map>((Organization value){ - return DropdownMenuItem( - value: value, - child: Text(value.description!), - ); - }).toList(), - onChanged: (Organization? newValue) async{ - _selectedClassValue = newValue!; - print(newValue.id); - _fetchedOrganization = await fetchOrganization(newValue.id!); - - _selectedPersonValues[tableIndex] = null; // Reset selected person value when class changes - - // Remove people with names( _fetchedOrganization!.people list) that match the names in dutyParticipants - _fetchedOrganization!.people.removeWhere((person) => - dutyParticipants.any((dutyParticipant) => - person.digital_id == dutyParticipant.person?.digital_id)); + Widget buildBatchDropDownButton(int tableIndex) { + return FutureBuilder>( + future: _fetchBatchData, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Colors.deepPurpleAccent), + size: 70, + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: Text('Something went wrong...'), + ); + } else if (!snapshot.hasData) { + return const Center( + child: Text('No batch found'), + ); + } + final batchData = snapshot.data!; + return DropdownButton( + value: _selectedBatchValues[tableIndex], + items: batchData.map((Organization batch) { + return DropdownMenuItem( + value: batch, child: Text(batch.name!.name_en ?? '')); + }).toList(), + onChanged: (Organization? newValue) async { + if (newValue == null) { + return; + } - setState(() { - _selectedClassValues[tableIndex] = newValue; - _dropDownPersonList[tableIndex] = _fetchedOrganization!.people; + if (newValue.organization_metadata.isEmpty) { + return; + } - }); - }, - ); + _fetchedOrganization = await fetchOrganization(newValue!.id!); + _dropDownClassList[tableIndex] = + _fetchedOrganization?.child_organizations ?? []; + _selectedClassValues[tableIndex] = + null; // Reset selected class value when batch changes + _selectedPersonValues[tableIndex] = + null; // Reset selected person value when batch changes + _dropDownPersonList[tableIndex] = []; // Reset selected person list value when batch changes + setState(() { + _selectedBatchValues[tableIndex] = newValue; + //print("batch values:${_selectedBatchValues[tableIndex]}"); + _dropDownClassList[tableIndex]; + _selectedClassValues[tableIndex]; + _selectedPersonValues[tableIndex]; + }); + }); + }, + ); } - Widget buildPersonDropDownButton(int tableIndex){ - - return DropdownButton( - value:_selectedPersonValues[tableIndex], - items: _dropDownPersonList[tableIndex].map>((Person value){ - if(value.preferred_name !=null){ - return DropdownMenuItem( - value: value.digital_id, - child: Text(value.preferred_name!), - ); - }else{ - return DropdownMenuItem( - value: null, - child:Text('No Preferred Name'), + Widget buildClassDropDownButton( + int tableIndex, List dutyParticipants) { + return DropdownButton( + value: _selectedClassValues[tableIndex], + items: _dropDownClassList[tableIndex] + .map>((Organization value) { + return DropdownMenuItem( + value: value, + child: Text(value.description!), ); - } + }).toList(), + onChanged: (Organization? newValue) async { + _selectedClassValue = newValue!; + print(newValue.id); + _fetchedOrganization = await fetchOrganization(newValue.id!); + + _selectedPersonValues[tableIndex] = + null; // Reset selected person value when class changes + + // Remove people with names( _fetchedOrganization!.people list) that match the names in dutyParticipants + _fetchedOrganization!.people.removeWhere((person) => + dutyParticipants.any((dutyParticipant) => + person.digital_id == dutyParticipant.person?.digital_id)); + + setState(() { + _selectedClassValues[tableIndex] = newValue; + _dropDownPersonList[tableIndex] = _fetchedOrganization!.people; + }); }, - ).toList(), - onChanged:(String? newValue) async{ - + ); + } + + Widget buildPersonDropDownButton(int tableIndex) { + return DropdownButton( + value: _selectedPersonValues[tableIndex], + items: _dropDownPersonList[tableIndex].map>( + (Person value) { + if (value.preferred_name != null) { + return DropdownMenuItem( + value: value.digital_id, + child: Text(value.preferred_name!), + ); + } else { + return DropdownMenuItem( + value: null, + child: Text('No Preferred Name'), + ); + } + }, + ).toList(), + onChanged: (String? newValue) async { setState(() { _selectedPersonValues[tableIndex] = newValue; - }); - }, - - ); + }, + ); } - Widget buildRoleDropDownButton(int tableIndex){ - - return DropdownButton( - value:_selectedRoleValues[tableIndex], - items: _dropDownRoleList.map>((String value){ - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }, - ).toList(), - onChanged:(String? newValue) async{ - + Widget buildRoleDropDownButton(int tableIndex) { + return DropdownButton( + value: _selectedRoleValues[tableIndex], + items: _dropDownRoleList.map>( + (String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }, + ).toList(), + onChanged: (String? newValue) async { setState(() { _selectedRoleValues[tableIndex] = newValue; }); - - if(_activitiesNames[tableIndex] !=null && _selectedRoleValues[tableIndex] !=null && _selectedPersonValues[tableIndex] !=null){ - - String? activityName = _activitiesNames[tableIndex]; - Activity? activity = _activitiesByAvinyaType.firstWhere((activityObject) => activityObject.name == activityName); - String? allocatedRole = _selectedRoleValues[tableIndex]; - String? personDigitalId = _selectedPersonValues[tableIndex]; - Person? person = _dropDownPersonList[tableIndex].firstWhere((personObject) => personObject.digital_id == personDigitalId); - - var dutyForParticipant = DutyParticipant( - activity_id: activity.id, - person_id: person.id, - role: allocatedRole, - ); - - bool hasLeaderRole = hasLeaderRoleWithActivity(activityName,allocatedRole); - - print('has a leader role ${hasLeaderRole}'); - - if(!hasLeaderRole){ - var result = await createDutyForParticipant(dutyForParticipant); + + if (_activitiesNames[tableIndex] != null && + _selectedRoleValues[tableIndex] != null && + _selectedPersonValues[tableIndex] != null) { + String? activityName = _activitiesNames[tableIndex]; + Activity? activity = _activitiesByAvinyaType.firstWhere( + (activityObject) => activityObject.name == activityName); + String? allocatedRole = _selectedRoleValues[tableIndex]; + String? personDigitalId = _selectedPersonValues[tableIndex]; + Person? person = _dropDownPersonList[tableIndex].firstWhere( + (personObject) => personObject.digital_id == personDigitalId); + + var dutyForParticipant = DutyParticipant( + activity_id: activity.id, + person_id: person.id, + role: allocatedRole, + ); + + bool hasLeaderRole = + hasLeaderRoleWithActivity(activityName, allocatedRole); + + print('has a leader role ${hasLeaderRole}'); + + if (!hasLeaderRole) { + var result = await createDutyForParticipant(dutyForParticipant); print("add participant for duty result : ${result.id}"); - - if(result.id != null){ - _selectedRoleValues[tableIndex] = null; //clear the drop down - _selectedPersonValues[tableIndex] = null; //clear the drop down - _selectedClassValues[tableIndex] = null; //clear the drop down - } - setState(() {}); - }else{ - showDialog( - context: context, - builder: (BuildContext context) { - - _selectedRoleValues[tableIndex] = null; //clear the drop down - _selectedPersonValues[tableIndex] = null; //clear the drop down - _selectedClassValues[tableIndex] = null; //clear the drop down - - return Container( - width: 300, - height: 100, - padding: EdgeInsets.all(8), - child: AlertDialog( - title: Text( - 'Error', - style: TextStyle(color: Colors.red), + + if (result.id != null) { + _selectedRoleValues[tableIndex] = null; //clear the drop down + _selectedPersonValues[tableIndex] = null; //clear the drop down + _selectedClassValues[tableIndex] = null; //clear the drop down + _selectedBatchValues[tableIndex] = null; //clear the drop down + } + setState(() {}); + } else { + showDialog( + context: context, + builder: (BuildContext context) { + _selectedRoleValues[tableIndex] = null; //clear the drop down + _selectedPersonValues[tableIndex] = null; //clear the drop down + _selectedClassValues[tableIndex] = null; //clear the drop down + _selectedBatchValues[tableIndex] = null; //clear the drop down + + return Container( + width: 300, + height: 100, + padding: EdgeInsets.all(8), + child: AlertDialog( + title: Text( + 'Error', + style: TextStyle(color: Colors.red), ), - content: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Icon( - Icons.close, - color: Colors.red, - size: 40, - ), - SizedBox(height: 10,), - Text( - "A ${allocatedRole} role participant is already added to this $activityName duty.", - textAlign: TextAlign.center, - ), - Text( - "You can't add another participant with a ${allocatedRole} role.If you'd like to add this participant as a ${allocatedRole}, please remove the current ${allocatedRole} first.", - textAlign: TextAlign.center, - ), + content: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + Icons.close, + color: Colors.red, + size: 40, + ), + SizedBox( + height: 10, + ), + Text( + "A ${allocatedRole} role participant is already added to this $activityName duty.", + textAlign: TextAlign.center, + ), + Text( + "You can't add another participant with a ${allocatedRole} role.If you'd like to add this participant as a ${allocatedRole}, please remove the current ${allocatedRole} first.", + textAlign: TextAlign.center, + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text('OK'), + ), ], ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text('OK'), - ), - ], - ), - ); - }, - ); - } - }else{ - - List missingValues = []; - - - if(_selectedRoleValues[tableIndex] == null){ - missingValues.add('Role is missing.'); - } - if(_selectedPersonValues[tableIndex] == null){ - missingValues.add('Person is missing.'); - } - - String errorMessage = 'The following values are missing: ${missingValues.join(', ')}'; + ); + }, + ); + } + } else { + List missingValues = []; + + if (_selectedRoleValues[tableIndex] == null) { + missingValues.add('Role is missing.'); + } + if (_selectedPersonValues[tableIndex] == null) { + missingValues.add('Person is missing.'); + } + + String errorMessage = + 'The following values are missing: ${missingValues.join(', ')}'; showDialog( - context: context, - builder: (BuildContext context) { - return Container( - width: 300, - height: 100, - padding: EdgeInsets.all(8), - child: AlertDialog( + context: context, + builder: (BuildContext context) { + return Container( + width: 300, + height: 100, + padding: EdgeInsets.all(8), + child: AlertDialog( title: Text( - 'Error', - style: TextStyle(color: Colors.red), - ), + 'Error', + style: TextStyle(color: Colors.red), + ), content: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Icon( + Icon( Icons.close, color: Colors.red, size: 40, - ), - SizedBox(height: 10,), - Text( + ), + SizedBox( + height: 10, + ), + Text( 'Cannot add duty for participant.', textAlign: TextAlign.center, - ), - Text( + ), + Text( errorMessage, textAlign: TextAlign.center, - ) + ) ], ), actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text('OK'), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text('OK'), + ), + ], ), - ], - ), - ); - }, + ); + }, ); - } - }, - ); -} + } + }, + ); + } -Future _selectStartDate(BuildContext context) async{ - final DateTime? picked = await showDatePicker( - context: context, + Future _selectStartDate(BuildContext context) async { + final DateTime? picked = await showDatePicker( + context: context, initialDate: DateTime.now(), firstDate: DateTime(1950), lastDate: DateTime(2100), ); - if(picked !=null){ + if (picked != null) { print(picked); String formattedDate = DateFormat('yyyy-MM-dd').format(picked); print(formattedDate); - + setState(() { _startDate.text = formattedDate; - _startDateSelected= true; + _startDateSelected = true; }); - }else if(picked == null){ + } else if (picked == null) { setState(() { - String formattedDate = ''; + String formattedDate = ''; _startDate.text = formattedDate; - _startDateSelected = false; + _startDateSelected = false; }); } -} + } -Future _selectEndDate(BuildContext context) async{ - final DateTime? picked = await showDatePicker( - context: context, + Future _selectEndDate(BuildContext context) async { + final DateTime? picked = await showDatePicker( + context: context, initialDate: DateTime.now(), firstDate: DateTime(1950), lastDate: DateTime(2100), ); - if(picked !=null){ + if (picked != null) { print(picked); String formattedDate = DateFormat('yyyy-MM-dd').format(picked); - + print(formattedDate); setState(() { _endDate.text = formattedDate; - _endDateSelected = true; // Set to true when end date is selected + _endDateSelected = true; // Set to true when end date is selected }); - if(_startDateSelected && _endDateSelected){ - - DateTime originalStartDateTime = DateTime.parse(_startDate.text); - DateTime originalEndDateTime = DateTime.parse(_endDate.text); - - var dutyRotationMetadata = DutyRotationMetaDetails( - id: _rotationMetaDetails.id ?? 0, - start_date:DateTime.utc( - originalStartDateTime.year, - originalStartDateTime.month, - originalStartDateTime.day, - 0, 0, 0, 0, 0).toIso8601String(), - - end_date:DateTime.utc( - originalEndDateTime.year, - originalEndDateTime.month, - originalEndDateTime.day, - 0, 0, 0, 0, 0).toIso8601String(), - organization_id: campusAppsPortalInstance.getUserPerson().organization!.id!, - ); - print("duty rotation meta data start date: ${dutyRotationMetadata.start_date}"); - print("duty rotation meta data end date: ${dutyRotationMetadata.end_date}"); + if (_startDateSelected && _endDateSelected) { + DateTime originalStartDateTime = DateTime.parse(_startDate.text); + DateTime originalEndDateTime = DateTime.parse(_endDate.text); + + var dutyRotationMetadata = DutyRotationMetaDetails( + id: _rotationMetaDetails.id ?? 0, + start_date: DateTime.utc( + originalStartDateTime.year, + originalStartDateTime.month, + originalStartDateTime.day, + 0, + 0, + 0, + 0, + 0) + .toIso8601String(), + end_date: DateTime.utc( + originalEndDateTime.year, + originalEndDateTime.month, + originalEndDateTime.day, + 0, + 0, + 0, + 0, + 0) + .toIso8601String(), + organization_id: + campusAppsPortalInstance.getUserPerson().organization!.id!, + ); + print( + "duty rotation meta data start date: ${dutyRotationMetadata.start_date}"); + print( + "duty rotation meta data end date: ${dutyRotationMetadata.end_date}"); var result = await updateDutyRotationMetadata(dutyRotationMetadata); print("update duty rotation ${result}"); - - _rotationMetaDetails = await fetchDutyRotationMetadataByOrganization(campusAppsPortalInstance.getUserPerson().organization!.id!); - - } - }else if(picked == null){ + _rotationMetaDetails = await fetchDutyRotationMetadataByOrganization( + campusAppsPortalInstance.getUserPerson().organization!.id!); + } + } else if (picked == null) { setState(() { - String formattedDate = ''; + String formattedDate = ''; _endDate.text = formattedDate; - _endDateSelected= false; + _endDateSelected = false; }); } -} - + } } diff --git a/campus/frontend/lib/avinya/attendance/lib/widgets/daily_attendance_report.dart b/campus/frontend/lib/avinya/attendance/lib/widgets/daily_attendance_report.dart index afe99e55..72a7b2db 100644 --- a/campus/frontend/lib/avinya/attendance/lib/widgets/daily_attendance_report.dart +++ b/campus/frontend/lib/avinya/attendance/lib/widgets/daily_attendance_report.dart @@ -32,7 +32,7 @@ class _DailyAttendanceReportState extends State { List _fetchedAttendanceAfterSchool = []; Organization? _fetchedOrganization; bool _isFetching = true; - List _fetchedStudentList = []; + List _fetchedStudentList = []; //calendar specific variables DateTime? _selectedDay; @@ -48,6 +48,11 @@ class _DailyAttendanceReportState extends State { late String formattedEndDate; var today = DateTime.now(); + List _batchData = []; + Organization? _selectedOrganizationValue; + List _fetchedOrganizations = []; + late Future> _fetchBatchData; + void selectWeek(DateTime today, activityId) async { // Update the variables to select the week final formatter = DateFormat('MMM d, yyyy'); @@ -58,15 +63,31 @@ class _DailyAttendanceReportState extends State { }); } - @override void initState() { super.initState(); + _fetchBatchData = _loadBatchData(); var today = DateTime.now(); activityId = campusAppsPortalInstance.activityIds['homeroom']!; selectWeek(today, activityId); } + Future> _loadBatchData() async { + _batchData = await fetchActiveOrganizationsByAvinyaType(86); + _selectedOrganizationValue = _batchData.isNotEmpty ? _batchData.last : null; + + if (_selectedOrganizationValue != null) { + int orgId = _selectedOrganizationValue!.id!; + _fetchedOrganization = await fetchOrganization(orgId); + _fetchedOrganizations = _fetchedOrganization?.child_organizations ?? []; + setState(() { + _fetchedOrganizations = _fetchedOrganizations; + }); + } + // this.updateDateRange(today, today); + return _batchData; + } + @override void didChangeDependencies() { super.didChangeDependencies(); @@ -129,71 +150,49 @@ class _DailyAttendanceReportState extends State { _fetchedOrganization!.id = parentOrgId; } } else { - var cols = - columnNames.map((label) => DataColumn(label: Text(label!))).toList(); + columnNames.map((label) => DataColumn(label: Text(label!))).toList(); _fetchedOrganization = await fetchOrganization(newValue!.id!); _fetchedAttendance = await getClassActivityAttendanceReportForPayment( - _fetchedOrganization!.id!, - activityId, - DateFormat('yyyy-MM-dd') - .format(DateFormat('MMM d, yyyy') - .parse(this.formattedStartDate)), - DateFormat('yyyy-MM-dd') - .format(DateFormat('MMM d, yyyy') - .parse(this.formattedEndDate))); - - if (_fetchedAttendance.length > 0) { - - columnNames.clear(); - List names = _fetchedAttendance - .map((attendance) => attendance - .sign_in_time - ?.split(" ")[0]) - .where((name) => - name != - null) // Filter out null values - .toList(); - columnNames.addAll(names); - } else { - columnNames.clear(); - } + _fetchedOrganization!.id!, + activityId, + DateFormat('yyyy-MM-dd') + .format(DateFormat('MMM d, yyyy').parse(this.formattedStartDate)), + DateFormat('yyyy-MM-dd') + .format(DateFormat('MMM d, yyyy').parse(this.formattedEndDate))); - columnNames = - columnNames.toSet().toList(); - columnNames.sort(); - columnNames.insert(0, "Name"); - columnNames.insert(1, "Digital ID"); - cols = columnNames - .map((label) => - DataColumn(label: Text(label!))) - .toList(); - print(cols.length); - if (_fetchedAttendance.length == 0) - _fetchedAttendance = new List.filled( - _fetchedOrganization!.people.length, - new ActivityAttendance( - person_id: -1)); - else { - for (int i = 0; - i < - _fetchedOrganization! - .people.length; - i++) { - if (_fetchedAttendance.indexWhere( - (attendance) => - attendance.person_id == - _fetchedOrganization! - .people[i].id) == - -1) { - _fetchedAttendance.add( - new ActivityAttendance( - person_id: -1)); - } - } - } + if (_fetchedAttendance.length > 0) { + columnNames.clear(); + List names = _fetchedAttendance + .map((attendance) => attendance.sign_in_time?.split(" ")[0]) + .where((name) => name != null) // Filter out null values + .toList(); + columnNames.addAll(names); + } else { + columnNames.clear(); + } + columnNames = columnNames.toSet().toList(); + columnNames.sort(); + columnNames.insert(0, "Name"); + columnNames.insert(1, "Digital ID"); + cols = + columnNames.map((label) => DataColumn(label: Text(label!))).toList(); + print(cols.length); + if (_fetchedAttendance.length == 0) + _fetchedAttendance = new List.filled( + _fetchedOrganization!.people.length, + new ActivityAttendance(person_id: -1)); + else { + for (int i = 0; i < _fetchedOrganization!.people.length; i++) { + if (_fetchedAttendance.indexWhere((attendance) => + attendance.person_id == _fetchedOrganization!.people[i].id) == + -1) { + _fetchedAttendance.add(new ActivityAttendance(person_id: -1)); + } + } + } } String? newSelectedVal; @@ -204,11 +203,11 @@ class _DailyAttendanceReportState extends State { setState(() { _fetchedOrganization; this._isFetching = false; - _data = MyData(_fetchedAttendance,columnNames,_fetchedOrganization,updateSelected); + _data = MyData(_fetchedAttendance, columnNames, _fetchedOrganization, + updateSelected); }); } - @override Widget build(BuildContext context) { var cols = @@ -223,159 +222,246 @@ class _DailyAttendanceReportState extends State { : Wrap( children: [ Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - for (var org in campusAppsPortalInstance - .getUserPerson() - .organization! - .child_organizations) - // create a text widget with some padding - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (org.child_organizations.length > 0) - Container( - margin: EdgeInsets.only( - left: 20, top: 20, bottom: 10), - child: Row(children: [ - Text('Select a class:'), - SizedBox(width: 10), - DropdownButton( - value: _selectedValue, - onChanged:_isFetching ? null: (Organization? newValue) async { - _selectedValue = newValue!; - print(newValue.id); - - _fetchedOrganization = - await fetchOrganization(newValue.id!); - - _fetchedAttendance = - await getClassActivityAttendanceReportForPayment( - _fetchedOrganization!.id!, - activityId, - DateFormat('yyyy-MM-dd') - .format(DateFormat( - 'MMM d, yyyy') - .parse(this - .formattedStartDate)), - DateFormat('yyyy-MM-dd') - .format(DateFormat( - 'MMM d, yyyy') - .parse(this - .formattedEndDate))); - - - if (_fetchedAttendance.length > 0) { - // Add null check here - // Process attendance data here - columnNames.clear(); - List names = _fetchedAttendance - .map((attendance) => attendance - .sign_in_time - ?.split(" ")[0]) - .where((name) => - name != - null) // Filter out null values - .toList(); - columnNames.addAll(names); - } else { - columnNames.clear(); - } - - columnNames = - columnNames.toSet().toList(); - columnNames.sort(); - columnNames.insert(0, "Name"); - columnNames.insert(1, "Digital ID"); - cols = columnNames - .map((label) => - DataColumn(label: Text(label!))) - .toList(); - print(cols.length); - if (_fetchedAttendance.length == 0) - _fetchedAttendance = new List.filled( - _fetchedOrganization!.people.length, - new ActivityAttendance( - person_id: -1)); - else { - for (int i = 0; - i < - _fetchedOrganization! - .people.length; - i++) { - if (_fetchedAttendance.indexWhere( - (attendance) => - attendance.person_id == - _fetchedOrganization! - .people[i].id) == - -1) { - _fetchedAttendance.add( - new ActivityAttendance( - person_id: -1)); - } - } - } - setState(() { - _fetchedOrganization; - _fetchedStudentList; - _data = MyData( - _fetchedAttendance, - columnNames, - _fetchedOrganization, - updateSelected); - }); - _isDisplayErrorMessage = false; - }, - items: org.child_organizations - .map((Organization value) { - return DropdownMenuItem( - value: value, - child: Text(value.description!), - ); - }).toList(), - ), - SizedBox(width: 20), - ElevatedButton( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox(width: 10), + Text('Select a Batch:'), + SizedBox(width: 10), + FutureBuilder>( + future: _fetchBatchData, + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Colors.deepPurpleAccent), + size: 70, + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: Text('Something went wrong...'), + ); + } else if (!snapshot.hasData) { + return const Center( + child: Text('No batch found'), + ); + } + final batchData = snapshot.data!; + return DropdownButton( + value: _selectedOrganizationValue, + items: batchData.map((Organization batch) { + return DropdownMenuItem( + value: batch, + child: Text(batch.name!.name_en ?? '')); + }).toList(), + onChanged: (Organization? newValue) async { + if (newValue == null) { + return; + } + + if (newValue.organization_metadata.isEmpty) { + return; + } + + _fetchedOrganization = + await fetchOrganization(newValue!.id!); + _fetchedOrganizations = _fetchedOrganization + ?.child_organizations ?? + []; + + setState(() { + _fetchedOrganizations; + _selectedValue = null; + _selectedOrganizationValue = newValue; + // batchStartDate = DateFormat('MMM d, yyyy') + // .format(DateTime.parse( + // _selectedOrganizationValue! + // .organization_metadata[0].value + // .toString())); + + // batchEndDate = DateFormat('MMM d, yyyy') + // .format(DateTime.parse( + // _selectedOrganizationValue! + // .organization_metadata[1].value + // .toString())); + }); + }); + }, + ), + SizedBox(width: 20), + // for (var org in campusAppsPortalInstance + // .getUserPerson() + // .organization! + // .child_organizations) + // create a text widget with some padding + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (_fetchedOrganizations.length > 0) + Container( + margin: EdgeInsets.only( + left: 20, top: 20, bottom: 10), + child: Row(children: [ + Text('Select a class:'), + SizedBox(width: 10), + DropdownButton( + value: _selectedValue, + onChanged: _isFetching + ? null + : (Organization? newValue) async { + _selectedValue = newValue!; + print(newValue.id); + + _fetchedOrganization = + await fetchOrganization( + newValue.id!); + + _fetchedAttendance = + await getClassActivityAttendanceReportForPayment( + _fetchedOrganization!.id!, + activityId, + DateFormat('yyyy-MM-dd') + .format(DateFormat( + 'MMM d, yyyy') + .parse(this + .formattedStartDate)), + DateFormat('yyyy-MM-dd') + .format(DateFormat( + 'MMM d, yyyy') + .parse(this + .formattedEndDate))); + + if (_fetchedAttendance.length > + 0) { + // Add null check here + // Process attendance data here + columnNames.clear(); + List names = + _fetchedAttendance + .map((attendance) => + attendance + .sign_in_time + ?.split(" ")[0]) + .where((name) => + name != + null) // Filter out null values + .toList(); + columnNames.addAll(names); + } else { + columnNames.clear(); + } + + columnNames = + columnNames.toSet().toList(); + columnNames.sort(); + columnNames.insert(0, "Name"); + columnNames.insert( + 1, "Digital ID"); + cols = columnNames + .map((label) => DataColumn( + label: Text(label!))) + .toList(); + print(cols.length); + if (_fetchedAttendance.length == + 0) + _fetchedAttendance = + new List.filled( + _fetchedOrganization! + .people.length, + new ActivityAttendance( + person_id: -1)); + else { + for (int i = 0; + i < + _fetchedOrganization! + .people.length; + i++) { + if (_fetchedAttendance.indexWhere( + (attendance) => + attendance + .person_id == + _fetchedOrganization! + .people[i] + .id) == + -1) { + _fetchedAttendance.add( + new ActivityAttendance( + person_id: -1)); + } + } + } + setState(() { + _fetchedOrganization; + _fetchedStudentList; + _data = MyData( + _fetchedAttendance, + columnNames, + _fetchedOrganization, + updateSelected); + }); + _isDisplayErrorMessage = false; + }, + items: _fetchedOrganizations + .map((Organization value) { + return DropdownMenuItem( + value: value, + child: Text(value.description!), + ); + }).toList(), + ), + SizedBox(width: 20), + ElevatedButton( style: ButtonStyle( textStyle: MaterialStateProperty.all( TextStyle(fontSize: 20), ), - elevation: MaterialStateProperty.all(20), + elevation: + MaterialStateProperty.all(20), backgroundColor: - MaterialStateProperty.all(Colors.greenAccent), + MaterialStateProperty.all( + Colors.greenAccent), foregroundColor: - MaterialStateProperty.all(Colors.black), + MaterialStateProperty.all( + Colors.black), ), onPressed: _isFetching ? null - : () { - if(_selectedValue == null){ - - setState(() { - _isDisplayErrorMessage = true; - }); - - }else{ - - Navigator.push( - context, - MaterialPageRoute( - builder: (_) => DateRangePicker( - updateDateRange, formattedStartDate)), - ); - setState(() { - _isDisplayErrorMessage = false; - }); - } - }, + : () { + if (_selectedValue == null) { + setState(() { + _isDisplayErrorMessage = true; + }); + } else { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => + DateRangePicker( + updateDateRange, + formattedStartDate)), + ); + setState(() { + _isDisplayErrorMessage = + false; + }); + } + }, child: Container( - height: 50, // Adjust the height as needed + height: + 50, // Adjust the height as needed child: Row( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, children: [ if (_isFetching) Padding( - padding: EdgeInsets.only(right: 10), + padding: + EdgeInsets.only(right: 10), child: SpinKitFadingCircle( color: Colors .black, // Customize the color of the indicator @@ -384,7 +470,8 @@ class _DailyAttendanceReportState extends State { ), ), if (!_isFetching) - Icon(Icons.calendar_today, color: Colors.black), + Icon(Icons.calendar_today, + color: Colors.black), SizedBox(width: 10), Text( '${this.formattedStartDate} - ${this.formattedEndDate}', @@ -398,52 +485,56 @@ class _DailyAttendanceReportState extends State { ), ), ), - ]), - ), - ]), + ]), + ), + ]), + ], + ), ], ), Container( margin: EdgeInsets.only(left: 20.0), - child: _isDisplayErrorMessage - ? Text( - 'Please select a value from the dropdown', - style: TextStyle(color: Colors.red), - ): - SizedBox(), + child: _isDisplayErrorMessage + ? Text( + 'Please select a value from the dropdown', + style: TextStyle(color: Colors.red), + ) + : SizedBox(), ), SizedBox(height: 32.0), SizedBox(height: 32.0), Wrap(children: [ if (_isFetching) - Container( - margin: EdgeInsets.only(top: 180), - child: SpinKitCircle( - color: (Colors.deepPurpleAccent), // Customize the color of the indicator - size: 50, // Customize the size of the indicator - ), - ) + Container( + margin: EdgeInsets.only(top: 180), + child: SpinKitCircle( + color: (Colors + .deepPurpleAccent), // Customize the color of the indicator + size: 50, // Customize the size of the indicator + ), + ) else if (_fetchedAttendance.length > 0) - ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith(dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, + ScrollConfiguration( + behavior: ScrollConfiguration.of(context) + .copyWith(dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, }), - child: PaginatedDataTable( - showCheckboxColumn: false, - source: _data, - columns: cols, - // header: const Center(child: Text('Daily Attendance')), - columnSpacing: 100, - horizontalMargin: 60, - rowsPerPage: 25, - ), - ) - else - Container( - margin: EdgeInsets.all(20), - child: Text('No attendance data found'), + child: PaginatedDataTable( + showCheckboxColumn: false, + source: _data, + columns: cols, + // header: const Center(child: Text('Daily Attendance')), + columnSpacing: 100, + horizontalMargin: 60, + rowsPerPage: 25, ), + ) + else + Container( + margin: EdgeInsets.all(20), + child: Text('No attendance data found'), + ), // (cols.length > 2 && _fetchedAttendance.length > 0) // ? PaginatedDataTable( // showCheckboxColumn: false, diff --git a/campus/frontend/lib/avinya/attendance/lib/widgets/late_attendance_report.dart b/campus/frontend/lib/avinya/attendance/lib/widgets/late_attendance_report.dart index 9382793f..e0a013c7 100644 --- a/campus/frontend/lib/avinya/attendance/lib/widgets/late_attendance_report.dart +++ b/campus/frontend/lib/avinya/attendance/lib/widgets/late_attendance_report.dart @@ -44,11 +44,15 @@ class _LateAttendanceReportState extends State { List ColumnNames = []; - late String formattedStartDate; late String formattedEndDate; var today = DateTime.now(); + List _batchData = []; + Organization? _selectedOrganizationValue; + List _fetchedOrganizations = []; + late Future> _fetchBatchData; + void selectWeek(DateTime today, activityId) async { // Update the variables to select the week final formatter = DateFormat('MMM d, yyyy'); @@ -62,6 +66,7 @@ class _LateAttendanceReportState extends State { @override void initState() { super.initState(); + _fetchBatchData = _loadBatchData(); var today = DateTime.now(); activityId = campusAppsPortalInstance.activityIds['homeroom']!; selectWeek(today, activityId); @@ -74,10 +79,26 @@ class _LateAttendanceReportState extends State { isFetching: _isFetching, selectedValue: _selectedValue, formattedStartDate: this.formattedStartDate, - formattedEndDate:this.formattedEndDate, + formattedEndDate: this.formattedEndDate, ); } + Future> _loadBatchData() async { + _batchData = await fetchActiveOrganizationsByAvinyaType(86); + _selectedOrganizationValue = _batchData.isNotEmpty ? _batchData.last : null; + + if (_selectedOrganizationValue != null) { + int orgId = _selectedOrganizationValue!.id!; + _fetchedOrganization = await fetchOrganization(orgId); + _fetchedOrganizations = _fetchedOrganization?.child_organizations ?? []; + setState(() { + _fetchedOrganizations = _fetchedOrganizations; + }); + } + // this.updateDateRange(today, today); + return _batchData; + } + @override void didChangeDependencies() async { super.didChangeDependencies(); @@ -170,7 +191,7 @@ class _LateAttendanceReportState extends State { }); } - List _buildDataColumns() { + List _buildDataColumns() { List ColumnNames = []; if (_selectedValue == null) { @@ -214,7 +235,6 @@ class _LateAttendanceReportState extends State { @override Widget build(BuildContext context) { - return SingleChildScrollView( child: campusAppsPortalPersonMetaDataInstance .getGroups() @@ -223,140 +243,200 @@ class _LateAttendanceReportState extends State { style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold)) : Wrap( children: [ - Row( + Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(width: 20), - Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - for (var org in campusAppsPortalInstance - .getUserPerson() - .organization! - .child_organizations) - // create a text widget with some padding - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (org.child_organizations.length > 0) - Container( - margin: EdgeInsets.only( - left: 20, top: 20, bottom: 10), - child: Row(children: [ - Text('Select a class:'), - SizedBox(width: 10), - DropdownButton( - value: _selectedValue, - onChanged: - (Organization? newValue) async { - _selectedValue = newValue ?? null; - int? parentOrgId = - campusAppsPortalInstance - .getUserPerson() - .organization! - .id; - if (_selectedValue == null) { - // _fetchedOrganization = null; - _fetchedStudentList = - await fetchOrganizationForAll( - parentOrgId!); - } else { - // _fetchedStudentList = []; - _fetchedOrganization = - await fetchOrganization( - newValue!.id!); - } - - if (_selectedValue == null) { - _fetchedAttendance = - await getLateAttendanceReportByParentOrg( - parentOrgId!, - activityId, - DateFormat('yyyy-MM-dd') - .format(DateFormat( - 'MMM d, yyyy') - .parse(this - .formattedStartDate)), - DateFormat('yyyy-MM-dd') - .format(DateFormat( - 'MMM d, yyyy') - .parse(this - .formattedEndDate))); - } else { - _fetchedAttendance = - await getLateAttendanceReportByDate( - _fetchedOrganization!.id!, - activityId, - DateFormat('yyyy-MM-dd') - .format(DateFormat( - 'MMM d, yyyy') - .parse(this - .formattedStartDate)), - DateFormat('yyyy-MM-dd') - .format(DateFormat( - 'MMM d, yyyy') - .parse(this - .formattedEndDate))); - } - - if (_selectedValue == null) { - setState(() { - if (_fetchedOrganization != - null) { - _fetchedOrganization!.people = - _fetchedStudentList; - _fetchedOrganization!.id = - parentOrgId; - _fetchedOrganization! - .description = "Select All"; - } else { - _fetchedOrganization = - Organization(); - _fetchedOrganization!.people = - _fetchedStudentList; - _fetchedOrganization!.id = - parentOrgId; - _fetchedOrganization! - .description = "Select All"; - } - _fetchedStudentList; - _data = MyData( - _fetchedAttendance, - _selectedValue, - updateSelected); - }); - } else { - setState(() { - _fetchedOrganization; - _fetchedStudentList; - _data = MyData( - _fetchedAttendance, - _selectedValue.description, - updateSelected); - }); - } - }, - items: [ + // for (var org in campusAppsPortalInstance + // .getUserPerson() + // .organization! + // .child_organizations) + // create a text widget with some padding + SizedBox(width: 10), + Text('Select a Batch:'), + SizedBox(width: 10), + FutureBuilder>( + future: _fetchBatchData, + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Colors.deepPurpleAccent), + size: 70, + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: Text('Something went wrong...'), + ); + } else if (!snapshot.hasData) { + return const Center( + child: Text('No batch found'), + ); + } + final batchData = snapshot.data!; + return DropdownButton( + value: _selectedOrganizationValue, + items: batchData.map((Organization batch) { + return DropdownMenuItem( + value: batch, + child: Text(batch.name!.name_en ?? '')); + }).toList(), + onChanged: (Organization? newValue) async { + if (newValue == null) { + return; + } + + if (newValue.organization_metadata.isEmpty) { + return; + } + + _fetchedOrganization = + await fetchOrganization(newValue!.id!); + _fetchedOrganizations = _fetchedOrganization + ?.child_organizations ?? + []; + + setState(() { + _fetchedOrganizations; + _selectedValue = null; + _selectedOrganizationValue = newValue; + // batchStartDate = DateFormat('MMM d, yyyy') + // .format(DateTime.parse( + // _selectedOrganizationValue! + // .organization_metadata[0].value + // .toString())); + + // batchEndDate = DateFormat('MMM d, yyyy') + // .format(DateTime.parse( + // _selectedOrganizationValue! + // .organization_metadata[1].value + // .toString())); + }); + }); + }, + ), + SizedBox(width: 20), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (_fetchedOrganizations.length > 0) + Container( + margin: EdgeInsets.only( + left: 20, top: 20, bottom: 10), + child: Row(children: [ + Text('Select a class:'), + SizedBox(width: 10), + DropdownButton( + value: _selectedValue, + onChanged: + (Organization? newValue) async { + _selectedValue = newValue ?? null; + int? parentOrgId = + campusAppsPortalInstance + .getUserPerson() + .organization! + .id; + if (_selectedValue == null) { + // _fetchedOrganization = null; + _fetchedStudentList = + await fetchOrganizationForAll( + parentOrgId!); + } else { + // _fetchedStudentList = []; + _fetchedOrganization = + await fetchOrganization( + newValue!.id!); + } + + if (_selectedValue == null) { + _fetchedAttendance = + await getLateAttendanceReportByParentOrg( + parentOrgId!, + activityId, + DateFormat('yyyy-MM-dd') + .format(DateFormat( + 'MMM d, yyyy') + .parse(this + .formattedStartDate)), + DateFormat('yyyy-MM-dd') + .format(DateFormat( + 'MMM d, yyyy') + .parse(this + .formattedEndDate))); + } else { + _fetchedAttendance = + await getLateAttendanceReportByDate( + _fetchedOrganization!.id!, + activityId, + DateFormat('yyyy-MM-dd') + .format(DateFormat( + 'MMM d, yyyy') + .parse(this + .formattedStartDate)), + DateFormat('yyyy-MM-dd') + .format(DateFormat( + 'MMM d, yyyy') + .parse(this + .formattedEndDate))); + } + + if (_selectedValue == null) { + setState(() { + if (_fetchedOrganization != null) { + _fetchedOrganization!.people = + _fetchedStudentList; + _fetchedOrganization!.id = + parentOrgId; + _fetchedOrganization! + .description = "Select All"; + } else { + _fetchedOrganization = + Organization(); + _fetchedOrganization!.people = + _fetchedStudentList; + _fetchedOrganization!.id = + parentOrgId; + _fetchedOrganization! + .description = "Select All"; + } + _fetchedStudentList; + _data = MyData(_fetchedAttendance, + _selectedValue, updateSelected); + }); + } else { + setState(() { + _fetchedOrganization; + _fetchedStudentList; + _data = MyData( + _fetchedAttendance, + _selectedValue.description, + updateSelected); + }); + } + }, + items: // Add "Select All" option - DropdownMenuItem( - value: null, - child: Text("Select All"), - ), + // DropdownMenuItem( + // value: null, + // child: Text("Select All"), + // ), // Add other organization options - ...org.child_organizations + _fetchedOrganizations .map((Organization value) { - return DropdownMenuItem< - Organization>( - value: value, - child: Text(value.description!), - ); - }), - ], - ), - ]), - ), - ]), - ], - ), + return DropdownMenuItem( + value: value, + child: Text(value.description!), + ); + }).toList(), + ), + ]), + ), + ]), SizedBox(width: 20), ElevatedButton( style: ButtonStyle( @@ -407,40 +487,44 @@ class _LateAttendanceReportState extends State { ), ), ), - SizedBox( + SizedBox( width: 10, ), - Expanded( - child: Container( - alignment: Alignment.bottomRight, - margin: EdgeInsets.only( - right: 20.0 - ), - width: 25.0, - height: 30.0, - child: this._isFetching ? null: DailyLateAttendanceExcelReportExport( - fetchedDailyLateAttendanceData: _fetchedAttendance, + Expanded( + child: Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.only(right: 20.0), + width: 25.0, + height: 30.0, + child: this._isFetching + ? null + : DailyLateAttendanceExcelReportExport( + fetchedDailyLateAttendanceData: + _fetchedAttendance, updateExcelState: updateExcelState, isFetching: _isFetching, selectedValue: _selectedValue, formattedStartDate: this.formattedStartDate, - formattedEndDate:this.formattedEndDate, + formattedEndDate: this.formattedEndDate, + ), ), + ) + ], ), - ) ], ), SizedBox(height: 16.0), SizedBox(height: 32.0), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, + Wrap( + //mainAxisAlignment: MainAxisAlignment.center, + //crossAxisAlignment: CrossAxisAlignment.center, children: [ if (_isFetching) Container( margin: EdgeInsets.only(top: 180), child: SpinKitCircle( - color: (Colors.deepPurpleAccent), // Customize the color of the indicator + color: (Colors + .deepPurpleAccent), // Customize the color of the indicator size: 50, // Customize the size of the indicator ), ) diff --git a/campus/frontend/lib/avinya/attendance/lib/widgets/monthly_payment_report.dart b/campus/frontend/lib/avinya/attendance/lib/widgets/monthly_payment_report.dart index 984f8833..d60489d6 100644 --- a/campus/frontend/lib/avinya/attendance/lib/widgets/monthly_payment_report.dart +++ b/campus/frontend/lib/avinya/attendance/lib/widgets/monthly_payment_report.dart @@ -20,7 +20,7 @@ class MonthlyPaymentReport extends StatefulWidget { required this.onYearMonthSelected}) : super(key: key); final Function(DateTime, DateTime) updateDateRangeForExcel; - final Function(int,int) onYearMonthSelected; + final Function(int, int) onYearMonthSelected; // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect @@ -68,6 +68,11 @@ class _MonthlyPaymentReportState extends State { late String formattedEndDate; var today = DateTime.now(); + List _batchData = []; + Organization? _selectedOrganizationValue; + List _fetchedOrganizations = []; + late Future> _fetchBatchData; + void selectWeek(DateTime today, activityId) async { // Calculate the start of the week (excluding weekends) based on the selected day DateTime startOfWeek = today.subtract(Duration(days: today.weekday - 1)); @@ -121,6 +126,7 @@ class _MonthlyPaymentReportState extends State { @override void initState() { super.initState(); + _fetchBatchData = _loadBatchData(); var today = DateTime.now(); activityId = campusAppsPortalInstance.activityIds['homeroom']!; selectWeek(today, activityId); @@ -129,6 +135,22 @@ class _MonthlyPaymentReportState extends State { _fetchLeaveDates(_year, _month); } + Future> _loadBatchData() async { + _batchData = await fetchActiveOrganizationsByAvinyaType(86); + _selectedOrganizationValue = _batchData.isNotEmpty ? _batchData.last : null; + + if (_selectedOrganizationValue != null) { + int orgId = _selectedOrganizationValue!.id!; + _fetchedOrganization = await fetchOrganization(orgId); + _fetchedOrganizations = _fetchedOrganization?.child_organizations ?? []; + setState(() { + _fetchedOrganizations = _fetchedOrganizations; + }); + } + // this.updateDateRange(today, today); + return _batchData; + } + Future _fetchLeaveDates(int year, int month) async { try { // Fetch leave dates and payment details for the month @@ -209,7 +231,7 @@ class _MonthlyPaymentReportState extends State { setState(() { _selected = selected; }); - widget.onYearMonthSelected(selected.year,selected.month); + widget.onYearMonthSelected(selected.year, selected.month); } } @@ -349,261 +371,381 @@ class _MonthlyPaymentReportState extends State { style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold)) : Wrap( children: [ - Row( + Column( children: [ SizedBox(width: 20), - Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + Row( + //mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - for (var org in campusAppsPortalInstance - .getUserPerson() - .organization! - .child_organizations) - // create a text widget with some padding - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (org.child_organizations.length > 0) - Container( - margin: EdgeInsets.only( - left: 20, top: 20, bottom: 10), - child: Row(children: [ - Text('Select a class:'), - SizedBox(width: 10), - DropdownButton( - value: _selectedValue, - onChanged: - (Organization? newValue) async { - _selectedValue = newValue!; - print(newValue.id); - _fetchedOrganization = - await fetchOrganization( - newValue.id!); - - _fetchedAttendance = - await getClassActivityAttendanceReportForPayment( - _fetchedOrganization!.id!, - activityId, - DateFormat('yyyy-MM-dd') - .format(DateFormat( - 'MMM d, yyyy') - .parse(this - .formattedStartDate)), - DateFormat('yyyy-MM-dd') - .format(DateFormat( - 'MMM d, yyyy') - .parse(this - .formattedEndDate))); - if (_fetchedAttendance.length > 0) { - // Add null check here - // Process attendance data here - columnNames.clear(); - List names = - _fetchedAttendance - .map((attendance) => - attendance.sign_in_time - ?.split(" ")[0]) - .where((name) => - name != - null) // Filter out null values - .toList(); - columnNames.addAll(names); - } else { - columnNames.clear(); - } + // for (var org in campusAppsPortalInstance + // .getUserPerson() + // .organization! + // .child_organizations) + // create a text widget with some padding + SizedBox(width: 10), + Text('Select a Batch:'), + SizedBox(width: 10), + FutureBuilder>( + future: _fetchBatchData, + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Colors.deepPurpleAccent), + size: 70, + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: Text('Something went wrong...'), + ); + } else if (!snapshot.hasData) { + return const Center( + child: Text('No batch found'), + ); + } + final batchData = snapshot.data!; + return DropdownButton( + value: _selectedOrganizationValue, + items: batchData.map((Organization batch) { + return DropdownMenuItem( + value: batch, + child: Text(batch.name!.name_en ?? '')); + }).toList(), + onChanged: (Organization? newValue) async { + if (newValue == null) { + return; + } + + if (newValue.organization_metadata.isEmpty) { + return; + } + + _fetchedOrganization = + await fetchOrganization(newValue!.id!); + _fetchedOrganizations = _fetchedOrganization + ?.child_organizations ?? + []; + + setState(() { + _fetchedOrganizations; + _selectedValue = null; + _selectedOrganizationValue = newValue; + // batchStartDate = DateFormat('MMM d, yyyy') + // .format(DateTime.parse( + // _selectedOrganizationValue! + // .organization_metadata[0].value + // .toString())); + + // batchEndDate = DateFormat('MMM d, yyyy') + // .format(DateTime.parse( + // _selectedOrganizationValue! + // .organization_metadata[1].value + // .toString())); + }); + }); + }, + ), + SizedBox(width: 20), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (_fetchedOrganizations.length > 0) + Container( + margin: EdgeInsets.only( + left: 20, top: 20, bottom: 10), + child: Row(children: [ + Text('Select a class:'), + SizedBox(width: 10), + DropdownButton( + value: _selectedValue, + onChanged: + (Organization? newValue) async { + _selectedValue = newValue!; + print(newValue.id); + _fetchedOrganization = + await fetchOrganization( + newValue.id!); + + _fetchedAttendance = + await getClassActivityAttendanceReportForPayment( + _fetchedOrganization!.id!, + activityId, + DateFormat('yyyy-MM-dd').format( + DateFormat('MMM d, yyyy') + .parse(this + .formattedStartDate)), + DateFormat('yyyy-MM-dd').format( + DateFormat('MMM d, yyyy') + .parse(this + .formattedEndDate))); + if (_fetchedAttendance.length > 0) { + // Add null check here + // Process attendance data here + columnNames.clear(); + List names = + _fetchedAttendance + .map((attendance) => + attendance.sign_in_time + ?.split(" ")[0]) + .where((name) => + name != + null) // Filter out null values + .toList(); + columnNames.addAll(names); + } else { + columnNames.clear(); + } - columnNames = - columnNames.toSet().toList(); - columnNames.sort(); - columnNames.insert(0, "Name"); - columnNames.insert(1, "NIC"); - columnNames.insert(columnNames.length, - "Present Count"); - columnNames.insert(columnNames.length, - "Absent Count"); - columnNames.insert(columnNames.length, - "Student Payment Rs."); - // columnNames.insert(columnNames.length, - // "Phone Payment Rs."); - cols = columnNames - .map((label) => DataColumn( - label: Text(label!))) - .toList(); - print(cols.length); - if (_fetchedAttendance.length == 0) - _fetchedAttendance = - new List.filled( - _fetchedOrganization! - .people.length, - new ActivityAttendance( - person_id: -1)); - else { - for (int i = 0; - i < - _fetchedOrganization! - .people.length; - i++) { - if (_fetchedAttendance.indexWhere( - (attendance) => - attendance - .person_id == - _fetchedOrganization! - .people[i].id) == - -1) { - _fetchedAttendance.add( - new ActivityAttendance( - person_id: -1)); - } + columnNames = + columnNames.toSet().toList(); + columnNames.sort(); + columnNames.insert(0, "Name"); + columnNames.insert(1, "NIC"); + columnNames.insert(columnNames.length, + "Present Count"); + columnNames.insert( + columnNames.length, "Absent Count"); + columnNames.insert(columnNames.length, + "Student Payment Rs."); + // columnNames.insert(columnNames.length, + // "Phone Payment Rs."); + cols = columnNames + .map((label) => + DataColumn(label: Text(label!))) + .toList(); + print(cols.length); + if (_fetchedAttendance.length == 0) + _fetchedAttendance = new List.filled( + _fetchedOrganization! + .people.length, + new ActivityAttendance( + person_id: -1)); + else { + for (int i = 0; + i < + _fetchedOrganization! + .people.length; + i++) { + if (_fetchedAttendance.indexWhere( + (attendance) => + attendance.person_id == + _fetchedOrganization! + .people[i].id) == + -1) { + _fetchedAttendance.add( + new ActivityAttendance( + person_id: -1)); } } - setState(() { - _fetchedOrganization; - _data = MyData( - _fetchedAttendance, - columnNames, - _fetchedOrganization, - updateSelected, - DailyPayment); - }); - }, - items: org.child_organizations - .map((Organization value) { - return DropdownMenuItem( - value: value, - child: Text(value.description!), - ); - }).toList(), + } + setState(() { + _fetchedOrganization; + _data = MyData( + _fetchedAttendance, + columnNames, + _fetchedOrganization, + updateSelected, + DailyPayment); + }); + }, + items: _fetchedOrganizations + .map((Organization value) { + return DropdownMenuItem( + value: value, + child: Text(value.description!), + ); + }).toList(), + ), + ]), + ), + ]), + SizedBox(width: 20), + // Container( + // margin: const EdgeInsets.only(left: 10.0), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // const Text( + // 'Monthly Payment Amount:', + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.bold, + // ), + // ), + // const SizedBox(height: 5), + // Text( + // // 'Rs. ${MonthlyPayment}', + // 'Rs.10000.00', + // style: const TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.normal, + // color: Colors.green, + // ), + // ), + // ], + // ), + // ), + // SizedBox(width: 20), + // Container( + // margin: const EdgeInsets.only(left: 10.0), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // const Text( + // 'Daily Payment Amount:', + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.bold, + // ), + // ), + // const SizedBox(height: 5), + // Text( + // 'Rs. ${DailyPayment}', + // style: const TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.normal, + // color: Colors.green, + // ), + // ), + // ], + // ), + // ), + SizedBox(width: 20), + Expanded( + child: Container( + alignment: Alignment.bottomRight, + margin: const EdgeInsets.only(right: 20.0), + width: 25.0, + height: 30.0, + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LeaveDatePicker( + organizationId: organization_id ?? + 0, // Provide a default value if needed + year: _selected?.year ?? + _year, // Ensure an `int` value is passed + month: _selected?.month ?? _month, + selectedDay: + _selectedDay ?? DateTime.now(), ), - ]), - ), - ]), - ], - ), - SizedBox(width: 20), - Container( - margin: const EdgeInsets.only(left: 10.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Monthly Payment Amount:', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 5), - Text( - // 'Rs. ${MonthlyPayment}', - 'Rs.10000.00', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.normal, - color: Colors.green, - ), - ), - ], - ), - ), - SizedBox(width: 20), - Container( - margin: const EdgeInsets.only(left: 10.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Daily Payment Amount:', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 5), - Text( - 'Rs. ${DailyPayment}', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.normal, - color: Colors.green, + )); + }, + child: const Text('Update Monthly Leave Dates'), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 5.0), + textStyle: const TextStyle(fontSize: 16), + ), ), ), - ], - ), - ), - SizedBox(width: 20), - Expanded( - child: Container( - alignment: Alignment.bottomRight, - margin: const EdgeInsets.only(right: 20.0), - width: 25.0, - height: 30.0, - child: ElevatedButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => LeaveDatePicker( - organizationId: organization_id ?? - 0, // Provide a default value if needed - year: _selected?.year ?? - _year, // Ensure an `int` value is passed - month: _selected?.month ?? _month, - selectedDay: _selectedDay ?? DateTime.now(), + ), + Padding( + padding: EdgeInsets.only(top: 20, left: 20), + child: Row( + children: [ + Text( + 'Select a Year & Month :', + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.bold), + ), + SizedBox( + width: 5, + ), + TextButton( + onPressed: () => + _onPressed(context: context, locale: 'en'), + child: Icon(Icons.calendar_month), + ), + if (_selected == null) + Container( + margin: EdgeInsets.only(left: 10.0), + child: const Text( + 'No month & year selected.', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.normal, + ), ), - )); - }, - child: const Text('Update Monthly Leave Dates'), - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric( - horizontal: 10.0, vertical: 5.0), - textStyle: const TextStyle(fontSize: 16), + ) + else + Container( + child: Text( + DateFormat.yMMMM() + .format(_selected!) + .toString(), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.normal), + ), + ), + ], ), ), - ), + SizedBox(width: 20), + ], ), - Padding( - padding: EdgeInsets.only(top: 20, left: 20), - child: Row( - children: [ - Text( - 'Select a Year & Month :', - style: TextStyle( - fontSize: 16, fontWeight: FontWeight.bold), - ), - SizedBox( - width: 5, - ), - TextButton( - onPressed: () => - _onPressed(context: context, locale: 'en'), - child: Icon(Icons.calendar_month), - ), - if (_selected == null) - Container( - margin: EdgeInsets.only(left: 10.0), - child: const Text( - 'No month & year selected.', + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Container( + margin: const EdgeInsets.only(left: 10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Monthly Payment Amount:', style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 5), + Text( + // 'Rs. ${MonthlyPayment}', + 'Rs.10000.00', + style: const TextStyle( fontSize: 14, fontWeight: FontWeight.normal, + color: Colors.green, ), ), - ) - else - Container( - child: Text( - DateFormat.yMMMM() - .format(_selected!) - .toString(), + ], + ), + ), + SizedBox(width: 20), + Container( + margin: + const EdgeInsets.only(left: 10.0, right: 10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Daily Payment Amount:', style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.normal), + fontSize: 14, + fontWeight: FontWeight.bold, + ), ), - ), - ], - ), - ), - SizedBox(width: 20), + const SizedBox(height: 5), + Text( + 'Rs. ${DailyPayment}', + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.normal, + color: Colors.green, + ), + ), + ], + ), + ), + ], + ) ], ), SizedBox(height: 16.0),