From e75e1a548b88ba955ce56e560cfc6763b7324081 Mon Sep 17 00:00:00 2001 From: lahirulakruwan Date: Tue, 5 Nov 2024 13:26:46 +0530 Subject: [PATCH 01/17] fetch classes api function bug fixed --- campus/frontend/lib/avinya/enrollment/lib/data/person.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/campus/frontend/lib/avinya/enrollment/lib/data/person.dart b/campus/frontend/lib/avinya/enrollment/lib/data/person.dart index a14ef06e..d4267aba 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/data/person.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/data/person.dart @@ -571,7 +571,7 @@ Future> fetchClasses(int? id) async { // Extract the child_organizations_for_dashboard field final List classes = - (jsonResponse['child_organizations_for_dashboard'] as List) + (jsonResponse['child_organizations'] as List) .map((data) => MainOrganization.fromJson(data)) .toList(); From c0453250efa1cbc60e2463ebcf3fdfa662e3b142 Mon Sep 17 00:00:00 2001 From: lahirulakruwan Date: Wed, 6 Nov 2024 09:03:36 +0530 Subject: [PATCH 02/17] Toast message added for monthly leave dates picker --- .../lib/avinya/attendance/lib/app.dart | 41 ++++++++++--------- .../lib/data/activity_attendance.dart | 3 ++ .../lib/avinya/attendance/pubspec.yaml | 2 +- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/campus/frontend/lib/avinya/attendance/lib/app.dart b/campus/frontend/lib/avinya/attendance/lib/app.dart index 2c354e20..728635d1 100644 --- a/campus/frontend/lib/avinya/attendance/lib/app.dart +++ b/campus/frontend/lib/avinya/attendance/lib/app.dart @@ -6,6 +6,7 @@ import 'package:gallery/auth.dart'; import 'package:gallery/data/campus_apps_portal.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:month_year_picker/month_year_picker.dart'; +import 'package:oktoast/oktoast.dart'; // import 'auth.dart'; import 'routing.dart'; @@ -90,25 +91,27 @@ class _CampusAttendanceManagementSystemState notifier: _routeState, child: SMSAuthScope( notifier: _auth, - child: MaterialApp.router( - routerDelegate: _routerDelegate, - routeInformationParser: _routeParser, - localizationsDelegates: [ - GlobalWidgetsLocalizations.delegate, - GlobalMaterialLocalizations.delegate, - MonthYearPickerLocalizations.delegate, - ], - // Revert back to pre-Flutter-2.5 transition behavior: - // https://github.com/flutter/flutter/issues/82053 - theme: ThemeData( - pageTransitionsTheme: const PageTransitionsTheme( - builders: { - TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(), - TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), - TargetPlatform.linux: FadeUpwardsPageTransitionsBuilder(), - TargetPlatform.macOS: CupertinoPageTransitionsBuilder(), - TargetPlatform.windows: FadeUpwardsPageTransitionsBuilder(), - }, + child: OKToast( + child: MaterialApp.router( + routerDelegate: _routerDelegate, + routeInformationParser: _routeParser, + localizationsDelegates: [ + GlobalWidgetsLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + MonthYearPickerLocalizations.delegate, + ], + // Revert back to pre-Flutter-2.5 transition behavior: + // https://github.com/flutter/flutter/issues/82053 + theme: ThemeData( + pageTransitionsTheme: const PageTransitionsTheme( + builders: { + TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(), + TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), + TargetPlatform.linux: FadeUpwardsPageTransitionsBuilder(), + TargetPlatform.macOS: CupertinoPageTransitionsBuilder(), + TargetPlatform.windows: FadeUpwardsPageTransitionsBuilder(), + }, + ), ), ), ), diff --git a/campus/frontend/lib/avinya/attendance/lib/data/activity_attendance.dart b/campus/frontend/lib/avinya/attendance/lib/data/activity_attendance.dart index fea7648a..62347f91 100644 --- a/campus/frontend/lib/avinya/attendance/lib/data/activity_attendance.dart +++ b/campus/frontend/lib/avinya/attendance/lib/data/activity_attendance.dart @@ -1,4 +1,5 @@ import 'dart:ui'; +import 'package:gallery/widgets/success_message.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; @@ -202,6 +203,7 @@ Future createMonthlyLeaveDates({ ); if (response.statusCode >= 200 && response.statusCode < 300) { + showSuccessToast("Monthly Leave Dates Added Successfully!"); print("Leave dates created successfully: ${response.body}"); } else { throw Exception( @@ -244,6 +246,7 @@ Future updateMonthlyLeaveDates({ ); if (response.statusCode >= 200 && response.statusCode < 300) { + showSuccessToast("Monthly Leave Dates Updated Successfully!"); print("Leave dates updated successfully: ${response.body}"); } else { throw Exception( diff --git a/campus/frontend/lib/avinya/attendance/pubspec.yaml b/campus/frontend/lib/avinya/attendance/pubspec.yaml index ae35423b..33a6e0a1 100644 --- a/campus/frontend/lib/avinya/attendance/pubspec.yaml +++ b/campus/frontend/lib/avinya/attendance/pubspec.yaml @@ -38,7 +38,7 @@ dependencies: flutter_svg: fl_chart: 0.60.0 month_year_picker: ^0.3.0+1 - + oktoast: ^3.4.0 pdf: ^3.6.4 dev_dependencies: From 5f2239e5b095183ec0d230446f8ab6b8799c6a06 Mon Sep 17 00:00:00 2001 From: YujithIsura Date: Wed, 6 Nov 2024 11:02:35 +0530 Subject: [PATCH 03/17] lint --- campus/bffs/profile/api/Dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/campus/bffs/profile/api/Dependencies.toml b/campus/bffs/profile/api/Dependencies.toml index 8746ac2b..a66dda68 100644 --- a/campus/bffs/profile/api/Dependencies.toml +++ b/campus/bffs/profile/api/Dependencies.toml @@ -10,7 +10,7 @@ distribution-version = "2201.8.7" [[package]] org = "avinyafoundation" name = "profile_bff" -version = "1.1.0" +version = "2.1.0" dependencies = [ {org = "ballerina", name = "graphql"}, {org = "ballerina", name = "http"}, From 40527f4eac50aca51a67428fdb46bba7fc5614fa Mon Sep 17 00:00:00 2001 From: lahirulakruwan Date: Fri, 8 Nov 2024 12:04:05 +0530 Subject: [PATCH 04/17] Added Monthly payment amount by organization api fetch function --- campus/bffs/attendance/api/Dependencies.toml | 2 +- .../bffs/attendance/api/attendance_client.bal | 13 +++ campus/bffs/attendance/api/service.bal | 42 ++++++++ campus/bffs/attendance/api/types.bal | 44 ++++++++- .../graphql_client/activity.graphql | 22 +++++ .../graphql_client_cg_src/client.bal | 12 +++ .../graphql_client_cg_src/types.bal | 26 +++++ .../attendance/graphql_client/schema.graphql | 11 ++- .../attendance/graphql_client/schema.json | 97 +++++++++++++++++++ campus/bffs/profile/api/Dependencies.toml | 2 +- 10 files changed, 264 insertions(+), 7 deletions(-) diff --git a/campus/bffs/attendance/api/Dependencies.toml b/campus/bffs/attendance/api/Dependencies.toml index c25ec358..ae8ac9c2 100644 --- a/campus/bffs/attendance/api/Dependencies.toml +++ b/campus/bffs/attendance/api/Dependencies.toml @@ -10,7 +10,7 @@ distribution-version = "2201.8.7" [[package]] org = "avinyafoundation" name = "campus_attendance_bff" -version = "1.1.0" +version = "2.1.0" dependencies = [ {org = "ballerina", name = "graphql"}, {org = "ballerina", name = "http"}, diff --git a/campus/bffs/attendance/api/attendance_client.bal b/campus/bffs/attendance/api/attendance_client.bal index ad9d4420..9a12f9ad 100644 --- a/campus/bffs/attendance/api/attendance_client.bal +++ b/campus/bffs/attendance/api/attendance_client.bal @@ -333,4 +333,17 @@ log:printInfo("Formatted Response: " + formattedJson); json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, GetMonthlyLeaveDatesRecordByIdResponse); } + + remote isolated function getOrganizationsByAvinyaTypeWithActiveStatus(int avinya_type, int active) returns GetOrganizationsByAvinyaTypeWithActiveStatusResponse|graphql:ClientError { + string query = string `query getOrganizationsByAvinyaTypeWithActiveStatus($avinya_type:Int!,$active:Int!) {organizations_by_avinya_type(avinya_type:$avinya_type,active:$active) {id name {name_en} description organization_metadata {key_name value} active}}`; + map variables = {"avinya_type": avinya_type, "active": active}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetOrganizationsByAvinyaTypeWithActiveStatusResponse); + } + remote isolated function getCalendarMetadataByOrgId(int organization_id) returns GetCalendarMetadataByOrgIdResponse|graphql:ClientError { + string query = string `query getCalendarMetadataByOrgId($organization_id:Int!) {calendar_metadata_by_org_id(organization_id:$organization_id) {id organization_id monthly_payment_amount}}`; + map variables = {"organization_id": organization_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetCalendarMetadataByOrgIdResponse); + } } diff --git a/campus/bffs/attendance/api/service.bal b/campus/bffs/attendance/api/service.bal index f2f3d0ef..8e7dff3a 100644 --- a/campus/bffs/attendance/api/service.bal +++ b/campus/bffs/attendance/api/service.bal @@ -935,4 +935,46 @@ service / on new http:Listener(9091) { } } + resource function get organizations_by_avinya_type_with_active_status/[int avinya_type_id]/[int active]() returns Organization[]|error { + GetOrganizationsByAvinyaTypeWithActiveStatusResponse|graphql:ClientError getOrganizationsByAvinyaTypeWithActiveStatusResponse = globalDataClient->getOrganizationsByAvinyaTypeWithActiveStatus(avinya_type_id,active); + if(getOrganizationsByAvinyaTypeWithActiveStatusResponse is GetOrganizationsByAvinyaTypeWithActiveStatusResponse) { + Organization[] organizations = []; + foreach var organization_record in getOrganizationsByAvinyaTypeWithActiveStatusResponse.organizations_by_avinya_type { + Organization|error organization = organization_record.cloneWithType(Organization); + if(organization is Organization) { + organizations.push(organization); + } else { + log:printError("Error while processing Application record received", organization); + return error("Error while processing Application record received: " + organization.message() + + ":: Detail: " + organization.detail().toString()); + } + } + + return organizations; + + } else { + log:printError("Error while creating application", getOrganizationsByAvinyaTypeWithActiveStatusResponse); + return error("Error while creating application: " + getOrganizationsByAvinyaTypeWithActiveStatusResponse.message() + + ":: Detail: " + getOrganizationsByAvinyaTypeWithActiveStatusResponse.detail().toString()); + } + } + + resource function get calendar_metadata_by_org_id/[int organization_id]() returns CalendarMetadata|error { + GetCalendarMetadataByOrgIdResponse|graphql:ClientError getCalendarMetadataByOrgIdResponse = globalDataClient->getCalendarMetadataByOrgId(organization_id); + if (getCalendarMetadataByOrgIdResponse is GetCalendarMetadataByOrgIdResponse) { + CalendarMetadata|error calendar_metadata_record = getCalendarMetadataByOrgIdResponse.calendar_metadata_by_org_id.cloneWithType(CalendarMetadata); + if (calendar_metadata_record is CalendarMetadata) { + return calendar_metadata_record; + } else { + log:printError("Error while processing Application record received", calendar_metadata_record); + return error("Error while processing Application record received: " + calendar_metadata_record.message() + + ":: Detail: " + calendar_metadata_record.detail().toString()); + } + } else { + log:printError("Error while creating application", getCalendarMetadataByOrgIdResponse); + return error("Error while creating application: " + getCalendarMetadataByOrgIdResponse.message() + + ":: Detail: " + getCalendarMetadataByOrgIdResponse.detail().toString()); + } + } + } diff --git a/campus/bffs/attendance/api/types.bal b/campus/bffs/attendance/api/types.bal index 23dd352c..1db5ec66 100644 --- a/campus/bffs/attendance/api/types.bal +++ b/campus/bffs/attendance/api/types.bal @@ -161,16 +161,20 @@ public type Evaluation record { }; public type Organization record { - int[]? parent_organizations?; + string? notes?; string? name_ta?; int[]? child_organizations?; - int? phone?; int? address_id?; string? name_si?; int? avinya_type?; - int? id?; + string? description?; + int? active?; + int[]? child_organizations_for_dashboard?; string? record_type?; - string name_en?; + int[]? parent_organizations?; + int? phone?; + int? id?; + string? name_en?; }; public type Person record { int? permanent_address_id?; @@ -291,6 +295,13 @@ public type MonthlyLeaveDates record { string? record_type?; }; +public type CalendarMetadata record { + string? record_type?; + int? id?; + int? organization_id; + anydata? monthly_payment_amount; +}; + public type GetAvinyaTypesResponse record {| map __extensions?; record {| @@ -861,3 +872,28 @@ public type GetMonthlyLeaveDatesRecordByIdResponse record {| string? updated; |}? monthly_leave_dates_record_by_id; |}; + +public type GetOrganizationsByAvinyaTypeWithActiveStatusResponse record {| + map __extensions?; + record {| + int? id; + record {| + string? name_en; + |} name; + string? description; + record {| + string? key_name; + string? value; + |}[]? organization_metadata; + int? active; + |}[] organizations_by_avinya_type; +|}; + +public type GetCalendarMetadataByOrgIdResponse record {| + map __extensions?; + record {| + int? id; + int? organization_id; + anydata? monthly_payment_amount; + |}? calendar_metadata_by_org_id; +|}; diff --git a/campus/bffs/attendance/graphql_client/activity.graphql b/campus/bffs/attendance/graphql_client/activity.graphql index 707f3c08..c866a39e 100644 --- a/campus/bffs/attendance/graphql_client/activity.graphql +++ b/campus/bffs/attendance/graphql_client/activity.graphql @@ -453,3 +453,25 @@ query getMonthlyLeaveDatesRecordById($organization_id:Int!,$year:Int!,$month:Int } } +query getOrganizationsByAvinyaTypeWithActiveStatus($avinya_type:Int!,$active:Int!) { + organizations_by_avinya_type(avinya_type:$avinya_type,active:$active) { + id + name { + name_en + } + description + organization_metadata{ + key_name + value + } + active + } +} + +query getCalendarMetadataByOrgId($organization_id: Int!) { + calendar_metadata_by_org_id(organization_id: $organization_id) { + id + organization_id + monthly_payment_amount + } +} diff --git a/campus/bffs/attendance/graphql_client/graphql_client_cg_src/client.bal b/campus/bffs/attendance/graphql_client/graphql_client_cg_src/client.bal index 526e92c5..d67ef753 100644 --- a/campus/bffs/attendance/graphql_client/graphql_client_cg_src/client.bal +++ b/campus/bffs/attendance/graphql_client/graphql_client_cg_src/client.bal @@ -237,4 +237,16 @@ public isolated client class GraphqlClient { json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, GetMonthlyLeaveDatesRecordByIdResponse); } + remote isolated function getOrganizationsByAvinyaTypeWithActiveStatus(int avinya_type, int active) returns GetOrganizationsByAvinyaTypeWithActiveStatusResponse|graphql:ClientError { + string query = string `query getOrganizationsByAvinyaTypeWithActiveStatus($avinya_type:Int!,$active:Int!) {organizations_by_avinya_type(avinya_type:$avinya_type,active:$active) {id name {name_en} description organization_metadata {key_name value} active}}`; + map variables = {"avinya_type": avinya_type, "active": active}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetOrganizationsByAvinyaTypeWithActiveStatusResponse); + } + remote isolated function getCalendarMetadataByOrgId(int organization_id) returns GetCalendarMetadataByOrgIdResponse|graphql:ClientError { + string query = string `query getCalendarMetadataByOrgId($organization_id:Int!) {calendar_metadata_by_org_id(organization_id:$organization_id) {id organization_id monthly_payment_amount}}`; + map variables = {"organization_id": organization_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetCalendarMetadataByOrgIdResponse); + } } diff --git a/campus/bffs/attendance/graphql_client/graphql_client_cg_src/types.bal b/campus/bffs/attendance/graphql_client/graphql_client_cg_src/types.bal index eda23b58..4055a5a0 100644 --- a/campus/bffs/attendance/graphql_client/graphql_client_cg_src/types.bal +++ b/campus/bffs/attendance/graphql_client/graphql_client_cg_src/types.bal @@ -296,6 +296,7 @@ public type Organization record { string? name_si?; int? avinya_type?; string? description?; + int? active?; int[]? child_organizations_for_dashboard?; string? record_type?; int[]? parent_organizations?; @@ -973,3 +974,28 @@ public type GetMonthlyLeaveDatesRecordByIdResponse record {| string? updated; |}? monthly_leave_dates_record_by_id; |}; + +public type GetOrganizationsByAvinyaTypeWithActiveStatusResponse record {| + map __extensions?; + record {| + int? id; + record {| + string? name_en; + |} name; + string? description; + record {| + string? key_name; + string? value; + |}[]? organization_metadata; + int? active; + |}[]? organizations_by_avinya_type; +|}; + +public type GetCalendarMetadataByOrgIdResponse record {| + map __extensions?; + record {| + int? id; + int? organization_id; + anydata? monthly_payment_amount; + |}? calendar_metadata_by_org_id; +|}; diff --git a/campus/bffs/attendance/graphql_client/schema.graphql b/campus/bffs/attendance/graphql_client/schema.graphql index 6c507b2c..1c007384 100644 --- a/campus/bffs/attendance/graphql_client/schema.graphql +++ b/campus/bffs/attendance/graphql_client/schema.graphql @@ -310,6 +310,12 @@ type AvinyaTypeData { description: String } +type CalendarMetaData { + id: Int + organization_id: Int + monthly_payment_amount: Decimal +} + input City { record_type: String = "city" id: Int @@ -707,6 +713,7 @@ input Organization { phone: Int description: String notes: String + active: Int name_en: String name_ta: String name_si: String @@ -726,6 +733,7 @@ type OrganizationData { people: [PersonData!] vacancies: [VacancyData!] organization_metadata: [OrganizationMetaData!] + active: Int } type OrganizationMetaData { @@ -885,7 +893,7 @@ type Query { organization_structure(name: String, id: Int): OrganizationStructureData organizations(level: Int!): OrganizationStructureData organization(name: String, id: Int): OrganizationData - organizations_by_avinya_type(avinya_type: Int): [OrganizationData!] + organizations_by_avinya_type(avinya_type: Int, active: Int = 0): [OrganizationData!] student_list_by_parent(id: Int): [PersonData!] person(name: String, id: Int): PersonData person_by_digital_id(id: String): PersonData @@ -960,6 +968,7 @@ type Query { cities(district_id: Int): [CityData!] all_organizations: [OrganizationData!] monthly_leave_dates_record_by_id(organization_id: Int!, year: Int!, month: Int!): MonthlyLeaveDatesData + calendar_metadata_by_org_id(organization_id: Int!): CalendarMetaData } input ResourceAllocation { diff --git a/campus/bffs/attendance/graphql_client/schema.json b/campus/bffs/attendance/graphql_client/schema.json index 04fba51b..be736a7e 100644 --- a/campus/bffs/attendance/graphql_client/schema.json +++ b/campus/bffs/attendance/graphql_client/schema.json @@ -713,6 +713,15 @@ "ofType": null }, "defaultValue": null + }, + { + "name": "active", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "0" } ], "type": { @@ -3164,6 +3173,31 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "calendar_metadata_by_org_id", + "args": [ + { + "name": "organization_id", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CalendarMetaData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -5850,6 +5884,17 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "active", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -10235,6 +10280,15 @@ }, "defaultValue": null }, + { + "name": "active", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, { "name": "name_en", "type": { @@ -10831,6 +10885,49 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "CalendarMetaData", + "fields": [ + { + "name": "id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "organization_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "monthly_payment_amount", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Decimal", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "AssetData", diff --git a/campus/bffs/profile/api/Dependencies.toml b/campus/bffs/profile/api/Dependencies.toml index 8746ac2b..a66dda68 100644 --- a/campus/bffs/profile/api/Dependencies.toml +++ b/campus/bffs/profile/api/Dependencies.toml @@ -10,7 +10,7 @@ distribution-version = "2201.8.7" [[package]] org = "avinyafoundation" name = "profile_bff" -version = "1.1.0" +version = "2.1.0" dependencies = [ {org = "ballerina", name = "graphql"}, {org = "ballerina", name = "http"}, From 64ded912f7259bd1453524875433efe9f1a361f1 Mon Sep 17 00:00:00 2001 From: YujithIsura Date: Fri, 8 Nov 2024 12:37:10 +0530 Subject: [PATCH 05/17] fixed attendance dashboard class loading issue --- .../lib/screens/dashboard/dashboard_screen.dart | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/campus/frontend/lib/avinya/attendance/lib/screens/dashboard/dashboard_screen.dart b/campus/frontend/lib/avinya/attendance/lib/screens/dashboard/dashboard_screen.dart index fc7e67f7..e01d3d4e 100644 --- a/campus/frontend/lib/avinya/attendance/lib/screens/dashboard/dashboard_screen.dart +++ b/campus/frontend/lib/avinya/attendance/lib/screens/dashboard/dashboard_screen.dart @@ -77,8 +77,7 @@ class _AttendanceDashboardScreenState extends State { if (_selectedOrganizationValue != null) { int orgId = _selectedOrganizationValue!.id!; _fetchedOrganization = await fetchOrganization(orgId); - _fetchedOrganizations = - _fetchedOrganization?.child_organizations_for_dashboard ?? []; + _fetchedOrganizations = _fetchedOrganization?.child_organizations ?? []; setState(() { _fetchedOrganizations = _fetchedOrganizations; }); @@ -413,9 +412,8 @@ class _AttendanceDashboardScreenState extends State { _fetchedOrganization = await fetchOrganization(newValue!.id!); - _fetchedOrganizations = _fetchedOrganization - ?.child_organizations_for_dashboard ?? - []; + _fetchedOrganizations = + _fetchedOrganization?.child_organizations ?? []; setState(() { _fetchedOrganizations; @@ -580,7 +578,7 @@ class _AttendanceDashboardScreenState extends State { _fetchedOrganization = await fetchOrganization(newValue!.id!); _fetchedOrganizations = _fetchedOrganization - ?.child_organizations_for_dashboard ?? + ?.child_organizations ?? []; setState(() { From 488a68b040d5dd7077133ce3caf3492753a4eff8 Mon Sep 17 00:00:00 2001 From: YujithIsura Date: Fri, 8 Nov 2024 14:35:01 +0530 Subject: [PATCH 06/17] batch selection feture added for bulk attendance marker --- .../lib/widgets/bulk_attedance_marker.dart | 345 +++++++++++------- campus/frontend/lib/data/person.dart | 59 ++- 2 files changed, 263 insertions(+), 141 deletions(-) diff --git a/campus/frontend/lib/avinya/attendance/lib/widgets/bulk_attedance_marker.dart b/campus/frontend/lib/avinya/attendance/lib/widgets/bulk_attedance_marker.dart index ee114516..b4b6461e 100644 --- a/campus/frontend/lib/avinya/attendance/lib/widgets/bulk_attedance_marker.dart +++ b/campus/frontend/lib/avinya/attendance/lib/widgets/bulk_attedance_marker.dart @@ -3,6 +3,8 @@ import 'package:attendance/data.dart'; import 'package:attendance/data/activity_attendance.dart'; import 'package:attendance/data/evaluation.dart'; import 'package:attendance/widgets/evaluation_list.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:intl/intl.dart'; import '../data/activity_instance.dart'; @@ -23,10 +25,17 @@ class _BulkAttendanceMarkerState extends State { List _fetchedAttendance = []; List _fetchedAttendanceAfterSchool = []; List _fetchedEvaluations = []; + late Future> _fetchBatchData; + Organization? _selectedOrganizationValue; + List _batchData = []; + List _fetchedOrganizations = []; + String batchStartDate = ""; + String batchEndDate = ""; @override void initState() { super.initState(); + _fetchBatchData = _loadBatchData(); if (campusAppsPortalInstance.isTeacher || campusAppsPortalInstance.isFoundation || campusAppsPortalInstance.isSecurity) { @@ -36,6 +45,25 @@ class _BulkAttendanceMarkerState extends State { } } + Future> _loadBatchData() async { + _batchData = await fetchActiveOrganizationsByAvinyaType(86); + _selectedOrganizationValue = _batchData.isNotEmpty ? _batchData.last : null; + 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())); + 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 toggleAttendance( int person_id, bool value, bool sign_in, bool after_school) async { // handle activity id fetch case @@ -185,141 +213,210 @@ class _BulkAttendanceMarkerState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, 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) - 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!); + Row( + children: [ + Text('Select a Batch:'), + SizedBox(height: 8), + 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; + } - _fetchedAttendance = - await getClassActivityAttendanceToday( - _fetchedOrganization!.id!, - activityId); - if (_fetchedAttendance.length == 0) - _fetchedAttendance = new List.filled( - _fetchedOrganization! - .people.length * - 2, // add 2 records for eign in and out - 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) { - // add 2 records for sing in and out - _fetchedAttendance.add( - new ActivityAttendance( - person_id: -1)); - _fetchedAttendance.add( - new ActivityAttendance( - person_id: -1)); + 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( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (_fetchedOrganizations.length > 0) + 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 getClassActivityAttendanceToday( + _fetchedOrganization!.id!, + activityId); + if (_fetchedAttendance.length == 0) + _fetchedAttendance = new List.filled( + _fetchedOrganization! + .people.length * + 2, // add 2 records for eign in and out + 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) { + // add 2 records for sing in and out + _fetchedAttendance.add( + new ActivityAttendance( + person_id: -1)); + _fetchedAttendance.add( + new ActivityAttendance( + person_id: -1)); + } } } - } - // if (campusAppsPortalInstance.isTeacher) { - _fetchedAttendanceAfterSchool = - await getClassActivityAttendanceToday( - _fetchedOrganization!.id!, - afterSchoolActivityId); - if (_fetchedAttendanceAfterSchool - .length == - 0) + // if (campusAppsPortalInstance.isTeacher) { _fetchedAttendanceAfterSchool = - new List.filled( - _fetchedOrganization! - .people.length, - new ActivityAttendance( - person_id: -1)); - else { - for (int i = 0; - i < - _fetchedOrganization! - .people.length; - i++) { - if (_fetchedAttendanceAfterSchool - .indexWhere((attendance) => - attendance.person_id == - _fetchedOrganization! - .people[i].id) == - -1) { - _fetchedAttendanceAfterSchool.add( - new ActivityAttendance( - person_id: -1)); + await getClassActivityAttendanceToday( + _fetchedOrganization!.id!, + afterSchoolActivityId); + if (_fetchedAttendanceAfterSchool + .length == + 0) + _fetchedAttendanceAfterSchool = + new List.filled( + _fetchedOrganization! + .people.length, + new ActivityAttendance( + person_id: -1)); + else { + for (int i = 0; + i < + _fetchedOrganization! + .people.length; + i++) { + if (_fetchedAttendanceAfterSchool + .indexWhere((attendance) => + attendance.person_id == + _fetchedOrganization! + .people[i].id) == + -1) { + _fetchedAttendanceAfterSchool.add( + new ActivityAttendance( + person_id: -1)); + } } } - } - if (activityInstance.id == -1) { - activityInstance = - await campusAttendanceSystemInstance - .getCheckinActivityInstance( - activityId); - } + if (activityInstance.id == -1) { + activityInstance = + await campusAttendanceSystemInstance + .getCheckinActivityInstance( + activityId); + } - _fetchedEvaluations = - await getActivityInstanceEvaluations( - activityInstance.id!); - if (_fetchedEvaluations.length == 0) - _fetchedEvaluations = new List.filled( - _fetchedOrganization!.people.length, - new Evaluation(evaluatee_id: -1)); - else { - for (int i = 0; - i < - _fetchedOrganization! - .people.length; - i++) { - if (_fetchedEvaluations.indexWhere( - (evaluation) => - evaluation.evaluatee_id == - _fetchedOrganization! - .people[i].id) == - -1) { - _fetchedEvaluations.add( - new Evaluation( - evaluatee_id: -1)); + _fetchedEvaluations = + await getActivityInstanceEvaluations( + activityInstance.id!); + if (_fetchedEvaluations.length == 0) + _fetchedEvaluations = new List.filled( + _fetchedOrganization! + .people.length, + new Evaluation(evaluatee_id: -1)); + else { + for (int i = 0; + i < + _fetchedOrganization! + .people.length; + i++) { + if (_fetchedEvaluations.indexWhere( + (evaluation) => + evaluation + .evaluatee_id == + _fetchedOrganization! + .people[i].id) == + -1) { + _fetchedEvaluations.add( + new Evaluation( + evaluatee_id: -1)); + } } } - } - // } + // } - setState(() {}); - }, - items: org.child_organizations - .map((Organization value) { - return DropdownMenuItem( - value: value, - child: Text(value.description!), - ); - }).toList(), - ), - ]), - ]), + setState(() {}); + }, + items: _fetchedOrganizations + .map((Organization value) { + return DropdownMenuItem( + value: value, + child: Text(value.description!), + ); + }).toList(), + ), + ]), + ]), + ], + ), ], ), SizedBox(height: 16.0), diff --git a/campus/frontend/lib/data/person.dart b/campus/frontend/lib/data/person.dart index 3781b823..caa5c1df 100644 --- a/campus/frontend/lib/data/person.dart +++ b/campus/frontend/lib/data/person.dart @@ -45,7 +45,7 @@ class Organization { var parent_organizations = []; var child_organizations_for_dashboard = []; var people = []; - var organization_metadata = []; + var organization_metadata = []; Organization({ this.id, @@ -53,9 +53,9 @@ class Organization { this.description, this.child_organizations = const [], this.parent_organizations = const [], - this.child_organizations_for_dashboard = const [], + this.child_organizations_for_dashboard = const [], this.people = const [], - this.organization_metadata = const[], + this.organization_metadata = const [], }); factory Organization.fromJson(Map json) { @@ -71,16 +71,18 @@ class Organization { ? List.from( json['parent_organizations'].map((x) => Organization.fromJson(x))) : [], - child_organizations_for_dashboard: json['child_organizations_for_dashboard'] != null - ? List.from( - json['child_organizations_for_dashboard'].map((x) => Organization.fromJson(x))) - : [], + child_organizations_for_dashboard: + json['child_organizations_for_dashboard'] != null + ? List.from( + json['child_organizations_for_dashboard'] + .map((x) => Organization.fromJson(x))) + : [], people: json['people'] != null ? List.from(json['people'].map((x) => Person.fromJson(x))) : [], organization_metadata: json['organization_metadata'] != null - ? List.from( - json['organization_metadata'].map((x) => OrganizationMetaData.fromJson(x))) + ? List.from(json['organization_metadata'] + .map((x) => OrganizationMetaData.fromJson(x))) : [], ); } @@ -95,10 +97,11 @@ class Organization { List.from(child_organizations.map((x) => x.toJson())), 'parent_organizations': List.from(parent_organizations.map((x) => x.toJson())), - 'child_organizations_for_dashboard': - List.from(child_organizations_for_dashboard.map((x) => x.toJson())), + 'child_organizations_for_dashboard': List.from( + child_organizations_for_dashboard.map((x) => x.toJson())), 'people': List.from(people.map((x) => x.toJson())), - 'organization_metadata':List.from(organization_metadata.map((x) => x.toJson())) + 'organization_metadata': + List.from(organization_metadata.map((x) => x.toJson())) // if (employees != null) 'employees': List.from(employees!.map((x) => x.toJson())), }; } @@ -125,7 +128,6 @@ Future fetchOrganization(int id) async { } } - Future> fetchOrganizationForAll(int id) async { final uri = Uri.parse( AppConfig.campusProfileBffApiUrl + '/student_list_by_parent_org_id') @@ -151,8 +153,9 @@ Future> fetchOrganizationForAll(int id) async { throw Exception('Failed to load Person'); } } -Future> fetchOrganizationsByAvinyaType(int avinya_type) async { - + +Future> fetchOrganizationsByAvinyaType( + int avinya_type) async { final response = await http.get( Uri.parse( '${AppConfig.campusAttendanceBffApiUrl}/organizations_by_avinya_type/$avinya_type'), @@ -164,11 +167,33 @@ Future> fetchOrganizationsByAvinyaType(int avinya_type) async ); if (response.statusCode > 199 && response.statusCode < 300) { + var resultsJson = json.decode(response.body).cast>(); + List organization = await resultsJson + .map((json) => Organization.fromJson(json)) + .toList(); + return organization; + } else { + throw Exception('Failed to load organizations'); + } +} + +Future> fetchActiveOrganizationsByAvinyaType( + int avinya_type) async { + final response = await http.get( + Uri.parse( + '${AppConfig.campusAttendanceBffApiUrl}/organizations_by_avinya_type_with_active_status/$avinya_type/1'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + ); + + if (response.statusCode > 199 && response.statusCode < 300) { var resultsJson = json.decode(response.body).cast>(); - List organization = - await resultsJson + List organization = await resultsJson .map((json) => Organization.fromJson(json)) .toList(); return organization; From 7cf3e80d46fc90fdaebba07f3275fba4a53e1b66 Mon Sep 17 00:00:00 2001 From: lahirulakruwan Date: Thu, 21 Nov 2024 14:50:22 +0530 Subject: [PATCH 07/17] 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), From c585e09542d54e6ba96c9318672299d01c338879 Mon Sep 17 00:00:00 2001 From: YujithIsura Date: Wed, 11 Dec 2024 09:28:40 +0530 Subject: [PATCH 08/17] mobile app version updated --- campus/bffs/attendance/api/Dependencies.toml | 2 +- campus/bffs/enrollment/api/Dependencies.toml | 2 +- campus/bffs/profile/api/Dependencies.toml | 2 +- campus/mobile/.fvmrc | 3 +++ campus/mobile/.gitignore | 3 +++ campus/mobile/.vscode/settings.json | 7 ++++--- campus/mobile/android/app/build.gradle | 10 +++++----- .../kotlin/com/example/mobile/MainActivity.kt | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 12 ++++++------ .../attendance/lib/data/upload-keystore.jks | Bin 0 -> 2760 bytes .../widgets/assign_duty_for_participant.dart | 17 ++++++++++------- .../lib/widgets/duty_attendance_marker.dart | 4 +++- campus/mobile/linux/CMakeLists.txt | 2 +- .../Flutter/GeneratedPluginRegistrant.swift | 2 +- .../macos/Runner.xcodeproj/project.pbxproj | 6 +++--- .../macos/Runner/Configs/AppInfo.xcconfig | 2 +- 16 files changed, 44 insertions(+), 32 deletions(-) create mode 100644 campus/mobile/.fvmrc create mode 100644 campus/mobile/lib/avinya/attendance/lib/data/upload-keystore.jks diff --git a/campus/bffs/attendance/api/Dependencies.toml b/campus/bffs/attendance/api/Dependencies.toml index ae8ac9c2..8cd1c0e7 100644 --- a/campus/bffs/attendance/api/Dependencies.toml +++ b/campus/bffs/attendance/api/Dependencies.toml @@ -140,7 +140,7 @@ modules = [ [[package]] org = "ballerina" name = "io" -version = "1.6.1" +version = "1.6.3" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} diff --git a/campus/bffs/enrollment/api/Dependencies.toml b/campus/bffs/enrollment/api/Dependencies.toml index d621aef7..7a384fb4 100644 --- a/campus/bffs/enrollment/api/Dependencies.toml +++ b/campus/bffs/enrollment/api/Dependencies.toml @@ -140,7 +140,7 @@ modules = [ [[package]] org = "ballerina" name = "io" -version = "1.6.1" +version = "1.6.3" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} diff --git a/campus/bffs/profile/api/Dependencies.toml b/campus/bffs/profile/api/Dependencies.toml index a66dda68..c424b4af 100644 --- a/campus/bffs/profile/api/Dependencies.toml +++ b/campus/bffs/profile/api/Dependencies.toml @@ -140,7 +140,7 @@ modules = [ [[package]] org = "ballerina" name = "io" -version = "1.6.1" +version = "1.6.3" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} diff --git a/campus/mobile/.fvmrc b/campus/mobile/.fvmrc new file mode 100644 index 00000000..2705bc24 --- /dev/null +++ b/campus/mobile/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "3.13.1" +} \ No newline at end of file diff --git a/campus/mobile/.gitignore b/campus/mobile/.gitignore index 24476c5d..43ae556a 100644 --- a/campus/mobile/.gitignore +++ b/campus/mobile/.gitignore @@ -42,3 +42,6 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/campus/mobile/.vscode/settings.json b/campus/mobile/.vscode/settings.json index b242572e..78f6b874 100644 --- a/campus/mobile/.vscode/settings.json +++ b/campus/mobile/.vscode/settings.json @@ -1,5 +1,6 @@ { - "githubPullRequests.ignoredPullRequestBranches": [ - "main" - ] + "githubPullRequests.ignoredPullRequestBranches": [ + "main" + ], + "dart.flutterSdkPath": ".fvm/versions/3.13.1" } \ No newline at end of file diff --git a/campus/mobile/android/app/build.gradle b/campus/mobile/android/app/build.gradle index 1ead4f15..23c648d5 100644 --- a/campus/mobile/android/app/build.gradle +++ b/campus/mobile/android/app/build.gradle @@ -31,8 +31,8 @@ if (keystorePropertiesFile.exists()) { android { - namespace "com.avinya.mobile" - compileSdkVersion flutter.compileSdkVersion + namespace "com.avinyanew.mobile" + compileSdkVersion 34 ndkVersion flutter.ndkVersion compileOptions { @@ -50,12 +50,12 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.avinya.mobile" + applicationId "com.avinyanew.mobile" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdkVersion 20 - targetSdkVersion flutter.targetSdkVersion - versionCode 4 + targetSdkVersion 34 + versionCode 5 versionName "1.0.2" multiDexEnabled true manifestPlaceholders += [ diff --git a/campus/mobile/android/app/src/main/kotlin/com/example/mobile/MainActivity.kt b/campus/mobile/android/app/src/main/kotlin/com/example/mobile/MainActivity.kt index e5aac7f9..13e7318e 100644 --- a/campus/mobile/android/app/src/main/kotlin/com/example/mobile/MainActivity.kt +++ b/campus/mobile/android/app/src/main/kotlin/com/example/mobile/MainActivity.kt @@ -1,4 +1,4 @@ -package com.avinya.mobile +package com.avinyanew.mobile import io.flutter.embedding.android.FlutterActivity diff --git a/campus/mobile/ios/Runner.xcodeproj/project.pbxproj b/campus/mobile/ios/Runner.xcodeproj/project.pbxproj index 01427f24..decbb687 100644 --- a/campus/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/campus/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -367,7 +367,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.avinya.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -384,7 +384,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinya.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -402,7 +402,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinya.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -418,7 +418,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinya.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -545,7 +545,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.avinya.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -567,7 +567,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.avinya.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/campus/mobile/lib/avinya/attendance/lib/data/upload-keystore.jks b/campus/mobile/lib/avinya/attendance/lib/data/upload-keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..d3dd77b956950f096ae56ca3a1245fb62d899979 GIT binary patch literal 2760 zcma);X*d*$8pmhG3^QZj8e?me>_;=k7LH6&WFOUV(I6wCP-MxZ24gRK941@#UC0_a zn6i!~`(Cov5XoV1yU)E(=eeKm{qR2T^Zx$t|NZ!XUNi;X0Rpn2De$}OFa@e1^#?bQ z1DHjD6TuX??N3ZVQy}I4B|$R56iE6{{QPGnvUC2&#RUg~vM3O}pHK(w^2-6?M%$n@ z{~o!}ieRC$RVyveH3#-H%D&WJDDK=NI+y`LAXz>T5QXMqhyME_2nGS5CD>sOR6`(% z4GdHO^F>9UCth9C-&GiQhTN;QcLh_x3;_{5%6etdWfM8(Cd|uNT0^guE@Q%M^R^8r z+W8qUW(=`B&Ap^dGNR{ljs!}03ifbrO2v&jz9fXtHQo?Q$=O(VH$sG$DLwZuA{@V2 zbDxs3au`?78d)T(DUcwKc0ENB9-rGI<=Gv-oD>Qk7>7aQVOG7ndbG}H0*dPHm+LyX zZ&UhC3z5Aq69eQ43Y=P>z3IBe>=&ly2b&xm+|ykv7?*gs0?{i^KU@{8a}1_`q7#-m z&P<8mR4>~E%)=lWqLn*T(La7WZaRoHS@xEyQcj%Dgxkv^$*t|7P5c&%Co3(xPn`MU zvn@#k&y>k!2vg*RS}W)*OMpiZ}J_4*u9(P7eZR0@>G8o6gjhK{aLj) zJ%JO1)wDXzXtN9;+QsJPP;p3$y}{MWlHK}Bc|{O#_INn;cEE1=Hlw7&rsmc+o*ExL z9MiF7ok^}vIM?fV~d;` z{OIZ{QRa#B>)M+xH##d6w;#OY_A`@}b2gG46s@+0zpv_w5j7VC-+%BuLLqhAxS@7n zp9g=+>4NHc`m2^ZzE7H6oZw zq|^ZKYdN^?d15`dgsFNNSy0l6y@L7SPRkVWe-&sn60Ji`9*XLJ_{USR2*;awm)gW1 z1#NC#QX&-ny0O|w`>h>A@O{Ajk(+kRP zl0PuT3$fsa+t!(R?jKJ`E^Y1^!9FewLOB&ByUher{ONtnxw-DvgCy`tfGiLOlCU0w@{et?=r9*Vh68TGWsr!)sVPju=dMUKk#wp{UQ zmYX*&nC20UpN|>qHaJxeojhQ0MWrOj^q`2z8H3o*EW+u~a>G{3;kZ8oe^)4&t5vb| z**N}k+6`aQni-B7i%WhBK+dn~IbPDb5~?3Wl*9EaFJG)zDj%+40(bTye)3yv32W(b zPE3ij;kUFFk=CAvuy@=_k)|`I2fc>jL*|M_Iz}#HR_+Ku0 zFLn!zFc>|w*sr*R31N67xd6TZFMtQY6W|DNMoaxI3S)%80#|R}A)zoDSPb^uISmyJ zG!~7ffU|!saj<7mzzILmQxFjFvxWby0RLA^i!o?ey3I?iuuOI_i{L0ZmG9qJ|4&SN z5CCO4n?5U&=@KgPN6xs%6fj>1R{X>4t+RU{Xl1=6%(-J!Z`H%|1Pd-NJZ+Jw&gMWPG$m%x5f+lQ|F2-5}_9NHHiaU0m1; z?e$gp%!uDLIlG8V`eUDtXkPLeh=x*mUk6YtR`mDk4U?5xL(hTu=WY|7*zy8?PT6LC zmnFW4-nK$k|LZTU+ajfErQKM^okrZ-rHlaA`Z!o&&?FkB6gB~Dvf@FDts?p=M!VRODidw4lER&FZU$+gZ1!hs!RH8Z&OZhs{t6OS+PmE8+>ZVq5N} zjq$;{Hl1)}fT0sVug_m@85}C;I^yew$A}-Kj~;w!k=O3y5-BcQqnDT(lv@+yY;*Hf-K_rc8}G zRN^*}nNN<_!W7MEkA+6MIIXwY(uf6Gm#w30>O_v4lR4#Lpk$=|X+aQEV60CX1U}9Q zq-OQZBxUow37t&Cje6`-o{uan*ADA9BueG8sq4~vjjmNXFDwHwp|%GaBCeaUizV52 zMAce6sxTdFlpAK?rE>`d*)-kwPavuRo?^F4YC?{9r-bpHe57PY9te-e^Ib`iI6G@zxb&L_iD>%_X6w<4uQhB@== z4pB;C6Ht8BV%W%Zd903T*OxSJ;ggCTmJ()-A2tFuN&3)$vF4f z6?;_<*ZCF^?l}tNnmq0@qxre^TrYf83n1};Ro|00H_gi;5(`(;D46uaJF)dzq#)ol4oP<2;j+(E}t)Z01 zsQLi6_i@hJouh(wtlgbr`)w|AMJf5zh79A;Ksfy);_FmkX{^byN~yQa(mjEY^A=X9Y?pvnF#sqBW6Ds>YFY|caFtj8&(LoG&O&wjxJpw#GWDM!{In<<=sba z&A*E@ks?Y59>aOG^9}iS(57e%n)}yx2LeI>U{r+KAImJ}1z6QGEjcill!6@dN(! literal 0 HcmV?d00001 diff --git a/campus/mobile/lib/avinya/attendance/lib/widgets/assign_duty_for_participant.dart b/campus/mobile/lib/avinya/attendance/lib/widgets/assign_duty_for_participant.dart index 123a8f0b..ba102c2d 100644 --- a/campus/mobile/lib/avinya/attendance/lib/widgets/assign_duty_for_participant.dart +++ b/campus/mobile/lib/avinya/attendance/lib/widgets/assign_duty_for_participant.dart @@ -119,6 +119,8 @@ class _AssignDutyForParticipantState extends State { @override Widget build(BuildContext context) { + const IconData customIcon = IconData(0xe6f2, fontFamily: 'MaterialIcons'); + return Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -216,8 +218,7 @@ class _AssignDutyForParticipantState extends State { child: Row( children: [ Icon( - IconData(0xe6f2, - fontFamily: 'MaterialIcons'), + customIcon, size: 25, color: Colors.deepPurpleAccent, ), @@ -225,11 +226,13 @@ class _AssignDutyForParticipantState extends State { width: 10, ), Text( - '${_activitiesNames[tableIndex]}', - overflow: TextOverflow.clip, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold)) + '${_activitiesNames[tableIndex]}', + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), ], ), ), diff --git a/campus/mobile/lib/avinya/attendance/lib/widgets/duty_attendance_marker.dart b/campus/mobile/lib/avinya/attendance/lib/widgets/duty_attendance_marker.dart index 42f02844..d1129ad8 100644 --- a/campus/mobile/lib/avinya/attendance/lib/widgets/duty_attendance_marker.dart +++ b/campus/mobile/lib/avinya/attendance/lib/widgets/duty_attendance_marker.dart @@ -208,6 +208,8 @@ class _DutyAttendanceMarkerState extends State { @override Widget build(BuildContext context) { + const IconData customIcon = IconData(0xe6f2, fontFamily: 'MaterialIcons'); + return Container( margin: EdgeInsets.only(left: 10.0), child: Column( @@ -218,7 +220,7 @@ class _DutyAttendanceMarkerState extends State { Row( children: [ Icon( - IconData(0xe6f2, fontFamily: 'MaterialIcons'), + customIcon, size: 25, color: Colors.deepPurpleAccent, ), diff --git a/campus/mobile/linux/CMakeLists.txt b/campus/mobile/linux/CMakeLists.txt index 09740baa..8f191d30 100644 --- a/campus/mobile/linux/CMakeLists.txt +++ b/campus/mobile/linux/CMakeLists.txt @@ -7,7 +7,7 @@ project(runner LANGUAGES CXX) set(BINARY_NAME "Avinya Apps") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.avinya.mobile") +set(APPLICATION_ID "com.avinyanew.mobile") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. diff --git a/campus/mobile/macos/Flutter/GeneratedPluginRegistrant.swift b/campus/mobile/macos/Flutter/GeneratedPluginRegistrant.swift index 5d6e6099..ddef6ebd 100644 --- a/campus/mobile/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/campus/mobile/macos/Flutter/GeneratedPluginRegistrant.swift @@ -15,7 +15,7 @@ import window_size func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterAppauthPlugin.register(with: registry.registrar(forPlugin: "FlutterAppauthPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) - FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) diff --git a/campus/mobile/macos/Runner.xcodeproj/project.pbxproj b/campus/mobile/macos/Runner.xcodeproj/project.pbxproj index d229d9ed..47b16cc9 100644 --- a/campus/mobile/macos/Runner.xcodeproj/project.pbxproj +++ b/campus/mobile/macos/Runner.xcodeproj/project.pbxproj @@ -384,7 +384,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinya.mobile.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mobile.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mobile"; @@ -398,7 +398,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinya.mobile.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mobile.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mobile"; @@ -412,7 +412,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinya.mobile.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mobile.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mobile"; diff --git a/campus/mobile/macos/Runner/Configs/AppInfo.xcconfig b/campus/mobile/macos/Runner/Configs/AppInfo.xcconfig index 3bcec571..425c2a74 100644 --- a/campus/mobile/macos/Runner/Configs/AppInfo.xcconfig +++ b/campus/mobile/macos/Runner/Configs/AppInfo.xcconfig @@ -8,7 +8,7 @@ PRODUCT_NAME = Avinya Apps; // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.avinya.mobile; +PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; // The copyright displayed in application information PRODUCT_COPYRIGHT = Copyright © 2023 com.avinya. All rights reserved. From 97f611ce9d5b92dff6f082aa88904634500f471c Mon Sep 17 00:00:00 2001 From: YujithIsura Date: Fri, 20 Dec 2024 10:21:59 +0530 Subject: [PATCH 09/17] student update error fixed in enrollment --- .../lib/widgets/student_create.dart | 616 ++++++++++-------- .../lib/widgets/student_update.dart | 158 +++-- 2 files changed, 471 insertions(+), 303 deletions(-) diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart index 2da852b3..b4f434fc 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart @@ -17,6 +17,7 @@ class _StudentCreateState extends State { List organizations = []; List avinyaTypes = []; List classes = []; + int _currentStep = 0; // Track the current step final GlobalKey _formKey = GlobalKey(); List cityList = []; @@ -102,221 +103,364 @@ class _StudentCreateState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: SingleChildScrollView( - padding: const EdgeInsets.all(16.0), - child: Center( - child: SizedBox( - width: 800, - child: Form( - key: _formKey, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // _buildProfileHeader(context), - const SizedBox(height: 20), - _buildSectionTitle(context, 'Student Information'), - _buildEditableField( - 'Preferred Name', userPerson.preferred_name, (value) { - userPerson.preferred_name = value; - }, - validator: (value) => - value!.isEmpty ? 'Preferred name is required' : null), - _buildEditableField('Full Name', userPerson.full_name, - (value) { - userPerson.full_name = value; - }, - validator: (value) => - value!.isEmpty ? 'Full name is required' : null), - _buildEditableField('NIC Number', userPerson.nic_no, (value) { - userPerson.nic_no = value; - }, validator: _validateNIC), - _buildDateOfBirthField(context), - _buildSexField(), - const SizedBox(height: 10), - FutureBuilder>( - future: fetchOrganizationList(), - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.waiting) { - return Container( - margin: EdgeInsets.only(top: 10), - child: SpinKitCircle( - color: (Color.fromARGB(255, 74, 161, 70)), - size: 70, + body: Center( + child: SizedBox( + width: 850, + child: Stepper( + type: StepperType.vertical, + currentStep: _currentStep, + onStepContinue: _nextStep, + onStepCancel: _previousStep, + steps: [ + // Step 1: Student Information Form + Step( + title: Text('Student Information'), + content: SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Center( + child: SizedBox( + width: 800, + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // _buildProfileHeader(context), + const SizedBox(height: 20), + _buildSectionTitle(context, 'Student Information'), + _buildEditableField( + 'Preferred Name', userPerson.preferred_name, + (value) { + userPerson.preferred_name = value; + }, + validator: (value) => value!.isEmpty + ? 'Preferred name is required' + : null), + _buildEditableField( + 'Full Name', userPerson.full_name, (value) { + userPerson.full_name = value; + }, + validator: (value) => value!.isEmpty + ? 'Full name is required' + : null), + _buildEditableField('NIC Number', userPerson.nic_no, + (value) { + userPerson.nic_no = value; + }, validator: _validateNIC), + _buildDateOfBirthField(context), + _buildSexField(), + const SizedBox(height: 10), + FutureBuilder>( + future: fetchOrganizationList(), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: + (Color.fromARGB(255, 74, 161, 70)), + size: 70, + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: Text('Something went wrong...'), + ); + } else if (!snapshot.hasData) { + return const Center( + child: Text('No organizations found'), + ); + } else if (snapshot.connectionState == + ConnectionState.done && + snapshot.hasData) { + WidgetsBinding.instance + .addPostFrameCallback((_) { + if (!isOrganizationsDataLoaded) { + setState(() { + isOrganizationsDataLoaded = true; + print( + "isorgdataload:${isOrganizationsDataLoaded}"); + }); + } + }); + organizations = snapshot.data!; + return _buildOrganizationField(); + } + return SizedBox(); + }), + _buildStudentClassField(), // Student Class based on organization.description + const SizedBox(height: 20), + _buildSectionTitle(context, 'Contact Information'), + _buildEditableField( + 'Personal Email', userPerson.email, (value) { + userPerson.email = value; + }), // Email format validation + + _buildEditableField( + 'Phone', userPerson.phone?.toString() ?? '', + (value) { + userPerson.phone = int.tryParse(value); + }, validator: _validatePhone), + _buildEditableField( + 'Street Address', + userPerson.mailing_address?.street_address ?? + 'N/A', (value) { + if (userPerson.mailing_address == null) { + userPerson.mailing_address = + Address(street_address: value); + } else { + userPerson.mailing_address!.street_address = + value; + } + }), + FutureBuilder>( + future: fetchDistrictList(), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: + (Color.fromARGB(255, 74, 161, 70)), + size: 70, + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: Text('Something went wrong...'), + ); + } else if (!snapshot.hasData) { + return const Center( + child: Text('No districts found'), + ); + } else if (snapshot.connectionState == + ConnectionState.done && + snapshot.hasData) { + WidgetsBinding.instance + .addPostFrameCallback((_) { + if (!isDistrictsDataLoaded) { + setState(() { + isDistrictsDataLoaded = true; + print( + "isDistrictsDataLoaded:${isDistrictsDataLoaded}"); + }); + } + }); + districts = snapshot.data!; + int? districtId = getDistrictIdByCityId( + selectedCityId, districts); + selectedDistrictId = + districtId ?? selectedDistrictId; + return Column( + children: [ + _buildDistrictField(), + _buildCityField(), + ], + ); + } + return SizedBox(); + }), + const SizedBox(height: 20), + _buildSectionTitle(context, 'Digital Information'), + _buildEditableField( + 'Digital ID', userPerson.digital_id, (value) { + userPerson.digital_id = value; + }), + FutureBuilder>( + future: fetchAvinyaTypeList(), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: + (Color.fromARGB(255, 74, 161, 70)), + size: 70, + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: Text('Something went wrong...'), + ); + } else if (!snapshot.hasData) { + return const Center( + child: Text('No avinya types found'), + ); + } else if (snapshot.connectionState == + ConnectionState.done && + snapshot.hasData) { + WidgetsBinding.instance + .addPostFrameCallback((_) { + if (!isAvinyaTypesDataLoaded) { + setState(() { + isAvinyaTypesDataLoaded = true; + print( + "isAvinyaTypesDataLoaded:${isAvinyaTypesDataLoaded}"); + }); + } + }); + avinyaTypes = snapshot.data!; + return _buildAvinyaTypeField(); + } + return SizedBox(); + }), + const SizedBox(height: 20), + _buildSectionTitle(context, 'Bank Information'), + _buildEditableField( + 'Bank Name', userPerson.bank_name, (value) { + userPerson.bank_name = value; + }), + _buildEditableField( + 'Bank Branch', userPerson.bank_branch, (value) { + userPerson.bank_branch = value; + }), + _buildEditableField('Bank Account Name', + userPerson.bank_account_name, (value) { + userPerson.bank_account_name = value; + }), + _buildEditableField('Account Number', + userPerson.bank_account_number, (value) { + userPerson.bank_account_number = value; + }), + + const SizedBox(height: 20), + _buildSectionTitle(context, 'More Information'), + ExpansionTile( + title: Text( + 'Click to expand more information', + style: Theme.of(context).textTheme.subtitle1, + ), + children: [ + // Guardian Information + _buildSectionTitle( + context, 'Guardian Information'), + _buildEditableField( + 'Guardian Name', userPerson.guardian_name, + (value) { + userPerson.guardian_name = value; + }, + validator: (value) => value!.isEmpty + ? 'Guardian name is required' + : null), + _buildEditableField( + 'Guardian Contact Number', + userPerson.guardian_contact_number + ?.toString() ?? + '', (value) { + userPerson.guardian_contact_number = + int.tryParse(value); + }, validator: _validatePhone), + + const SizedBox(height: 20), + + // O/L Results Section + _buildSectionTitle(context, 'O/L Results'), + // _buildEditableField('Subject 1', userPerson.ol_subject1, + // (value) { + // userPerson.ol_subject1 = value; + // }), + // _buildEditableField('Subject 2', userPerson.ol_subject2, + // (value) { + // userPerson.ol_subject2 = value; + // }), + // _buildEditableField('Subject 3', userPerson.ol_subject3, + // (value) { + // userPerson.ol_subject3 = value; + // }), + // _buildEditableField( + // 'Other Results', userPerson.ol_other_results, + // (value) { + // userPerson.ol_other_results = value; + // }), + + const SizedBox(height: 20), + + // Add other expandable sections here if needed + ], ), - ); - } else if (snapshot.hasError) { - return const Center( - child: Text('Something went wrong...'), - ); - } else if (!snapshot.hasData) { - return const Center( - child: Text('No organizations found'), - ); - } else if (snapshot.connectionState == - ConnectionState.done && - snapshot.hasData) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (!isOrganizationsDataLoaded) { - setState(() { - isOrganizationsDataLoaded = true; - print( - "isorgdataload:${isOrganizationsDataLoaded}"); - }); - } - }); - organizations = snapshot.data!; - return _buildOrganizationField(); - } - return SizedBox(); - }), - _buildStudentClassField(), // Student Class based on organization.description - const SizedBox(height: 20), - _buildSectionTitle(context, 'Contact Information'), - _buildEditableField('Personal Email', userPerson.email, - (value) { - userPerson.email = value; - }), // Email format validation - - _buildEditableField( - 'Phone', userPerson.phone?.toString() ?? '', (value) { - userPerson.phone = int.tryParse(value); - }, validator: _validatePhone), - _buildEditableField('Street Address', - userPerson.mailing_address?.street_address ?? 'N/A', - (value) { - if (userPerson.mailing_address == null) { - userPerson.mailing_address = - Address(street_address: value); - } else { - userPerson.mailing_address!.street_address = value; - } - }), - FutureBuilder>( - future: fetchDistrictList(), - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.waiting) { - return Container( - margin: EdgeInsets.only(top: 10), - child: SpinKitCircle( - color: (Color.fromARGB(255, 74, 161, 70)), - size: 70, - ), - ); - } else if (snapshot.hasError) { - return const Center( - child: Text('Something went wrong...'), - ); - } else if (!snapshot.hasData) { - return const Center( - child: Text('No districts found'), - ); - } else if (snapshot.connectionState == - ConnectionState.done && - snapshot.hasData) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (!isDistrictsDataLoaded) { - setState(() { - isDistrictsDataLoaded = true; - print( - "isDistrictsDataLoaded:${isDistrictsDataLoaded}"); - }); - } - }); - districts = snapshot.data!; - int? districtId = - getDistrictIdByCityId(selectedCityId, districts); - selectedDistrictId = districtId ?? selectedDistrictId; - return Column( - children: [ - _buildDistrictField(), - _buildCityField(), - ], - ); - } - return SizedBox(); - }), - const SizedBox(height: 20), - _buildSectionTitle(context, 'Digital Information'), - _buildEditableField('Digital ID', userPerson.digital_id, - (value) { - userPerson.digital_id = value; - }), - FutureBuilder>( - future: fetchAvinyaTypeList(), - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.waiting) { - return Container( - margin: EdgeInsets.only(top: 10), - child: SpinKitCircle( - color: (Color.fromARGB(255, 74, 161, 70)), - size: 70, - ), - ); - } else if (snapshot.hasError) { - return const Center( - child: Text('Something went wrong...'), - ); - } else if (!snapshot.hasData) { - return const Center( - child: Text('No avinya types found'), - ); - } else if (snapshot.connectionState == - ConnectionState.done && - snapshot.hasData) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (!isAvinyaTypesDataLoaded) { - setState(() { - isAvinyaTypesDataLoaded = true; - print( - "isAvinyaTypesDataLoaded:${isAvinyaTypesDataLoaded}"); - }); - } - }); - avinyaTypes = snapshot.data!; - return _buildAvinyaTypeField(); - } - return SizedBox(); - }), - const SizedBox(height: 20), - _buildSectionTitle(context, 'Bank Information'), - _buildEditableField('Bank Name', userPerson.bank_name, - (value) { - userPerson.bank_name = value; - }), - _buildEditableField('Bank Branch', userPerson.bank_branch, - (value) { - userPerson.bank_branch = value; - }), - _buildEditableField( - 'Bank Account Name', userPerson.bank_account_name, - (value) { - userPerson.bank_account_name = value; - }), - _buildEditableField( - 'Account Number', userPerson.bank_account_number, - (value) { - userPerson.bank_account_number = value; - }), - // const SizedBox(height: 20), - // _buildSectionTitle(context, 'Professional Information'), - // _buildEditableField('Current Job', userPerson.current_job, - // (value) { - // userPerson.current_job = value; - // }), - // _buildEditableTextArea('Comments', userPerson.notes, (value) { - // userPerson.notes = value; - // }), - const SizedBox(height: 40), - _buildSaveButton(isDistrictsDataLoaded, - isOrganizationsDataLoaded, isAvinyaTypesDataLoaded), - ], + + // const SizedBox(height: 20), + // _buildSectionTitle(context, 'Professional Information'), + // _buildEditableField('Current Job', userPerson.current_job, + // (value) { + // userPerson.current_job = value; + // }), + // _buildEditableTextArea('Comments', userPerson.notes, (value) { + // userPerson.notes = value; + // }), + const SizedBox(height: 40), + _buildSaveButton( + isDistrictsDataLoaded, + isOrganizationsDataLoaded, + isAvinyaTypesDataLoaded), + ], + ), + ), + ), + ), + ), + isActive: _currentStep >= 0, ), - ), + // Step 2: File Upload + Step( + title: Text('Upload Files'), + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildSectionTitle(context, 'File Upload'), + _buildFileUploadWidget('Upload Profile Photo'), + _buildFileUploadWidget('Upload NIC Copy'), + _buildFileUploadWidget('Upload O/L Certificate'), + ], + ), + isActive: _currentStep >= 1, + ), + ]), + ), + )); + } + + // Navigate to the next step + void _nextStep() { + if (_currentStep == 0) { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + setState(() { + _currentStep += 1; + }); + } + } else if (_currentStep < 1) { + setState(() { + _currentStep += 1; + }); + } + } + + // Navigate to the previous step + void _previousStep() { + if (_currentStep > 0) { + setState(() { + _currentStep -= 1; + }); + } + } + + // Mock function for file upload widget + Widget _buildFileUploadWidget(String label) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + ElevatedButton( + onPressed: () { + // Logic to handle file upload + }, + child: Text('Upload $label'), ), - ), + ], ), ); } @@ -397,54 +541,6 @@ class _StudentCreateState extends State { ); } - Widget _buildEditableTextArea( - String label, String? initialValue, Function(String) onSave, - {int minLines = 1, int maxLines = 5}) { - // Set maxLines to a desired value for textarea - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - children: [ - Expanded( - flex: 4, - child: Text( - label, - style: Theme.of(context).textTheme.bodyText1, - ), - ), - Expanded( - flex: 6, - child: TextFormField( - initialValue: initialValue ?? '', - decoration: InputDecoration( - contentPadding: - const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0), - border: OutlineInputBorder(), - ), - onSaved: (value) => onSave(value!), - minLines: minLines, // Minimum lines to display - maxLines: maxLines, // Maximum lines to display - maxLength: 1000, // Maximum character limit - buildCounter: (BuildContext context, - {required int currentLength, - required bool isFocused, - required int? maxLength}) { - return Text( - '$currentLength/${maxLength ?? 1000}', // Display character count - style: TextStyle( - color: currentLength > (maxLength ?? 1000) - ? Colors.red - : null, // Change color if limit exceeded - ), - ); - }, - ), - ), - ], - ), - ); - } - Widget _buildSexField() { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart index 9e5499e2..321c8074 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart @@ -41,49 +41,101 @@ class _StudentUpdateState extends State { await fetchAvinyaTypeList(); } - Future getUserPerson() async { - Person user = await fetchPerson(widget.id); - classes = await fetchClasses( - (user.organization?.parent_organizations?.isNotEmpty ?? false) - ? user.organization?.parent_organizations?.first.id - : null); + // Future getUserPerson() async { + // Person user = await fetchPerson(widget.id); + // classes = await fetchClasses( + // (user.organization?.parent_organizations?.isNotEmpty ?? false) + // ? user.organization?.parent_organizations?.first.id + // : null); + + // setState(() { + // classes = classes; + // userPerson = user; + // selectedSex = userPerson.sex; + // userPerson.avinya_type_id = user.avinya_type_id; + // selectedDistrictId = user.mailing_address?.city?.district!.id; + // // Safely assign city and organization IDs with fallbacks + // selectedCityId = userPerson.mailing_address?.city?.id ?? + // 0; // Default to 0 or another fallback value + // if (selectedDistrictId != null) { + // _loadCities(selectedDistrictId, selectedCityId); + // } - setState(() { - classes = classes; - userPerson = user; - selectedSex = userPerson.sex; - userPerson.avinya_type_id = user.avinya_type_id; - selectedDistrictId = user.mailing_address?.city?.district!.id; - // Safely assign city and organization IDs with fallbacks - selectedCityId = userPerson.mailing_address?.city?.id ?? - 0; // Default to 0 or another fallback value - if (selectedDistrictId != null) { - _loadCities(selectedDistrictId, selectedCityId); + // selectedOrgId = + // userPerson.organization?.id ?? 0; // Similarly handle organization ID + // selectedClassId = userPerson.organization?.id ?? + // 0; // Ensure organization ID is used for class as well + + // // Handling date of birth + // String? dob = userPerson.date_of_birth; + // print("Date of Birth String: $dob"); + + // // Safely try parsing the date of birth + // if (dob == null || dob.isEmpty) { + // selectedDateOfBirth = DateTime.now(); // Default if dob is null or empty + // } else { + // try { + // selectedDateOfBirth = + // DateTime.parse(dob); // Use DateTime.parse directly + // } catch (e) { + // print('Error parsing date: $e'); + // selectedDateOfBirth = + // DateTime.now(); // Fallback to now if parsing fails + // } + // } + // }); + // } + Future getUserPerson() async { + try { + Person user = await fetchPerson(widget.id); + + // Safely check if parent_organizations exist and are not empty + final parentOrganizationId = + (user.organization?.parent_organizations?.isNotEmpty ?? false) + ? user.organization?.parent_organizations?.first.id + : null; + + // Fetch classes with a fallback to an empty list if null + if (parentOrganizationId != null) { + classes = await fetchClasses(parentOrganizationId); + } else { + classes = []; } - selectedOrgId = - userPerson.organization?.id ?? 0; // Similarly handle organization ID - selectedClassId = userPerson.organization?.id ?? - 0; // Ensure organization ID is used for class as well - - // Handling date of birth - String? dob = userPerson.date_of_birth; - print("Date of Birth String: $dob"); + setState(() { + userPerson = user; + selectedSex = userPerson.sex; + userPerson.avinya_type_id = user.avinya_type_id; + + // Safely assign district, city, and organization IDs with fallbacks + selectedDistrictId = user.mailing_address?.city?.district?.id; + selectedCityId = userPerson.mailing_address?.city?.id ?? 0; + if (selectedDistrictId != null) { + _loadCities(selectedDistrictId, selectedCityId); + } - // Safely try parsing the date of birth - if (dob == null || dob.isEmpty) { - selectedDateOfBirth = DateTime.now(); // Default if dob is null or empty - } else { - try { - selectedDateOfBirth = - DateTime.parse(dob); // Use DateTime.parse directly - } catch (e) { - print('Error parsing date: $e'); - selectedDateOfBirth = - DateTime.now(); // Fallback to now if parsing fails + selectedOrgId = userPerson.organization?.id ?? 0; + selectedClassId = classes.isNotEmpty ? classes.first.id : 0; + + // Handling date of birth safely + String? dob = userPerson.date_of_birth; + print("Date of Birth String: $dob"); + + if (dob == null || dob.isEmpty) { + selectedDateOfBirth = DateTime.now(); + } else { + try { + selectedDateOfBirth = DateTime.parse(dob); + } catch (e) { + print('Error parsing date: $e'); + selectedDateOfBirth = DateTime.now(); + } } - } - }); + }); + } catch (e) { + print('Error fetching user data: $e'); + // Optionally handle the error further, e.g., show a dialog or fallback UI + } } Future> fetchDistrictList() async { @@ -101,7 +153,8 @@ class _StudentUpdateState extends State { // } // } Future> fetchOrganizationList() async { - return await fetchOrganizations(); + final result = await fetchOrganizations(); + return result ?? []; // Fallback to an empty list } // Future fetchOrganizationList() async { @@ -199,7 +252,8 @@ class _StudentUpdateState extends State { ); } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { + snapshot.hasData && + snapshot.data!.isNotEmpty) { WidgetsBinding.instance .addPostFrameCallback((_) { if (!isOrganizationsDataLoaded) { @@ -212,8 +266,9 @@ class _StudentUpdateState extends State { }); organizations = snapshot.data!; return _buildOrganizationField(); + } else { + return SizedBox(); } - return SizedBox(); }), // _buildOrganizationField(), _buildStudentClassField(), // Student Class based on organization.description @@ -621,6 +676,24 @@ class _StudentUpdateState extends State { } Widget _buildOrganizationField() { + if (organizations.isEmpty) { + return const Center( + child: Text('No organizations available to display'), + ); + } + + final parentOrganizationId = + (userPerson.organization?.parent_organizations != null && + userPerson.organization!.parent_organizations!.isNotEmpty) + ? userPerson.organization!.parent_organizations!.first.id + : 0; + // Ensure parentOrganizationId is in the organizations list or set it to null + final validParentOrganizationId = organizations.any((org) => + org.id == parentOrganizationId && + (org.avinya_type?.id == 105 || org.avinya_type?.id == 86)) + ? parentOrganizationId + : null; + return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( @@ -635,8 +708,7 @@ class _StudentUpdateState extends State { Expanded( flex: 6, child: DropdownButtonFormField( - value: - userPerson.organization?.parent_organizations?.first.id ?? 0, + value: validParentOrganizationId, items: organizations .where((org) => org.avinya_type?.id == 105 || From 02e66b03085227066433c6db3f53718678aec379 Mon Sep 17 00:00:00 2001 From: YujithIsura Date: Fri, 20 Dec 2024 12:25:18 +0530 Subject: [PATCH 10/17] lint --- .../frontend/lib/avinya/enrollment/lib/data/person.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/campus/frontend/lib/avinya/enrollment/lib/data/person.dart b/campus/frontend/lib/avinya/enrollment/lib/data/person.dart index d4267aba..f3ca3f0b 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/data/person.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/data/person.dart @@ -245,6 +245,8 @@ class Person { String? bank_account_number; String? bank_name; String? bank_branch; + String? guardian_name; + int? guardian_contact_number; String? digital_id; String? bank_account_name; int? avinya_phone; @@ -284,6 +286,8 @@ class Person { this.bank_branch, this.digital_id, this.bank_account_name, + this.guardian_name, + this.guardian_contact_number, this.avinya_phone, this.academy_org_id, this.created, @@ -321,6 +325,8 @@ class Person { bank_name: json['bank_name'], bank_branch: json['bank_branch'], digital_id: json['digital_id'], + guardian_name: json['guardian_name'], + guardian_contact_number: json['guardian_contact_number'], bank_account_name: json['bank_account_name'], avinya_phone: json['avinya_phone'], academy_org_id: json['academy_org_id'], @@ -370,6 +376,9 @@ class Person { if (bank_account_number != null) 'bank_account_number': bank_account_number, if (bank_name != null) 'bank_name': bank_name, + if (guardian_name != null) 'guardian_name': guardian_name, + if (guardian_contact_number != null) + 'guardian_contact_number': guardian_contact_number, if (bank_branch != null) 'bank_branch': bank_branch, if (digital_id != null) 'digital_id': digital_id, if (bank_account_name != null) 'bank_account_name': bank_account_name, From 499ca214b3396144456f198f90b30aa275adabb1 Mon Sep 17 00:00:00 2001 From: YujithIsura Date: Fri, 20 Dec 2024 12:25:27 +0530 Subject: [PATCH 11/17] lint --- campus/mobile/android/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/campus/mobile/android/app/build.gradle b/campus/mobile/android/app/build.gradle index 23c648d5..dab5ff07 100644 --- a/campus/mobile/android/app/build.gradle +++ b/campus/mobile/android/app/build.gradle @@ -55,7 +55,7 @@ android { // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdkVersion 20 targetSdkVersion 34 - versionCode 5 + versionCode 6 versionName "1.0.2" multiDexEnabled true manifestPlaceholders += [ From 0e961b2713dc93ea6cb7e54fc04c49b7ea1f4fba Mon Sep 17 00:00:00 2001 From: YujithIsura Date: Thu, 2 Jan 2025 15:36:20 +0530 Subject: [PATCH 12/17] enrollment update and insert bug fixed --- .../lib/widgets/student_create.dart | 10 +++++----- .../lib/widgets/student_update.dart | 20 ++++++++++++------- .../enrollment/lib/widgets/students.dart | 13 ++---------- campus/mobile/.vscode/launch.json | 10 +++++++++- campus/mobile/android/app/build.gradle | 8 ++++---- .../kotlin/com/example/mobile/MainActivity.kt | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 12 +++++------ campus/mobile/linux/CMakeLists.txt | 2 +- .../macos/Runner.xcodeproj/project.pbxproj | 6 +++--- .../macos/Runner/Configs/AppInfo.xcconfig | 2 +- 10 files changed, 45 insertions(+), 40 deletions(-) diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart index b4f434fc..72611b90 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart @@ -697,8 +697,7 @@ class _StudentCreateState extends State { Expanded( flex: 6, child: DropdownButtonFormField( - value: userPerson.organization?.parent_organizations?.first.id ?? - userPerson.organization_id, + value: selectedOrgId, items: [ DropdownMenuItem( value: null, // Default item for when no selection is made @@ -720,8 +719,8 @@ class _StudentCreateState extends State { classes = await fetchClasses(newValue); } setState(() { - userPerson.organization_id = - newValue; // Update the organization ID + selectedOrgId = newValue; + userPerson.organization?.id = newValue; }); }, decoration: InputDecoration( @@ -955,7 +954,8 @@ class _StudentCreateState extends State { onChanged: (value) { setState(() { selectedClassId = value; - userPerson.organization?.id = value; + userPerson.organization_id = + value; // Update the organization ID }); }, decoration: const InputDecoration( diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart index 321c8074..591c3edc 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart @@ -115,7 +115,8 @@ class _StudentUpdateState extends State { } selectedOrgId = userPerson.organization?.id ?? 0; - selectedClassId = classes.isNotEmpty ? classes.first.id : 0; + selectedClassId = + (userPerson.organization != null) ? userPerson.organization!.id : 0; // Handling date of birth safely String? dob = userPerson.date_of_birth; @@ -446,8 +447,8 @@ class _StudentUpdateState extends State { return 'Phone number is required'; } final phoneRegex = RegExp(r'^[0-9]+$'); - if (!phoneRegex.hasMatch(value) || value.length < 10) { - return 'Enter a valid phone number (at least 10 digits)'; + if (!phoneRegex.hasMatch(value) || value.length < 9) { + return 'Enter a valid phone number (at least 9 digits)'; } return null; } @@ -682,6 +683,9 @@ class _StudentUpdateState extends State { ); } + // final parentOrganizationId = + // (userPerson.organization != null) ? userPerson.organization!.id : 0; + final parentOrganizationId = (userPerson.organization?.parent_organizations != null && userPerson.organization!.parent_organizations!.isNotEmpty) @@ -708,7 +712,7 @@ class _StudentUpdateState extends State { Expanded( flex: 6, child: DropdownButtonFormField( - value: validParentOrganizationId, + value: validParentOrganizationId ?? userPerson.organization_id, items: organizations .where((org) => org.avinya_type?.id == 105 || @@ -945,13 +949,15 @@ class _StudentUpdateState extends State { flex: 6, child: DropdownButtonFormField( value: isValidClass - ? selectedClassId - : null, // Validate selectedClassId + ? (userPerson.organization != null) + ? userPerson.organization!.id + : 0 + : selectedClassId, // Validate selectedClassId items: _getClassOptions(), onChanged: (value) { setState(() { selectedClassId = value; - userPerson.organization?.id = value; + userPerson.organization_id = value; }); }, decoration: const InputDecoration( diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/students.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/students.dart index 6f1691d5..fb074206 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/widgets/students.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/students.dart @@ -8,13 +8,12 @@ import 'package:gallery/avinya/enrollment/lib/screens/student_create_screen.dart import 'package:gallery/avinya/enrollment/lib/screens/student_update_screen.dart'; import 'person_data_excel_report.dart'; -enum AvinyaTypeId { Empower, IT, CS, FutureEnrollees } +enum AvinyaTypeId { Empower, IT, CS } const avinyaTypeId = { AvinyaTypeId.Empower: 37, AvinyaTypeId.IT: 10, AvinyaTypeId.CS: 96, - AvinyaTypeId.FutureEnrollees: 103, }; class Students extends StatefulWidget { @@ -37,7 +36,6 @@ class _StudentsState extends State { AvinyaTypeId.Empower, AvinyaTypeId.IT, AvinyaTypeId.CS, - AvinyaTypeId.FutureEnrollees ]; List columnNames = []; @@ -75,19 +73,16 @@ class _StudentsState extends State { AvinyaTypeId.Empower, AvinyaTypeId.IT, AvinyaTypeId.CS, - AvinyaTypeId.FutureEnrollees ]; } else { filteredAvinyaTypeIdValues = [ AvinyaTypeId.Empower, - AvinyaTypeId.FutureEnrollees ]; } } else { // Default value if newValue is null or invalid filteredAvinyaTypeIdValues = [ AvinyaTypeId.Empower, - AvinyaTypeId.FutureEnrollees ]; } @@ -231,14 +226,12 @@ class _StudentsState extends State { .isBefore(DateTime.parse('2024-03-01'))) { filteredAvinyaTypeIdValues = [ AvinyaTypeId.Empower, - AvinyaTypeId.FutureEnrollees ]; } else { filteredAvinyaTypeIdValues = [ AvinyaTypeId.Empower, AvinyaTypeId.IT, AvinyaTypeId.CS, - AvinyaTypeId.FutureEnrollees ]; } @@ -308,9 +301,7 @@ class _StudentsState extends State { return DropdownMenuItem( value: typeId, child: Text( - typeId.name == 'FutureEnrollees' - ? 'FUTURE ENROLLEES' - : typeId.name.toUpperCase(), + typeId.name.toUpperCase(), ), ); }).toList(), diff --git a/campus/mobile/.vscode/launch.json b/campus/mobile/.vscode/launch.json index 54b0c04a..16bd8ad4 100644 --- a/campus/mobile/.vscode/launch.json +++ b/campus/mobile/.vscode/launch.json @@ -53,6 +53,14 @@ "request": "launch", "type": "dart", "flutterMode": "release" - } + }, + { + "name": "debug android Tab", + "request": "launch", + "type": "dart", + "flutterMode": "debug", + "deviceId": "emulator-5556", + "runTestsOnDevice": false + }, ] } \ No newline at end of file diff --git a/campus/mobile/android/app/build.gradle b/campus/mobile/android/app/build.gradle index dab5ff07..0044fdd9 100644 --- a/campus/mobile/android/app/build.gradle +++ b/campus/mobile/android/app/build.gradle @@ -31,7 +31,7 @@ if (keystorePropertiesFile.exists()) { android { - namespace "com.avinyanew.mobile" + namespace "com.avinyav2.mobile" compileSdkVersion 34 ndkVersion flutter.ndkVersion @@ -50,12 +50,12 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.avinyanew.mobile" + applicationId "com.avinyav2.mobile" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion 20 + minSdkVersion 21 targetSdkVersion 34 - versionCode 6 + versionCode 8 versionName "1.0.2" multiDexEnabled true manifestPlaceholders += [ diff --git a/campus/mobile/android/app/src/main/kotlin/com/example/mobile/MainActivity.kt b/campus/mobile/android/app/src/main/kotlin/com/example/mobile/MainActivity.kt index 13e7318e..88acb031 100644 --- a/campus/mobile/android/app/src/main/kotlin/com/example/mobile/MainActivity.kt +++ b/campus/mobile/android/app/src/main/kotlin/com/example/mobile/MainActivity.kt @@ -1,4 +1,4 @@ -package com.avinyanew.mobile +package com.avinyav2.mobile import io.flutter.embedding.android.FlutterActivity diff --git a/campus/mobile/ios/Runner.xcodeproj/project.pbxproj b/campus/mobile/ios/Runner.xcodeproj/project.pbxproj index decbb687..d0cf11de 100644 --- a/campus/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/campus/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -367,7 +367,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyav2.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -384,7 +384,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyav2.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -402,7 +402,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyav2.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -418,7 +418,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyav2.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -545,7 +545,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyav2.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -567,7 +567,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyav2.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/campus/mobile/linux/CMakeLists.txt b/campus/mobile/linux/CMakeLists.txt index 8f191d30..786a22a0 100644 --- a/campus/mobile/linux/CMakeLists.txt +++ b/campus/mobile/linux/CMakeLists.txt @@ -7,7 +7,7 @@ project(runner LANGUAGES CXX) set(BINARY_NAME "Avinya Apps") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.avinyanew.mobile") +set(APPLICATION_ID "com.avinyav2.mobile") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. diff --git a/campus/mobile/macos/Runner.xcodeproj/project.pbxproj b/campus/mobile/macos/Runner.xcodeproj/project.pbxproj index 47b16cc9..67a42edd 100644 --- a/campus/mobile/macos/Runner.xcodeproj/project.pbxproj +++ b/campus/mobile/macos/Runner.xcodeproj/project.pbxproj @@ -384,7 +384,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyav2.mobile.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mobile.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mobile"; @@ -398,7 +398,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyav2.mobile.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mobile.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mobile"; @@ -412,7 +412,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.avinyav2.mobile.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mobile.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mobile"; diff --git a/campus/mobile/macos/Runner/Configs/AppInfo.xcconfig b/campus/mobile/macos/Runner/Configs/AppInfo.xcconfig index 425c2a74..7f03c208 100644 --- a/campus/mobile/macos/Runner/Configs/AppInfo.xcconfig +++ b/campus/mobile/macos/Runner/Configs/AppInfo.xcconfig @@ -8,7 +8,7 @@ PRODUCT_NAME = Avinya Apps; // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.avinyanew.mobile; +PRODUCT_BUNDLE_IDENTIFIER = com.avinyav2.mobile; // The copyright displayed in application information PRODUCT_COPYRIGHT = Copyright © 2023 com.avinya. All rights reserved. From 92ff9e081dd27951bf3588bb36b31563337e7481 Mon Sep 17 00:00:00 2001 From: lahirulakruwan Date: Fri, 3 Jan 2025 08:55:11 +0530 Subject: [PATCH 13/17] Student File upload changes added --- campus/bffs/enrollment/api/Dependencies.toml | 14 +- campus/bffs/enrollment/api/client.bal | 11 +- campus/bffs/enrollment/api/service.bal | 168 +++- campus/bffs/enrollment/api/types.bal | 49 + .../graphql_client/enrollment.graphql | 23 + .../graphql_client_cg_src/client.bal | 10 +- .../graphql_client_cg_src/types.bal | 60 ++ .../enrollment/graphql_client/schema.graphql | 81 +- .../enrollment/graphql_client/schema.json | 947 ++++++++++++++++-- 9 files changed, 1292 insertions(+), 71 deletions(-) diff --git a/campus/bffs/enrollment/api/Dependencies.toml b/campus/bffs/enrollment/api/Dependencies.toml index d621aef7..1e1d3bbf 100644 --- a/campus/bffs/enrollment/api/Dependencies.toml +++ b/campus/bffs/enrollment/api/Dependencies.toml @@ -15,7 +15,9 @@ dependencies = [ {org = "ballerina", name = "graphql"}, {org = "ballerina", name = "http"}, {org = "ballerina", name = "io"}, + {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "log"}, + {org = "ballerina", name = "mime"}, {org = "ballerina", name = "test"}, {org = "ballerinai", name = "observe"} ] @@ -108,7 +110,7 @@ modules = [ [[package]] org = "ballerina" name = "http" -version = "2.10.17" +version = "2.10.19" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -140,7 +142,7 @@ modules = [ [[package]] org = "ballerina" name = "io" -version = "1.6.1" +version = "1.6.3" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} @@ -185,6 +187,9 @@ dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.__internal"} ] +modules = [ + {org = "ballerina", packageName = "lang.array", moduleName = "lang.array"} +] [[package]] org = "ballerina" @@ -274,6 +279,9 @@ dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.int"} ] +modules = [ + {org = "ballerina", packageName = "mime", moduleName = "mime"} +] [[package]] org = "ballerina" @@ -357,7 +365,7 @@ dependencies = [ [[package]] org = "ballerina" name = "websocket" -version = "2.10.2" +version = "2.10.3" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "constraint"}, diff --git a/campus/bffs/enrollment/api/client.bal b/campus/bffs/enrollment/api/client.bal index c20529a1..d8b36eb0 100644 --- a/campus/bffs/enrollment/api/client.bal +++ b/campus/bffs/enrollment/api/client.bal @@ -35,11 +35,12 @@ public isolated client class GraphqlClient { return check performDataBinding(graphqlResponse, GetPersonsResponse); } remote isolated function getPersonById(int id) returns GetPersonByIdResponse|graphql:ClientError { - string query = string `query getPersonById($id:Int!) {person_by_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email mailing_address {city {id name {name_en name_si name_ta} district {id name {name_en}}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job}}`; + string query = string `query getPersonById($id:Int!) {person_by_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email mailing_address {city {id name {name_en name_si name_ta} district {id name {name_en}}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job document_list {document document_type}}}`; map variables = {"id": id}; json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, GetPersonByIdResponse); } + remote isolated function updatePerson(Person person, City? permanent_address_city = (), Address? mailing_address = (), Address? permanent_address = (), City? mailing_address_city = ()) returns UpdatePersonResponse|graphql:ClientError { string query = string `mutation updatePerson($person:Person!,$permanent_address:Address,$permanent_address_city:City,$mailing_address:Address,$mailing_address_city:City) {update_person(person:$person,permanent_address:$permanent_address,permanent_address_city:$permanent_address_city,mailing_address:$mailing_address,mailing_address_city:$mailing_address_city) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email permanent_address {city {id name {name_en name_si name_ta}} street_address phone id} mailing_address {city {id name {name_en name_si name_ta}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job}}`; map variables = {"permanent_address_city": permanent_address_city, "mailing_address": mailing_address, "person": person, "permanent_address": permanent_address, "mailing_address_city": mailing_address_city}; @@ -65,9 +66,15 @@ public isolated client class GraphqlClient { return check performDataBinding(graphqlResponse, GetAllOrganizationsResponse); } remote isolated function insertPerson(Person person, Address? mailing_address = (), City? mailing_address_city = ()) returns InsertPersonResponse|graphql:ClientError { - string query = string `mutation insertPerson($person:Person!,$mailing_address:Address,$mailing_address_city:City) {insert_person(person:$person,mailing_address:$mailing_address,mailing_address_city:$mailing_address_city) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email permanent_address {city {id name {name_en name_si name_ta}} street_address phone id} mailing_address {city {id name {name_en name_si name_ta}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job}}`; + string query = string `mutation insertPerson($person:Person!,$mailing_address:Address,$mailing_address_city:City) {insert_person(person:$person,mailing_address:$mailing_address,mailing_address_city:$mailing_address_city) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email permanent_address {city {id name {name_en name_si name_ta}} street_address phone id} mailing_address {city {id name {name_en name_si name_ta}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job documents_id}}`; map variables = {"mailing_address": mailing_address, "person": person, "mailing_address_city": mailing_address_city}; json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, InsertPersonResponse); } + remote isolated function uploadDocument(UserDocument user_document) returns UploadDocumentResponse|graphql:ClientError { + string query = string `mutation uploadDocument($user_document:UserDocument!) {upload_document(user_document:$user_document) {id folder_id nic_front_id nic_back_id birth_certificate_front_id birth_certificate_back_id ol_certificate_id al_certificate_id additional_certificate_01_id additional_certificate_02_id additional_certificate_03_id additional_certificate_04_id additional_certificate_05_id}}`; + map variables = {"user_document": user_document}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, UploadDocumentResponse); + } } diff --git a/campus/bffs/enrollment/api/service.bal b/campus/bffs/enrollment/api/service.bal index c376358a..1fcd8f58 100644 --- a/campus/bffs/enrollment/api/service.bal +++ b/campus/bffs/enrollment/api/service.bal @@ -1,6 +1,9 @@ import ballerina/graphql; import ballerina/http; +import ballerina/io; +import ballerina/lang.array; import ballerina/log; +import ballerina/mime; public function initClientConfig() returns ConnectionConfig { ConnectionConfig _clientConig = {}; @@ -155,11 +158,11 @@ service / on new http:Listener(9095) { City? permanent_address_city = permanent_address?.city; City? mailing_address_city = mailing_address?.city; - if(permanent_address is Address){ + if (permanent_address is Address) { permanent_address.city = (); } - if(mailing_address is Address){ + if (mailing_address is Address) { mailing_address.city = (); } @@ -183,7 +186,7 @@ service / on new http:Listener(9095) { } } - resource function post add_person(@http:Payload Person person) returns Person|error { + resource function post add_person(@http:Payload Person person) returns Person|ErrorDetail|error { Address? mailing_address = person?.mailing_address; City? mailing_address_city = mailing_address?.city; @@ -201,13 +204,164 @@ service / on new http:Listener(9095) { return person_record; } else { log:printError("Error while processing Application record received", person_record); - return error("Error while processing Application record received: " + person_record.message() + - ":: Detail: " + person_record.detail().toString()); + return { + "message": person_record.message().toString(), + "errorCode": "500" + }; } } else { log:printError("Error while creating application", addPersonResponse); - return error("Error while creating application: " + addPersonResponse.message() + - ":: Detail: " + addPersonResponse.detail().toString()); + return { + "message": addPersonResponse.message().toString(), + "errorCode": "500" + }; + } + } + resource function post upload_document(http:Request req) returns UserDocument|ErrorDetail|error { + + UserDocument document = {}; + UserDocument document_details = {}; + int document_row_id = 0; + string document_type = ""; + + if (req.getContentType().startsWith("multipart/form-data")) { + + mime:Entity[] bodyParts = check req.getBodyParts(); + string base64EncodedStringDocument = ""; + + foreach var part in bodyParts { + mime:ContentDisposition contentDisposition = part.getContentDisposition(); + + if (contentDisposition.name == "document_details") { + + json document_details_in_json = check part.getJson(); + document_details = check document_details_in_json.cloneWithType(UserDocument); + document_row_id = document_details?.id ?: 0; + document_type = document_details?.document_type ?: ""; + + } else if (contentDisposition.name == "document") { + + stream|mime:ParserError str = part.getByteStream(); + + if str is stream { + + byte[] allBytes = []; // Initialize an empty byte array + + // Iterate through the stream and collect all chunks + error? e = str.forEach(function(byte[] chunk) { + array:push(allBytes, ...chunk); // Efficiently append all bytes from chunk + }); + + byte[] base64EncodedDocument = (check mime:base64Encode(allBytes)); + base64EncodedStringDocument = check string:fromBytes(base64EncodedDocument); + + } + } + + } + + document = { + id: document_row_id, + document_type: document_type, + document: base64EncodedStringDocument + }; + + } + + UploadDocumentResponse|graphql:ClientError uploadDocumentResponse = globalDataClient->uploadDocument(document); + if (uploadDocumentResponse is UploadDocumentResponse) { + UserDocument|error document_record = uploadDocumentResponse.upload_document.cloneWithType(UserDocument); + if (document_record is UserDocument) { + return document_record; + } else { + log:printError("Error while processing Application record received", document_record); + return { + "message": document_record.message().toString(), + "errorCode": "500" + }; + } + } else { + log:printError("Error while creating application", uploadDocumentResponse); + return { + "message": uploadDocumentResponse.message().toString(), + "errorCode": "500" + }; } } + // resource function post add_person(http:Request req) returns Person|error { + // UserDocumentList[] documents = []; + // Person person = {}; + // Address? mailing_address = {}; + // City? mailing_address_city = {}; + + // if (req.getContentType().startsWith("multipart/form-data")) { + // mime:Entity[] bodyParts = check req.getBodyParts(); + + // foreach var part in bodyParts { + // mime:ContentDisposition contentDisposition = part.getContentDisposition(); + + // if (contentDisposition.name == "person") { + // // Extract JSON string and convert to Person record + // json personJson = check part.getJson(); + // person = check personJson.cloneWithType(Person); + // mailing_address = person?.mailing_address; + // mailing_address_city = mailing_address?.city; + + // if (mailing_address is Address) { + // mailing_address.city = (); + // } + + // person.mailing_address = (); + + // } else if (contentDisposition.name == "documents") { + + // // Get the filename from Content-Disposition + // string? documentName = contentDisposition.fileName; + + // stream|mime:ParserError str = part.getByteStream(); + + // //Extract file name without extension + // string:RegExp r = re `\.`; + // string[] split_document_name = r.split(documentName ?: ""); + + // if str is stream { + + // byte[] allBytes = []; // Initialize an empty byte array + + // // Iterate through the stream and collect all chunks + // error? e = str.forEach(function(byte[] chunk) { + // array:push(allBytes, ...chunk); // Efficiently append all bytes from chunk + // }); + + // byte[] base64EncodedDocument = (check mime:base64Encode(allBytes)); + // string base64EncodedStringDocument = check string:fromBytes(base64EncodedDocument); + + // UserDocumentList document = { + // document_name: split_document_name[0], + // document: base64EncodedStringDocument + + // }; + // //io:println(document); + // documents.push(document); + // } + // } + + // } + // } + // InsertPersonResponse|graphql:ClientError addPersonResponse = globalDataClient->insertPerson(documents, person, mailing_address, mailing_address_city); + // if (addPersonResponse is InsertPersonResponse) { + // Person|error person_record = addPersonResponse.insert_person.cloneWithType(Person); + // if (person_record is Person) { + // return person_record; + // } else { + // log:printError("Error while processing Application record received", person_record); + // return error("Error while processing Application record received: " + person_record.message() + + // ":: Detail: " + person_record.detail().toString()); + // } + // } else { + // log:printError("Error while creating application", addPersonResponse); + // return error("Error while creating application: " + addPersonResponse.message() + + // ":: Detail: " + addPersonResponse.detail().toString()); + // } + // } } diff --git a/campus/bffs/enrollment/api/types.bal b/campus/bffs/enrollment/api/types.bal index 0ab9fc86..41b4a14a 100644 --- a/campus/bffs/enrollment/api/types.bal +++ b/campus/bffs/enrollment/api/types.bal @@ -105,16 +105,42 @@ public type Person record { string? full_name?; string? nic_no?; int? phone?; + UserDocument[]? documentList?; int? organization_id?; int? updated_by?; string? academy_org_name?; string? asgardeo_id?; + int? documents_id?; string? updated?; string? preferred_name?; string? jwt_sub_id?; int? academy_org_id?; }; +public type UserDocument record { + string? birth_certificate_back_id?; + string? additional_certificate_01_id?; + string? additional_certificate_02_id?; + string? nic_back_id?; + string? document?; + string? additional_certificate_05_id?; + string? additional_certificate_04_id?; + string? additional_certificate_03_id?; + string? record_type?; + string? al_certificate_id?; + string? nic_front_id?; + string? ol_certificate_id?; + string? birth_certificate_front_id?; + int? id?; + string? folder_id?; + string? document_type?; +}; + +public type ErrorDetail record { + string message; + int errorCode; +}; + public type GetPersonsResponse record {| map __extensions?; record {| @@ -267,6 +293,10 @@ public type GetPersonByIdResponse record {| int? created_by; int? updated_by; string? current_job; + record {| + string? document; + string? document_type; + |}[]? document_list; |}? person_by_id; |}; @@ -488,5 +518,24 @@ public type InsertPersonResponse record {| int? created_by; int? updated_by; string? current_job; + int? documents_id; |}? insert_person; |}; +public type UploadDocumentResponse record {| + map __extensions?; + record {| + int? id; + string? folder_id; + string? nic_front_id; + string? nic_back_id; + string? birth_certificate_front_id; + string? birth_certificate_back_id; + string? ol_certificate_id; + string? al_certificate_id; + string? additional_certificate_01_id; + string? additional_certificate_02_id; + string? additional_certificate_03_id; + string? additional_certificate_04_id; + string? additional_certificate_05_id; + |}? upload_document; +|}; diff --git a/campus/bffs/enrollment/graphql_client/enrollment.graphql b/campus/bffs/enrollment/graphql_client/enrollment.graphql index de66aee4..25fb5514 100644 --- a/campus/bffs/enrollment/graphql_client/enrollment.graphql +++ b/campus/bffs/enrollment/graphql_client/enrollment.graphql @@ -148,6 +148,10 @@ query getPersonById($id: Int!) { created_by updated_by current_job + document_list { + document + document_type + } } } @@ -384,5 +388,24 @@ mutation insertPerson( created_by updated_by current_job + documents_id + } +} + +mutation uploadDocument($user_document: UserDocument!) { + upload_document(user_document: $user_document) { + id + folder_id + nic_front_id + nic_back_id + birth_certificate_front_id + birth_certificate_back_id + ol_certificate_id + al_certificate_id + additional_certificate_01_id + additional_certificate_02_id + additional_certificate_03_id + additional_certificate_04_id + additional_certificate_05_id } } diff --git a/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/client.bal b/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/client.bal index b9ffc3be..023c2005 100644 --- a/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/client.bal +++ b/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/client.bal @@ -34,7 +34,7 @@ public isolated client class GraphqlClient { return check performDataBinding(graphqlResponse, GetPersonsResponse); } remote isolated function getPersonById(int id) returns GetPersonByIdResponse|graphql:ClientError { - string query = string `query getPersonById($id:Int!) {person_by_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email mailing_address {city {id name {name_en name_si name_ta} district {id name {name_en}}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job}}`; + string query = string `query getPersonById($id:Int!) {person_by_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email mailing_address {city {id name {name_en name_si name_ta} district {id name {name_en}}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job document_list {document document_type}}}`; map variables = {"id": id}; json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, GetPersonByIdResponse); @@ -70,9 +70,15 @@ public isolated client class GraphqlClient { return check performDataBinding(graphqlResponse, GetAllOrganizationsResponse); } remote isolated function insertPerson(Person person, Address? mailing_address = (), City? mailing_address_city = ()) returns InsertPersonResponse|graphql:ClientError { - string query = string `mutation insertPerson($person:Person!,$mailing_address:Address,$mailing_address_city:City) {insert_person(person:$person,mailing_address:$mailing_address,mailing_address_city:$mailing_address_city) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email permanent_address {city {id name {name_en name_si name_ta}} street_address phone id} mailing_address {city {id name {name_en name_si name_ta}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job}}`; + string query = string `mutation insertPerson($person:Person!,$mailing_address:Address,$mailing_address_city:City) {insert_person(person:$person,mailing_address:$mailing_address,mailing_address_city:$mailing_address_city) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email permanent_address {city {id name {name_en name_si name_ta}} street_address phone id} mailing_address {city {id name {name_en name_si name_ta}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job documents_id}}`; map variables = {"mailing_address": mailing_address, "person": person, "mailing_address_city": mailing_address_city}; json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, InsertPersonResponse); } + remote isolated function uploadDocument(UserDocument user_document) returns UploadDocumentResponse|graphql:ClientError { + string query = string `mutation uploadDocument($user_document:UserDocument!) {upload_document(user_document:$user_document) {id folder_id nic_front_id nic_back_id birth_certificate_front_id birth_certificate_back_id ol_certificate_id al_certificate_id additional_certificate_01_id additional_certificate_02_id additional_certificate_03_id additional_certificate_04_id additional_certificate_05_id}}`; + map variables = {"user_document": user_document}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, UploadDocumentResponse); + } } diff --git a/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/types.bal b/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/types.bal index c0a7539e..fa9cc955 100644 --- a/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/types.bal +++ b/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/types.bal @@ -274,6 +274,20 @@ public type Inventory record { int? person_id?; }; +public type MonthlyLeaveDates record { + string? leave_dates?; + int? month?; + int[] leave_dates_list?; + int? year?; + string? created?; + int? total_days_in_month?; + int? organization_id?; + int? id?; + anydata? daily_amount?; + string? updated?; + string? record_type?; +}; + public type Organization record { string? notes?; string? name_ta?; @@ -282,6 +296,7 @@ public type Organization record { string? name_si?; int? avinya_type?; string? description?; + int? active?; int[]? child_organizations_for_dashboard?; string? record_type?; int[]? parent_organizations?; @@ -321,10 +336,12 @@ public type Person record { string? full_name?; string? nic_no?; int? phone?; + UserDocument[]? documentList?; int? organization_id?; int? updated_by?; string? academy_org_name?; string? asgardeo_id?; + int? documents_id?; string? updated?; string? preferred_name?; string? jwt_sub_id?; @@ -406,6 +423,25 @@ public type Supply record { int? person_id?; }; +public type UserDocument record { + string? birth_certificate_back_id?; + string? additional_certificate_01_id?; + string? additional_certificate_02_id?; + string? nic_back_id?; + string? document?; + string? additional_certificate_05_id?; + string? additional_certificate_04_id?; + string? additional_certificate_03_id?; + string? record_type?; + string? al_certificate_id?; + string? nic_front_id?; + string? ol_certificate_id?; + string? birth_certificate_front_id?; + int? id?; + string? folder_id?; + string? document_type?; +}; + public type Vacancy record { int? organization_id?; string? name?; @@ -579,6 +615,10 @@ public type GetPersonByIdResponse record {| int? created_by; int? updated_by; string? current_job; + record {| + string? document; + string? document_type; + |}[]? document_list; |}? person_by_id; |}; @@ -801,5 +841,25 @@ public type InsertPersonResponse record {| int? created_by; int? updated_by; string? current_job; + int? documents_id; |}? insert_person; |}; + +public type UploadDocumentResponse record {| + map __extensions?; + record {| + int? id; + string? folder_id; + string? nic_front_id; + string? nic_back_id; + string? birth_certificate_front_id; + string? birth_certificate_back_id; + string? ol_certificate_id; + string? al_certificate_id; + string? additional_certificate_01_id; + string? additional_certificate_02_id; + string? additional_certificate_03_id; + string? additional_certificate_04_id; + string? additional_certificate_05_id; + |}? upload_document; +|}; diff --git a/campus/bffs/enrollment/graphql_client/schema.graphql b/campus/bffs/enrollment/graphql_client/schema.graphql index 06ef54a0..13e3913f 100644 --- a/campus/bffs/enrollment/graphql_client/schema.graphql +++ b/campus/bffs/enrollment/graphql_client/schema.graphql @@ -310,6 +310,12 @@ type AvinyaTypeData { description: String } +type CalendarMetaData { + id: Int + organization_id: Int + monthly_payment_amount: Decimal +} + input City { record_type: String = "city" id: Int @@ -384,6 +390,24 @@ type DistrictData { cities: [CityData!]! } +type DocumentsData { + id: Int + folder_id: String + nic_front_id: String + nic_back_id: String + birth_certificate_front_id: String + birth_certificate_back_id: String + ol_certificate_id: String + al_certificate_id: String + additional_certificate_01_id: String + additional_certificate_02_id: String + additional_certificate_03_id: String + additional_certificate_04_id: String + additional_certificate_05_id: String + document_type: String + document: String +} + input DutyParticipant { record_type: String = "duty_participant" id: Int @@ -607,6 +631,31 @@ type LocalizedName { name_si: String } +input MonthlyLeaveDates { + record_type: String = "monthly_leave_dates" + id: Int + year: Int + month: Int + total_days_in_month: Int + organization_id: Int + leave_dates_list: [Int!]! + leave_dates: String + daily_amount: Decimal + created: String + updated: String +} + +type MonthlyLeaveDatesData { + id: Int + year: Int + month: Int + organization_id: Int + leave_dates_list: [Int!] + daily_amount: Decimal + created: String + updated: String +} + type Mutation { add_avinya_type(avinya_type: AvinyaType!): AvinyaTypeData update_avinya_type(avinya_type: AvinyaType!): AvinyaTypeData @@ -667,6 +716,9 @@ type Mutation { update_consumable_depletion(inventories: [Inventory!]!): [InventoryData!] update_person(person: Person!, permanent_address: Address, permanent_address_city: City, mailing_address: Address, mailing_address_city: City): PersonData insert_person(person: Person!, mailing_address: Address, mailing_address_city: City): PersonData + upload_document(user_document: UserDocument!): DocumentsData + add_monthly_leave_dates(monthly_leave_dates: MonthlyLeaveDates!): MonthlyLeaveDatesData + update_monthly_leave_dates(monthly_leave_dates: MonthlyLeaveDates!): MonthlyLeaveDatesData } input Organization { @@ -680,6 +732,7 @@ input Organization { phone: Int description: String notes: String + active: Int name_en: String name_ta: String name_si: String @@ -699,6 +752,7 @@ type OrganizationData { people: [PersonData!] vacancies: [VacancyData!] organization_metadata: [OrganizationMetaData!] + active: Int } type OrganizationMetaData { @@ -749,6 +803,8 @@ input Person { academy_org_name: String branch_code: String current_job: String + documents_id: Int + documentList: [UserDocument!] created_by: Int updated_by: Int } @@ -790,6 +846,8 @@ type PersonData { current_job: String created_by: Int updated_by: Int + documents_id: Int + document_list: [DocumentsData!] } type PlaceData { @@ -858,7 +916,7 @@ type Query { organization_structure(name: String, id: Int): OrganizationStructureData organizations(level: Int!): OrganizationStructureData organization(name: String, id: Int): OrganizationData - organizations_by_avinya_type(avinya_type: Int): [OrganizationData!] + organizations_by_avinya_type(avinya_type: Int, active: Int = 0): [OrganizationData!] student_list_by_parent(id: Int): [PersonData!] person(name: String, id: Int): PersonData person_by_digital_id(id: String): PersonData @@ -932,6 +990,8 @@ type Query { districts: [DistrictData!] cities(district_id: Int): [CityData!] all_organizations: [OrganizationData!] + monthly_leave_dates_record_by_id(organization_id: Int!, year: Int!, month: Int!): MonthlyLeaveDatesData + calendar_metadata_by_org_id(organization_id: Int!): CalendarMetaData } input ResourceAllocation { @@ -1043,6 +1103,25 @@ type TotalActivityParticipantAttendanceCountByDateData { daily_total: Int } +input UserDocument { + record_type: String = "user_document" + id: Int + folder_id: String + nic_front_id: String + nic_back_id: String + birth_certificate_front_id: String + birth_certificate_back_id: String + ol_certificate_id: String + al_certificate_id: String + additional_certificate_01_id: String + additional_certificate_02_id: String + additional_certificate_03_id: String + additional_certificate_04_id: String + additional_certificate_05_id: String + document_type: String + document: String +} + input Vacancy { record_type: String = "vacancy" id: Int diff --git a/campus/bffs/enrollment/graphql_client/schema.json b/campus/bffs/enrollment/graphql_client/schema.json index 1479556a..f9b259b4 100644 --- a/campus/bffs/enrollment/graphql_client/schema.json +++ b/campus/bffs/enrollment/graphql_client/schema.json @@ -423,6 +423,36 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "documents_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "document_list", + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "DocumentsData", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -713,6 +743,15 @@ "ofType": null }, "defaultValue": null + }, + { + "name": "active", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "0" } ], "type": { @@ -3113,6 +3152,82 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "monthly_leave_dates_record_by_id", + "args": [ + { + "name": "organization_id", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "year", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "month", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "MonthlyLeaveDatesData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "calendar_metadata_by_org_id", + "args": [ + { + "name": "organization_id", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CalendarMetaData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -5799,6 +5914,17 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "active", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -6980,6 +7106,112 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "MonthlyLeaveDatesData", + "fields": [ + { + "name": "id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "year", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "month", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "organization_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "leave_dates_list", + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "daily_amount", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Decimal", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "created", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "updated", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "Mutation", @@ -8753,36 +8985,111 @@ }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ProvinceData", - "fields": [ + }, { - "name": "id", - "args": [], + "name": "upload_document", + "args": [ + { + "name": "user_document", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "UserDocument", + "ofType": null + } + }, + "defaultValue": null + } + ], "type": { - "kind": "SCALAR", - "name": "Int", + "kind": "OBJECT", + "name": "DocumentsData", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "name", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", + "name": "add_monthly_leave_dates", + "args": [ + { + "name": "monthly_leave_dates", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "MonthlyLeaveDates", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "MonthlyLeaveDatesData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "update_monthly_leave_dates", + "args": [ + { + "name": "monthly_leave_dates", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "MonthlyLeaveDates", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "MonthlyLeaveDatesData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "ProvinceData", + "fields": [ + { + "name": "id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", "name": "LocalizedName", "ofType": null } @@ -8884,6 +9191,127 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "INPUT_OBJECT", + "name": "MonthlyLeaveDates", + "fields": null, + "inputFields": [ + { + "name": "record_type", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": "\"monthly_leave_dates\"" + }, + { + "name": "id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "year", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "month", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "total_days_in_month", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "organization_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "leave_dates_list", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + } + }, + "defaultValue": null + }, + { + "name": "leave_dates", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "daily_amount", + "type": { + "kind": "SCALAR", + "name": "Decimal", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "created", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "updated", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "EvaluationCriteriaAnswerOptionData", @@ -9272,6 +9700,32 @@ }, "defaultValue": null }, + { + "name": "documents_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "documentList", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "UserDocument", + "ofType": null + } + } + }, + "defaultValue": null + }, { "name": "created_by", "type": { @@ -9907,6 +10361,15 @@ }, "defaultValue": null }, + { + "name": "active", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, { "name": "name_en", "type": { @@ -9941,7 +10404,7 @@ }, { "kind": "INPUT_OBJECT", - "name": "EducationExperience", + "name": "UserDocument", "fields": null, "inputFields": [ { @@ -9951,7 +10414,7 @@ "name": "String", "ofType": null }, - "defaultValue": "\"education_experience\"" + "defaultValue": "\"user_document\"" }, { "name": "id", @@ -9963,16 +10426,16 @@ "defaultValue": null }, { - "name": "person_id", + "name": "folder_id", "type": { "kind": "SCALAR", - "name": "Int", + "name": "String", "ofType": null }, "defaultValue": null }, { - "name": "school", + "name": "nic_front_id", "type": { "kind": "SCALAR", "name": "String", @@ -9981,7 +10444,7 @@ "defaultValue": null }, { - "name": "start_date", + "name": "nic_back_id", "type": { "kind": "SCALAR", "name": "String", @@ -9990,7 +10453,7 @@ "defaultValue": null }, { - "name": "end_date", + "name": "birth_certificate_front_id", "type": { "kind": "SCALAR", "name": "String", @@ -9999,41 +10462,195 @@ "defaultValue": null }, { - "name": "evaluation_id", + "name": "birth_certificate_back_id", "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } + "kind": "SCALAR", + "name": "String", + "ofType": null }, "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "DutyRotationMetaData", - "fields": [ + }, { - "name": "id", - "args": [], + "name": "ol_certificate_id", "type": { "kind": "SCALAR", - "name": "Int", + "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null + "defaultValue": null + }, + { + "name": "al_certificate_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "additional_certificate_01_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "additional_certificate_02_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "additional_certificate_03_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "additional_certificate_04_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "additional_certificate_05_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "document_type", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "document", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "EducationExperience", + "fields": null, + "inputFields": [ + { + "name": "record_type", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": "\"education_experience\"" + }, + { + "name": "id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "person_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "school", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "start_date", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "end_date", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "evaluation_id", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "DutyRotationMetaData", + "fields": [ + { + "name": "id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null }, { "name": "start_date", @@ -10312,6 +10929,181 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "DocumentsData", + "fields": [ + { + "name": "id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "folder_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "nic_front_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "nic_back_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "birth_certificate_front_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "birth_certificate_back_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ol_certificate_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "al_certificate_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "additional_certificate_01_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "additional_certificate_02_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "additional_certificate_03_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "additional_certificate_04_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "additional_certificate_05_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "document_type", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "document", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "Supply", @@ -10503,6 +11295,49 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "CalendarMetaData", + "fields": [ + { + "name": "id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "organization_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "monthly_payment_amount", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Decimal", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "AssetData", From 9ba4ef220870619731fc1da2723b9f30689708f5 Mon Sep 17 00:00:00 2001 From: YujithIsura Date: Mon, 6 Jan 2025 11:32:46 +0530 Subject: [PATCH 14/17] bug fixed in avinya type of student update --- .../enrollment/lib/widgets/student_update.dart | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart index 591c3edc..9aa738de 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart @@ -772,13 +772,16 @@ class _StudentUpdateState extends State { } // Determine the Avinya Type ID - final int? avinyaTypeId = (userPerson.date_of_birth != null && - calculateAge(userPerson.date_of_birth) != null && - calculateAge(userPerson.date_of_birth)! < 19) - ? 103 // Auto-select Future Enrollees if under 18 - : (userPerson.avinya_type_id ?? - userPerson.avinya_type - ?.id); // Fallback to avinya_type?.id if avinya_type_id is null + // final int? avinyaTypeId = (userPerson.date_of_birth != null && + // calculateAge(userPerson.date_of_birth) != null && + // calculateAge(userPerson.date_of_birth)! < 19) + // ? 103 // Auto-select Future Enrollees if under 18 + // : (userPerson.avinya_type_id ?? + // userPerson.avinya_type + // ?.id); // Fallback to avinya_type?.id if avinya_type_id is null + + final int? avinyaTypeId = + (userPerson.avinya_type_id ?? userPerson.avinya_type?.id); // Filter avinyaTypes based on the selected IDs final filteredAvinyaTypes = avinyaTypes.where((org) { From 51b708dadde0e5b66297813cc1e70e274101b5aa Mon Sep 17 00:00:00 2001 From: YujithIsura Date: Mon, 6 Jan 2025 11:34:24 +0530 Subject: [PATCH 15/17] student file upload WIP --- .../avinya/enrollment/lib/data/person.dart | 99 ++++++- .../lib/widgets/file_upload_widget.dart | 143 +++++++++++ .../lib/widgets/student_create.dart | 242 ++++++++++-------- .../lib/avinya/enrollment/pubspec.yaml | 3 + .../flutter/generated_plugin_registrant.cc | 4 + .../linux/flutter/generated_plugins.cmake | 1 + .../Flutter/GeneratedPluginRegistrant.swift | 2 + campus/frontend/pubspec.yaml | 3 + .../flutter/generated_plugin_registrant.cc | 3 + .../windows/flutter/generated_plugins.cmake | 1 + 10 files changed, 385 insertions(+), 116 deletions(-) create mode 100644 campus/frontend/lib/avinya/enrollment/lib/widgets/file_upload_widget.dart diff --git a/campus/frontend/lib/avinya/enrollment/lib/data/person.dart b/campus/frontend/lib/avinya/enrollment/lib/data/person.dart index f3ca3f0b..e8570a7e 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/data/person.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/data/person.dart @@ -1,11 +1,13 @@ import 'dart:developer'; -import 'package:gallery/avinya/enrollment/lib/screens/students_screen.dart'; +import 'dart:typed_data'; import 'package:gallery/widgets/success_message.dart'; import 'package:gallery/widgets/error_message.dart'; import 'package:flutter/material.dart'; import 'package:gallery/config/app_config.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; +import 'package:http_parser/http_parser.dart'; +import 'package:mime/mime.dart'; class MainOrganization { int? id; @@ -490,12 +492,12 @@ Future createPerson(BuildContext context, Person person) async { if (response.statusCode == 201) { Person person = Person.fromJson(json.decode(response.body)); showSuccessToast("Student Profile Successfully Created!"); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StudentsScreen(), - ), - ); + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => StudentsScreen(), + // ), + // ); return person; } else { log(response.body + " Status code =" + response.statusCode.toString()); @@ -648,3 +650,86 @@ Future> fetchCities(id) async { throw Exception('Failed to get City Data'); } } + +// Future uploadFile( +// Uint8List file, Map documentDetails) async { +// try { +// // Create the multipart request +// final uri = +// Uri.parse('${AppConfig.campusEnrollmentsBffApiUrl}/upload_document'); +// final request = http.MultipartRequest('POST', uri); + +// // Set the headers +// request.headers.addAll({ +// 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', +// 'accept': 'application/ld+json', +// }); + +// // Add the document_details as a JSON string +// request.fields['document_details'] = jsonEncode(documentDetails); + +// // Determine the MIME type of the file +// final mimeType = lookupMimeType(file.path) ?? 'application/octet-stream'; + +// // Attach the file to the request +// request.files.add( +// http.MultipartFile( +// 'document', // Key for the file in form-data +// file.readAsBytes().asStream(), +// file.lengthSync(), +// filename: basename(file.path), +// contentType: MediaType.parse(mimeType), +// ), +// ); + +// // Send the request +// final response = await request.send(); + +// return response; +// } catch (e) { +// print('Error uploading file: $e'); +// return null; +// } +// } + +Future uploadFile( + Uint8List fileBytes, Map documentDetails) async { + try { + // Create the multipart request + final uri = + Uri.parse('${AppConfig.campusEnrollmentsBffApiUrl}/upload_document'); + final request = http.MultipartRequest('POST', uri); + + // Set the headers + request.headers.addAll({ + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + 'accept': 'application/ld+json', + }); + + // Add the document_details as a JSON string + request.fields['document_details'] = jsonEncode(documentDetails); + + // Determine the MIME type of the file + final mimeType = lookupMimeType('', headerBytes: fileBytes) ?? + 'application/octet-stream'; + + // Attach the file to the request + request.files.add( + http.MultipartFile( + 'document', // Key for the file in form-data + Stream.fromIterable([fileBytes]), // Convert Uint8List to stream + fileBytes.length, // The length of the file + filename: 'document.png', // Adjust this as needed + contentType: MediaType.parse(mimeType), + ), + ); + + // Send the request + final response = await request.send(); + + return response; + } catch (e) { + print('Error uploading file: $e'); + return null; + } +} diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/file_upload_widget.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/file_upload_widget.dart new file mode 100644 index 00000000..2c019647 --- /dev/null +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/file_upload_widget.dart @@ -0,0 +1,143 @@ +import 'dart:typed_data'; +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:gallery/avinya/enrollment/lib/data/person.dart'; + +class FileUploadWidget extends StatefulWidget { + final String documentType; + + const FileUploadWidget({Key? key, required this.documentType}) + : super(key: key); + + @override + State createState() => _FileUploadWidgetState(); +} + +class _FileUploadWidgetState extends State { + Uint8List? _selectedImageBytes; + String? _validationError; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Please upload the required file for "${widget.documentType}".', + style: const TextStyle(fontSize: 16.0, fontWeight: FontWeight.w400), + ), + const SizedBox(height: 20), + _buildFileInputField( + label: widget.documentType, + imageBytes: _selectedImageBytes, + fieldKey: widget.documentType, + onTap: () async { + final imageBytes = await _pickFile(); + if (imageBytes != null) { + var documentDetails = { + "id": 14, + "document_type": "additionalCertificate05" + }; + await uploadFile(imageBytes, documentDetails); + setState(() { + _selectedImageBytes = imageBytes; + _validationError = null; // Clear any errors + }); + } + }, + ), + const SizedBox(height: 20), + ], + ); + } + + Widget _buildFileInputField({ + required String label, + required Uint8List? imageBytes, + required String fieldKey, + required void Function()? onTap, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: double.infinity, + child: InkWell( + onTap: onTap, + child: Container( + width: 330, + height: 90, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(4.0), + ), + child: Row( + children: [ + imageBytes == null + ? const Icon( + Icons.add_a_photo_rounded, + size: 35.0, + color: Color(0xFF000080), + ) + : Image.memory( + imageBytes, + height: 80.0, + width: 80.0, + fit: BoxFit.cover, + ), + const SizedBox(width: 30.0), + RichText( + text: TextSpan( + text: label, + style: const TextStyle( + color: Color(0xFF000080), + fontStyle: FontStyle.normal, + fontSize: 18, + fontWeight: FontWeight.w500, + ), + children: const [ + TextSpan( + text: ' *', + style: TextStyle(color: Colors.red), + ), + ], + ), + ), + ], + ), + ), + ), + ), + if (_validationError != null) + Padding( + padding: const EdgeInsets.only(left: 12.0, top: 8.0), + child: Text( + _validationError!, + style: const TextStyle(color: Colors.red, fontSize: 12), + ), + ), + ], + ); + } + + Future _pickFile() async { + if (kIsWeb) { + // For Web: Use FilePicker + final result = await FilePicker.platform.pickFiles(type: FileType.image); + if (result != null && result.files.single.bytes != null) { + return result.files.single.bytes; + } + } else { + // For Mobile: Use ImagePicker + final XFile? pickedFile = + await ImagePicker().pickImage(source: ImageSource.gallery); + if (pickedFile != null) { + return await pickedFile.readAsBytes(); + } + } + return null; + } +} diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart index 72611b90..6ebc2a27 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:gallery/avinya/enrollment/lib/widgets/file_upload_widget.dart'; import 'package:intl/intl.dart'; import 'package:gallery/avinya/enrollment/lib/data/person.dart'; @@ -327,60 +328,60 @@ class _StudentCreateState extends State { }), const SizedBox(height: 20), - _buildSectionTitle(context, 'More Information'), - ExpansionTile( - title: Text( - 'Click to expand more information', - style: Theme.of(context).textTheme.subtitle1, - ), - children: [ - // Guardian Information - _buildSectionTitle( - context, 'Guardian Information'), - _buildEditableField( - 'Guardian Name', userPerson.guardian_name, - (value) { - userPerson.guardian_name = value; - }, - validator: (value) => value!.isEmpty - ? 'Guardian name is required' - : null), - _buildEditableField( - 'Guardian Contact Number', - userPerson.guardian_contact_number - ?.toString() ?? - '', (value) { - userPerson.guardian_contact_number = - int.tryParse(value); - }, validator: _validatePhone), - - const SizedBox(height: 20), - - // O/L Results Section - _buildSectionTitle(context, 'O/L Results'), - // _buildEditableField('Subject 1', userPerson.ol_subject1, - // (value) { - // userPerson.ol_subject1 = value; - // }), - // _buildEditableField('Subject 2', userPerson.ol_subject2, - // (value) { - // userPerson.ol_subject2 = value; - // }), - // _buildEditableField('Subject 3', userPerson.ol_subject3, - // (value) { - // userPerson.ol_subject3 = value; - // }), - // _buildEditableField( - // 'Other Results', userPerson.ol_other_results, - // (value) { - // userPerson.ol_other_results = value; - // }), - - const SizedBox(height: 20), - - // Add other expandable sections here if needed - ], - ), + // _buildSectionTitle(context, 'More Information'), + // ExpansionTile( + // title: Text( + // 'Click to expand more information', + // style: Theme.of(context).textTheme.subtitle1, + // ), + // children: [ + // // Guardian Information + // _buildSectionTitle( + // context, 'Guardian Information'), + // _buildEditableField( + // 'Guardian Name', userPerson.guardian_name, + // (value) { + // userPerson.guardian_name = value; + // }, + // validator: (value) => value!.isEmpty + // ? 'Guardian name is required' + // : null), + // _buildEditableField( + // 'Guardian Contact Number', + // userPerson.guardian_contact_number + // ?.toString() ?? + // '', (value) { + // userPerson.guardian_contact_number = + // int.tryParse(value); + // }, validator: _validatePhone), + + // const SizedBox(height: 20), + + // // O/L Results Section + // _buildSectionTitle(context, 'O/L Results'), + // // _buildEditableField('Subject 1', userPerson.ol_subject1, + // // (value) { + // // userPerson.ol_subject1 = value; + // // }), + // // _buildEditableField('Subject 2', userPerson.ol_subject2, + // // (value) { + // // userPerson.ol_subject2 = value; + // // }), + // // _buildEditableField('Subject 3', userPerson.ol_subject3, + // // (value) { + // // userPerson.ol_subject3 = value; + // // }), + // // _buildEditableField( + // // 'Other Results', userPerson.ol_other_results, + // // (value) { + // // userPerson.ol_other_results = value; + // // }), + + // const SizedBox(height: 20), + + // // Add other expandable sections here if needed + // ], + // ), // const SizedBox(height: 20), // _buildSectionTitle(context, 'Professional Information'), @@ -391,11 +392,11 @@ class _StudentCreateState extends State { // _buildEditableTextArea('Comments', userPerson.notes, (value) { // userPerson.notes = value; // }), - const SizedBox(height: 40), - _buildSaveButton( - isDistrictsDataLoaded, - isOrganizationsDataLoaded, - isAvinyaTypesDataLoaded), + // const SizedBox(height: 40), + // _buildSaveButton( + // isDistrictsDataLoaded, + // isOrganizationsDataLoaded, + // isAvinyaTypesDataLoaded), ], ), ), @@ -407,14 +408,49 @@ class _StudentCreateState extends State { // Step 2: File Upload Step( title: Text('Upload Files'), - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildSectionTitle(context, 'File Upload'), - _buildFileUploadWidget('Upload Profile Photo'), - _buildFileUploadWidget('Upload NIC Copy'), - _buildFileUploadWidget('Upload O/L Certificate'), - ], + content: SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Center( + child: SizedBox( + width: 800, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // _buildSectionTitle(context, 'File Upload'), + // GridView inside SingleChildScrollView + GridView.builder( + shrinkWrap: true, // Avoid infinite size issue + physics: NeverScrollableScrollPhysics(), + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, // 2 items per row + crossAxisSpacing: 16.0, + mainAxisSpacing: 16.0, + childAspectRatio: + 1.5, // Adjust the aspect ratio to take up more space + ), + itemCount: 8, + itemBuilder: (context, index) { + List documentTypes = [ + 'NIC Front', + 'NIC Back', + 'Birth Certificate Front', + 'Birth Certificate Back', + 'O/L Certificate', + 'A/L Certificate', + 'Additional Certificate', + 'Another Document' + ]; + + return FileUploadWidget( + documentType: documentTypes[index], + ); + }, + ), + ], + ), + ), + ), ), isActive: _currentStep >= 1, ), @@ -425,20 +461,48 @@ class _StudentCreateState extends State { // Navigate to the next step void _nextStep() { - if (_currentStep == 0) { + bool isEnabled = isDistrictsDataLoaded && + isOrganizationsDataLoaded && + isAvinyaTypesDataLoaded; + print('is enabled:${isEnabled}'); + if (_currentStep == 0 && isEnabled) { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); + createPerson(context, userPerson); setState(() { _currentStep += 1; }); } - } else if (_currentStep < 1) { + } else if (_currentStep < 1 && isEnabled) { setState(() { _currentStep += 1; }); } } + // Widget _buildSaveButton(bool isDistrictsDataLoaded, + // bool isOrganizationsDataLoaded, bool isAvinyaTypesDataLoaded) { + // bool isEnabled = isDistrictsDataLoaded && + // isOrganizationsDataLoaded && + // isAvinyaTypesDataLoaded; + // print('is enabled:${isEnabled}'); + + // return Center( + // child: ElevatedButton( + // onPressed: isEnabled + // ? () { + // if (_formKey.currentState!.validate()) { + // _formKey.currentState!.save(); + // // Save userPerson changes + // createPerson(context, userPerson); + // } + // } + // : null, + // child: const Text('Create Student & Continue'), + // ), + // ); + // } + // Navigate to the previous step void _previousStep() { if (_currentStep > 0) { @@ -448,23 +512,6 @@ class _StudentCreateState extends State { } } - // Mock function for file upload widget - Widget _buildFileUploadWidget(String label) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - children: [ - ElevatedButton( - onPressed: () { - // Logic to handle file upload - }, - child: Text('Upload $label'), - ), - ], - ), - ); - } - String? _validateEmail(String? value) { if (value == null || value.isEmpty) { return 'Email is required'; @@ -855,29 +902,6 @@ class _StudentCreateState extends State { .toList(); } - Widget _buildSaveButton(bool isDistrictsDataLoaded, - bool isOrganizationsDataLoaded, bool isAvinyaTypesDataLoaded) { - bool isEnabled = isDistrictsDataLoaded && - isOrganizationsDataLoaded && - isAvinyaTypesDataLoaded; - print('is enabled:${isEnabled}'); - - return Center( - child: ElevatedButton( - onPressed: isEnabled - ? () { - if (_formKey.currentState!.validate()) { - _formKey.currentState!.save(); - // Save userPerson changes - createPerson(context, userPerson); - } - } - : null, - child: const Text('Create Student'), - ), - ); - } - Widget _buildDateOfBirthField(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), diff --git a/campus/frontend/lib/avinya/enrollment/pubspec.yaml b/campus/frontend/lib/avinya/enrollment/pubspec.yaml index 1e2b4e2b..ce8bd2df 100644 --- a/campus/frontend/lib/avinya/enrollment/pubspec.yaml +++ b/campus/frontend/lib/avinya/enrollment/pubspec.yaml @@ -36,6 +36,9 @@ dependencies: month_year_picker: ^0.3.0+1 oktoast: ^3.4.0 fl_chart: ^0.60.0 + dotted_border: ^2.0.0+1 + image_picker: ^1.0.8 + file_picker: ^5.2.10 dev_dependencies: flutter_lints: ^2.0.1 diff --git a/campus/frontend/linux/flutter/generated_plugin_registrant.cc b/campus/frontend/linux/flutter/generated_plugin_registrant.cc index 6adbd2c4..c259cda9 100644 --- a/campus/frontend/linux/flutter/generated_plugin_registrant.cc +++ b/campus/frontend/linux/flutter/generated_plugin_registrant.cc @@ -6,10 +6,14 @@ #include "generated_plugin_registrant.h" +#include #include #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/campus/frontend/linux/flutter/generated_plugins.cmake b/campus/frontend/linux/flutter/generated_plugins.cmake index f32b910e..7c9fef0b 100644 --- a/campus/frontend/linux/flutter/generated_plugins.cmake +++ b/campus/frontend/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux url_launcher_linux window_size ) diff --git a/campus/frontend/macos/Flutter/GeneratedPluginRegistrant.swift b/campus/frontend/macos/Flutter/GeneratedPluginRegistrant.swift index ea440b1c..a7c59bdd 100644 --- a/campus/frontend/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/campus/frontend/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import file_selector_macos import flutter_appauth import package_info_plus_macos import path_provider_foundation @@ -13,6 +14,7 @@ import url_launcher_macos import window_size func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FlutterAppauthPlugin.register(with: registry.registrar(forPlugin: "FlutterAppauthPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/campus/frontend/pubspec.yaml b/campus/frontend/pubspec.yaml index 853e39d4..a89770b3 100644 --- a/campus/frontend/pubspec.yaml +++ b/campus/frontend/pubspec.yaml @@ -61,6 +61,9 @@ dependencies: qr_code_scanner: ^1.0.1 flutter_date_range_picker: ^0.0.14 fl_chart: 0.60.0 + dotted_border: ^2.0.0+1 + image_picker: ^1.0.8 + file_picker: ^5.2.10 pdf: ^3.6.4 month_year_picker: ^0.3.0+1 diff --git a/campus/frontend/windows/flutter/generated_plugin_registrant.cc b/campus/frontend/windows/flutter/generated_plugin_registrant.cc index 7a1ff3b7..cd2d5c19 100644 --- a/campus/frontend/windows/flutter/generated_plugin_registrant.cc +++ b/campus/frontend/windows/flutter/generated_plugin_registrant.cc @@ -6,10 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); WindowSizePluginRegisterWithRegistrar( diff --git a/campus/frontend/windows/flutter/generated_plugins.cmake b/campus/frontend/windows/flutter/generated_plugins.cmake index fc786d6b..a22fdb08 100644 --- a/campus/frontend/windows/flutter/generated_plugins.cmake +++ b/campus/frontend/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows url_launcher_windows window_size ) From 9e3446fbf3da54297d6787bc1ee86772e6568aff Mon Sep 17 00:00:00 2001 From: lahirulakruwan Date: Thu, 9 Jan 2025 09:36:17 +0530 Subject: [PATCH 16/17] Class icons added to the icon folder --- campus/bffs/attendance/api/Dependencies.toml | 4 ++-- campus/bffs/profile/api/Dependencies.toml | 4 ++-- campus/frontend/assets/icons/icon8-shark-100.png | Bin 0 -> 9729 bytes 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 campus/frontend/assets/icons/icon8-shark-100.png diff --git a/campus/bffs/attendance/api/Dependencies.toml b/campus/bffs/attendance/api/Dependencies.toml index 8cd1c0e7..510c6388 100644 --- a/campus/bffs/attendance/api/Dependencies.toml +++ b/campus/bffs/attendance/api/Dependencies.toml @@ -108,7 +108,7 @@ modules = [ [[package]] org = "ballerina" name = "http" -version = "2.10.17" +version = "2.10.19" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -357,7 +357,7 @@ dependencies = [ [[package]] org = "ballerina" name = "websocket" -version = "2.10.2" +version = "2.10.3" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "constraint"}, diff --git a/campus/bffs/profile/api/Dependencies.toml b/campus/bffs/profile/api/Dependencies.toml index c424b4af..3dc05362 100644 --- a/campus/bffs/profile/api/Dependencies.toml +++ b/campus/bffs/profile/api/Dependencies.toml @@ -108,7 +108,7 @@ modules = [ [[package]] org = "ballerina" name = "http" -version = "2.10.17" +version = "2.10.19" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -357,7 +357,7 @@ dependencies = [ [[package]] org = "ballerina" name = "websocket" -version = "2.10.2" +version = "2.10.3" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "constraint"}, diff --git a/campus/frontend/assets/icons/icon8-shark-100.png b/campus/frontend/assets/icons/icon8-shark-100.png new file mode 100644 index 0000000000000000000000000000000000000000..1c5cb402ac4145f6f994f7a3852ae375394f09ac GIT binary patch literal 9729 zcmV+cCjQxpP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXfC6-ARq8O4N_db-mhs|a?*2ps+7PuL zk^Q3BXDMxOV!+>gpJE;VoIU1|A?veWaI_xCn`s2#Sx+j~Z# zr{yh4M&zTS>o~LW;>*WH*%rZryFuAF3JcKF)6i2>QIQBL62Xx%orJlIa2L+NnU#m` zO+qvsI~oyeD+}a$g?czG&;MXr{?eRjxl4S#E&E#IKj;5PWcIR$Ga`DlRdYCvlr^^^ z+NcGWvKgp8io0+In#(=%*bWWi-~JlnbmAx}I{iEl#B6TCIX#zz1-p*@e~9 zi>sg%@2vSF_GiNi^bzT3A=2K0Js2E*tdvsQ5qU~8jbGL5dBQ)o)@6efm#w=RvMIB`$h2}!rbBKn#+wbEfXVU8hTPPn$yj|u>(ZAJFpdZ)K_kPe(amZM*#9yKI$=S zU!90d_a-G`TQ=cP2xXuC`9(J{re)xqo{J+r3xL4EN=#q(X&X()GiM>LoPv>OlSbJ@ zdpZfXG!X6XfT90`LRF!(|1bzWQ(gIVUwpMo%SNquMdKPoeFot+K^y?OHxWlxF3!xH zGaI07<9q8>R5WbsN-wIee6ne*!T8AVUrNf?e;)XD{>&NN|F>UYFc_q@uAat|C#gGr zoc4xBEYplt(sdlub8+Psq0A^|pAXG2aAfA7xjm!be^IDtgm7ykk(P#$`9?t>*qdxi z{!hd1Ej96VrjqNg-)J-pHr=7b{*oZe0K_nGPS3-YSBRdJ8ee6EXm9_^&EF$(6@cbRz@1-$ zGq(WIV{_)Y2<+cUw5JnWsYmN8w|p^(}BH)kBxq3npp3=EEGPB}eJEhp6K|+l+L|PkBW|Wv*ysoewtFL%!>qJ}P z*(fSozgB~PLs$x+C#K*oo`o|rd%_LQ3iQ!e`34Hx@6x5<`1Z~H@iu4Uj87;jTlWMa zpU5jL;NxHUGMd8?Z!&^qnjGA|gB>sbf!>Y|0F0D0JhK*HB%i%IPX)>{2{+dfZmh)) zhhop*O+q5TNCZOh};86tbxtJk(m>3dR~H6dx*5RpcLP(tK9sB`0{gc zdf7CDD}BMAybk>ypTBR~V0Sm(q$D(D3Ok&{S2Hq3=mYx`U`){fz!^`1URFI0IXW|;EHxz+o@p0 zOLQ3q*@Xqp`g!jsF~HJ82Xd8Wi5;-mMCxnc-(H5T(gShH{VRs&_X~d#r`+9@!GF`O(YaTPe>wR z;c|3uV*JNl5|n8YsyjirsSagZpj3-eJX*J_@HeI9^)qbbPlDtd$!R1kTs|f=bfNU` z+m6}W4XAI{R&4qE`0|M`Zj;T(Tf8tjIPj2YT2*i3o*ys#m^&@p-ThCZ$zaZ`ytR9N z|GgiT%)9Q@P&l#yuq-o5V{M)6`SVsny}jfV72)uB$SEq~s^!aQs;;KLvy(_$6M91O z+aii+8jfk1IJ5JxLxb1@!6Xs6J1yV83Z;EcL<$`lStKqhKj*?_qC`8}2-Q~uw0hj0 zdpqlQUC>6|xPoNPSeXR6ThsN5?z+mY=|yGNn8Cn1UN?U1PYt z&rY|^2cwW`TK3$gh6Zi_8*kusxyULm!kd`H)vH$#@cU`2t0&UYf@U}-9_qhH#Bkuu z%EL%b!|d~+%;*e+RL$chY3Vg%gQ*vYvTXu~cA?BD3jWv0x1QJ;Z!=NG6{NFzM`urc z<$rhARc-~CpL0{AH9h48(X?${)!S=lzW4hs6>9%aW!qkNM)o6nU;Ey!uBLsz$t+!U zt!-H|Ow;1T;VPPs9;0;LJlu(i%wDtzx7SPEk)uSq+rhSROdH?NxfJN$1YCKAVB0Za zqESqLFOIYf#JIQ~5^k&^+R=hi9I7koe}p4PF4z|ucMh2di*El?ab&=}`{=9R{#Ss7 zxBuP3Kzr+c5kiTE@tJ{e1>#-Jg7f+_|wh+_61-dEv=Tn9(S%{1Uvg&l)7X zWSD(E29EB>3icz01Ml2LIHynE-vF>9A^LW_jd<+~vgw^i@)Ng7lw|pzU ze6n1yAn`1{^KV`c`utr+LfR9ZC${=i7rw7FG%)a0P@1h2$M)?fH#dj0++5N!Gs&A# z%F$iBiS~9QqG6<_$G>tySOGs)Fn}KC6P*tc4M%zwMp7!#o(@c34`xp%j`XaN{hjk+ z`g<5WSp^W#EOmQt%l?awLQk0>H9LMA?W)Cjf94&$=K% z7+Q(Bvhz`qaBK)`Z$|SboHKM1ZmuKJ+6ZvW6A0Yj*?A-u{=P^qnIHh2C$^nvKD0Fq zur_7ZE1fRqdjf-@JhQ)#(#4Ab$Sy1-8V=J`U5(k(i7PvQ!XCXcqp`KWrr{}>6IWznHQdfD3Cg11JTnK>jbDo1pK zP~Axet79=afM`!Ak&YHnsz=kJpC40k3b-Ia>}VvaY}*s@`^)3Y=E1Zt-TZJ$su)?o zH#FfBqszUDe+Q+G?AwnT+7bpxOikf^_umJ=K=qN)i4JGQ?CAo)NIji#Ir2_TzZf?Q zBQ2f8#VZlRL8##rgQt$7EQ^8T2LVvRS88_rXKWK_3OVm!J@*4&S&*80^^Y=UUsKdw zv-2&0%#!i~%QW97wmBm+XYog~@)v*C63GUn2lc6{i2WrK`6Pk{Dk-;M$qku#ORmW+ zSUN8OQG>{JVbe^WJ!dwFqjn`TaB zvI2cXS{q}Yd2TFc%#MT@tT~R^@53>P<+bMaV5FuK?P$U5?IPOKfgKE>;LW;1hiTcgPzW06ldwpmwH{Ll5 zab(1Pxe!aS@mIW#JvczZyd^lZ^GAvThjtO|Y{NVE>X9B|_WS7H_2wA~f0H57(Mqst z57;VXqphv4eDZ<=i05Jgg23!s9=$Kx=l?mt^o(>qykR|=GiSw{O$sXzKu%xSi|7SDl~5bDdlTN8iKM+{M%kZ*)}PwZ$fj$R$tN1 zRsx51<4B)Q;-WLAy$Lf|dpzd%D4H!(U(vAlCsUq}eCAj%4h6Z3%&=|$jmPC={nx%q zYW_te!VRH0&%I6Rbi0{fUQS9z2F*1!gnT`OTNglfiH} zD4siq*1CFn+S_5s0Svd)gNo%&MLSyvw=|%+JtWLsG-enZJbnlO@2mwA4jhh$9SLED zgJ@n4w!aSrtJCwBz0}*hcglvY2?^qB-q)U%w`{Azo^6{}UQc_wR(td)hqmva;+0p~ zyLBtgr%vJT?m^RZ5|Wb8reG&-Gy}mPZ~pE@KyllKhrm{Jx3m!L?TY0A_jH17oskn3 z?Pwt~&M zEJPSH7P!4$u3E92#cS4(TQa$2=DFx>X<;xJq;OVjLD5!U&+E_qmYS*|Pg*n*<}V$! z*`(;(^(I!oAMc#2am5W~lO@vMMYJ#GjG`3LhDKB@%9(Oqy;$>B?YS= zC^c+jrLxs(5xF7eu*b+MD4^`-o0wO&0%Ho23F7(l3;)eqzk4w@L=7E6HB!^@&R&2W z8X$0R7vgY|vijz6{h7%S@pljn#O5Oa6$%lpZ$v58FQUz=t=JSBPcMQg5adisR&1D! zSnCma0LTVNNKRte+O;fOdjsBcEO#eETSFt89{WcGxZ{z(!iq+D{kh-L*V8lRjEiUH zyo(;L0K&dj%;4DbLuOlh>|BgeKdG(U^6;3#3*h3K%vtcY?Cth7?|&^fW#)fGUG6GT z6htGDy!zwEWzXw>CfL_UMotcH@8ov*;z>+NK`F(&6)U)U^(v<4=d<+s>kttdtE*8~ zEUx9sEj;Jm#zZlLeJFEmc8|E+*giiBb#-#ilBfMG`_FMK`TSfGL5At0ceZL!HFi9@SkaaGKm#?2A8edYVkBNv& z(=@JHzMM55`T!X@7nb=kn#SsCp8mJ*V3{U2-hCH|$;rI>>@OJ%2GLw@+=Vk@X+OG- z=5Qjze+`+tb7~eS@C%4yNbj;<<<(<8-+=zHdMC%2u%Ujt`Snkk7)^tLSQJp{KPqwj0>h zMzo`qNLv%(=6b@7HG~^a5o)T7oeuW*Vhseaqv6z+y1Gqh&G0v(| zir+u=GY)Kf3*9hSP+m?X9AY34An5lq5C{?q2C+w-s~kbo(A{2?p&@P;n%jlATrkSl zQiCC)4UGUbwT1n&`Sq_aXpj9J7i5^3WgGG>?5``~K>?@XFj#)$jjVd_d+{b+c#j!P zBphbbKRiZHdk5Ek=!0B$`)wm-N-3i55o6*u36 z<2(V$iO^bC$5a3EEtFE+`{?H=o*S1OF%C*8{N3HO*45KiUr%d&J+1W(gn}by>thW2 zLP|aBQs$?Q?fUuYBgzxxvJ+(EVdd=VFgN*Io9{dEhv(=#ei(qHv^3V<@nIIMT6xiN zvt57u6R$k;ED6cUY}oj95>ry*P0ou_ite^H8c$Z!SY1uS@e}yFNB{nn4O9xeU}^UA z^*f$AGh1RDF779rLW;`Qy-!2?@~s=cYiTae+TrItHOD#r@^ko`>R>2s=;nJqO3|Fz zqpME}r4-No=*Jw}vzNTmQttoa7tk*v=s1k8tBbm$$Ec~QqVDK121oZGrH(3iRulD1 zO~p^E$6Xz~6RWK8C@o*N4tQFSQqQ!^lH|O?kupzO2Kmd^keHcGUrPhN_Erw<*g;2A zGr7gZxDzJtT#5)Y7R=|w{sXi(HqzJA!|cV2FS_Tsy{SLh0^)+ad|xq z^!F1U9LxmP0-s9FTXIWE{?dU=&zh4xJ(Xi7|94stDK20CC6IsDG+keN=bg;Gb}fU} z*ybZ5BxUDOSbiOv!->DCj*g~A_Py~2W;9A}Ny(&JxZ!Y6I)5IAD=KKNsYOI6nsfg7 zWTJ?sk&-@*84KpK{H7b3y?7CZ!$Dt9k3_@aLV>$%Z{)$W{3W3b&$Wk!g?Z-$*|9;<1D}N22xx?x?3=92*oWNMbnv9Jd3<#tBDQ-=xc4H;lv3J@7PI7 zdOGPj*^_GJp2S4*N=vA!+(rGd<0MT>BfIc)@0=<`gv68-W-M61ikogCtDt~@&qrUc zFB$lN@<#7W&tF#2+q}2+oe|{v>y46Q+7CcJ<8V6p$X`FgRm)Fb=cH?p<`$BjLdb$h zoNHjX++@vLOy=wb^tU$A*U`q&-MeY7sU?5L3_J-5V=J74)Qk+$GBY{8cOTUU50R0b zO=ezhyxEkYX&M>1IV`$nHN|u1(AnHVz~{?UO5LAYuz1_sF39!QZ#1-!z6sq$H{j9pd=D{Y;xao$2`#yUgu^5g{c#okeS|!HPy{I(5nctbTh1x%+Ni>l)mI z$OE2)1n&LZ=O~ypGv4Y9JO*TX1Q7_DXU;Dvc||nt+J+e(#I|i!d-SNB*uS6L;u4Zl zC$^8CTT+ZWA%Rne4s(3pJ`9JGf*CW$rZ!yyLZhAX9>1u5qx$0_&R+M_YwsOl4 z-xfiN%h!KG;Kzo;A@_Xt(-aRK0KHIb%c9}LN%p?+Cdc>g!?sLNs@GQbjrF^p+COYp zvhtxal-dH!({-KeK71Q1-}9ac^_Ib4kU#(Sd4_x06rw;4qByQZ-qMhl-2Hv84PQWg z$ptA~{@`j&mp^No?zrRO4O}%&>gYtUEsM5>29ECDLsdm3{l3^y1f^5}+_ zVbS#uxV4b}&nP~Ppch|t6}N9#KjCo6;hhz{@Z=^CK}$}KU4?7gvD@}yajPMxTZVp{ zGBod~P8AAoQ_usdU6j@es#e54p`|4?RKNTm-%r3dw4be%4YFSeKT{#=srmy?#nd?mB`eq6jN)e?ISI+h z-1*4E6wW?>_{Fwue)!d|;qU6kQB;7qCwSyeC`D&YHBf~W41_xN~!GvFDYG~tJ|@; zVX`8e!QFT3CH0AqBm6Chw&JFnxaFR^&w0g0?UAGW;yd3(OYmY$z&}xu2zGFw((35? zL~X^U*a@Era>)cKSiL^iuxN6)oO1Q*)i_-)qTvXEK0m!39dx&~$N%zC5CL^akUuKL zAC<>?qkijCvFqZdn9{O!_bOyFf_r}13T}I7J=$6J)O}rD{NT%9J>%l&vtjl2Vs&(( z6pzS#_jrCI!ekmT&u+T zoggXm%T{pvhKI)ODZ#!zzW4brAPxgZ>G^#ptD_UE*N1KM$@*QJe-vMSE-tAcfRwIS zzs%BDpn+FVgGyAFvZcY)QcpDP{BG9-^0D`)@4c*TS7Ny}gI zrPTbTtI~28l}yW9s=0Gk_yVna&P*GeDvlgcX?csMBXV7GTG~i>r?a`4tkvxRVE}*E>Fkk;S6>4_Pf0$n7-}#S8?ux-RKa9IkXbo+~d4`P?!YYAS^ zv;^P|(d3tgN@^%6TmRM4We-m*AT>dhNCd!Eu{orxwUtBLcf{gYY3JWpv3f=l-+usd zK@RL?DM30uY@!NcTjue2x1r$ieH%>v5Os) z@K3FKo`}mkoj8}RAON+M1^=SpMJyY$wRI@e4dQfQ@8Zc?vD6( zOq6-o|8=55y^LQ@HRn}>?DsS$B zS9H+eCgPB8ibuh`!!l#O=nBn{&>Ul`<{N zrY5j#M9DYmDz`ivZ!=lW-4`zt>UM6~im30P6lPn;$j~(!Eh!O4ejezW2s~O+*6^K) zhK4K&{G*6u0fYty5Ql-0cWyDTZOo=-RMZ6cZEfYIe~ve~5UvP80BpDY4TU-s6Ha4TeVNg_rOyj-_ zUFODf*$-L6`0EdtDf!C|3+m%46c#NddE8LB7zUchi`^dp#r3Iqi)($&L$QxIN|)VV zs5I>lg2YlCH4R5W9^yWG%t}SgSkDNDL8*OFO?ywvt|u@0zTRQ37(oF1&HL)o@|Ii$ zEWonS&T_I!97b$T>F*ao-Zw3G$sgjw7&FU0oowsYD+00QvaSz_arQlPH86dqleLC9$1>vbrLgS25*_CWbTOPWO3&%IDa*pFtw&jwLbxBB4G1>? zXo-m!Ia%Y^w=Asg9xR_9ltQ6S03WZb*isR1I+a|Jf)GnheNm7P7}?X&&Xe?J_xEGA zw4Ht+f}W8+zSCz}SU!JjC1=|VeTUU|l-qvnQYBoB=87A#hDj?}D!`qHpq=NIJ8`*C zp%5w>MH~(sc{ymwW9z7B6uY|@v#lK!8~|Hc2rp=w+*w<(`8Stph>GWm?IDHB*OltJ zRExtQj?xL-$z@sCfj~^W;UUVlu>(PDe;@YnIdp}kgqL)*zdu#+&h8ei}2;))d{f8|5d9JcBZ zL)RTM&mVcW13|2gPSmL6Jf)N=!gfUcJZZpu=HT0y6LvPPSV3m2*f8JL?8D-6;V3@$ zxepZ%6K!Z3nxs_^!W#-+60{el;ug56Y?WQj#&U&;AXaDiXzPY(kkP z3bnbeV)KTniaT8j##w-08Hm^)1JKTK;#P$tqs926w?FX7%UKMrR6$BttX~dXE4q%B zIKCiuAQ-zf)HFe{HF+?4`|v5H%b6=rkc}HPrKxX$h?W-j1polH!s_h8Y;K9|Br5fs z?Xli_IZW6S;fiw%i$gOu2=W Date: Tue, 21 Jan 2025 20:58:05 +0530 Subject: [PATCH 17/17] Student document upload api changes added --- campus/bffs/enrollment/api/client.bal | 11 +- campus/bffs/enrollment/api/service.bal | 26 + campus/bffs/enrollment/api/types.bal | 16 +- .../graphql_client/enrollment.graphql | 12 +- .../graphql_client_cg_src/client.bal | 8 +- .../graphql_client_cg_src/types.bal | 15 +- .../enrollment/graphql_client/schema.graphql | 5 +- .../enrollment/graphql_client/schema.json | 89 +-- campus/bffs/profile/api/person_client.bal | 6 +- campus/bffs/profile/api/types.bal | 48 +- .../graphql_client_cg_src/client.bal | 2 +- .../graphql_client_cg_src/types.bal | 25 + .../profile/graphql_client/person.graphql | 78 +-- .../profile/graphql_client/schema.graphql | 55 +- .../bffs/profile/graphql_client/schema.json | 527 +++++++++++++++++ .../avinya/enrollment/lib/data/person.dart | 159 +++-- .../lib/widgets/file_upload_widget.dart | 25 +- .../lib/widgets/student_create.dart | 55 +- .../lib/widgets/student_update.dart | 556 ++++++++++++------ 19 files changed, 1351 insertions(+), 367 deletions(-) diff --git a/campus/bffs/enrollment/api/client.bal b/campus/bffs/enrollment/api/client.bal index d8b36eb0..aa899f67 100644 --- a/campus/bffs/enrollment/api/client.bal +++ b/campus/bffs/enrollment/api/client.bal @@ -34,13 +34,13 @@ public isolated client class GraphqlClient { json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, GetPersonsResponse); } + remote isolated function getPersonById(int id) returns GetPersonByIdResponse|graphql:ClientError { - string query = string `query getPersonById($id:Int!) {person_by_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email mailing_address {city {id name {name_en name_si name_ta} district {id name {name_en}}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job document_list {document document_type}}}`; + string query = string `query getPersonById($id:Int!) {person_by_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email mailing_address {city {id name {name_en name_si name_ta} district {id name {name_en}}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job documents_id}}`; map variables = {"id": id}; json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, GetPersonByIdResponse); } - remote isolated function updatePerson(Person person, City? permanent_address_city = (), Address? mailing_address = (), Address? permanent_address = (), City? mailing_address_city = ()) returns UpdatePersonResponse|graphql:ClientError { string query = string `mutation updatePerson($person:Person!,$permanent_address:Address,$permanent_address_city:City,$mailing_address:Address,$mailing_address_city:City) {update_person(person:$person,permanent_address:$permanent_address,permanent_address_city:$permanent_address_city,mailing_address:$mailing_address,mailing_address_city:$mailing_address_city) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email permanent_address {city {id name {name_en name_si name_ta}} street_address phone id} mailing_address {city {id name {name_en name_si name_ta}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job}}`; map variables = {"permanent_address_city": permanent_address_city, "mailing_address": mailing_address, "person": person, "permanent_address": permanent_address, "mailing_address_city": mailing_address_city}; @@ -77,4 +77,11 @@ public isolated client class GraphqlClient { json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, UploadDocumentResponse); } + + remote isolated function getAllDocuments(int id) returns GetAllDocumentsResponse|graphql:ClientError { + string query = string `query getAllDocuments($id:Int!) {document_list(id:$id) {document document_type}}`; + map variables = {"id": id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetAllDocumentsResponse); + } } diff --git a/campus/bffs/enrollment/api/service.bal b/campus/bffs/enrollment/api/service.bal index 1fcd8f58..55e9bacf 100644 --- a/campus/bffs/enrollment/api/service.bal +++ b/campus/bffs/enrollment/api/service.bal @@ -288,6 +288,32 @@ service / on new http:Listener(9095) { }; } } + + resource function get document_list/[int id]() returns UserDocument[]|error { + GetAllDocumentsResponse|graphql:ClientError getDocumentsResponse = globalDataClient->getAllDocuments(id); + if (getDocumentsResponse is GetAllDocumentsResponse) { + UserDocument[] document_datas = []; + foreach var document_data in getDocumentsResponse.document_list { + UserDocument|error document_data_record = document_data.cloneWithType(UserDocument); + if (document_data_record is UserDocument) { + document_datas.push(document_data_record); + } else { + log:printError("Error while processing Application record received", document_data_record); + return error("Error while processing Application record received: " + document_data_record.message() + + ":: Detail: " + document_data_record.detail().toString()); + } + } + + return document_datas; + + } else { + log:printError("Error while getting application", getDocumentsResponse); + return error("Error while getting application: " + getDocumentsResponse.message() + + ":: Detail: " + getDocumentsResponse.detail().toString()); + } + } + + // resource function post add_person(http:Request req) returns Person|error { // UserDocumentList[] documents = []; // Person person = {}; diff --git a/campus/bffs/enrollment/api/types.bal b/campus/bffs/enrollment/api/types.bal index 41b4a14a..39115551 100644 --- a/campus/bffs/enrollment/api/types.bal +++ b/campus/bffs/enrollment/api/types.bal @@ -82,6 +82,7 @@ public type Person record { string? notes?; int[]? parent_student?; string? date_of_birth?; + int? parent_organization_id?; int? avinya_type_id?; Address? permanent_address?; int? mailing_address_id?; @@ -105,7 +106,6 @@ public type Person record { string? full_name?; string? nic_no?; int? phone?; - UserDocument[]? documentList?; int? organization_id?; int? updated_by?; string? academy_org_name?; @@ -293,13 +293,9 @@ public type GetPersonByIdResponse record {| int? created_by; int? updated_by; string? current_job; - record {| - string? document; - string? document_type; - |}[]? document_list; + int? documents_id; |}? person_by_id; |}; - public type UpdatePersonResponse record {| map __extensions?; record {| @@ -539,3 +535,11 @@ public type UploadDocumentResponse record {| string? additional_certificate_05_id; |}? upload_document; |}; + +public type GetAllDocumentsResponse record {| + map __extensions?; + record {| + string? document; + string? document_type; + |}[] document_list; +|}; diff --git a/campus/bffs/enrollment/graphql_client/enrollment.graphql b/campus/bffs/enrollment/graphql_client/enrollment.graphql index 25fb5514..3cb2e042 100644 --- a/campus/bffs/enrollment/graphql_client/enrollment.graphql +++ b/campus/bffs/enrollment/graphql_client/enrollment.graphql @@ -148,10 +148,7 @@ query getPersonById($id: Int!) { created_by updated_by current_job - document_list { - document - document_type - } + documents_id } } @@ -409,3 +406,10 @@ mutation uploadDocument($user_document: UserDocument!) { additional_certificate_05_id } } + +query getAllDocuments($id: Int!) { + document_list(id: $id) { + document + document_type + } +} \ No newline at end of file diff --git a/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/client.bal b/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/client.bal index 023c2005..d70885b4 100644 --- a/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/client.bal +++ b/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/client.bal @@ -34,7 +34,7 @@ public isolated client class GraphqlClient { return check performDataBinding(graphqlResponse, GetPersonsResponse); } remote isolated function getPersonById(int id) returns GetPersonByIdResponse|graphql:ClientError { - string query = string `query getPersonById($id:Int!) {person_by_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email mailing_address {city {id name {name_en name_si name_ta} district {id name {name_en}}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job document_list {document document_type}}}`; + string query = string `query getPersonById($id:Int!) {person_by_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email mailing_address {city {id name {name_en name_si name_ta} district {id name {name_en}}} street_address phone id} phone organization {id description notes address {id} avinya_type {id name} name {name_en} parent_organizations {id name {name_en}}} avinya_type_id notes nic_no passport_no id_no email street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id bank_branch created_by updated_by current_job documents_id}}`; map variables = {"id": id}; json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, GetPersonByIdResponse); @@ -81,4 +81,10 @@ public isolated client class GraphqlClient { json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, UploadDocumentResponse); } + remote isolated function getAllDocuments(int id) returns GetAllDocumentsResponse|graphql:ClientError { + string query = string `query getAllDocuments($id:Int!) {document_list(id:$id) {document document_type}}`; + map variables = {"id": id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetAllDocumentsResponse); + } } diff --git a/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/types.bal b/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/types.bal index fa9cc955..c13ba621 100644 --- a/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/types.bal +++ b/campus/bffs/enrollment/graphql_client/graphql_client_cg_src/types.bal @@ -313,6 +313,7 @@ public type Person record { string? notes?; int[]? parent_student?; string? date_of_birth?; + int? parent_organization_id?; int? avinya_type_id?; Address? permanent_address?; int? mailing_address_id?; @@ -336,7 +337,6 @@ public type Person record { string? full_name?; string? nic_no?; int? phone?; - UserDocument[]? documentList?; int? organization_id?; int? updated_by?; string? academy_org_name?; @@ -615,10 +615,7 @@ public type GetPersonByIdResponse record {| int? created_by; int? updated_by; string? current_job; - record {| - string? document; - string? document_type; - |}[]? document_list; + int? documents_id; |}? person_by_id; |}; @@ -863,3 +860,11 @@ public type UploadDocumentResponse record {| string? additional_certificate_05_id; |}? upload_document; |}; + +public type GetAllDocumentsResponse record {| + map __extensions?; + record {| + string? document; + string? document_type; + |}[]? document_list; +|}; diff --git a/campus/bffs/enrollment/graphql_client/schema.graphql b/campus/bffs/enrollment/graphql_client/schema.graphql index 13e3913f..df1d3fdd 100644 --- a/campus/bffs/enrollment/graphql_client/schema.graphql +++ b/campus/bffs/enrollment/graphql_client/schema.graphql @@ -780,6 +780,7 @@ input Person { mailing_address_id: Int phone: Int organization_id: Int + parent_organization_id: Int avinya_type_id: Int notes: String nic_no: String @@ -804,7 +805,6 @@ input Person { branch_code: String current_job: String documents_id: Int - documentList: [UserDocument!] created_by: Int updated_by: Int } @@ -842,12 +842,12 @@ type PersonData { bank_account_name: String academy_org_id: Int organization_id: Int + parent_organization_id: Int branch_code: String current_job: String created_by: Int updated_by: Int documents_id: Int - document_list: [DocumentsData!] } type PlaceData { @@ -987,6 +987,7 @@ type Query { consumable_yearly_report(organization_id: Int, consumable_id: Int, year: Int): [InventoryData!] persons(organization_id: Int, avinya_type_id: Int): [PersonData!] person_by_id(id: Int): PersonData + document_list(id: Int!): [DocumentsData!] districts: [DistrictData!] cities(district_id: Int): [CityData!] all_organizations: [OrganizationData!] diff --git a/campus/bffs/enrollment/graphql_client/schema.json b/campus/bffs/enrollment/graphql_client/schema.json index f9b259b4..fe268cea 100644 --- a/campus/bffs/enrollment/graphql_client/schema.json +++ b/campus/bffs/enrollment/graphql_client/schema.json @@ -381,18 +381,18 @@ "deprecationReason": null }, { - "name": "branch_code", + "name": "parent_organization_id", "args": [], "type": { "kind": "SCALAR", - "name": "String", + "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "current_job", + "name": "branch_code", "args": [], "type": { "kind": "SCALAR", @@ -403,18 +403,18 @@ "deprecationReason": null }, { - "name": "created_by", + "name": "current_job", "args": [], "type": { "kind": "SCALAR", - "name": "Int", + "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "updated_by", + "name": "created_by", "args": [], "type": { "kind": "SCALAR", @@ -425,7 +425,7 @@ "deprecationReason": null }, { - "name": "documents_id", + "name": "updated_by", "args": [], "type": { "kind": "SCALAR", @@ -436,20 +436,12 @@ "deprecationReason": null }, { - "name": "document_list", + "name": "documents_id", "args": [], "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "DocumentsData", - "ofType": null - } - } + "kind": "SCALAR", + "name": "Int", + "ofType": null }, "isDeprecated": false, "deprecationReason": null @@ -3086,6 +3078,39 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "document_list", + "args": [ + { + "name": "id", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "DocumentsData", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "districts", "args": [], @@ -9477,6 +9502,15 @@ }, "defaultValue": null }, + { + "name": "parent_organization_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, { "name": "avinya_type_id", "type": { @@ -9709,23 +9743,6 @@ }, "defaultValue": null }, - { - "name": "documentList", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UserDocument", - "ofType": null - } - } - }, - "defaultValue": null - }, { "name": "created_by", "type": { diff --git a/campus/bffs/profile/api/person_client.bal b/campus/bffs/profile/api/person_client.bal index 548f6dde..f9462733 100644 --- a/campus/bffs/profile/api/person_client.bal +++ b/campus/bffs/profile/api/person_client.bal @@ -27,12 +27,12 @@ public isolated client class GraphqlClient { graphql:Client clientEp = check new (serviceUrl, graphqlClientConfig); self.graphqlClient = clientEp; } - + remote isolated function getPerson(string id) returns GetPersonResponse|graphql:ClientError { - string query = string `query getPerson($id:String!) {person_by_digital_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email permanent_address {city {id name {name_en name_si name_ta}} street_address phone id} mailing_address {city {id name {name_en name_si name_ta}} street_address phone id} phone organization {id description notes address {id} avinya_type {id} phone name {name_en name_si name_ta} child_organizations {id name {name_en} description child_organizations {id name {name_en} description child_organizations {id name {name_en} description people {id digital_id}}}} parent_organizations {id parent_organizations {id}}} avinya_type {id active global_type name foundation_type focus level description} avinya_type_id notes nic_no passport_no id_no email child_students {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id jwt_email permanent_address {id} mailing_address {id} phone organization {id} avinya_type {id} avinya_type_id notes nic_no passport_no id_no email child_students {id} parent_students {id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id} parent_students {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id jwt_email permanent_address {id} mailing_address {id} phone organization {id} avinya_type {id} avinya_type_id notes nic_no passport_no id_no email child_students {id} parent_students {id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id}}`; + string query = string `query getPerson($id:String!) {person_by_digital_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email permanent_address {city {id name {name_en name_si name_ta}} street_address phone id} mailing_address {city {id name {name_en name_si name_ta}} street_address phone id} phone organization {id description notes address {id} avinya_type {id} phone name {name_en name_si name_ta} child_organizations {id name {name_en} description child_organizations {id name {name_en} description child_organizations {id name {name_en} description people {id digital_id}}}} parent_organizations {id parent_organizations {id}}} avinya_type {id active global_type name foundation_type focus level description} avinya_type_id notes nic_no passport_no id_no email child_students {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id jwt_email permanent_address {id} mailing_address {id} phone organization {id} avinya_type {id} avinya_type_id notes nic_no passport_no id_no email child_students {id} parent_students {id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id} parent_students {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id jwt_email permanent_address {id} mailing_address {id} phone organization {id} avinya_type {id} avinya_type_id notes nic_no passport_no id_no email child_students {id} parent_students {id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id current_job documents_id}}`; map variables = {"id": id}; json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); - return check performDataBinding(graphqlResponse, GetPersonResponse); + return check performDataBinding(graphqlResponse, GetPersonResponse); } remote isolated function getOrganization(int id) returns GetOrganizationResponse|graphql:ClientError { diff --git a/campus/bffs/profile/api/types.bal b/campus/bffs/profile/api/types.bal index 0073a653..847424bf 100644 --- a/campus/bffs/profile/api/types.bal +++ b/campus/bffs/profile/api/types.bal @@ -246,10 +246,12 @@ public type Organization record { public type Person record { int? permanent_address_id?; string? street_address?; + string? bank_branch?; string? bank_account_number?; string? notes?; int[]? parent_student?; string? date_of_birth?; + int? parent_organization_id?; int? avinya_type_id?; Address? permanent_address?; int? mailing_address_id?; @@ -262,23 +264,48 @@ public type Person record { string? digital_id?; string? sex?; string? passport_no?; + string? current_job?; + int? created_by?; string? record_type?; Address? mailing_address?; + string? branch_code?; int[]? child_student?; string? bank_account_name?; - string? bank_branch?; int? avinya_phone?; string? full_name?; string? nic_no?; int? phone?; int? organization_id?; + int? updated_by?; + string? academy_org_name?; string? asgardeo_id?; + int? documents_id?; + UserDocument[]? document_list?; string? updated?; string? preferred_name?; string? jwt_sub_id?; int? academy_org_id?; }; +public type UserDocument record { + string? birth_certificate_back_id?; + string? additional_certificate_01_id?; + string? additional_certificate_02_id?; + string? nic_back_id?; + string? document?; + string? additional_certificate_05_id?; + string? additional_certificate_04_id?; + string? additional_certificate_03_id?; + string? record_type?; + string? al_certificate_id?; + string? nic_front_id?; + string? ol_certificate_id?; + string? birth_certificate_front_id?; + int? id?; + string? folder_id?; + string? document_type?; +}; + public type Prospect record { string? street_address?; boolean? contacted?; @@ -391,12 +418,12 @@ public type GetPersonResponse record {| record {| int? id; record {| - string name_en; + string? name_en; string? name_si; string? name_ta; |} name; |} city; - string street_address; + string? street_address; int? phone; int? id; |}? permanent_address; @@ -404,12 +431,12 @@ public type GetPersonResponse record {| record {| int? id; record {| - string name_en; + string? name_en; string? name_si; string? name_ta; |} name; |} city; - string street_address; + string? street_address; int? phone; int? id; |}? mailing_address; @@ -426,26 +453,26 @@ public type GetPersonResponse record {| |}? avinya_type; int? phone; record {| - string name_en; + string? name_en; string? name_si; string? name_ta; |} name; record {| int? id; record {| - string name_en; + string? name_en; |} name; string? description; record {| int? id; record {| - string name_en; + string? name_en; |} name; string? description; record {| int? id; record {| - string name_en; + string? name_en; |} name; string? description; record {| @@ -569,9 +596,10 @@ public type GetPersonResponse record {| string? bank_account_number; string? bank_account_name; int? academy_org_id; + string? current_job; + int? documents_id; |}? person_by_digital_id; |}; - public type GetOrganizationResponse record {| map __extensions?; record {| diff --git a/campus/bffs/profile/graphql_client/graphql_client_cg_src/client.bal b/campus/bffs/profile/graphql_client/graphql_client_cg_src/client.bal index b783683b..d3ca22c9 100644 --- a/campus/bffs/profile/graphql_client/graphql_client_cg_src/client.bal +++ b/campus/bffs/profile/graphql_client/graphql_client_cg_src/client.bal @@ -28,7 +28,7 @@ public isolated client class GraphqlClient { self.graphqlClient = clientEp; } remote isolated function getPerson(string id) returns GetPersonResponse|graphql:ClientError { - string query = string `query getPerson($id:String!) {person_by_digital_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email permanent_address {city {id name {name_en name_si name_ta}} street_address phone id} mailing_address {city {id name {name_en name_si name_ta}} street_address phone id} phone organization {id description notes address {id} avinya_type {id} phone name {name_en name_si name_ta} child_organizations {id name {name_en} description child_organizations {id name {name_en} description child_organizations {id name {name_en} description people {id digital_id}}}} parent_organizations {id parent_organizations {id}}} avinya_type {id active global_type name foundation_type focus level description} avinya_type_id notes nic_no passport_no id_no email child_students {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id jwt_email permanent_address {id} mailing_address {id} phone organization {id} avinya_type {id} avinya_type_id notes nic_no passport_no id_no email child_students {id} parent_students {id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id} parent_students {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id jwt_email permanent_address {id} mailing_address {id} phone organization {id} avinya_type {id} avinya_type_id notes nic_no passport_no id_no email child_students {id} parent_students {id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id}}`; + string query = string `query getPerson($id:String!) {person_by_digital_id(id:$id) {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id created updated jwt_email permanent_address {city {id name {name_en name_si name_ta}} street_address phone id} mailing_address {city {id name {name_en name_si name_ta}} street_address phone id} phone organization {id description notes address {id} avinya_type {id} phone name {name_en name_si name_ta} child_organizations {id name {name_en} description child_organizations {id name {name_en} description child_organizations {id name {name_en} description people {id digital_id}}}} parent_organizations {id parent_organizations {id}}} avinya_type {id active global_type name foundation_type focus level description} avinya_type_id notes nic_no passport_no id_no email child_students {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id jwt_email permanent_address {id} mailing_address {id} phone organization {id} avinya_type {id} avinya_type_id notes nic_no passport_no id_no email child_students {id} parent_students {id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id} parent_students {id preferred_name full_name date_of_birth sex asgardeo_id jwt_sub_id jwt_email permanent_address {id} mailing_address {id} phone organization {id} avinya_type {id} avinya_type_id notes nic_no passport_no id_no email child_students {id} parent_students {id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id} street_address digital_id avinya_phone bank_name bank_account_number bank_account_name academy_org_id current_job documents_id}}`; map variables = {"id": id}; json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, GetPersonResponse); diff --git a/campus/bffs/profile/graphql_client/graphql_client_cg_src/types.bal b/campus/bffs/profile/graphql_client/graphql_client_cg_src/types.bal index 0dcec6be..5e3f74c7 100644 --- a/campus/bffs/profile/graphql_client/graphql_client_cg_src/types.bal +++ b/campus/bffs/profile/graphql_client/graphql_client_cg_src/types.bal @@ -296,6 +296,7 @@ public type Organization record { string? name_si?; int? avinya_type?; string? description?; + int? active?; int[]? child_organizations_for_dashboard?; string? record_type?; int[]? parent_organizations?; @@ -312,6 +313,7 @@ public type Person record { string? notes?; int[]? parent_student?; string? date_of_birth?; + int? parent_organization_id?; int? avinya_type_id?; Address? permanent_address?; int? mailing_address_id?; @@ -339,6 +341,8 @@ public type Person record { int? updated_by?; string? academy_org_name?; string? asgardeo_id?; + int? documents_id?; + UserDocument[]? document_list?; string? updated?; string? preferred_name?; string? jwt_sub_id?; @@ -420,6 +424,25 @@ public type Supply record { int? person_id?; }; +public type UserDocument record { + string? birth_certificate_back_id?; + string? additional_certificate_01_id?; + string? additional_certificate_02_id?; + string? nic_back_id?; + string? document?; + string? additional_certificate_05_id?; + string? additional_certificate_04_id?; + string? additional_certificate_03_id?; + string? record_type?; + string? al_certificate_id?; + string? nic_front_id?; + string? ol_certificate_id?; + string? birth_certificate_front_id?; + int? id?; + string? folder_id?; + string? document_type?; +}; + public type Vacancy record { int? organization_id?; string? name?; @@ -636,6 +659,8 @@ public type GetPersonResponse record {| string? bank_account_number; string? bank_account_name; int? academy_org_id; + string? current_job; + int? documents_id; |}? person_by_digital_id; |}; diff --git a/campus/bffs/profile/graphql_client/person.graphql b/campus/bffs/profile/graphql_client/person.graphql index bc004494..c7ed209f 100644 --- a/campus/bffs/profile/graphql_client/person.graphql +++ b/campus/bffs/profile/graphql_client/person.graphql @@ -1,5 +1,5 @@ -query getPerson($id:String!){ - person_by_digital_id(id:$id) { +query getPerson($id: String!) { + person_by_digital_id(id: $id) { id preferred_name full_name @@ -41,47 +41,47 @@ query getPerson($id:String!){ id description notes - address{ + address { id } - avinya_type{ + avinya_type { id } phone - name{ + name { name_en name_si name_ta } - child_organizations{ + child_organizations { + id + name { + name_en + } + description + child_organizations { id - name{ - name_en + name { + name_en } description child_organizations { + id + name { + name_en + } + description + people { id - name{ - name_en - } - description - child_organizations { - id - name{ - name_en - } - description - people { - id - digital_id - } - } + digital_id + } } + } } - parent_organizations{ + parent_organizations { id - parent_organizations{ - id + parent_organizations { + id } } } @@ -110,17 +110,17 @@ query getPerson($id:String!){ asgardeo_id jwt_sub_id jwt_email - permanent_address{ + permanent_address { id } - mailing_address{ + mailing_address { id } phone - organization{ + organization { id } - avinya_type{ + avinya_type { id } avinya_type_id @@ -129,10 +129,10 @@ query getPerson($id:String!){ passport_no id_no email - child_students{ + child_students { id } - parent_students{ + parent_students { id } street_address @@ -152,17 +152,17 @@ query getPerson($id:String!){ asgardeo_id jwt_sub_id jwt_email - permanent_address{ + permanent_address { id } - mailing_address{ + mailing_address { id } phone - organization{ + organization { id } - avinya_type{ + avinya_type { id } avinya_type_id @@ -171,10 +171,10 @@ query getPerson($id:String!){ passport_no id_no email - child_students{ + child_students { id } - parent_students{ + parent_students { id } street_address @@ -192,6 +192,8 @@ query getPerson($id:String!){ bank_account_number bank_account_name academy_org_id + current_job + documents_id } } diff --git a/campus/bffs/profile/graphql_client/schema.graphql b/campus/bffs/profile/graphql_client/schema.graphql index 6c507b2c..4ca6ac38 100644 --- a/campus/bffs/profile/graphql_client/schema.graphql +++ b/campus/bffs/profile/graphql_client/schema.graphql @@ -310,6 +310,12 @@ type AvinyaTypeData { description: String } +type CalendarMetaData { + id: Int + organization_id: Int + monthly_payment_amount: Decimal +} + input City { record_type: String = "city" id: Int @@ -384,6 +390,24 @@ type DistrictData { cities: [CityData!]! } +type DocumentsData { + id: Int + folder_id: String + nic_front_id: String + nic_back_id: String + birth_certificate_front_id: String + birth_certificate_back_id: String + ol_certificate_id: String + al_certificate_id: String + additional_certificate_01_id: String + additional_certificate_02_id: String + additional_certificate_03_id: String + additional_certificate_04_id: String + additional_certificate_05_id: String + document_type: String + document: String +} + input DutyParticipant { record_type: String = "duty_participant" id: Int @@ -692,6 +716,7 @@ type Mutation { update_consumable_depletion(inventories: [Inventory!]!): [InventoryData!] update_person(person: Person!, permanent_address: Address, permanent_address_city: City, mailing_address: Address, mailing_address_city: City): PersonData insert_person(person: Person!, mailing_address: Address, mailing_address_city: City): PersonData + upload_document(user_document: UserDocument!): DocumentsData add_monthly_leave_dates(monthly_leave_dates: MonthlyLeaveDates!): MonthlyLeaveDatesData update_monthly_leave_dates(monthly_leave_dates: MonthlyLeaveDates!): MonthlyLeaveDatesData } @@ -707,6 +732,7 @@ input Organization { phone: Int description: String notes: String + active: Int name_en: String name_ta: String name_si: String @@ -726,6 +752,7 @@ type OrganizationData { people: [PersonData!] vacancies: [VacancyData!] organization_metadata: [OrganizationMetaData!] + active: Int } type OrganizationMetaData { @@ -753,6 +780,7 @@ input Person { mailing_address_id: Int phone: Int organization_id: Int + parent_organization_id: Int avinya_type_id: Int notes: String nic_no: String @@ -776,6 +804,8 @@ input Person { academy_org_name: String branch_code: String current_job: String + documents_id: Int + document_list: [UserDocument!] created_by: Int updated_by: Int } @@ -813,10 +843,13 @@ type PersonData { bank_account_name: String academy_org_id: Int organization_id: Int + parent_organization_id: Int branch_code: String current_job: String created_by: Int updated_by: Int + documents_id: Int + document_list: [DocumentsData!] } type PlaceData { @@ -885,7 +918,7 @@ type Query { organization_structure(name: String, id: Int): OrganizationStructureData organizations(level: Int!): OrganizationStructureData organization(name: String, id: Int): OrganizationData - organizations_by_avinya_type(avinya_type: Int): [OrganizationData!] + organizations_by_avinya_type(avinya_type: Int, active: Int = 0): [OrganizationData!] student_list_by_parent(id: Int): [PersonData!] person(name: String, id: Int): PersonData person_by_digital_id(id: String): PersonData @@ -960,6 +993,7 @@ type Query { cities(district_id: Int): [CityData!] all_organizations: [OrganizationData!] monthly_leave_dates_record_by_id(organization_id: Int!, year: Int!, month: Int!): MonthlyLeaveDatesData + calendar_metadata_by_org_id(organization_id: Int!): CalendarMetaData } input ResourceAllocation { @@ -1071,6 +1105,25 @@ type TotalActivityParticipantAttendanceCountByDateData { daily_total: Int } +input UserDocument { + record_type: String = "user_document" + id: Int + folder_id: String + nic_front_id: String + nic_back_id: String + birth_certificate_front_id: String + birth_certificate_back_id: String + ol_certificate_id: String + al_certificate_id: String + additional_certificate_01_id: String + additional_certificate_02_id: String + additional_certificate_03_id: String + additional_certificate_04_id: String + additional_certificate_05_id: String + document_type: String + document: String +} + input Vacancy { record_type: String = "vacancy" id: Int diff --git a/campus/bffs/profile/graphql_client/schema.json b/campus/bffs/profile/graphql_client/schema.json index 04fba51b..d5a0f5be 100644 --- a/campus/bffs/profile/graphql_client/schema.json +++ b/campus/bffs/profile/graphql_client/schema.json @@ -380,6 +380,17 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "parent_organization_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "branch_code", "args": [], @@ -423,6 +434,36 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "documents_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "document_list", + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "DocumentsData", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -713,6 +754,15 @@ "ofType": null }, "defaultValue": null + }, + { + "name": "active", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": "0" } ], "type": { @@ -3164,6 +3214,31 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "calendar_metadata_by_org_id", + "args": [ + { + "name": "organization_id", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CalendarMetaData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -5850,6 +5925,17 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "active", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -8911,6 +8997,31 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "upload_document", + "args": [ + { + "name": "user_document", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "UserDocument", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "DocumentsData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "add_monthly_leave_dates", "args": [ @@ -9377,6 +9488,15 @@ }, "defaultValue": null }, + { + "name": "parent_organization_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, { "name": "avinya_type_id", "type": { @@ -9600,6 +9720,32 @@ }, "defaultValue": null }, + { + "name": "documents_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "document_list", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "UserDocument", + "ofType": null + } + } + }, + "defaultValue": null + }, { "name": "created_by", "type": { @@ -10235,6 +10381,15 @@ }, "defaultValue": null }, + { + "name": "active", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, { "name": "name_en", "type": { @@ -10267,6 +10422,160 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "INPUT_OBJECT", + "name": "UserDocument", + "fields": null, + "inputFields": [ + { + "name": "record_type", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": "\"user_document\"" + }, + { + "name": "id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "folder_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "nic_front_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "nic_back_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "birth_certificate_front_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "birth_certificate_back_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "ol_certificate_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "al_certificate_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "additional_certificate_01_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "additional_certificate_02_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "additional_certificate_03_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "additional_certificate_04_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "additional_certificate_05_id", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "document_type", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "document", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "EducationExperience", @@ -10640,6 +10949,181 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "DocumentsData", + "fields": [ + { + "name": "id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "folder_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "nic_front_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "nic_back_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "birth_certificate_front_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "birth_certificate_back_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ol_certificate_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "al_certificate_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "additional_certificate_01_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "additional_certificate_02_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "additional_certificate_03_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "additional_certificate_04_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "additional_certificate_05_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "document_type", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "document", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "Supply", @@ -10831,6 +11315,49 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "CalendarMetaData", + "fields": [ + { + "name": "id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "organization_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "monthly_payment_amount", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Decimal", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "AssetData", diff --git a/campus/frontend/lib/avinya/enrollment/lib/data/person.dart b/campus/frontend/lib/avinya/enrollment/lib/data/person.dart index e8570a7e..2ab23ed3 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/data/person.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/data/person.dart @@ -219,6 +219,27 @@ class Address { }; } +class UserDocument { + int? id; + String? document_type; + String? document; + + UserDocument({this.id, this.document, this.document_type}); + + factory UserDocument.fromJson(Map json) { + return UserDocument( + id: json['id'], + document: json['document'], + document_type: json['document_type']); + } + + Map toJson() => { + if (id != null) 'id': id, + if (document != null) 'document': document, + if (document_type != null) 'document_type': document_type + }; +} + class Person { int? id; String? record_type; @@ -236,6 +257,7 @@ class Person { int? phone; int? organization_id; MainOrganization? organization; + int? parent_organization_id; AvinyaType? avinya_type; String? asgardeo_id; String? jwt_sub_id; @@ -256,6 +278,7 @@ class Person { String? created; String? updated; String? current_job; + int? documents_id; var parent_students = []; Person( @@ -275,6 +298,7 @@ class Person { this.phone, this.organization_id, this.organization, + this.parent_organization_id, this.avinya_type, this.asgardeo_id, this.jwt_sub_id, @@ -295,56 +319,58 @@ class Person { this.created, this.updated, this.parent_students = const [], - this.current_job}); + this.current_job, + this.documents_id}); factory Person.fromJson(Map json) { return Person( - id: json['id'], - record_type: json['record_type'], - preferred_name: json['preferred_name'], - full_name: json['full_name'], - notes: json['notes'], - date_of_birth: json['date_of_birth'], - sex: json['sex'], - avinya_type_id: json['avinya_type_id'], - passport_no: json['passport_no'], - permanent_address_id: json['permanent_address_id'], - mailing_address_id: json['mailing_address_id'], - nic_no: json['nic_no'], - id_no: json['id_no'], - phone: json['phone'], - organization_id: json['organization_id'], - asgardeo_id: json['asgardeo_id'], - jwt_sub_id: json['jwt_sub_id'], - jwt_email: json['jwt_email'], - email: json['email'], - permanent_address: Address.fromJson( - json['permanent_address'] != null ? json['permanent_address'] : {}), - mailing_address: Address.fromJson( - json['mailing_address'] != null ? json['mailing_address'] : {}), - street_address: json['street_address'], - bank_account_number: json['bank_account_number'], - bank_name: json['bank_name'], - bank_branch: json['bank_branch'], - digital_id: json['digital_id'], - guardian_name: json['guardian_name'], - guardian_contact_number: json['guardian_contact_number'], - bank_account_name: json['bank_account_name'], - avinya_phone: json['avinya_phone'], - academy_org_id: json['academy_org_id'], - organization: MainOrganization.fromJson( - json['organization'] != null ? json['organization'] : {}), - avinya_type: AvinyaType.fromJson( - json['avinya_type'] != null ? json['avinya_type'] : {}), - created: json['created'], - updated: json['updated'], - parent_students: json['parent_students'] != null - ? json['parent_students'] - .map((eval_json) => Person.fromJson(eval_json)) - .toList() - : [], - current_job: json['current_job'], - ); + id: json['id'], + record_type: json['record_type'], + preferred_name: json['preferred_name'], + full_name: json['full_name'], + notes: json['notes'], + date_of_birth: json['date_of_birth'], + sex: json['sex'], + avinya_type_id: json['avinya_type_id'], + passport_no: json['passport_no'], + permanent_address_id: json['permanent_address_id'], + mailing_address_id: json['mailing_address_id'], + nic_no: json['nic_no'], + id_no: json['id_no'], + phone: json['phone'], + organization_id: json['organization_id'], + asgardeo_id: json['asgardeo_id'], + jwt_sub_id: json['jwt_sub_id'], + jwt_email: json['jwt_email'], + email: json['email'], + permanent_address: Address.fromJson( + json['permanent_address'] != null ? json['permanent_address'] : {}), + mailing_address: Address.fromJson( + json['mailing_address'] != null ? json['mailing_address'] : {}), + street_address: json['street_address'], + bank_account_number: json['bank_account_number'], + bank_name: json['bank_name'], + bank_branch: json['bank_branch'], + digital_id: json['digital_id'], + guardian_name: json['guardian_name'], + guardian_contact_number: json['guardian_contact_number'], + bank_account_name: json['bank_account_name'], + avinya_phone: json['avinya_phone'], + academy_org_id: json['academy_org_id'], + organization: MainOrganization.fromJson( + json['organization'] != null ? json['organization'] : {}), + parent_organization_id: json['parent_organization_id'], + avinya_type: AvinyaType.fromJson( + json['avinya_type'] != null ? json['avinya_type'] : {}), + created: json['created'], + updated: json['updated'], + parent_students: json['parent_students'] != null + ? json['parent_students'] + .map((eval_json) => Person.fromJson(eval_json)) + .toList() + : [], + current_job: json['current_job'], + documents_id: json['documents_id']); } Map toJson() => { @@ -366,6 +392,8 @@ class Person { if (phone != null) 'phone': phone, if (organization != null) 'organization_id': organization!.id, if (organization_id != null) 'organization_id': organization_id, + if (parent_organization_id != null) + 'parent_organization_id': parent_organization_id, if (asgardeo_id != null) 'asgardeo_id': asgardeo_id, if (jwt_sub_id != null) 'jwt_sub_id': jwt_sub_id, if (jwt_email != null) 'jwt_email': jwt_email, @@ -392,6 +420,7 @@ class Person { if (updated != null) 'updated': updated, // 'parent_students': [parent_students], if (current_job != null) 'current_job': current_job, + if (documents_id != null) 'documents_id': documents_id, }; map(DataRow Function(dynamic evaluation) param0) {} @@ -440,6 +469,29 @@ class Province { }; } +Future?> fetchDocuments(int id) async { + List? userDocuments; + final response = await http.get( + Uri.parse('${AppConfig.campusEnrollmentsBffApiUrl}/document_list/$id'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + ); + if (response.statusCode > 199 && response.statusCode < 300) { + var resultsJson = json.decode(response.body).cast>(); + userDocuments = await resultsJson + .map((json) => UserDocument.fromJson(json)) + .toList(); + return userDocuments; + } else if (response.statusCode >= 500) { + return null; + } else { + throw Exception('Failed to get user documents'); + } +} + Future> fetchPersons( int organization_id, int avinya_type_id) async { final response = await http.get( @@ -453,11 +505,11 @@ Future> fetchPersons( ); if (response.statusCode > 199 && response.statusCode < 300) { var resultsJson = json.decode(response.body).cast>(); - List activityAttendances = + List persons = await resultsJson.map((json) => Person.fromJson(json)).toList(); - return activityAttendances; + return persons; } else { - throw Exception('Failed to get Daily Attendances Summary Data'); + throw Exception('Failed to get persons Data'); } } @@ -507,7 +559,7 @@ Future createPerson(BuildContext context, Person person) async { } } -Future updatePerson(Person person) async { +Future updatePerson(Person person) async { final response = await http.put( Uri.parse(AppConfig.campusEnrollmentsBffApiUrl + '/update_person'), headers: { @@ -517,12 +569,13 @@ Future updatePerson(Person person) async { body: jsonEncode(person.toJson()), ); if (response.statusCode == 200) { + Person updatedPerson = Person.fromJson(json.decode(response.body)); showSuccessToast("Student Profile Successfully Updated!"); - return response; + return updatedPerson; } else { showErrorToast( response.body + " Status code =" + response.statusCode.toString()); - return response; + return person; // throw Exception('Failed to update Person.'); } } diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/file_upload_widget.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/file_upload_widget.dart index 2c019647..49ec050a 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/widgets/file_upload_widget.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/file_upload_widget.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; @@ -6,9 +7,18 @@ import 'package:file_picker/file_picker.dart'; import 'package:gallery/avinya/enrollment/lib/data/person.dart'; class FileUploadWidget extends StatefulWidget { + final int userDocumentId; final String documentType; + final String documentTypeLabel; + String? stringImage; - const FileUploadWidget({Key? key, required this.documentType}) + FileUploadWidget({ + Key? key, + required this.userDocumentId, + required this.documentType, + required this.documentTypeLabel, + this.stringImage + }) : super(key: key); @override @@ -25,20 +35,21 @@ class _FileUploadWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Please upload the required file for "${widget.documentType}".', + 'Please upload the required file for "${widget.documentTypeLabel}".', style: const TextStyle(fontSize: 16.0, fontWeight: FontWeight.w400), ), const SizedBox(height: 20), _buildFileInputField( - label: widget.documentType, - imageBytes: _selectedImageBytes, - fieldKey: widget.documentType, + label: widget.documentTypeLabel, + imageBytes:_selectedImageBytes !=null ? _selectedImageBytes + : widget.stringImage == null ? null: base64Decode(widget.stringImage!), + fieldKey: widget.documentTypeLabel, onTap: () async { final imageBytes = await _pickFile(); if (imageBytes != null) { var documentDetails = { - "id": 14, - "document_type": "additionalCertificate05" + "id": widget.userDocumentId, + "document_type": widget.documentType }; await uploadFile(imageBytes, documentDetails); setState(() { diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart index 6ebc2a27..6e84f312 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_create.dart @@ -21,6 +21,7 @@ class _StudentCreateState extends State { int _currentStep = 0; // Track the current step final GlobalKey _formKey = GlobalKey(); List cityList = []; + late Person createdPerson = Person(); String? selectedSex; int? selectedCityId; @@ -108,6 +109,8 @@ class _StudentCreateState extends State { child: SizedBox( width: 850, child: Stepper( + connectorColor: + MaterialStateProperty.all(Color.fromARGB(255, 74, 161, 70)), type: StepperType.vertical, currentStep: _currentStep, onStepContinue: _nextStep, @@ -429,21 +432,41 @@ class _StudentCreateState extends State { childAspectRatio: 1.5, // Adjust the aspect ratio to take up more space ), - itemCount: 8, + itemCount: 11, itemBuilder: (context, index) { - List documentTypes = [ + List documentTypesLabels = [ 'NIC Front', 'NIC Back', 'Birth Certificate Front', 'Birth Certificate Back', 'O/L Certificate', 'A/L Certificate', - 'Additional Certificate', - 'Another Document' + 'Additional Certificate 01', + 'Additional Certificate 02', + 'Additional Certificate 03', + 'Additional Certificate 04', + 'Additional Certificate 05', + ]; + + List documentTypes = [ + 'nicFront', + 'nicBack', + 'birthCertificateFront', + 'birthCertificateBack', + 'olDocument', + 'alDocument', + 'additionalCertificate01', + 'additionalCertificate02', + 'additionalCertificate03', + 'additionalCertificate04', + 'additionalCertificate05' ]; return FileUploadWidget( + userDocumentId: createdPerson.documents_id ?? 0, + documentTypeLabel: documentTypesLabels[index], documentType: documentTypes[index], + stringImage: null, ); }, ), @@ -460,7 +483,7 @@ class _StudentCreateState extends State { } // Navigate to the next step - void _nextStep() { + void _nextStep() async { bool isEnabled = isDistrictsDataLoaded && isOrganizationsDataLoaded && isAvinyaTypesDataLoaded; @@ -468,16 +491,21 @@ class _StudentCreateState extends State { if (_currentStep == 0 && isEnabled) { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); - createPerson(context, userPerson); - setState(() { - _currentStep += 1; - }); + createdPerson = await createPerson(context, userPerson); + if (createdPerson.id != null) { + setState(() { + _currentStep += 1; + }); + } } - } else if (_currentStep < 1 && isEnabled) { - setState(() { - _currentStep += 1; - }); + } else if (_currentStep == 1) { + Navigator.pop(context); } + // } else if (_currentStep < 1 && isEnabled) { + // setState(() { + // _currentStep += 1; + // }); + // } } // Widget _buildSaveButton(bool isDistrictsDataLoaded, @@ -768,6 +796,7 @@ class _StudentCreateState extends State { setState(() { selectedOrgId = newValue; userPerson.organization?.id = newValue; + userPerson.parent_organization_id = newValue; }); }, decoration: InputDecoration( diff --git a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart index 9aa738de..5bc8ff9a 100644 --- a/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart +++ b/campus/frontend/lib/avinya/enrollment/lib/widgets/student_update.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:gallery/avinya/enrollment/lib/widgets/file_upload_widget.dart'; import 'package:intl/intl.dart'; import 'package:gallery/avinya/enrollment/lib/data/person.dart'; @@ -17,8 +18,11 @@ class _StudentUpdateState extends State { List organizations = []; List avinyaTypes = []; List classes = []; + int _currentStep = 0; // Track the current step final GlobalKey _formKey = GlobalKey(); List cityList = []; + late Person updatedPerson = Person(); + List userDocuments = []; String? selectedSex; int? selectedCityId; @@ -195,198 +199,380 @@ class _StudentUpdateState extends State { Widget build(BuildContext context) { return Scaffold( body: userPerson.preferred_name == null - ? const Center(child: CircularProgressIndicator()) - : SingleChildScrollView( - padding: const EdgeInsets.all(16.0), - child: Center( - child: SizedBox( - width: 800, - child: Form( - key: _formKey, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildProfileHeader(context), - const SizedBox(height: 20), - _buildSectionTitle(context, 'Student Information'), - _buildEditableField( - 'Preferred Name', userPerson.preferred_name, - (value) { - userPerson.preferred_name = value; - }, - validator: (value) => value!.isEmpty - ? 'Preferred name is required' - : null), - _buildEditableField('Full Name', userPerson.full_name, - (value) { - userPerson.full_name = value; - }, - validator: (value) => value!.isEmpty - ? 'Full name is required' - : null), - _buildEditableField('NIC Number', userPerson.nic_no, - (value) { - userPerson.nic_no = value; - }, validator: _validateNIC), - _buildDateOfBirthField(context), - _buildSexField(), - const SizedBox(height: 10), - FutureBuilder>( - future: fetchOrganizationList(), - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.waiting) { - return Container( - margin: EdgeInsets.only(top: 10), - child: SpinKitCircle( - color: (Color.fromARGB(255, 74, 161, 70)), - size: 70, - ), - ); - } else if (snapshot.hasError) { - return const Center( - child: Text('Something went wrong...'), - ); - } else if (!snapshot.hasData) { - return const Center( - child: Text('No organizations found'), - ); - } else if (snapshot.connectionState == - ConnectionState.done && - snapshot.hasData && - snapshot.data!.isNotEmpty) { - WidgetsBinding.instance - .addPostFrameCallback((_) { - if (!isOrganizationsDataLoaded) { - setState(() { - isOrganizationsDataLoaded = true; - print( - "isorgdataload:${isOrganizationsDataLoaded}"); - }); - } - }); - organizations = snapshot.data!; - return _buildOrganizationField(); - } else { - return SizedBox(); - } - }), - // _buildOrganizationField(), - _buildStudentClassField(), // Student Class based on organization.description - const SizedBox(height: 20), - _buildSectionTitle(context, 'Contact Information'), - _buildEditableField('Personal Email', userPerson.email, - (value) { - userPerson.email = value; - }), - _buildEditableField( - 'Phone', userPerson.phone?.toString() ?? '', - (value) { - userPerson.phone = int.tryParse(value); - }, validator: _validatePhone), - _buildEditableField('Street Address', - userPerson.mailing_address?.street_address ?? 'N/A', - (value) { - if (userPerson.mailing_address == null) { - userPerson.mailing_address = - Address(street_address: value); - } else { - userPerson.mailing_address!.street_address = value; - } - }), - FutureBuilder>( - future: fetchDistrictList(), - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.waiting) { - return Container( - margin: EdgeInsets.only(top: 10), - child: SpinKitCircle( - color: (Color.fromARGB(255, 74, 161, 70)), - size: 70, - ), - ); - } else if (snapshot.hasError) { - return const Center( - child: Text('Something went wrong...'), - ); - } else if (!snapshot.hasData) { - return const Center( - child: Text('No districts found'), - ); - } else if (snapshot.connectionState == - ConnectionState.done && - snapshot.hasData) { - WidgetsBinding.instance - .addPostFrameCallback((_) { - if (!isDistrictsDataLoaded) { - setState(() { - isDistrictsDataLoaded = true; - print( - "isDistrictsDataLoaded:${isDistrictsDataLoaded}"); - }); - } - }); - districts = snapshot.data!; - return Column( - children: [ - _buildDistrictField(), - _buildCityField(), - ], - ); - } - - return SizedBox(); - }), - const SizedBox(height: 20), - _buildSectionTitle(context, 'Digital Information'), - _buildEditableField('Digital ID', userPerson.digital_id, - (value) { - userPerson.digital_id = value; - }), - _buildAvinyaTypeField(), - const SizedBox(height: 20), - _buildSectionTitle(context, 'Bank Information'), - _buildEditableField('Bank Name', userPerson.bank_name, - (value) { - userPerson.bank_name = value; - }), - _buildEditableField( - 'Bank Branch', userPerson.bank_branch, (value) { - userPerson.bank_branch = value; - }), - _buildEditableField( - 'Bank Account Name', userPerson.bank_account_name, - (value) { - userPerson.bank_account_name = value; - }), - _buildEditableField( - 'Account Number', userPerson.bank_account_number, - (value) { - userPerson.bank_account_number = value; - }), - const SizedBox(height: 20), - _buildSectionTitle(context, 'Professional Information'), - _buildEditableField( - 'Current Job', userPerson.current_job, (value) { - userPerson.current_job = value; - }), - _buildEditableTextArea('Comments', userPerson.notes, - (value) { - userPerson.notes = value; - }), - const SizedBox(height: 40), - _buildSaveButton( - isDistrictsDataLoaded, isOrganizationsDataLoaded), - ], + ? const Center( + child: SpinKitCircle( + color: (Color.fromARGB(255, 74, 161, 70)), + size: 70, + ), + ) + : Center( + child: SizedBox( + width: 850, + child: Stepper( + connectorColor: MaterialStateProperty.all( + Color.fromARGB(255, 74, 161, 70)), + type: StepperType.vertical, + currentStep: _currentStep, + onStepContinue: _nextStep, + onStepCancel: _previousStep, + steps: [ + Step( + title: Text('Student Information'), + content: SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Center( + child: SizedBox( + width: 800, + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildProfileHeader(context), + const SizedBox(height: 20), + _buildSectionTitle( + context, 'Student Information'), + _buildEditableField('Preferred Name', + userPerson.preferred_name, (value) { + userPerson.preferred_name = value; + }, + validator: (value) => value!.isEmpty + ? 'Preferred name is required' + : null), + _buildEditableField( + 'Full Name', userPerson.full_name, + (value) { + userPerson.full_name = value; + }, + validator: (value) => value!.isEmpty + ? 'Full name is required' + : null), + _buildEditableField( + 'NIC Number', userPerson.nic_no, (value) { + userPerson.nic_no = value; + }, validator: _validateNIC), + _buildDateOfBirthField(context), + _buildSexField(), + const SizedBox(height: 10), + FutureBuilder>( + future: fetchOrganizationList(), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Color.fromARGB( + 255, 74, 161, 70)), + size: 70, + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: + Text('Something went wrong...'), + ); + } else if (!snapshot.hasData) { + return const Center( + child: + Text('No organizations found'), + ); + } else if (snapshot.connectionState == + ConnectionState.done && + snapshot.hasData && + snapshot.data!.isNotEmpty) { + WidgetsBinding.instance + .addPostFrameCallback((_) { + if (!isOrganizationsDataLoaded) { + setState(() { + isOrganizationsDataLoaded = + true; + print( + "isorgdataload:${isOrganizationsDataLoaded}"); + }); + } + }); + organizations = snapshot.data!; + return _buildOrganizationField(); + } else { + return SizedBox(); + } + }), + // _buildOrganizationField(), + _buildStudentClassField(), // Student Class based on organization.description + const SizedBox(height: 20), + _buildSectionTitle( + context, 'Contact Information'), + _buildEditableField( + 'Personal Email', userPerson.email, + (value) { + userPerson.email = value; + }), + _buildEditableField('Phone', + userPerson.phone?.toString() ?? '', + (value) { + userPerson.phone = int.tryParse(value); + }, validator: _validatePhone), + _buildEditableField( + 'Street Address', + userPerson.mailing_address + ?.street_address ?? + 'N/A', (value) { + if (userPerson.mailing_address == null) { + userPerson.mailing_address = + Address(street_address: value); + } else { + userPerson.mailing_address! + .street_address = value; + } + }), + FutureBuilder>( + future: fetchDistrictList(), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Color.fromARGB( + 255, 74, 161, 70)), + size: 70, + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: + Text('Something went wrong...'), + ); + } else if (!snapshot.hasData) { + return const Center( + child: Text('No districts found'), + ); + } else if (snapshot.connectionState == + ConnectionState.done && + snapshot.hasData) { + WidgetsBinding.instance + .addPostFrameCallback((_) { + if (!isDistrictsDataLoaded) { + setState(() { + isDistrictsDataLoaded = true; + print( + "isDistrictsDataLoaded:${isDistrictsDataLoaded}"); + }); + } + }); + districts = snapshot.data!; + return Column( + children: [ + _buildDistrictField(), + _buildCityField(), + ], + ); + } + + return SizedBox(); + }), + const SizedBox(height: 20), + _buildSectionTitle( + context, 'Digital Information'), + _buildEditableField( + 'Digital ID', userPerson.digital_id, + (value) { + userPerson.digital_id = value; + }), + _buildAvinyaTypeField(), + const SizedBox(height: 20), + _buildSectionTitle( + context, 'Bank Information'), + _buildEditableField( + 'Bank Name', userPerson.bank_name, + (value) { + userPerson.bank_name = value; + }), + _buildEditableField( + 'Bank Branch', userPerson.bank_branch, + (value) { + userPerson.bank_branch = value; + }), + _buildEditableField('Bank Account Name', + userPerson.bank_account_name, (value) { + userPerson.bank_account_name = value; + }), + _buildEditableField('Account Number', + userPerson.bank_account_number, (value) { + userPerson.bank_account_number = value; + }), + const SizedBox(height: 20), + _buildSectionTitle( + context, 'Professional Information'), + _buildEditableField( + 'Current Job', userPerson.current_job, + (value) { + userPerson.current_job = value; + }), + _buildEditableTextArea( + 'Comments', userPerson.notes, (value) { + userPerson.notes = value; + }), + const SizedBox(height: 40), + // _buildSaveButton(isDistrictsDataLoaded, + // isOrganizationsDataLoaded), + ], + ), + ), + ), + ), + ), + isActive: _currentStep >= 0, ), - ), + Step( + title: Text('Upload Files'), + content: FutureBuilder?>( + future: fetchDocuments(userPerson.documents_id ?? 0), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Color.fromARGB(255, 74, 161, 70)), + size: 70, + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: Text('Something went wrong...'), + ); + } else if (!snapshot.hasData || + snapshot.data == null) { + return const Center( + child: Text('No user documents found'), + ); + } else if (snapshot.connectionState == + ConnectionState.done && + snapshot.hasData) { + userDocuments = snapshot.data!; + return SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Center( + child: SizedBox( + width: 800, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + // _buildSectionTitle(context, 'File Upload'), + // GridView inside SingleChildScrollView + GridView.builder( + shrinkWrap: + true, // Avoid infinite size issue + physics: + NeverScrollableScrollPhysics(), + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: + 2, // 2 items per row + crossAxisSpacing: 16.0, + mainAxisSpacing: 16.0, + childAspectRatio: + 1.5, // Adjust the aspect ratio to take up more space + ), + itemCount: 11, + itemBuilder: (context, index) { + List documentTypesLabels = [ + 'NIC Front', + 'NIC Back', + 'Birth Certificate Front', + 'Birth Certificate Back', + 'O/L Certificate', + 'A/L Certificate', + 'Additional Certificate 01', + 'Additional Certificate 02', + 'Additional Certificate 03', + 'Additional Certificate 04', + 'Additional Certificate 05' + ]; + + List documentTypes = [ + 'nicFront', + 'nicBack', + 'birthCertificateFront', + 'birthCertificateBack', + 'olDocument', + 'alDocument', + 'additionalCertificate01', + 'additionalCertificate02', + 'additionalCertificate03', + 'additionalCertificate04', + 'additionalCertificate05' + ]; + final filteredDocument = + userDocuments.firstWhere( + (document) => + document + .document_type == + documentTypes[index], + orElse: () => UserDocument( + document: null, + document_type: null)); + return FileUploadWidget( + userDocumentId: + userPerson.documents_id ?? 0, + documentTypeLabel: + documentTypesLabels[index], + documentType: + documentTypes[index], + stringImage: + filteredDocument.document, + ); + }, + ), + ], + ), + ), + ), + ); + } + + return SizedBox(); + }), + isActive: _currentStep >= 1, + ) + ], ), ), ), ); } + // Navigate to the next step + void _nextStep() async { + bool isEnabled = isDistrictsDataLoaded && isOrganizationsDataLoaded; + print('is enabled:${isEnabled}'); + if (_currentStep == 0 && isEnabled) { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + updatedPerson = await updatePerson(userPerson); + if (updatedPerson.id != null) { + setState(() { + _currentStep += 1; + }); + } + } + // } else if (_currentStep < 1 && isEnabled) { + } else if (_currentStep == 1) { + Navigator.pop(context); + } + } + + void _previousStep() { + if (_currentStep > 0) { + setState(() { + _currentStep -= 1; + }); + } + } + Widget _buildProfileHeader(BuildContext context) { String imagePath = selectedSex == 'Male' ? 'assets/images/student_profile_male.jpg' // Replace with the male profile image path