diff --git a/campus/bffs/asset/api/Dependencies.toml b/campus/bffs/asset/api/Dependencies.toml index 2c3c856e..63509364 100644 --- a/campus/bffs/asset/api/Dependencies.toml +++ b/campus/bffs/asset/api/Dependencies.toml @@ -5,6 +5,7 @@ [ballerina] dependencies-toml-version = "2" +distribution-version = "2201.5.0" [[package]] org = "avinyafoundation" @@ -25,20 +26,19 @@ modules = [ [[package]] org = "ballerina" name = "auth" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "crypto"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "lang.string"}, - {org = "ballerina", name = "log"}, - {org = "ballerina", name = "regex"} + {org = "ballerina", name = "log"} ] [[package]] org = "ballerina" name = "cache" -version = "3.3.0" +version = "3.5.0" dependencies = [ {org = "ballerina", name = "constraint"}, {org = "ballerina", name = "jballerina.java"}, @@ -49,7 +49,7 @@ dependencies = [ [[package]] org = "ballerina" name = "constraint" -version = "1.0.2" +version = "1.2.0" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -57,7 +57,7 @@ dependencies = [ [[package]] org = "ballerina" name = "crypto" -version = "2.3.1" +version = "2.3.2" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "time"} @@ -66,20 +66,18 @@ dependencies = [ [[package]] org = "ballerina" name = "file" -version = "1.5.0" +version = "1.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "log"}, {org = "ballerina", name = "os"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] [[package]] org = "ballerina" name = "graphql" -version = "1.5.2" +version = "1.8.1" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "file"}, @@ -92,18 +90,20 @@ dependencies = [ {org = "ballerina", name = "log"}, {org = "ballerina", name = "mime"}, {org = "ballerina", name = "oauth2"}, - {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"}, {org = "ballerina", name = "websocket"} ] modules = [ {org = "ballerina", packageName = "graphql", moduleName = "graphql"}, - {org = "ballerina", packageName = "graphql", moduleName = "graphql.parser"} + {org = "ballerina", packageName = "graphql", moduleName = "graphql.parser"}, + {org = "ballerina", packageName = "graphql", moduleName = "graphql.subgraph"} ] [[package]] org = "ballerina" name = "http" -version = "2.5.3" +version = "2.8.2" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -116,6 +116,7 @@ dependencies = [ {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "lang.decimal"}, {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.regexp"}, {org = "ballerina", name = "lang.runtime"}, {org = "ballerina", name = "lang.string"}, {org = "ballerina", name = "lang.value"}, @@ -123,7 +124,6 @@ dependencies = [ {org = "ballerina", name = "mime"}, {org = "ballerina", name = "oauth2"}, {org = "ballerina", name = "observe"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"}, {org = "ballerina", name = "url"} ] @@ -134,7 +134,7 @@ modules = [ [[package]] org = "ballerina" name = "io" -version = "1.3.1" +version = "1.4.1" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} @@ -151,7 +151,7 @@ version = "0.0.0" [[package]] org = "ballerina" name = "jwt" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "cache"}, {org = "ballerina", name = "crypto"}, @@ -159,7 +159,6 @@ dependencies = [ {org = "ballerina", name = "lang.int"}, {org = "ballerina", name = "lang.string"}, {org = "ballerina", name = "log"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] @@ -194,7 +193,9 @@ org = "ballerina" name = "lang.int" version = "0.0.0" dependencies = [ - {org = "ballerina", name = "jballerina.java"} + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"}, + {org = "ballerina", name = "lang.object"} ] [[package]] @@ -238,7 +239,7 @@ dependencies = [ [[package]] org = "ballerina" name = "log" -version = "2.5.1" +version = "2.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, @@ -252,7 +253,7 @@ modules = [ [[package]] org = "ballerina" name = "mime" -version = "2.5.1" +version = "2.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, @@ -262,19 +263,20 @@ dependencies = [ [[package]] org = "ballerina" name = "oauth2" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "cache"}, {org = "ballerina", name = "crypto"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "log"}, - {org = "ballerina", name = "time"} + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} ] [[package]] org = "ballerina" name = "observe" -version = "1.0.6" +version = "1.0.7" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -282,21 +284,12 @@ dependencies = [ [[package]] org = "ballerina" name = "os" -version = "1.5.0" +version = "1.6.0" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"} ] -[[package]] -org = "ballerina" -name = "regex" -version = "1.3.2" -dependencies = [ - {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "lang.string"} -] - [[package]] org = "ballerina" name = "task" @@ -337,7 +330,7 @@ dependencies = [ [[package]] org = "ballerina" name = "websocket" -version = "2.5.1" +version = "2.8.1" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "constraint"}, @@ -351,7 +344,6 @@ dependencies = [ {org = "ballerina", name = "lang.value"}, {org = "ballerina", name = "log"}, {org = "ballerina", name = "oauth2"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] @@ -367,4 +359,3 @@ modules = [ {org = "ballerinai", packageName = "observe", moduleName = "observe"} ] - diff --git a/campus/bffs/attendance/api/Dependencies.toml b/campus/bffs/attendance/api/Dependencies.toml index 0cfde532..9c0e4731 100644 --- a/campus/bffs/attendance/api/Dependencies.toml +++ b/campus/bffs/attendance/api/Dependencies.toml @@ -5,6 +5,7 @@ [ballerina] dependencies-toml-version = "2" +distribution-version = "2201.5.0" [[package]] org = "avinyafoundation" @@ -25,20 +26,19 @@ modules = [ [[package]] org = "ballerina" name = "auth" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "crypto"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "lang.string"}, - {org = "ballerina", name = "log"}, - {org = "ballerina", name = "regex"} + {org = "ballerina", name = "log"} ] [[package]] org = "ballerina" name = "cache" -version = "3.3.0" +version = "3.5.0" dependencies = [ {org = "ballerina", name = "constraint"}, {org = "ballerina", name = "jballerina.java"}, @@ -49,7 +49,7 @@ dependencies = [ [[package]] org = "ballerina" name = "constraint" -version = "1.0.2" +version = "1.2.0" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -66,20 +66,18 @@ dependencies = [ [[package]] org = "ballerina" name = "file" -version = "1.5.0" +version = "1.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "log"}, {org = "ballerina", name = "os"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] [[package]] org = "ballerina" name = "graphql" -version = "1.5.2" +version = "1.8.1" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "file"}, @@ -92,18 +90,20 @@ dependencies = [ {org = "ballerina", name = "log"}, {org = "ballerina", name = "mime"}, {org = "ballerina", name = "oauth2"}, - {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"}, {org = "ballerina", name = "websocket"} ] modules = [ {org = "ballerina", packageName = "graphql", moduleName = "graphql"}, - {org = "ballerina", packageName = "graphql", moduleName = "graphql.parser"} + {org = "ballerina", packageName = "graphql", moduleName = "graphql.parser"}, + {org = "ballerina", packageName = "graphql", moduleName = "graphql.subgraph"} ] [[package]] org = "ballerina" name = "http" -version = "2.5.3" +version = "2.8.3" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -116,6 +116,7 @@ dependencies = [ {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "lang.decimal"}, {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.regexp"}, {org = "ballerina", name = "lang.runtime"}, {org = "ballerina", name = "lang.string"}, {org = "ballerina", name = "lang.value"}, @@ -123,7 +124,6 @@ dependencies = [ {org = "ballerina", name = "mime"}, {org = "ballerina", name = "oauth2"}, {org = "ballerina", name = "observe"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"}, {org = "ballerina", name = "url"} ] @@ -134,7 +134,7 @@ modules = [ [[package]] org = "ballerina" name = "io" -version = "1.3.1" +version = "1.4.1" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} @@ -151,7 +151,7 @@ version = "0.0.0" [[package]] org = "ballerina" name = "jwt" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "cache"}, {org = "ballerina", name = "crypto"}, @@ -159,7 +159,6 @@ dependencies = [ {org = "ballerina", name = "lang.int"}, {org = "ballerina", name = "lang.string"}, {org = "ballerina", name = "log"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] @@ -194,7 +193,9 @@ org = "ballerina" name = "lang.int" version = "0.0.0" dependencies = [ - {org = "ballerina", name = "jballerina.java"} + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"}, + {org = "ballerina", name = "lang.object"} ] [[package]] @@ -238,7 +239,7 @@ dependencies = [ [[package]] org = "ballerina" name = "log" -version = "2.5.1" +version = "2.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, @@ -252,7 +253,7 @@ modules = [ [[package]] org = "ballerina" name = "mime" -version = "2.5.1" +version = "2.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, @@ -262,19 +263,20 @@ dependencies = [ [[package]] org = "ballerina" name = "oauth2" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "cache"}, {org = "ballerina", name = "crypto"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "log"}, - {org = "ballerina", name = "time"} + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} ] [[package]] org = "ballerina" name = "observe" -version = "1.0.6" +version = "1.0.7" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -282,21 +284,12 @@ dependencies = [ [[package]] org = "ballerina" name = "os" -version = "1.5.0" +version = "1.6.0" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"} ] -[[package]] -org = "ballerina" -name = "regex" -version = "1.3.2" -dependencies = [ - {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "lang.string"} -] - [[package]] org = "ballerina" name = "task" @@ -337,7 +330,7 @@ dependencies = [ [[package]] org = "ballerina" name = "websocket" -version = "2.5.1" +version = "2.8.2" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "constraint"}, @@ -351,7 +344,6 @@ dependencies = [ {org = "ballerina", name = "lang.value"}, {org = "ballerina", name = "log"}, {org = "ballerina", name = "oauth2"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] @@ -367,4 +359,3 @@ modules = [ {org = "ballerinai", packageName = "observe", moduleName = "observe"} ] - diff --git a/campus/bffs/attendance/api/attendance_client.bal b/campus/bffs/attendance/api/attendance_client.bal index 13790736..b3b74129 100644 --- a/campus/bffs/attendance/api/attendance_client.bal +++ b/campus/bffs/attendance/api/attendance_client.bal @@ -175,4 +175,73 @@ public isolated client class GraphqlClient { json|error row_count = check responseData.delete_evaluation; return row_count; } + + remote isolated function getDutyParticipants(int organization_id) returns GetDutyParticipantsResponse|graphql:ClientError { + string query = string `query getDutyParticipants($organization_id:Int!) {duty_participants(organization_id:$organization_id) {id activity {id name description} person {id preferred_name digital_id organization {name {name_en} description}} role}}`; + map variables = {"organization_id": organization_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetDutyParticipantsResponse); + } + remote isolated function createDutyForParticipant(DutyParticipant dutyparticipant) returns CreateDutyForParticipantResponse|graphql:ClientError { + string query = string `mutation createDutyForParticipant($dutyparticipant:DutyParticipant!) {add_duty_for_participant(dutyparticipant:$dutyparticipant) {id activity_id person_id role created}}`; + map variables = {"dutyparticipant": dutyparticipant}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, CreateDutyForParticipantResponse); + } + remote isolated function getActivitiesByAvinyaType(int avinya_type_id) returns GetActivitiesByAvinyaTypeResponse|graphql:ClientError { + string query = string `query getActivitiesByAvinyaType($avinya_type_id:Int!) {activities_by_avinya_type(avinya_type_id:$avinya_type_id) {id name description notes}}`; + map variables = {"avinya_type_id": avinya_type_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetActivitiesByAvinyaTypeResponse); + } + remote isolated function updateDutyRotationMetaData(DutyRotationMetaDetails dutyRotation) returns UpdateDutyRotationMetaDataResponse|graphql:ClientError { + string query = string `mutation updateDutyRotationMetaData($dutyRotation:DutyRotationMetaDetails!) {update_duty_rotation_metadata(duty_rotation:$dutyRotation) {id start_date end_date organization_id}}`; + map variables = {"dutyRotation": dutyRotation}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, UpdateDutyRotationMetaDataResponse); + } + + remote isolated function deleteDutyForParticipant(int id) returns json|error { + string query = string `mutation deleteDutyForParticipant($id: Int!) {delete_duty_for_participant(id:$id)}`; + map variables = {"id": id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + map responseMap = >graphqlResponse; + json responseData = responseMap.get("data"); + json|error row_count = check responseData.delete_duty_for_participant; + return row_count; + } + + remote isolated function getDutyRotationMetadataByOrganization(int organization_id) returns GetDutyRotationMetadataByOrganizationResponse|graphql:ClientError { + string query = string `query getDutyRotationMetadataByOrganization($organization_id:Int!) {duty_rotation_metadata_by_organization(organization_id:$organization_id) {id start_date end_date organization_id}}`; + map variables = {"organization_id": organization_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetDutyRotationMetadataByOrganizationResponse); + } + + remote isolated function getDutyParticipantsByDutyActivityId(int organization_id, int duty_activity_id) returns GetDutyParticipantsByDutyActivityIdResponse|graphql:ClientError { + string query = string `query getDutyParticipantsByDutyActivityId($organization_id:Int!,$duty_activity_id:Int!) {duty_participants_by_duty_activity_id(organization_id:$organization_id,duty_activity_id:$duty_activity_id) {id activity {id name description} person {id preferred_name digital_id organization {name {name_en} description}} role}}`; + map variables = {"organization_id": organization_id, "duty_activity_id": duty_activity_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetDutyParticipantsByDutyActivityIdResponse); + } + remote isolated function addDutyAttendance(ActivityParticipantAttendance duty_attendance) returns AddDutyAttendanceResponse|graphql:ClientError { + string query = string `mutation addDutyAttendance($duty_attendance:ActivityParticipantAttendance!) {add_duty_attendance(duty_attendance:$duty_attendance) {id activity_instance_id person_id sign_in_time in_marked_by created}}`; + map variables = {"duty_attendance": duty_attendance}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, AddDutyAttendanceResponse); + } + + remote isolated function getDutyAttendanceToday(int organization_id, int activity_id) returns GetDutyAttendanceTodayResponse|graphql:ClientError { + string query = string `query getDutyAttendanceToday($organization_id:Int!,$activity_id:Int!) {duty_attendance_today(organization_id:$organization_id,activity_id:$activity_id) {id person_id activity_instance_id sign_in_time in_marked_by created}}`; + map variables = {"organization_id": organization_id, "activity_id": activity_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetDutyAttendanceTodayResponse); + } + + remote isolated function getDutyParticipant(int person_id) returns GetDutyParticipantResponse|graphql:ClientError { + string query = string `query getDutyParticipant($person_id:Int!) {duty_participant(person_id:$person_id) {id activity {id name description} person {id preferred_name digital_id organization {name {name_en} description}} role}}`; + map variables = {"person_id": person_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetDutyParticipantResponse); + } } diff --git a/campus/bffs/attendance/api/service.bal b/campus/bffs/attendance/api/service.bal index d9d73ca1..0d5353e4 100644 --- a/campus/bffs/attendance/api/service.bal +++ b/campus/bffs/attendance/api/service.bal @@ -446,5 +446,200 @@ service / on new http:Listener(9091) { ":: Detail: " + getActivityInstanceEvaluationsResponse.detail().toString()); } } + + resource function get duty_participants/[int organization_id]() returns DutyParticipant[]|error { + GetDutyParticipantsResponse|graphql:ClientError getDutyParticipantsResponse = globalDataClient->getDutyParticipants(organization_id); + if(getDutyParticipantsResponse is GetDutyParticipantsResponse) { + DutyParticipant[] dutyParticipants = []; + foreach var duty_participant in getDutyParticipantsResponse.duty_participants { + DutyParticipant|error dutyParticipant = duty_participant.cloneWithType(DutyParticipant); + if(dutyParticipant is DutyParticipant) { + dutyParticipants.push(dutyParticipant); + } else { + log:printError("Error while processing Application record received",dutyParticipant); + return error("Error while processing Application record received: " + dutyParticipant.message() + + ":: Detail: " + dutyParticipant.detail().toString()); + } + } + + return dutyParticipants; + + } else { + log:printError("Error while getting application", getDutyParticipantsResponse ); + return error("Error while getting application: " + getDutyParticipantsResponse .message() + + ":: Detail: " + getDutyParticipantsResponse.detail().toString()); + } + } + + resource function post duty_for_participant (@http:Payload DutyParticipant dutyParticipant) returns DutyParticipant|error { + CreateDutyForParticipantResponse|graphql:ClientError createDutyForParticipantResponse = globalDataClient->createDutyForParticipant(dutyParticipant); + if(createDutyForParticipantResponse is CreateDutyForParticipantResponse) { + DutyParticipant|error duty_for_participant_record = createDutyForParticipantResponse.add_duty_for_participant.cloneWithType(DutyParticipant); + if(duty_for_participant_record is DutyParticipant) { + return duty_for_participant_record; + } else { + log:printError("Error while processing Application record received", duty_for_participant_record); + return error("Error while processing Application record received: " + duty_for_participant_record.message() + + ":: Detail: " + duty_for_participant_record.detail().toString()); + } + } else { + log:printError("Error while creating application", createDutyForParticipantResponse); + return error("Error while creating application: " + createDutyForParticipantResponse.message() + + ":: Detail: " + createDutyForParticipantResponse.detail().toString()); + } + } + + resource function get activities_by_avinya_type/[int avinya_type_id]() returns Activity[]|error { + GetActivitiesByAvinyaTypeResponse|graphql:ClientError getActivitiesByAvinyaTypeResponse = globalDataClient->getActivitiesByAvinyaType(avinya_type_id); + if(getActivitiesByAvinyaTypeResponse is GetActivitiesByAvinyaTypeResponse) { + Activity[] activitiesByAvinyaType = []; + foreach var activity_by_avinya_type in getActivitiesByAvinyaTypeResponse.activities_by_avinya_type { + Activity|error activityByAvinyaType = activity_by_avinya_type.cloneWithType(Activity); + if(activityByAvinyaType is Activity) { + activitiesByAvinyaType.push(activityByAvinyaType); + } else { + log:printError("Error while processing Application record received",activityByAvinyaType); + return error("Error while processing Application record received: " + activityByAvinyaType.message() + + ":: Detail: " + activityByAvinyaType.detail().toString()); + } + } + + return activitiesByAvinyaType; + + } else { + log:printError("Error while getting application", getActivitiesByAvinyaTypeResponse ); + return error("Error while getting application: " + getActivitiesByAvinyaTypeResponse .message() + + ":: Detail: " + getActivitiesByAvinyaTypeResponse.detail().toString()); + } + } + + resource function delete duty_for_participant/[int id]() returns json|error { + json|error delete_count = globalDataClient->deleteDutyForParticipant(id); + return delete_count; + } + + + resource function put update_duty_rotation_metadata(@http:Payload DutyRotationMetaDetails dutyRotationMetadata) returns DutyRotationMetaDetails|error { + UpdateDutyRotationMetaDataResponse|graphql:ClientError updateDutyRotationMetaDataResponse = globalDataClient->updateDutyRotationMetaData(dutyRotationMetadata); + if(updateDutyRotationMetaDataResponse is UpdateDutyRotationMetaDataResponse) { + DutyRotationMetaDetails|error duty_rotation__meta_data_record = updateDutyRotationMetaDataResponse.update_duty_rotation_metadata.cloneWithType(DutyRotationMetaDetails); + if(duty_rotation__meta_data_record is DutyRotationMetaDetails) { + return duty_rotation__meta_data_record; + } else { + log:printError("Error while processing Application record received", duty_rotation__meta_data_record); + return error("Error while processing Application record received: " + duty_rotation__meta_data_record.message() + + ":: Detail: " + duty_rotation__meta_data_record.detail().toString()); + } + } else { + log:printError("Error while updating application", updateDutyRotationMetaDataResponse); + return error("Error while updating application: " + updateDutyRotationMetaDataResponse.message() + + ":: Detail: " + updateDutyRotationMetaDataResponse.detail().toString()); + } + } + + resource function get duty_rotation_metadata_by_organization/[int organization_id]() returns DutyRotationMetaDetails|error { + GetDutyRotationMetadataByOrganizationResponse|graphql:ClientError getDutyRotationMetadataByOrganizationResponse = globalDataClient->getDutyRotationMetadataByOrganization(organization_id); + if(getDutyRotationMetadataByOrganizationResponse is GetDutyRotationMetadataByOrganizationResponse) { + DutyRotationMetaDetails|error duty_rotation_metadata_by_organization_record = getDutyRotationMetadataByOrganizationResponse.duty_rotation_metadata_by_organization.cloneWithType(DutyRotationMetaDetails); + if(duty_rotation_metadata_by_organization_record is DutyRotationMetaDetails) { + return duty_rotation_metadata_by_organization_record; + } else { + log:printError("Error while processing Application record received", duty_rotation_metadata_by_organization_record); + return error("Error while processing Application record received: " + duty_rotation_metadata_by_organization_record.message() + + ":: Detail: " + duty_rotation_metadata_by_organization_record.detail().toString()); + } + + }else if(getDutyRotationMetadataByOrganizationResponse is graphql:ClientError){ + + DutyRotationMetaDetails duty ={ end_date: (),start_date: (),organization_id:(),id:()}; + + return duty; + } + } + + resource function get duty_participants_by_duty_activity_id/[int organization_id]/[int duty_activity_id]() returns DutyParticipant[]|error { + GetDutyParticipantsByDutyActivityIdResponse|graphql:ClientError getDutyParticipantsByDutyActivityIdResponse = globalDataClient->getDutyParticipantsByDutyActivityId(organization_id, duty_activity_id); + if(getDutyParticipantsByDutyActivityIdResponse is GetDutyParticipantsByDutyActivityIdResponse) { + DutyParticipant[] dutyParticipants = []; + foreach var duty_participant_by_duty_activity_id in getDutyParticipantsByDutyActivityIdResponse.duty_participants_by_duty_activity_id { + DutyParticipant|error dutyParticipantByDutyActivityId = duty_participant_by_duty_activity_id.cloneWithType(DutyParticipant); + if(dutyParticipantByDutyActivityId is DutyParticipant) { + dutyParticipants.push(dutyParticipantByDutyActivityId); + } else { + log:printError("Error while processing Application record received",dutyParticipantByDutyActivityId); + return error("Error while processing Application record received: " + dutyParticipantByDutyActivityId.message() + + ":: Detail: " + dutyParticipantByDutyActivityId.detail().toString()); + } + } + + return dutyParticipants; + + } else { + log:printError("Error while getting application", getDutyParticipantsByDutyActivityIdResponse ); + return error("Error while getting application: " + getDutyParticipantsByDutyActivityIdResponse .message() + + ":: Detail: " + getDutyParticipantsByDutyActivityIdResponse.detail().toString()); + } + } + + resource function post duty_attendance (@http:Payload ActivityParticipantAttendance dutyAttendance) returns ActivityParticipantAttendance|error { + AddDutyAttendanceResponse|graphql:ClientError addDutyAttendanceResponse = globalDataClient->addDutyAttendance(dutyAttendance); + if(addDutyAttendanceResponse is AddDutyAttendanceResponse) { + ActivityParticipantAttendance|error duty_attendance_record = addDutyAttendanceResponse.add_duty_attendance.cloneWithType(ActivityParticipantAttendance); + if(duty_attendance_record is ActivityParticipantAttendance) { + return duty_attendance_record; + } else { + log:printError("Error while processing Application record received", duty_attendance_record); + return error("Error while processing Application record received: " + duty_attendance_record.message() + + ":: Detail: " + duty_attendance_record.detail().toString()); + } + } else { + log:printError("Error while creating application", addDutyAttendanceResponse); + return error("Error while creating application: " + addDutyAttendanceResponse.message() + + ":: Detail: " + addDutyAttendanceResponse.detail().toString()); + } + } + + resource function get duty_attendance_today/[int organization_id]/[int activity_id]() returns ActivityParticipantAttendance[]|error { + GetDutyAttendanceTodayResponse|graphql:ClientError getDutyAttendanceTodayResponse = globalDataClient->getDutyAttendanceToday(organization_id, activity_id); + if(getDutyAttendanceTodayResponse is GetDutyAttendanceTodayResponse) { + ActivityParticipantAttendance[] dutyParticipantAttendances = []; + foreach var duty_attendance_record in getDutyAttendanceTodayResponse.duty_attendance_today { + ActivityParticipantAttendance|error dutyParticipantAttendance = duty_attendance_record.cloneWithType(ActivityParticipantAttendance); + if(dutyParticipantAttendance is ActivityParticipantAttendance) { + dutyParticipantAttendances.push(dutyParticipantAttendance); + } else { + log:printError("Error while processing Application record received", dutyParticipantAttendance); + return error("Error while processing Application record received: " + dutyParticipantAttendance.message() + + ":: Detail: " + dutyParticipantAttendance.detail().toString()); + } + } + + return dutyParticipantAttendances; + + } else { + log:printError("Error while creating application", getDutyAttendanceTodayResponse); + return error("Error while creating application: " + getDutyAttendanceTodayResponse.message() + + ":: Detail: " + getDutyAttendanceTodayResponse.detail().toString()); + } + } + + resource function get duty_participant/[int person_id]() returns DutyParticipant|error { + GetDutyParticipantResponse|graphql:ClientError getDutyParticipantResponse = globalDataClient->getDutyParticipant(person_id); + if(getDutyParticipantResponse is GetDutyParticipantResponse) { + DutyParticipant|error duty_participant_record = getDutyParticipantResponse.duty_participant.cloneWithType(DutyParticipant); + if(duty_participant_record is DutyParticipant) { + return duty_participant_record; + } else { + log:printError("Error while processing Application record received",duty_participant_record); + return error("Error while processing Application record received: " + duty_participant_record.message() + + ":: Detail: " + duty_participant_record.detail().toString()); + } + }else if(getDutyParticipantResponse is graphql:ClientError){ + + DutyParticipant dutyParticipant ={ role: (),activity: (),person:(),id:()}; + + return dutyParticipant; + } + } } diff --git a/campus/bffs/attendance/api/types.bal b/campus/bffs/attendance/api/types.bal index 0fcb22aa..ddc3db83 100644 --- a/campus/bffs/attendance/api/types.bal +++ b/campus/bffs/attendance/api/types.bal @@ -185,6 +185,7 @@ public type Person record { string? passport_no?; string? record_type?; Address? mailing_address?; + string? branch_code?; int[]? child_student?; string? bank_account_name?; int? avinya_phone?; @@ -192,6 +193,7 @@ public type Person record { string? nic_no?; int? phone?; int? organization_id?; + string? academy_org_name?; string? asgardeo_id?; string? updated?; string? preferred_name?; @@ -231,6 +233,26 @@ public type Vacancy record { string? record_type?; }; +public type DutyParticipant record { + string? role?; + Activity? activity?; + Person? person?; + string? created?; + int? activity_id?; + int? id?; + string? updated?; + string? record_type?; + int? person_id?; +}; + +public type DutyRotationMetaDetails record { + string? end_date?; + int? organization_id?; + int? id?; + string? record_type?; + string? start_date?; +}; + public type GetAvinyaTypesResponse record {| map __extensions?; record {| @@ -505,4 +527,141 @@ public type UpdateEvaluationsResponse record {| int? activity_instance_id; string? updated; |}? update_evaluation; +|}; + +public type GetDutyParticipantsResponse record {| + map __extensions?; + record {| + int? id; + record {| + int? id; + string? name; + string? description; + |}? activity; + record {| + int? id; + string? preferred_name; + string? digital_id; + record {| + record {| + string name_en; + |} name; + string? description; + |}? organization; + |}? person; + string? role; + |}[] duty_participants; +|}; + +public type CreateDutyForParticipantResponse record {| + map __extensions?; + record {| + int? id; + int? activity_id; + int? person_id; + string? role; + string? created; + |}? add_duty_for_participant; +|}; + +public type GetActivitiesByAvinyaTypeResponse record {| + map __extensions?; + record {| + int? id; + string? name; + string? description; + string? notes; + |}[] activities_by_avinya_type; +|}; + +public type UpdateDutyRotationMetaDataResponse record {| + map __extensions?; + record {| + int? id; + string? start_date; + string? end_date; + int? organization_id; + |}? update_duty_rotation_metadata; +|}; + +public type GetDutyRotationMetadataByOrganizationResponse record {| + map __extensions?; + record {| + int? id; + string? start_date; + string? end_date; + int? organization_id; + |}? duty_rotation_metadata_by_organization; +|}; + +public type GetDutyParticipantsByDutyActivityIdResponse record {| + map __extensions?; + record {| + int? id; + record {| + int? id; + string? name; + string? description; + |}? activity; + record {| + int? id; + string? preferred_name; + string? digital_id; + record {| + record {| + string name_en; + |} name; + string? description; + |}? organization; + |}? person; + string? role; + |}[] duty_participants_by_duty_activity_id; +|}; + +public type AddDutyAttendanceResponse record {| + map __extensions?; + record {| + int? id; + int? activity_instance_id; + int? person_id; + string? sign_in_time; + string? in_marked_by; + string? created; + |}? add_duty_attendance; +|}; + +public type GetDutyAttendanceTodayResponse record {| + map __extensions?; + record {| + int? id; + int? person_id; + int? activity_instance_id; + string? sign_in_time; + string? in_marked_by; + string? created; + |}[] duty_attendance_today; +|}; + +public type GetDutyParticipantResponse record {| + map __extensions?; + record {| + int? id; + record {| + int? id; + string? name; + string? description; + |}? activity; + record {| + int? id; + string? preferred_name; + string? digital_id; + record {| + record {| + string name_en; + |} name; + string? description; + |}? organization; + |}? person; + string? role; + |}? duty_participant; |}; \ No newline at end of file diff --git a/campus/bffs/attendance/graphql_client/activity.graphql b/campus/bffs/attendance/graphql_client/activity.graphql index 9fb1dbb9..e52d39f6 100644 --- a/campus/bffs/attendance/graphql_client/activity.graphql +++ b/campus/bffs/attendance/graphql_client/activity.graphql @@ -182,3 +182,134 @@ mutation updateEvaluations($evaluation: Evaluation!) updated } } + +query getDutyParticipants($organization_id: Int!) { + duty_participants(organization_id:$organization_id) { + id + activity{ + id + name + description + } + person{ + id + preferred_name + digital_id + organization{ + name{ + name_en + } + description + } + } + role + } +} + +mutation createDutyForParticipant($dutyparticipant: DutyParticipant!) +{ + add_duty_for_participant(dutyparticipant:$dutyparticipant){ + id + activity_id + person_id + role + created + } +} + +query getActivitiesByAvinyaType($avinya_type_id: Int!) { + activities_by_avinya_type(avinya_type_id:$avinya_type_id){ + id + name + description + notes + } +} + +mutation updateDutyRotationMetaData($dutyRotation:DutyRotationMetaDetails!) +{ + update_duty_rotation_metadata(duty_rotation:$dutyRotation){ + id + start_date + end_date + organization_id + } +} + +query getDutyRotationMetadataByOrganization($organization_id: Int!){ + duty_rotation_metadata_by_organization(organization_id: $organization_id){ + id + start_date + end_date + organization_id + } +} + +query getDutyParticipantsByDutyActivityId($organization_id: Int!, $duty_activity_id: Int!) { + duty_participants_by_duty_activity_id(organization_id:$organization_id, duty_activity_id:$duty_activity_id) { + id + activity{ + id + name + description + } + person{ + id + preferred_name + digital_id + organization{ + name{ + name_en + } + description + } + } + role + } +} + +mutation addDutyAttendance($duty_attendance: ActivityParticipantAttendance!) +{ + add_duty_attendance(duty_attendance:$duty_attendance){ + id + activity_instance_id + person_id + sign_in_time + in_marked_by + created + } +} + +query getDutyAttendanceToday($organization_id: Int!, $activity_id: Int!) { + duty_attendance_today(organization_id:$organization_id, activity_id: $activity_id) { + id + person_id + activity_instance_id + sign_in_time + in_marked_by + created + } +} + +query getDutyParticipant($person_id: Int!) { + duty_participant(person_id:$person_id) { + id + activity{ + id + name + description + } + person{ + id + preferred_name + digital_id + organization{ + name{ + name_en + } + description + } + } + role + } +} \ No newline at end of file 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 bce895f5..8d502ef5 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 @@ -105,4 +105,58 @@ public isolated client class GraphqlClient { json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, UpdateEvaluationsResponse); } + remote isolated function getDutyParticipants(int organization_id) returns GetDutyParticipantsResponse|graphql:ClientError { + string query = string `query getDutyParticipants($organization_id:Int!) {duty_participants(organization_id:$organization_id) {id activity {id name description} person {id preferred_name digital_id organization {name {name_en} description}} role}}`; + map variables = {"organization_id": organization_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetDutyParticipantsResponse); + } + remote isolated function createDutyForParticipant(DutyParticipant dutyparticipant) returns CreateDutyForParticipantResponse|graphql:ClientError { + string query = string `mutation createDutyForParticipant($dutyparticipant:DutyParticipant!) {add_duty_for_participant(dutyparticipant:$dutyparticipant) {id activity_id person_id role created}}`; + map variables = {"dutyparticipant": dutyparticipant}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, CreateDutyForParticipantResponse); + } + remote isolated function getActivitiesByAvinyaType(int avinya_type_id) returns GetActivitiesByAvinyaTypeResponse|graphql:ClientError { + string query = string `query getActivitiesByAvinyaType($avinya_type_id:Int!) {activities_by_avinya_type(avinya_type_id:$avinya_type_id) {id name description notes}}`; + map variables = {"avinya_type_id": avinya_type_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetActivitiesByAvinyaTypeResponse); + } + remote isolated function updateDutyRotationMetaData(DutyRotationMetaDetails dutyRotation) returns UpdateDutyRotationMetaDataResponse|graphql:ClientError { + string query = string `mutation updateDutyRotationMetaData($dutyRotation:DutyRotationMetaDetails!) {update_duty_rotation_metadata(duty_rotation:$dutyRotation) {id start_date end_date organization_id}}`; + map variables = {"dutyRotation": dutyRotation}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, UpdateDutyRotationMetaDataResponse); + } + remote isolated function getDutyRotationMetadataByOrganization(int organization_id) returns GetDutyRotationMetadataByOrganizationResponse|graphql:ClientError { + string query = string `query getDutyRotationMetadataByOrganization($organization_id:Int!) {duty_rotation_metadata_by_organization(organization_id:$organization_id) {id start_date end_date organization_id}}`; + map variables = {"organization_id": organization_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetDutyRotationMetadataByOrganizationResponse); + } + remote isolated function getDutyParticipantsByDutyActivityId(int organization_id, int duty_activity_id) returns GetDutyParticipantsByDutyActivityIdResponse|graphql:ClientError { + string query = string `query getDutyParticipantsByDutyActivityId($organization_id:Int!,$duty_activity_id:Int!) {duty_participants_by_duty_activity_id(organization_id:$organization_id,duty_activity_id:$duty_activity_id) {id activity {id name description} person {id preferred_name digital_id organization {name {name_en} description}} role}}`; + map variables = {"organization_id": organization_id, "duty_activity_id": duty_activity_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetDutyParticipantsByDutyActivityIdResponse); + } + remote isolated function addDutyAttendance(ActivityParticipantAttendance duty_attendance) returns AddDutyAttendanceResponse|graphql:ClientError { + string query = string `mutation addDutyAttendance($duty_attendance:ActivityParticipantAttendance!) {add_duty_attendance(duty_attendance:$duty_attendance) {id activity_instance_id person_id sign_in_time in_marked_by created}}`; + map variables = {"duty_attendance": duty_attendance}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, AddDutyAttendanceResponse); + } + remote isolated function getDutyAttendanceToday(int organization_id, int activity_id) returns GetDutyAttendanceTodayResponse|graphql:ClientError { + string query = string `query getDutyAttendanceToday($organization_id:Int!,$activity_id:Int!) {duty_attendance_today(organization_id:$organization_id,activity_id:$activity_id) {id person_id activity_instance_id sign_in_time in_marked_by created}}`; + map variables = {"organization_id": organization_id, "activity_id": activity_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetDutyAttendanceTodayResponse); + } + remote isolated function getDutyParticipant(int person_id) returns GetDutyParticipantResponse|graphql:ClientError { + string query = string `query getDutyParticipant($person_id:Int!) {duty_participant(person_id:$person_id) {id activity {id name description} person {id preferred_name digital_id organization {name {name_en} description}} role}}`; + map variables = {"person_id": person_id}; + json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); + return check performDataBinding(graphqlResponse, GetDutyParticipantResponse); + } } 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 b00dc2ce..d9375653 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 @@ -150,6 +150,26 @@ public type Consumable record { string? manufacturer?; }; +public type DutyParticipant record { + string? role?; + Activity? activity?; + Person? person?; + string? created?; + int? activity_id?; + int? id?; + string? updated?; + string? record_type?; + int? person_id?; +}; + +public type DutyRotationMetaDetails record { + string? end_date?; + int? organization_id?; + int? id?; + string? record_type?; + string? start_date?; +}; + public type EducationExperience record { string? end_date?; int[]? evaluation_id?; @@ -627,3 +647,140 @@ public type UpdateEvaluationsResponse record {| string? updated; |}? update_evaluation; |}; + +public type GetDutyParticipantsResponse record {| + map __extensions?; + record {| + int? id; + record {| + int? id; + string? name; + string? description; + |}? activity; + record {| + int? id; + string? preferred_name; + string? digital_id; + record {| + record {| + string name_en; + |} name; + string? description; + |}? organization; + |}? person; + string? role; + |}[] duty_participants; +|}; + +public type CreateDutyForParticipantResponse record {| + map __extensions?; + record {| + int? id; + int? activity_id; + int? person_id; + string? role; + string? created; + |}? add_duty_for_participant; +|}; + +public type GetActivitiesByAvinyaTypeResponse record {| + map __extensions?; + record {| + int? id; + string? name; + string? description; + string? notes; + |}[]? activities_by_avinya_type; +|}; + +public type UpdateDutyRotationMetaDataResponse record {| + map __extensions?; + record {| + int? id; + string? start_date; + string? end_date; + int? organization_id; + |}? update_duty_rotation_metadata; +|}; + +public type GetDutyRotationMetadataByOrganizationResponse record {| + map __extensions?; + record {| + int? id; + string? start_date; + string? end_date; + int? organization_id; + |}? duty_rotation_metadata_by_organization; +|}; + +public type GetDutyParticipantsByDutyActivityIdResponse record {| + map __extensions?; + record {| + int? id; + record {| + int? id; + string? name; + string? description; + |}? activity; + record {| + int? id; + string? preferred_name; + string? digital_id; + record {| + record {| + string name_en; + |} name; + string? description; + |}? organization; + |}? person; + string? role; + |}[] duty_participants_by_duty_activity_id; +|}; + +public type AddDutyAttendanceResponse record {| + map __extensions?; + record {| + int? id; + int? activity_instance_id; + int? person_id; + string? sign_in_time; + string? in_marked_by; + string? created; + |}? add_duty_attendance; +|}; + +public type GetDutyAttendanceTodayResponse record {| + map __extensions?; + record {| + int? id; + int? person_id; + int? activity_instance_id; + string? sign_in_time; + string? in_marked_by; + string? created; + |}[]? duty_attendance_today; +|}; + +public type GetDutyParticipantResponse record {| + map __extensions?; + record {| + int? id; + record {| + int? id; + string? name; + string? description; + |}? activity; + record {| + int? id; + string? preferred_name; + string? digital_id; + record {| + record {| + string name_en; + |} name; + string? description; + |}? organization; + |}? person; + string? role; + |}? duty_participant; +|}; diff --git a/campus/bffs/attendance/graphql_client/schema.graphql b/campus/bffs/attendance/graphql_client/schema.graphql index 000969c5..c68fd045 100644 --- a/campus/bffs/attendance/graphql_client/schema.graphql +++ b/campus/bffs/attendance/graphql_client/schema.graphql @@ -313,6 +313,44 @@ type DistrictData { cities: [CityData!]! } +input DutyParticipant { + record_type: String = "" + id: Int + activity_id: Int + activity: Activity + person_id: Int + person: Person + role: String + created: String + updated: String +} + +type DutyParticipantData { + id: Int + person_id: Int + person: PersonData + activity: ActivityData + activity_id: Int + role: String + created: String + updated: String +} + +type DutyRotationMetaData { + id: Int + start_date: String + end_date: String + organization_id: Int +} + +input DutyRotationMetaDetails { + record_type: String = "" + id: Int + start_date: String + end_date: String + organization_id: Int +} + input EducationExperience { record_type: String = "" id: Int @@ -531,6 +569,10 @@ type Mutation { update_resource_allocation(resourceAllocation: ResourceAllocation!): ResourceAllocationData add_inventory(inventory: Inventory!): InventoryData update_inventory(inventory: Inventory!): InventoryData + add_duty_for_participant(dutyparticipant: DutyParticipant!): DutyParticipantData + delete_duty_for_participant(id: Int!): Int + update_duty_rotation_metadata(duty_rotation: DutyRotationMetaDetails!): DutyRotationMetaData + add_duty_attendance(duty_attendance: ActivityParticipantAttendance!): ActivityParticipantAttendanceData } input Organization { @@ -760,6 +802,12 @@ type Query { inventory(id: Int!): InventoryData inventories: [InventoryData!]! resource_allocations_report(organization_id: Int, avinya_type_id: Int): [ResourceAllocationData!]! + duty_participants(organization_id: Int): [DutyParticipantData!]! + activities_by_avinya_type(avinya_type_id: Int): [ActivityData!] + duty_rotation_metadata_by_organization(organization_id: Int): DutyRotationMetaData + duty_participants_by_duty_activity_id(organization_id: Int, duty_activity_id: Int): [DutyParticipantData!]! + duty_attendance_today(organization_id: Int, activity_id: Int): [ActivityParticipantAttendanceData!] + duty_participant(person_id: Int): DutyParticipantData } input ResourceAllocation { diff --git a/campus/bffs/attendance/graphql_client/schema.json b/campus/bffs/attendance/graphql_client/schema.json index def1bf3f..79f83d32 100644 --- a/campus/bffs/attendance/graphql_client/schema.json +++ b/campus/bffs/attendance/graphql_client/schema.json @@ -2333,6 +2333,190 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "duty_participants", + "args": [ + { + "name": "organization_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "DutyParticipantData", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "activities_by_avinya_type", + "args": [ + { + "name": "avinya_type_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "ActivityData", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "duty_rotation_metadata_by_organization", + "args": [ + { + "name": "organization_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "DutyRotationMetaData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "duty_participants_by_duty_activity_id", + "args": [ + { + "name": "organization_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "duty_activity_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "DutyParticipantData", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "duty_attendance_today", + "args": [ + { + "name": "organization_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "activity_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "ActivityParticipantAttendanceData", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "duty_participant", + "args": [ + { + "name": "person_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "DutyParticipantData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -3380,6 +3564,61 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "INPUT_OBJECT", + "name": "DutyRotationMetaDetails", + "fields": null, + "inputFields": [ + { + "name": "record_type", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": "\"\"" + }, + { + "name": "id", + "type": { + "kind": "SCALAR", + "name": "Int", + "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": "organization_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "ActivityParticipant", @@ -5108,22 +5347,120 @@ "deprecationReason": null }, { - "name": "consumable", + "name": "consumable", + "args": [], + "type": { + "kind": "OBJECT", + "name": "ConsumableData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "organization", + "args": [], + "type": { + "kind": "OBJECT", + "name": "OrganizationData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "person", + "args": [], + "type": { + "kind": "OBJECT", + "name": "PersonData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "quantity", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "quantity_in", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "quantity_out", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "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": "DutyParticipantData", + "fields": [ + { + "name": "id", "args": [], "type": { - "kind": "OBJECT", - "name": "ConsumableData", + "kind": "SCALAR", + "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "organization", + "name": "person_id", "args": [], "type": { - "kind": "OBJECT", - "name": "OrganizationData", + "kind": "SCALAR", + "name": "Int", "ofType": null }, "isDeprecated": false, @@ -5141,18 +5478,18 @@ "deprecationReason": null }, { - "name": "quantity", + "name": "activity", "args": [], "type": { - "kind": "SCALAR", - "name": "Int", + "kind": "OBJECT", + "name": "ActivityData", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "quantity_in", + "name": "activity_id", "args": [], "type": { "kind": "SCALAR", @@ -5163,11 +5500,11 @@ "deprecationReason": null }, { - "name": "quantity_out", + "name": "role", "args": [], "type": { "kind": "SCALAR", - "name": "Int", + "name": "String", "ofType": null }, "isDeprecated": false, @@ -6838,6 +7175,106 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "add_duty_for_participant", + "args": [ + { + "name": "dutyparticipant", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "DutyParticipant", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "DutyParticipantData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "delete_duty_for_participant", + "args": [ + { + "name": "id", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "update_duty_rotation_metadata", + "args": [ + { + "name": "duty_rotation", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "DutyRotationMetaDetails", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "DutyRotationMetaData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "add_duty_attendance", + "args": [ + { + "name": "duty_attendance", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "ActivityParticipantAttendance", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "ActivityParticipantAttendanceData", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -7993,6 +8430,60 @@ "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", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "end_date", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "organization_id", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "__Type", @@ -10920,6 +11411,97 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "INPUT_OBJECT", + "name": "DutyParticipant", + "fields": null, + "inputFields": [ + { + "name": "record_type", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": "\"\"" + }, + { + "name": "id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "activity_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "activity", + "type": { + "kind": "INPUT_OBJECT", + "name": "Activity", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "person_id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "person", + "type": { + "kind": "INPUT_OBJECT", + "name": "Person", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "role", + "type": { + "kind": "SCALAR", + "name": "String", + "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": "__Directive", diff --git a/campus/bffs/pcti_notes/api/Dependencies.toml b/campus/bffs/pcti_notes/api/Dependencies.toml index 9a11dcc5..22bb3117 100644 --- a/campus/bffs/pcti_notes/api/Dependencies.toml +++ b/campus/bffs/pcti_notes/api/Dependencies.toml @@ -5,24 +5,24 @@ [ballerina] dependencies-toml-version = "2" +distribution-version = "2201.5.0" [[package]] org = "ballerina" name = "auth" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "crypto"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "lang.string"}, - {org = "ballerina", name = "log"}, - {org = "ballerina", name = "regex"} + {org = "ballerina", name = "log"} ] [[package]] org = "ballerina" name = "cache" -version = "3.3.0" +version = "3.5.0" dependencies = [ {org = "ballerina", name = "constraint"}, {org = "ballerina", name = "jballerina.java"}, @@ -33,7 +33,7 @@ dependencies = [ [[package]] org = "ballerina" name = "constraint" -version = "1.0.2" +version = "1.2.0" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -41,7 +41,7 @@ dependencies = [ [[package]] org = "ballerina" name = "crypto" -version = "2.3.0" +version = "2.3.1" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "time"} @@ -50,20 +50,18 @@ dependencies = [ [[package]] org = "ballerina" name = "file" -version = "1.5.0" +version = "1.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "log"}, {org = "ballerina", name = "os"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] [[package]] org = "ballerina" name = "graphql" -version = "1.5.2" +version = "1.8.1" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "file"}, @@ -76,18 +74,20 @@ dependencies = [ {org = "ballerina", name = "log"}, {org = "ballerina", name = "mime"}, {org = "ballerina", name = "oauth2"}, - {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"}, {org = "ballerina", name = "websocket"} ] modules = [ {org = "ballerina", packageName = "graphql", moduleName = "graphql"}, - {org = "ballerina", packageName = "graphql", moduleName = "graphql.parser"} + {org = "ballerina", packageName = "graphql", moduleName = "graphql.parser"}, + {org = "ballerina", packageName = "graphql", moduleName = "graphql.subgraph"} ] [[package]] org = "ballerina" name = "http" -version = "2.5.3" +version = "2.8.1" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -100,6 +100,7 @@ dependencies = [ {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "lang.decimal"}, {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.regexp"}, {org = "ballerina", name = "lang.runtime"}, {org = "ballerina", name = "lang.string"}, {org = "ballerina", name = "lang.value"}, @@ -107,7 +108,6 @@ dependencies = [ {org = "ballerina", name = "mime"}, {org = "ballerina", name = "oauth2"}, {org = "ballerina", name = "observe"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"}, {org = "ballerina", name = "url"} ] @@ -118,7 +118,7 @@ modules = [ [[package]] org = "ballerina" name = "io" -version = "1.3.1" +version = "1.4.1" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} @@ -135,7 +135,7 @@ version = "0.0.0" [[package]] org = "ballerina" name = "jwt" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "cache"}, {org = "ballerina", name = "crypto"}, @@ -143,7 +143,6 @@ dependencies = [ {org = "ballerina", name = "lang.int"}, {org = "ballerina", name = "lang.string"}, {org = "ballerina", name = "log"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] @@ -178,7 +177,9 @@ org = "ballerina" name = "lang.int" version = "0.0.0" dependencies = [ - {org = "ballerina", name = "jballerina.java"} + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"}, + {org = "ballerina", name = "lang.object"} ] [[package]] @@ -222,7 +223,7 @@ dependencies = [ [[package]] org = "ballerina" name = "log" -version = "2.5.1" +version = "2.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, @@ -236,7 +237,7 @@ modules = [ [[package]] org = "ballerina" name = "mime" -version = "2.5.1" +version = "2.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, @@ -246,19 +247,20 @@ dependencies = [ [[package]] org = "ballerina" name = "oauth2" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "cache"}, {org = "ballerina", name = "crypto"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "log"}, - {org = "ballerina", name = "time"} + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} ] [[package]] org = "ballerina" name = "observe" -version = "1.0.6" +version = "1.0.7" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -266,25 +268,16 @@ dependencies = [ [[package]] org = "ballerina" name = "os" -version = "1.5.0" +version = "1.6.0" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"} ] -[[package]] -org = "ballerina" -name = "regex" -version = "1.3.2" -dependencies = [ - {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "lang.string"} -] - [[package]] org = "ballerina" name = "task" -version = "2.3.1" +version = "2.3.2" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "time"} @@ -305,7 +298,7 @@ modules = [ [[package]] org = "ballerina" name = "time" -version = "2.2.4" +version = "2.2.5" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -313,7 +306,7 @@ dependencies = [ [[package]] org = "ballerina" name = "url" -version = "2.2.3" +version = "2.2.4" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -321,7 +314,7 @@ dependencies = [ [[package]] org = "ballerina" name = "websocket" -version = "2.5.1" +version = "2.8.1" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "constraint"}, @@ -335,7 +328,6 @@ dependencies = [ {org = "ballerina", name = "lang.value"}, {org = "ballerina", name = "log"}, {org = "ballerina", name = "oauth2"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] @@ -367,4 +359,3 @@ modules = [ {org = "user", packageName = "api", moduleName = "api"} ] - diff --git a/campus/bffs/profile/api/Dependencies.toml b/campus/bffs/profile/api/Dependencies.toml index b41ae8c7..ad197bc7 100644 --- a/campus/bffs/profile/api/Dependencies.toml +++ b/campus/bffs/profile/api/Dependencies.toml @@ -5,6 +5,7 @@ [ballerina] dependencies-toml-version = "2" +distribution-version = "2201.5.0" [[package]] org = "avinyafoundation" @@ -25,20 +26,19 @@ modules = [ [[package]] org = "ballerina" name = "auth" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "crypto"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "lang.string"}, - {org = "ballerina", name = "log"}, - {org = "ballerina", name = "regex"} + {org = "ballerina", name = "log"} ] [[package]] org = "ballerina" name = "cache" -version = "3.3.0" +version = "3.5.0" dependencies = [ {org = "ballerina", name = "constraint"}, {org = "ballerina", name = "jballerina.java"}, @@ -49,7 +49,7 @@ dependencies = [ [[package]] org = "ballerina" name = "constraint" -version = "1.0.2" +version = "1.2.0" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -66,20 +66,18 @@ dependencies = [ [[package]] org = "ballerina" name = "file" -version = "1.5.0" +version = "1.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "log"}, {org = "ballerina", name = "os"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] [[package]] org = "ballerina" name = "graphql" -version = "1.5.2" +version = "1.8.1" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "file"}, @@ -92,18 +90,20 @@ dependencies = [ {org = "ballerina", name = "log"}, {org = "ballerina", name = "mime"}, {org = "ballerina", name = "oauth2"}, - {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"}, {org = "ballerina", name = "websocket"} ] modules = [ {org = "ballerina", packageName = "graphql", moduleName = "graphql"}, - {org = "ballerina", packageName = "graphql", moduleName = "graphql.parser"} + {org = "ballerina", packageName = "graphql", moduleName = "graphql.parser"}, + {org = "ballerina", packageName = "graphql", moduleName = "graphql.subgraph"} ] [[package]] org = "ballerina" name = "http" -version = "2.5.3" +version = "2.8.2" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -116,6 +116,7 @@ dependencies = [ {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "lang.decimal"}, {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.regexp"}, {org = "ballerina", name = "lang.runtime"}, {org = "ballerina", name = "lang.string"}, {org = "ballerina", name = "lang.value"}, @@ -123,7 +124,6 @@ dependencies = [ {org = "ballerina", name = "mime"}, {org = "ballerina", name = "oauth2"}, {org = "ballerina", name = "observe"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"}, {org = "ballerina", name = "url"} ] @@ -134,7 +134,7 @@ modules = [ [[package]] org = "ballerina" name = "io" -version = "1.3.1" +version = "1.4.1" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} @@ -151,7 +151,7 @@ version = "0.0.0" [[package]] org = "ballerina" name = "jwt" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "cache"}, {org = "ballerina", name = "crypto"}, @@ -159,7 +159,6 @@ dependencies = [ {org = "ballerina", name = "lang.int"}, {org = "ballerina", name = "lang.string"}, {org = "ballerina", name = "log"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] @@ -194,7 +193,9 @@ org = "ballerina" name = "lang.int" version = "0.0.0" dependencies = [ - {org = "ballerina", name = "jballerina.java"} + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"}, + {org = "ballerina", name = "lang.object"} ] [[package]] @@ -238,7 +239,7 @@ dependencies = [ [[package]] org = "ballerina" name = "log" -version = "2.5.1" +version = "2.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, @@ -252,7 +253,7 @@ modules = [ [[package]] org = "ballerina" name = "mime" -version = "2.5.1" +version = "2.7.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, @@ -262,19 +263,20 @@ dependencies = [ [[package]] org = "ballerina" name = "oauth2" -version = "2.5.0" +version = "2.8.0" dependencies = [ {org = "ballerina", name = "cache"}, {org = "ballerina", name = "crypto"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "log"}, - {org = "ballerina", name = "time"} + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} ] [[package]] org = "ballerina" name = "observe" -version = "1.0.6" +version = "1.0.7" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -282,21 +284,12 @@ dependencies = [ [[package]] org = "ballerina" name = "os" -version = "1.5.0" +version = "1.6.0" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"} ] -[[package]] -org = "ballerina" -name = "regex" -version = "1.3.2" -dependencies = [ - {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "lang.string"} -] - [[package]] org = "ballerina" name = "task" @@ -337,7 +330,7 @@ dependencies = [ [[package]] org = "ballerina" name = "websocket" -version = "2.5.1" +version = "2.8.1" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "constraint"}, @@ -351,7 +344,6 @@ dependencies = [ {org = "ballerina", name = "lang.value"}, {org = "ballerina", name = "log"}, {org = "ballerina", name = "oauth2"}, - {org = "ballerina", name = "regex"}, {org = "ballerina", name = "time"} ] @@ -367,4 +359,3 @@ modules = [ {org = "ballerinai", packageName = "observe", moduleName = "observe"} ] - diff --git a/campus/bffs/profile/api/person_client.bal b/campus/bffs/profile/api/person_client.bal index 2d1918f9..8b92d72c 100644 --- a/campus/bffs/profile/api/person_client.bal +++ b/campus/bffs/profile/api/person_client.bal @@ -29,7 +29,7 @@ public isolated client class GraphqlClient { } 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}} 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}}`; map variables = {"id": id}; json graphqlResponse = check self.graphqlClient->executeWithType(query, variables); return check performDataBinding(graphqlResponse, GetPersonResponse); diff --git a/campus/bffs/profile/api/types.bal b/campus/bffs/profile/api/types.bal index 924e3ba4..6ab58c6e 100644 --- a/campus/bffs/profile/api/types.bal +++ b/campus/bffs/profile/api/types.bal @@ -457,6 +457,9 @@ public type GetPersonResponse record {| |}[]? child_organizations; record {| int? id; + record {| + int? id; + |}[]? parent_organizations; |}[]? parent_organizations; |}? organization; 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 1e121a12..8de1b8aa 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}} 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}}`; 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 6f355fd0..27c38f6c 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 @@ -458,6 +458,9 @@ public type GetPersonResponse record {| |}[]? child_organizations; record {| int? id; + record {| + int? id; + |}[]? parent_organizations; |}[]? parent_organizations; |}? organization; record {| diff --git a/campus/bffs/profile/graphql_client/person.graphql b/campus/bffs/profile/graphql_client/person.graphql index 5d3821c1..ea03f22c 100644 --- a/campus/bffs/profile/graphql_client/person.graphql +++ b/campus/bffs/profile/graphql_client/person.graphql @@ -80,6 +80,9 @@ query getPerson($id:String!){ } parent_organizations{ id + parent_organizations{ + id + } } } avinya_type { diff --git a/campus/frontend/assets/config/dev.json b/campus/frontend/assets/config/dev.json index 77503b33..d5561825 100644 --- a/campus/frontend/assets/config/dev.json +++ b/campus/frontend/assets/config/dev.json @@ -1,6 +1,6 @@ { - "campusProfileBffApiUrl" : "http://localhost:9090", - "campusAttendanceBffApiUrl" : "http://localhost:9091", + "campusProfileBffApiUrl" : "http://192.168.1.100:9090", + "campusAttendanceBffApiUrl" : "http://192.168.1.100:9091", "campusPctiNotesBffApiUrl" : "http://localhost:9092", "campusPctiFeedbackBffApiUrl" : "http://localhost:9093", "campusAssetsBffApiUrl" : "http://localhost:9094", diff --git a/campus/frontend/lib/avinya/asset_admin/lib/widgets/resource_allocation_report.dart b/campus/frontend/lib/avinya/asset_admin/lib/widgets/resource_allocation_report.dart index 523d9249..a2b1a5d9 100644 --- a/campus/frontend/lib/avinya/asset_admin/lib/widgets/resource_allocation_report.dart +++ b/campus/frontend/lib/avinya/asset_admin/lib/widgets/resource_allocation_report.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:asset_admin/data.dart'; import 'package:gallery/data/campus_apps_portal.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; class ResourceAllocationReport extends StatefulWidget { const ResourceAllocationReport({super.key}); @@ -164,12 +165,20 @@ bool organizationsLoaded = false; ); }).toList(), ), - if (!organizationsLoaded && !campusAppsPortalInstance.isTeacher) - CircularProgressIndicator(), + if(!campusAppsPortalInstance.isTeacher) + if (!organizationsLoaded) + Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Colors + .blue), // Customize the color of the indicator + size: 40, // Customize the size of the indicator + ), + ), SizedBox(width: 20), Container( margin: EdgeInsets.only( - left: 30, top: 20, bottom: 10), + left: 10, top: 20, bottom: 10), child: Row( children: [ Text('Select a Asset Type:'), @@ -209,8 +218,14 @@ bool organizationsLoaded = false; }).toList(), ), if (!assetTypesLoaded) - CircularProgressIndicator(), - + Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Colors + .blue), // Customize the color of the indicator + size: 40, // Customize the size of the indicator + ), + ), ], ), ), diff --git a/campus/frontend/lib/avinya/attendance/lib/app.dart b/campus/frontend/lib/avinya/attendance/lib/app.dart index 7f6917ce..b4229d86 100644 --- a/campus/frontend/lib/avinya/attendance/lib/app.dart +++ b/campus/frontend/lib/avinya/attendance/lib/app.dart @@ -51,6 +51,8 @@ class _CampusAttendanceManagementSystemState '/avinya_types', '/#access_token', '/person_attendance_report', + '/duty_participants', + '/duty_attendance_marker', '/late_attendance_report', '/qr_attendance_marker' ], @@ -124,6 +126,12 @@ class _CampusAttendanceManagementSystemState final lateAttendanceReportRoute = ParsedRoute( '/late_attendance_report', '/late_attendance_report', {}, {}); + final dutyParticipantsRoute = ParsedRoute( + '/duty_participants','/duty_participants', {}, {}); + + final dutyAttendanceMarkerRoute = ParsedRoute( + '/duty_attendance_marker','/duty_attendance_marker', {}, {}); + final qrAttendanceMarkerRoute = ParsedRoute('/qr_attendance_marker', '/qr_attendance_marker', {}, {}); @@ -144,8 +152,13 @@ class _CampusAttendanceManagementSystemState return dailyAttendanceReportRoute; } else if (signedIn && from == weeklyPaymentReportRoute) { return weeklyPaymentReportRoute; - } else if (signedIn && from == personAttendanceReportRoute) { + } else if (signedIn && from == personAttendanceReportRoute){ return personAttendanceReportRoute; + } else if (signedIn && from == dutyParticipantsRoute){ + return dutyParticipantsRoute; + } else if (signedIn && from == dutyAttendanceMarkerRoute){ + return dutyAttendanceMarkerRoute; + }else if (signedIn && from == qrAttendanceMarkerRoute) { } else if (signedIn && from == lateAttendanceReportRoute) { return lateAttendanceReportRoute; } else if (signedIn && from == qrAttendanceMarkerRoute) { diff --git a/campus/frontend/lib/avinya/attendance/lib/data.dart b/campus/frontend/lib/avinya/attendance/lib/data.dart index 3f75c7a4..623f088b 100644 --- a/campus/frontend/lib/avinya/attendance/lib/data.dart +++ b/campus/frontend/lib/avinya/attendance/lib/data.dart @@ -9,3 +9,5 @@ export 'data/vacancy.dart'; export 'data/application.dart'; export 'data/avinya_type.dart'; export 'data/activity.dart'; +export 'data/duty_participant.dart'; +export 'data/duty_rotation_metadata.dart'; diff --git a/campus/frontend/lib/avinya/attendance/lib/data/activity.dart b/campus/frontend/lib/avinya/attendance/lib/data/activity.dart index 200af41a..1a7c0b71 100644 --- a/campus/frontend/lib/avinya/attendance/lib/data/activity.dart +++ b/campus/frontend/lib/avinya/attendance/lib/data/activity.dart @@ -87,6 +87,24 @@ Future> fetchActivitys() async { } } +Future> fetchActivitiesByAvinyaType(int avinyaTypeID) async{ + +final response = await http + .get(Uri.parse(AppConfig.campusAttendanceBffApiUrl + '/activities_by_avinya_type/$avinyaTypeID')); + + if (response.statusCode == 200){ + var resultsJson = json.decode(response.body).cast>(); + List activitiesByAvinyaType = await resultsJson + .map((json) => Activity.fromJson(json)) + .toList(); + + return activitiesByAvinyaType; + + }else{ + throw Exception('Failed to load Activities'); + } +} + Future fetchActivity(String name) async { final response = await http.get( Uri.parse(AppConfig.campusAttendanceBffApiUrl + '/activity/$name'), 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 582f5c3a..e5a61ce1 100644 --- a/campus/frontend/lib/avinya/attendance/lib/data/activity_attendance.dart +++ b/campus/frontend/lib/avinya/attendance/lib/data/activity_attendance.dart @@ -321,3 +321,44 @@ Future> getLateAttendanceReportByDate( 'Failed to get Activity Participant Attendance report for organization ID $organization_id and activity $activity_id'); } } + +Future createDutyActivityAttendance( + ActivityAttendance activityAttendance) async { + final response = await http.post( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/duty_attendance'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + body: jsonEncode(activityAttendance.toJson()), + ); + if (response.statusCode > 199 && response.statusCode < 300) { + return ActivityAttendance.fromJson(jsonDecode(response.body)); + } else { + throw Exception('Failed to create Duty Activity Participant Attendance.'); + } +} + +Future> getDutyAttendanceToday( + int organization_id, int activity_id) async { + final response = await http.get( + Uri.parse( + '${AppConfig.campusAttendanceBffApiUrl}/duty_attendance_today/$organization_id/$activity_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>(); + List dutyAttendances = await resultsJson + .map((json) => ActivityAttendance.fromJson(json)) + .toList(); + return dutyAttendances; + } else { + throw Exception( + 'Failed to get Duty Participant Attendance for org ID $organization_id and activity $activity_id for today.'); + } +} \ No newline at end of file diff --git a/campus/frontend/lib/avinya/attendance/lib/data/duty_participant.dart b/campus/frontend/lib/avinya/attendance/lib/data/duty_participant.dart new file mode 100644 index 00000000..3155ebd6 --- /dev/null +++ b/campus/frontend/lib/avinya/attendance/lib/data/duty_participant.dart @@ -0,0 +1,168 @@ + + + +import 'package:http/http.dart' as http; + +import 'dart:developer'; + +import 'package:gallery/data/person.dart'; + +import 'activity.dart'; + +import 'package:gallery/config/app_config.dart'; + +import 'dart:convert'; + +class DutyParticipant{ + + int? id; + int? activity_id; + Activity? activity; + int? person_id; + Person? person; + String? role; + String? created; + + DutyParticipant({ + this.id, + this.activity_id, + this.activity, + this.person_id, + this.person, + this.role, + this.created, + }); + + factory DutyParticipant.fromJson(Map json){ + log(json.toString()); + + Activity? activityObj; + Person? personObj; + + if(json['activity'] != null){ + activityObj = Activity.fromJson(json['activity']); + } + + if(json['person'] != null){ + personObj = Person.fromJson(json['person']); + } + + return DutyParticipant( + id: json['id'], + activity_id: json['activity_id'], + activity: activityObj, + person_id: json['person_id'], + person: personObj, + role: json['role'], + created: json['created'], + ); + } + + Map toJson() => { + if (id != null) 'id': id, + if (activity_id != null) 'activity_id': activity_id, + if (activity != null) 'activity': activity, + if (person_id != null) 'person_id': person_id, + if (person != null) 'person': person, + if (role != null) 'role': role, + if (created !=null) 'created':created, + + }; + +} + +Future> fetchDutyParticipants(int organization_id) async{ + + final response = await http.get( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/duty_participants/$organization_id'), + headers:{ + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + ); + + if (response.statusCode == 200) { + var resultsJson = json.decode(response.body).cast>(); + List fetchDutyForParticipants = await resultsJson + .map((json) => DutyParticipant.fromJson(json)) + .toList(); + return fetchDutyForParticipants; + } else { + throw Exception('Failed to load duty participants for organization ID $organization_id'); + } +} + + +Future createDutyForParticipant(DutyParticipant dutyParticipant) async{ + + final response = await http.post( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/duty_for_participant'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + body: jsonEncode(dutyParticipant.toJson()), + ); + if (response.statusCode > 199 && response.statusCode < 300) { + return DutyParticipant.fromJson(jsonDecode(response.body)); + } else { + throw Exception('Failed to create duty for participant.'); + } +} + +Future deleteDutyForParticipant(int id) async { + final response = await http.delete( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/duty_for_participant/$id'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + ); + if (response.statusCode > 199 && response.statusCode < 300) { + return int.parse(response.body); + } else { + throw Exception('Failed to delete Duty For Participant.'); + } +} + +Future> fetchDutyParticipantsByDutyActivityId(int organization_id,int duty_activity_id) async{ + + final response = await http.get( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/duty_participants_by_duty_activity_id/$organization_id/$duty_activity_id'), + headers:{ + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + ); + + if (response.statusCode == 200) { + var resultsJson = json.decode(response.body).cast>(); + List fetchDutyForParticipants = await resultsJson + .map((json) => DutyParticipant.fromJson(json)) + .toList(); + return fetchDutyForParticipants; + } else { + throw Exception('Failed to load duty participants for organization ID $organization_id and duty activity ID $duty_activity_id'); + } +} + +Future fetchDutyParticipant(int personId) async { + final response = await http.get( + Uri.parse(AppConfig.campusAttendanceBffApiUrl + '/duty_participant/$personId'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ' + AppConfig.campusBffApiKey, + }, + ); + + if (response.statusCode == 200) { + DutyParticipant dutyParticipant = DutyParticipant.fromJson(json.decode(response.body)); + return dutyParticipant; + } else { + return null; + } +} \ No newline at end of file diff --git a/campus/frontend/lib/avinya/attendance/lib/data/duty_rotation_metadata.dart b/campus/frontend/lib/avinya/attendance/lib/data/duty_rotation_metadata.dart new file mode 100644 index 00000000..b9ba179b --- /dev/null +++ b/campus/frontend/lib/avinya/attendance/lib/data/duty_rotation_metadata.dart @@ -0,0 +1,74 @@ + + +import 'dart:convert'; +import 'dart:developer'; +import 'package:http/http.dart' as http; +import 'package:gallery/config/app_config.dart'; + +class DutyRotationMetaDetails{ + + int? id; + String? start_date; + String? end_date; + int? organization_id; + + DutyRotationMetaDetails({ + this.id, + this.start_date, + this.end_date, + this.organization_id, + }); + + factory DutyRotationMetaDetails.fromJson(Map json){ + log(json.toString()); + return DutyRotationMetaDetails( + id: json['id'], + start_date: json['start_date'], + end_date: json['end_date'], + organization_id: json['organization_id'], + ); + } + + Map toJson() => { + if (id != null) 'id': id, + if (start_date != null) 'start_date': start_date, + if (end_date != null) 'end_date': end_date, + if (organization_id !=null) 'organization_id' : organization_id, + }; + +} + +Future updateDutyRotationMetadata(DutyRotationMetaDetails dutyRotationMetadata) async { + final response = await http.put( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/update_duty_rotation_metadata'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + body: jsonEncode(dutyRotationMetadata.toJson()), + ); + if (response.statusCode == 200) { + return DutyRotationMetaDetails.fromJson(jsonDecode(response.body)); + } else { + throw Exception('Failed to update Duty Rotation.'); + } +} + +Future fetchDutyRotationMetadataByOrganization(int organization_id) async { + final response = await http.get( + Uri.parse(AppConfig.campusAttendanceBffApiUrl + '/duty_rotation_metadata_by_organization/$organization_id'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ' + AppConfig.campusBffApiKey, + }, + ); + + if (response.statusCode == 200) { + DutyRotationMetaDetails dutyRotationMetaDetails = DutyRotationMetaDetails.fromJson(json.decode(response.body)); + print(dutyRotationMetaDetails.toJson()); + return dutyRotationMetaDetails; + } else { + throw Exception('Failed to load duty rotation metadata'); + } +} \ No newline at end of file diff --git a/campus/frontend/lib/avinya/attendance/lib/screens/duty_attendance_marker.dart b/campus/frontend/lib/avinya/attendance/lib/screens/duty_attendance_marker.dart new file mode 100644 index 00000000..682a619b --- /dev/null +++ b/campus/frontend/lib/avinya/attendance/lib/screens/duty_attendance_marker.dart @@ -0,0 +1,36 @@ + + + +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter/src/widgets/placeholder.dart'; + +import 'package:attendance/widgets/duty_attendance_marker.dart'; + +class DutyAttendanceMarkerScreen extends StatefulWidget { + const DutyAttendanceMarkerScreen({super.key}); + + @override + State createState() => _DutyAttendanceMarkerScreenState(); +} + +class _DutyAttendanceMarkerScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Duty Attendance Marker"), + ), + body: SingleChildScrollView( + child: Container( + child: Column( + children: [ + DutyAttendanceMarker(), + ], + ), + ), + ), + + ); + } +} \ No newline at end of file diff --git a/campus/frontend/lib/avinya/attendance/lib/screens/duty_participants.dart b/campus/frontend/lib/avinya/attendance/lib/screens/duty_participants.dart new file mode 100644 index 00000000..4e88a243 --- /dev/null +++ b/campus/frontend/lib/avinya/attendance/lib/screens/duty_participants.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:attendance/widgets/assign_duty_for_participant.dart'; + + +class DutyParticipantsScreen extends StatefulWidget { + const DutyParticipantsScreen({super.key}); + + @override + State createState() => _DutyParticipantsScreenState(); +} + +class _DutyParticipantsScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Duty Participants"), + ), + body: SingleChildScrollView( + child: Container( + child: Column( + children: [ + AssignDutyForParticipant(), + ], + ), + ), + ), + + ); + } +} \ No newline at end of file diff --git a/campus/frontend/lib/avinya/attendance/lib/screens/scaffold.dart b/campus/frontend/lib/avinya/attendance/lib/screens/scaffold.dart index 9e803a55..46e2acac 100644 --- a/campus/frontend/lib/avinya/attendance/lib/screens/scaffold.dart +++ b/campus/frontend/lib/avinya/attendance/lib/screens/scaffold.dart @@ -15,7 +15,7 @@ class SMSScaffold extends StatelessWidget { '/daily_attendance_report', '/late_attendance_report', '/weekly_payment_report', - '/person_attendance_report', + '/duty_participants', ]; static const studentPageNames = [ @@ -23,6 +23,12 @@ class SMSScaffold extends StatelessWidget { '/person_attendance_report', ]; + static const leaderParticipantPageNames = [ + '/attendance_marker', + '/person_attendance_report', + '/duty_attendance_marker', + ]; + const SMSScaffold({ super.key, }); @@ -57,8 +63,30 @@ class SMSScaffold extends StatelessWidget { title: 'Weekly Payment Report', icon: Icons.paid, ), + AdaptiveScaffoldDestination( + title: 'Assign duties', + icon: Icons.work, + ), ]; - } else { + }else if(campusAppsPortalInstance.isStudent + && campusAppsPortalInstance.getLeaderParticipant().role == 'leader'){ + + destinations = const[ + AdaptiveScaffoldDestination( + title: 'Attendance Marker', + icon: Icons.person_outline, + ), + AdaptiveScaffoldDestination( + title: 'Payment Report', + icon: Icons.summarize, + ), + AdaptiveScaffoldDestination( + title: 'Duty Attendance Marker', + icon: Icons.people, + ), + + ]; + }else { destinations = const [ AdaptiveScaffoldDestination( title: 'Attendance Marker', @@ -73,6 +101,7 @@ class SMSScaffold extends StatelessWidget { return Scaffold( body: AdaptiveNavigationScaffold( + bottomNavigationOverflow: 7, selectedIndex: selectedIndex, appBar: AppBar( title: const Text('Avinya Academy - Campus Attendance Portal'), @@ -126,7 +155,12 @@ class SMSScaffold extends StatelessWidget { campusAppsPortalInstance.isSecurity || campusAppsPortalInstance.isFoundation) { routeState.go(pageNames[idx]); - } else { + }else if(campusAppsPortalInstance.isStudent + && campusAppsPortalInstance.getLeaderParticipant().role == 'leader'){ + + routeState.go(leaderParticipantPageNames[idx]); + + }else { routeState.go(studentPageNames[idx]); } }, @@ -153,7 +187,11 @@ class SMSScaffold extends StatelessWidget { campusAppsPortalInstance.isSecurity || campusAppsPortalInstance.isFoundation) { index = pageNames.indexOf(pathTemplate); - } else { + }else if(campusAppsPortalInstance.isStudent + && campusAppsPortalInstance.getLeaderParticipant().role == 'leader'){ + + index = leaderParticipantPageNames.indexOf(pathTemplate); + }else { index = studentPageNames.indexOf(pathTemplate); } diff --git a/campus/frontend/lib/avinya/attendance/lib/screens/scaffold_body.dart b/campus/frontend/lib/avinya/attendance/lib/screens/scaffold_body.dart index 9e05a38c..9701054f 100644 --- a/campus/frontend/lib/avinya/attendance/lib/screens/scaffold_body.dart +++ b/campus/frontend/lib/avinya/attendance/lib/screens/scaffold_body.dart @@ -7,6 +7,9 @@ import 'package:attendance/screens/daily_attendance_report.dart'; import 'package:flutter/material.dart'; import 'package:attendance/screens/weekly_payment_report.dart'; import 'package:attendance/screens/person_attendance_report.dart'; +import 'package:attendance/screens/duty_participants.dart'; +import 'package:attendance/screens/duty_attendance_marker.dart'; +//import 'package:attendance/screens/qr_attendance_marker.dart'; import 'package:attendance/screens/late_attendance_report.dart'; import '../routing.dart'; @@ -76,6 +79,16 @@ class SMSScaffoldBody extends StatelessWidget { key: ValueKey('person_attendance_report'), child: PersonAttendanceReportScreen(), ) + else if (currentRoute.pathTemplate.startsWith('/duty_participants')) + const FadeTransitionPage( + key: ValueKey('duty_participants'), + child: DutyParticipantsScreen(), + ) + else if (currentRoute.pathTemplate.startsWith('/duty_attendance_marker')) + const FadeTransitionPage( + key: ValueKey('duty_participants_attendance_marker'), + child: DutyAttendanceMarkerScreen(), + ) // Avoid building a Navigator with an empty `pages` list when the // RouteState is set to an unexpected path, such as /signin. // 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 new file mode 100644 index 00000000..77f977bc --- /dev/null +++ b/campus/frontend/lib/avinya/attendance/lib/widgets/assign_duty_for_participant.dart @@ -0,0 +1,929 @@ +import 'dart:html'; + +import 'package:flutter/material.dart'; +import 'package:attendance/data.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +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(); +} + +class _AssignDutyForParticipantState extends State { + + var _selectedClassValue; + var _selectedPersonValue; + Organization? _fetchedOrganization; + + late List> _dropDownPersonList; + late List _selectedClassValues; + late List _selectedPersonValues; + late List _selectedRoleValues; + + List _dutyParticipants = []; + List _activitiesByAvinyaType = []; + List _activitiesNames = []; + List _dutyRelatedParticipantsFilterAndStore = []; //filter And Store duty Relavant Participants + List _dropDownRoleList = ['leader','member']; + late DutyRotationMetaDetails _rotationMetaDetails; + + late TextEditingController _startDate; + late TextEditingController _endDate; + + bool _startDateSelected = true; + bool _endDateSelected = true; + + + @override + void initState(){ + super.initState(); + loadActivitiesByAvinyaType(); + loadRotationMetadetails(); + _startDate = TextEditingController(); + _endDate = TextEditingController(); + } + + @override + void dispose() { + _startDate.dispose(); + _endDate.dispose(); + super.dispose(); + } + + bool hasLeaderRoleWithActivity(String? activityName,String? allocatedRole){ + print('duty participants : ${_dutyParticipants}'); + bool hasLeaderRoleWithActivity; + + if(allocatedRole == "leader"){ + hasLeaderRoleWithActivity = _dutyParticipants.any((participant)=>participant.activity?.name == activityName && participant.role == 'leader'); + + if(hasLeaderRoleWithActivity){ + return true; + }else{ + return false; + } + }else{ + return false; + } + } + + Future> loadDutyParticipantsData(int organization_id) async{ + + print('organization id inside loadDutyParticipantsData() methos : ${organization_id}'); + 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{ + setState(() { + _startDateSelected = false; + _endDateSelected = false; + }); + } + + } + + 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(); + + _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); + + } + + + + @override + void didChangeDependencies(){ + super.didChangeDependencies(); + print(''); + print('execute did change dependencies'); + } + + @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( + 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( + controller: _endDate, + decoration: InputDecoration( + icon: Icon(Icons.calendar_today), + 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), + ), + ), + ],), + ) + else + Container( + margin: EdgeInsets.only(left: 17.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + height: 10, + ), + Container( + width: 300, + child: TextField( + 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( + 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), + ), + ), + ], + ), + ), + 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, + ), + Icon( + IconData(0xe6f2, fontFamily: 'MaterialIcons'), + size: 25, + color: Colors.blueAccent, + ), + 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: 120, + 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: 120, + 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 + .blue), + size: 70, + ), + ); + }, + ), + ], + ) + ); + } + + Widget buildTable(List dutyRelatedParticipantsFilterAndStore,int tableIndex,List dutyParticipants){ + return Card( + 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){ + + bool isLeader = participant.role == '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,), + 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)); + + setState(() { + _selectedClassValues[tableIndex] = newValue; + _dropDownPersonList[tableIndex] = _fetchedOrganization!.people; + + }); + }, + ); + + } + + 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{ + + 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); + 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), + ), + 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 leader role participant is already added to this $activityName duty.", + textAlign: TextAlign.center, + ), + Text( + "You can't add another participant with a leader role.If you'd like to add this participant as a leader, please remove the current leader first.", + textAlign: TextAlign.center, + ), + ], + ), + 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(', ')}'; + + showDialog( + 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), + ), + content: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + Icons.close, + color: Colors.red, + size: 40, + ), + SizedBox(height: 10,), + Text( + 'Cannot add duty for participant.', + textAlign: TextAlign.center, + ), + Text( + errorMessage, + textAlign: TextAlign.center, + ) + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text('OK'), + ), + ], + ), + ); + }, + ); + } + }, + ); +} + +Future _selectStartDate(BuildContext context) async{ + final DateTime? picked = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1950), + lastDate: DateTime(2100), + ); + if(picked !=null){ + print(picked); + String formattedDate = DateFormat('yyyy-MM-dd').format(picked); + print(formattedDate); + + setState(() { + _startDate.text = formattedDate; + _startDateSelected= true; + }); + }else if(picked == null){ + setState(() { + String formattedDate = ''; + _startDate.text = formattedDate; + _startDateSelected = false; + }); + } +} + +Future _selectEndDate(BuildContext context) async{ + final DateTime? picked = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1950), + lastDate: DateTime(2100), + ); + 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 + }); + + 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){ + setState(() { + String formattedDate = ''; + _endDate.text = formattedDate; + _endDateSelected= false; + }); + } +} + +} diff --git a/campus/frontend/lib/avinya/attendance/lib/widgets/attedance_marker.dart b/campus/frontend/lib/avinya/attendance/lib/widgets/attedance_marker.dart index b70d9e72..be2d0c99 100644 --- a/campus/frontend/lib/avinya/attendance/lib/widgets/attedance_marker.dart +++ b/campus/frontend/lib/avinya/attendance/lib/widgets/attedance_marker.dart @@ -8,6 +8,7 @@ import 'package:attendance/data/evaluation.dart'; // import 'package:attendance/widgets/evaluation_list.dart'; import 'dart:convert'; import 'package:gallery/avinya/attendance/lib/widgets/evaluation_list.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:gallery/avinya/attendance/lib/widgets/qr_image.dart'; class AttendanceMarker extends StatefulWidget { @@ -354,7 +355,14 @@ class _AttendanceMarkerState extends State { } // By default, show a loading spinner. - return const CircularProgressIndicator(); + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Colors + .blue), // Customize the color of the indicator + size: 70, // Customize the size of the indicator + ), + ); }, ); // diff --git a/campus/frontend/lib/avinya/attendance/lib/widgets/duty_attendance_marker.dart b/campus/frontend/lib/avinya/attendance/lib/widgets/duty_attendance_marker.dart new file mode 100644 index 00000000..40220cf4 --- /dev/null +++ b/campus/frontend/lib/avinya/attendance/lib/widgets/duty_attendance_marker.dart @@ -0,0 +1,524 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:attendance/data/activity_attendance.dart'; +import 'package:flutter/src/widgets/placeholder.dart'; +import 'package:attendance/data.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:gallery/constants.dart'; +import '../data/activity_instance.dart'; +import 'package:attendance/data/evaluation.dart'; + + +class DutyAttendanceMarker extends StatefulWidget { + const DutyAttendanceMarker({super.key}); + + @override + State createState() => _DutyAttendanceMarkerState(); +} + +class _DutyAttendanceMarkerState extends State { + + +var workActivityId = 0; +var workActivityInstance = ActivityInstance(id: -1); + +List _dutyParticipants = []; +List _fetchedDutyAttendance = []; +List _fetchedEvaluations = []; +List selectedRows = []; + + + + @override + void initState(){ + super.initState(); + workActivityId = campusAppsPortalInstance.activityIds['work']!; + loadDutyParticipants(); + loadDutyAttendance(); + loadEvaluations(); + } + + + Future submitDutyAttendance(DutyParticipant dutyParticipant,TimeOfDay selectedTime) async{ + + if (workActivityInstance.id == -1) { + workActivityInstance = await campusAttendanceSystemInstance + .getCheckinActivityInstance(workActivityId); + } + + int index = -1; + + index = _fetchedDutyAttendance.indexWhere((attendance) => + attendance.person_id == dutyParticipant.person!.id && attendance.sign_in_time != null); + + print( + 'index: $index person_id: ${dutyParticipant.person!.id} _fetchedAttendance lenth ${_fetchedDutyAttendance.length}'); + + if (index == -1) { + index = _fetchedDutyAttendance + .indexWhere((attendance) => attendance.person_id == -1); + if (index == -1) { + print( + 'index is still -1 => index: $index person_id: ${dutyParticipant.person!.id} '); + // if index is still -1 then there is no empty slot + // so we need to create a new slot + _fetchedDutyAttendance.add(ActivityAttendance( + person_id: -1, sign_in_time: null, sign_out_time: null)); + index = _fetchedDutyAttendance.length - 1; + } + } + + ActivityAttendance activityAttendance = ActivityAttendance( + person_id: -1, sign_in_time: null, sign_out_time: null); + + activityAttendance = ActivityAttendance( + activity_instance_id: workActivityInstance.id, + person_id: dutyParticipant.person!.id, + sign_in_time: DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, selectedTime.hour, selectedTime.minute).toString(), + in_marked_by: campusAppsPortalInstance.getUserPerson().digital_id, + ); + + + createDutyActivityAttendance(activityAttendance); + + _fetchedDutyAttendance[index] = activityAttendance; + + } + + Future toggleAbsent(DutyParticipant dutyParticipant, bool value) async{ + + if (workActivityInstance.id == -1) { + + workActivityInstance = await campusAttendanceSystemInstance.getCheckinActivityInstance(workActivityId); + + } + + if(value == true){ + + final Evaluation evaluation = Evaluation( + evaluatee_id: dutyParticipant.person!.id, + evaluator_id: campusAppsPortalInstance.getUserPerson().id, + evaluation_criteria_id: 54, + activity_instance_id: workActivityInstance.id, + response: "absence", + notes: "", + grade: 0 + ); + await createEvaluation([evaluation]); + + }else if(value == false){ + + var evaluation = _fetchedEvaluations.firstWhere((evaluation) => + evaluation.evaluatee_id == + dutyParticipant.person!.id!); + await deleteEvaluation(evaluation.id!.toString()); + + } + + } + + + Future loadDutyParticipants() async{ + + int? parentOrganizationId = campusAppsPortalInstance.getUserPerson(). + organization!.parent_organizations[0].parent_organizations[0].id; + + + + final dutyParticipants = await fetchDutyParticipantsByDutyActivityId( + parentOrganizationId!,campusAppsPortalInstance.getLeaderParticipant().activity!.id!); + + setState(() { + _dutyParticipants = dutyParticipants; + }); + } + + Future loadDutyAttendance() async{ + + int? parentOrganizationId = campusAppsPortalInstance.getUserPerson(). + organization!.parent_organizations[0].parent_organizations[0].id; + + final dutyAttendance = await getDutyAttendanceToday( + parentOrganizationId!,workActivityId); + setState(() { + _fetchedDutyAttendance = dutyAttendance; + }); + } + + Future loadEvaluations() async{ + + if (workActivityInstance.id == -1) { + workActivityInstance = await campusAttendanceSystemInstance + .getCheckinActivityInstance( + workActivityId); + } + + final evaluations = await getActivityInstanceEvaluations(workActivityInstance.id!); + + setState(() { + _fetchedEvaluations = evaluations; + }); + + } + + + + + TimeOfDay? _getInitialTime(DutyParticipant participant) { + final attendance = _fetchedDutyAttendance.firstWhere( + (attendance) => + attendance.person_id == participant.person!.id! && + attendance.sign_in_time != null,); + + if (attendance.sign_in_time != null) { + + final dateTime = DateTime.parse(attendance.sign_in_time.toString()); + return TimeOfDay.fromDateTime(dateTime); + } else { + + return null; + } + } + + + @override + Widget build(BuildContext context) { + + return Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 60, + ), + Row( + children: [ + SizedBox( + width: 17, + ), + Icon( + IconData(0xe6f2, fontFamily: 'MaterialIcons'), + size: 25, + color: Colors.blueAccent, + ), + SizedBox( + width: 10, + ), + Text( + 'Duty :', + overflow: TextOverflow.clip, + style: TextStyle(fontSize: 16,fontWeight: FontWeight.normal) + ), + SizedBox( + width: 20, + ), + + Flexible( + flex: 2, + child: Container( + width: 200, + child: Text( + campusAppsPortalInstance.getLeaderParticipant().activity!.name!, + overflow: TextOverflow.clip, + style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold) + ), + ), + ), + SizedBox( + height: 50, + ) + ], + ), + SizedBox( + height: 30, + ), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child:Row( + children: [ + SizedBox( + width: 15, + ), + Container( + child: _dutyParticipants.isEmpty ? SizedBox(): buildTable(), + ) + ], + ), + ), + ], + ), + ); + } + +Widget buildTable(){ + return Card( + child: Padding( + padding:const EdgeInsets.all(8.0), + child: Column( + children: [ + + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Container( + width: 1100, + 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( + "Status", + style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), + ), + ), + DataColumn( + label: Text( + "Time", + style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), + ), + ), + DataColumn( + label: Text( + "Absent", + style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), + ), + ), + ], + + rows: _dutyParticipants.map((participant){ + + bool isAbsent = true; + if (_fetchedEvaluations + .firstWhere( + (evaluation) => + evaluation.evaluatee_id == + participant.person!.id!, + orElse: () => new Evaluation( + evaluatee_id: -1)) + .evaluatee_id != + -1) + isAbsent = false; + + 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( + _fetchedDutyAttendance + .firstWhere( + (attendance) => + attendance.person_id == + participant.person!.id! && + attendance.sign_in_time != + null, + orElse: () => + new ActivityAttendance( + sign_in_time: null) + ) + .sign_in_time != + null ? + Text( + "Present", + style: TextStyle( + color: Colors.green + ), + ): + Text( + "Absent", + style: TextStyle( + color: Colors.red + ), + ), + ), + + if(_fetchedDutyAttendance.firstWhere((attendance) => + attendance.person_id == participant.person!.id! + && attendance.sign_in_time != null, + orElse: () => + new ActivityAttendance( + person_id: -1) + ).person_id !=-1) + DataCell( + TimePickerCell( + onTimeSelected: (TimeOfDay selectedTime){ + // Handle the selected time here. + print('Selected Time: $selectedTime'); + }, + initialTime:_getInitialTime(participant), + isButtonEnabled:isAbsent, + ), + ) + else + DataCell( + TimePickerCell( + onTimeSelected: (TimeOfDay selectedTime) async{ + // Handle the selected time here. + print('Selected Time: $selectedTime'); + await submitDutyAttendance(participant,selectedTime); + + setState(() {}); + }, + initialTime:null, + isButtonEnabled:isAbsent, + ), + ), + + if (_fetchedEvaluations + .firstWhere( + (evaluation) => + evaluation.evaluatee_id == + participant.person!.id!, + orElse: () => new Evaluation( + evaluatee_id: -1)) + .evaluatee_id != + -1) + + DataCell(Checkbox( // Add a Checkbox to the cell + value: _fetchedEvaluations + .firstWhere((evaluation) => + evaluation.evaluatee_id == + participant.person!.id!) + .response!=null, + onChanged: (bool? value) async{ + await toggleAbsent(participant,value!); + + _fetchedEvaluations = + await getActivityInstanceEvaluations( + workActivityInstance.id!); + setState(() {}); + }, + ) + ) + else + DataCell(Checkbox( // Add a Checkbox to the cell + value: false, + onChanged: (bool? value) async{ + await toggleAbsent(participant,value!); + + _fetchedEvaluations = + await getActivityInstanceEvaluations( + workActivityInstance.id!); + setState(() {}); + }, + ) + ) + ], + ); + }).toList(), + ), + ), + ), + ], + ), + ), + ); + } + + +} + +class TimePickerCell extends StatefulWidget { + + final ValueChanged onTimeSelected; + final TimeOfDay? initialTime; + final bool isButtonEnabled; + + + TimePickerCell({required this.onTimeSelected,this.initialTime,required this.isButtonEnabled}); + + @override + State createState() => _TimePickerCellState(); +} + +class _TimePickerCellState extends State { + + TimeOfDay? _selectedTime; + + @override + void initState() { + super.initState(); + _selectedTime = widget.initialTime; + + // Initialize _selectedTime with initialTime + } + + + @override + Widget build(BuildContext context) { + + + + if(widget.initialTime !=null){ + _selectedTime = widget.initialTime; + }else if(widget.initialTime ==null){ + _selectedTime = widget.initialTime; + } + + + return Container( + width: 120, + height: 70, + child: Row( + children: [ + + if(_selectedTime !=null) + Text( + _selectedTime?.format(context) ?? '', + style: TextStyle( + color: _selectedTime != null ? Colors.black : Colors.grey, + ) + ), + + if(_selectedTime == null) + ElevatedButton( + onPressed: widget.isButtonEnabled ? () async{ + final selectedTime = await showTimePicker( + context: context, + initialTime: _selectedTime ?? TimeOfDay.now(), + ); + + if(selectedTime !=null){ + setState(() { + _selectedTime = selectedTime; + + }); + + widget.onTimeSelected(selectedTime); + } + }:null, + child: Text('Pick a Time'), + ) + ], + ), + ); + + } +} \ No newline at end of file diff --git a/campus/frontend/lib/avinya/attendance/lib/widgets/person_attendance_report.dart b/campus/frontend/lib/avinya/attendance/lib/widgets/person_attendance_report.dart index d4b8d169..25b5fb28 100644 --- a/campus/frontend/lib/avinya/attendance/lib/widgets/person_attendance_report.dart +++ b/campus/frontend/lib/avinya/attendance/lib/widgets/person_attendance_report.dart @@ -4,6 +4,7 @@ import 'package:attendance/data/activity_attendance.dart'; import 'package:intl/intl.dart'; import 'package:gallery/data/campus_apps_portal.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; import '../routing.dart'; List getWeekdaysFromDate(DateTime fromDate, int numberOfWeekdays) { @@ -140,7 +141,14 @@ class _PersonAttendanceMarkerReportState }// } else if (snapshot.hasError) { // return Text("${snapshot.error}"); // } - return CircularProgressIndicator(); + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Colors + .blue), // Customize the color of the indicator + size: 70, // Customize the size of the indicator + ), + ); }, ); } diff --git a/campus/frontend/lib/data/campus_apps_portal.dart b/campus/frontend/lib/data/campus_apps_portal.dart index cd4f5777..af95dd6d 100644 --- a/campus/frontend/lib/data/campus_apps_portal.dart +++ b/campus/frontend/lib/data/campus_apps_portal.dart @@ -1,5 +1,5 @@ import 'dart:developer'; - +import 'package:gallery/avinya/attendance/lib/data/duty_participant.dart'; import 'package:gallery/data/person.dart'; import '../auth.dart'; @@ -34,6 +34,8 @@ class CampusAppsPortal { bool isFoundation = false; bool isGroupFetched = false; + DutyParticipant leaderParticipant = new DutyParticipant(); + final activityIds = { 'school-day': 1, 'arrival': 2, @@ -102,6 +104,14 @@ class CampusAppsPortal { return userPerson; } + void setLeaderParticipant(DutyParticipant dutyLeaderParticipant){ + leaderParticipant = dutyLeaderParticipant; + } + + DutyParticipant getLeaderParticipant(){ + return leaderParticipant; + } + // void setApplication(Application? application) { // this.application = application!; // } @@ -200,6 +210,16 @@ class CampusAppsPortal { this.isStudent) { this.isGroupFetched = true; } + + if(isStudent){ + DutyParticipant? dutyParticipant = await fetchDutyParticipant(person.id!); + + if( dutyParticipant !=null && dutyParticipant.role == 'leader'){ + campusAppsPortalInstance.setLeaderParticipant(dutyParticipant); + } + + } + } } } catch (e) { diff --git a/campus/mobile/.vscode/launch.json b/campus/mobile/.vscode/launch.json index 2ce097ff..24877418 100644 --- a/campus/mobile/.vscode/launch.json +++ b/campus/mobile/.vscode/launch.json @@ -29,7 +29,7 @@ "request": "launch", "type": "dart", "flutterMode": "debug", - "deviceId": "TECNO KG5j", + "deviceId": "R9WR114BT3J", "runTestsOnDevice": false, // "args": [ // "--flavor", diff --git a/campus/mobile/assets/config/dev.json b/campus/mobile/assets/config/dev.json index 18cae289..61d7f205 100644 --- a/campus/mobile/assets/config/dev.json +++ b/campus/mobile/assets/config/dev.json @@ -1,6 +1,6 @@ { - "campusProfileBffApiUrl" : "http://localhost:9090", - "campusAttendanceBffApiUrl" : "http://localhost:9091", + "campusProfileBffApiUrl" : "http://192.168.1.100:9090", + "campusAttendanceBffApiUrl" : "http://192.168.1.100:9091", "campusPctiNotesBffApiUrl" : "http://localhost:9092", "campusPctiFeedbackBffApiUrl" : "http://localhost:9093", "campusAssetsBffApiUrl" : "http://localhost:9094", diff --git a/campus/mobile/lib/avinya/attendance/lib/app.dart b/campus/mobile/lib/avinya/attendance/lib/app.dart index 51da3d6d..10a6b956 100644 --- a/campus/mobile/lib/avinya/attendance/lib/app.dart +++ b/campus/mobile/lib/avinya/attendance/lib/app.dart @@ -51,7 +51,9 @@ class _CampusAttendanceManagementSystemState '/avinya_types', '/#access_token', '/person_attendance_report', - '/qr_attendance_marker' + '/qr_attendance_marker', + '/duty_participants', + '/duty_attendance_marker', ], guard: _guard, initialRoute: '/attendance_marker', @@ -124,6 +126,12 @@ class _CampusAttendanceManagementSystemState final qrAttendanceMarkerRoute = ParsedRoute('/qr_attendance_marker', '/qr_attendance_marker', {}, {}); + final dutyParticipantsRoute = ParsedRoute( + '/duty_participants','/duty_participants', {}, {}); + + final dutyAttendanceMarkerRoute = ParsedRoute( + '/duty_attendance_marker','/duty_attendance_marker', {}, {}); + // // Go to /apply if the user is not signed in log("_guard signed in $signedIn"); // log("_guard JWT sub ${jwt_sub}"); @@ -145,6 +153,10 @@ class _CampusAttendanceManagementSystemState return personAttendanceReportRoute; } else if (signedIn && from == qrAttendanceMarkerRoute) { return qrAttendanceMarkerRoute; + }else if (signedIn && from == dutyParticipantsRoute){ + return dutyParticipantsRoute; + } else if (signedIn && from == dutyAttendanceMarkerRoute){ + return dutyAttendanceMarkerRoute; } // Go to /application if the user is signed in and tries to go to /signin. else if (signedIn && from == signInRoute) { diff --git a/campus/mobile/lib/avinya/attendance/lib/data.dart b/campus/mobile/lib/avinya/attendance/lib/data.dart index 36065bfc..fa635ddc 100644 --- a/campus/mobile/lib/avinya/attendance/lib/data.dart +++ b/campus/mobile/lib/avinya/attendance/lib/data.dart @@ -9,3 +9,5 @@ export 'data/vacancy.dart'; export 'data/application.dart'; export 'data/avinya_type.dart'; export 'data/activity.dart'; +export 'data/duty_participant.dart'; +export 'data/duty_rotation_metadata.dart'; diff --git a/campus/mobile/lib/avinya/attendance/lib/data/activity.dart b/campus/mobile/lib/avinya/attendance/lib/data/activity.dart index d9aef65f..734d6185 100644 --- a/campus/mobile/lib/avinya/attendance/lib/data/activity.dart +++ b/campus/mobile/lib/avinya/attendance/lib/data/activity.dart @@ -87,6 +87,24 @@ Future> fetchActivitys() async { } } +Future> fetchActivitiesByAvinyaType(int avinyaTypeID) async{ + +final response = await http + .get(Uri.parse(AppConfig.campusAttendanceBffApiUrl + '/activities_by_avinya_type/$avinyaTypeID')); + + if (response.statusCode == 200){ + var resultsJson = json.decode(response.body).cast>(); + List activitiesByAvinyaType = await resultsJson + .map((json) => Activity.fromJson(json)) + .toList(); + + return activitiesByAvinyaType; + + }else{ + throw Exception('Failed to load Activities'); + } +} + Future fetchActivity(String name) async { final response = await http.get( Uri.parse(AppConfig.campusAttendanceBffApiUrl + '/activity/$name'), diff --git a/campus/mobile/lib/avinya/attendance/lib/data/activity_attendance.dart b/campus/mobile/lib/avinya/attendance/lib/data/activity_attendance.dart index 1ad42a3b..a1df387c 100644 --- a/campus/mobile/lib/avinya/attendance/lib/data/activity_attendance.dart +++ b/campus/mobile/lib/avinya/attendance/lib/data/activity_attendance.dart @@ -255,3 +255,44 @@ Future> getClassActivityAttendanceReportByParentOrg( 'Failed to get Activity Participant Attendance report for activity $activity_id'); } } + +Future createDutyActivityAttendance( + ActivityAttendance activityAttendance) async { + final response = await http.post( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/duty_attendance'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + body: jsonEncode(activityAttendance.toJson()), + ); + if (response.statusCode > 199 && response.statusCode < 300) { + return ActivityAttendance.fromJson(jsonDecode(response.body)); + } else { + throw Exception('Failed to create Duty Activity Participant Attendance.'); + } +} + +Future> getDutyAttendanceToday( + int organization_id, int activity_id) async { + final response = await http.get( + Uri.parse( + '${AppConfig.campusAttendanceBffApiUrl}/duty_attendance_today/$organization_id/$activity_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>(); + List dutyAttendances = await resultsJson + .map((json) => ActivityAttendance.fromJson(json)) + .toList(); + return dutyAttendances; + } else { + throw Exception( + 'Failed to get Duty Participant Attendance for org ID $organization_id and activity $activity_id for today.'); + } +} \ No newline at end of file diff --git a/campus/mobile/lib/avinya/attendance/lib/data/duty_participant.dart b/campus/mobile/lib/avinya/attendance/lib/data/duty_participant.dart new file mode 100644 index 00000000..a2a1844f --- /dev/null +++ b/campus/mobile/lib/avinya/attendance/lib/data/duty_participant.dart @@ -0,0 +1,168 @@ + + + +import 'package:http/http.dart' as http; + +import 'dart:developer'; + +import 'package:mobile/data/person.dart'; + +import 'activity.dart'; + +import 'package:mobile/config/app_config.dart'; + +import 'dart:convert'; + +class DutyParticipant{ + + int? id; + int? activity_id; + Activity? activity; + int? person_id; + Person? person; + String? role; + String? created; + + DutyParticipant({ + this.id, + this.activity_id, + this.activity, + this.person_id, + this.person, + this.role, + this.created, + }); + + factory DutyParticipant.fromJson(Map json){ + log(json.toString()); + + Activity? activityObj; + Person? personObj; + + if(json['activity'] != null){ + activityObj = Activity.fromJson(json['activity']); + } + + if(json['person'] != null){ + personObj = Person.fromJson(json['person']); + } + + return DutyParticipant( + id: json['id'], + activity_id: json['activity_id'], + activity: activityObj, + person_id: json['person_id'], + person: personObj, + role: json['role'], + created: json['created'], + ); + } + + Map toJson() => { + if (id != null) 'id': id, + if (activity_id != null) 'activity_id': activity_id, + if (activity != null) 'activity': activity, + if (person_id != null) 'person_id': person_id, + if (person != null) 'person': person, + if (role != null) 'role': role, + if (created !=null) 'created':created, + + }; + +} + +Future> fetchDutyParticipants(int organization_id) async{ + + final response = await http.get( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/duty_participants/$organization_id'), + headers:{ + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + ); + + if (response.statusCode == 200) { + var resultsJson = json.decode(response.body).cast>(); + List fetchDutyForParticipants = await resultsJson + .map((json) => DutyParticipant.fromJson(json)) + .toList(); + return fetchDutyForParticipants; + } else { + throw Exception('Failed to load duty participants for organization ID $organization_id'); + } +} + + +Future createDutyForParticipant(DutyParticipant dutyParticipant) async{ + + final response = await http.post( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/duty_for_participant'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + body: jsonEncode(dutyParticipant.toJson()), + ); + if (response.statusCode > 199 && response.statusCode < 300) { + return DutyParticipant.fromJson(jsonDecode(response.body)); + } else { + throw Exception('Failed to create duty for participant.'); + } +} + +Future deleteDutyForParticipant(int id) async { + final response = await http.delete( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/duty_for_participant/$id'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + ); + if (response.statusCode > 199 && response.statusCode < 300) { + return int.parse(response.body); + } else { + throw Exception('Failed to delete Duty For Participant.'); + } +} + +Future> fetchDutyParticipantsByDutyActivityId(int organization_id,int duty_activity_id) async{ + + final response = await http.get( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/duty_participants_by_duty_activity_id/$organization_id/$duty_activity_id'), + headers:{ + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + ); + + if (response.statusCode == 200) { + var resultsJson = json.decode(response.body).cast>(); + List fetchDutyForParticipants = await resultsJson + .map((json) => DutyParticipant.fromJson(json)) + .toList(); + return fetchDutyForParticipants; + } else { + throw Exception('Failed to load duty participants for organization ID $organization_id and duty activity ID $duty_activity_id'); + } +} + +Future fetchDutyParticipant(int personId) async { + final response = await http.get( + Uri.parse(AppConfig.campusAttendanceBffApiUrl + '/duty_participant/$personId'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ' + AppConfig.campusBffApiKey, + }, + ); + + if (response.statusCode == 200) { + DutyParticipant dutyParticipant = DutyParticipant.fromJson(json.decode(response.body)); + return dutyParticipant; + } else { + return null; + } +} \ No newline at end of file diff --git a/campus/mobile/lib/avinya/attendance/lib/data/duty_rotation_metadata.dart b/campus/mobile/lib/avinya/attendance/lib/data/duty_rotation_metadata.dart new file mode 100644 index 00000000..84f3cad5 --- /dev/null +++ b/campus/mobile/lib/avinya/attendance/lib/data/duty_rotation_metadata.dart @@ -0,0 +1,75 @@ + + +import 'dart:convert'; +import 'dart:developer'; +import 'package:http/http.dart' as http; +import 'package:mobile/config/app_config.dart'; + +class DutyRotationMetaDetails{ + + int? id; + String? start_date; + String? end_date; + int? organization_id; + + DutyRotationMetaDetails({ + this.id, + this.start_date, + this.end_date, + this.organization_id, + }); + + factory DutyRotationMetaDetails.fromJson(Map json){ + log(json.toString()); + return DutyRotationMetaDetails( + id: json['id'], + start_date: json['start_date'], + end_date: json['end_date'], + organization_id: json['organization_id'], + ); + } + + Map toJson() => { + if (id != null) 'id': id, + if (start_date != null) 'start_date': start_date, + if (end_date != null) 'end_date': end_date, + if (organization_id !=null) 'organization_id' : organization_id, + }; + +} + +Future updateDutyRotationMetadata(DutyRotationMetaDetails dutyRotationMetadata) async { + final response = await http.put( + Uri.parse('${AppConfig.campusAttendanceBffApiUrl}/update_duty_rotation_metadata'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': 'Bearer ${AppConfig.campusBffApiKey}', + }, + body: jsonEncode(dutyRotationMetadata.toJson()), + ); + if (response.statusCode == 200) { + return DutyRotationMetaDetails.fromJson(jsonDecode(response.body)); + } else { + throw Exception('Failed to update Duty Rotation.'); + } +} + +Future fetchDutyRotationMetadataByOrganization(int organization_id) async { + final response = await http.get( + Uri.parse(AppConfig.campusAttendanceBffApiUrl + '/duty_rotation_metadata_by_organization/$organization_id'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'accept': 'application/json', + 'Authorization': 'Bearer ' + AppConfig.campusBffApiKey, + }, + ); + + if (response.statusCode == 200) { + DutyRotationMetaDetails dutyRotationMetaDetails = DutyRotationMetaDetails.fromJson(json.decode(response.body)); + print(dutyRotationMetaDetails.toJson()); + return dutyRotationMetaDetails; + } else { + throw Exception('Failed to load duty rotation metadata'); + } +} + diff --git a/campus/mobile/lib/avinya/attendance/lib/screens/duty_attendance_marker.dart b/campus/mobile/lib/avinya/attendance/lib/screens/duty_attendance_marker.dart new file mode 100644 index 00000000..682a619b --- /dev/null +++ b/campus/mobile/lib/avinya/attendance/lib/screens/duty_attendance_marker.dart @@ -0,0 +1,36 @@ + + + +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter/src/widgets/placeholder.dart'; + +import 'package:attendance/widgets/duty_attendance_marker.dart'; + +class DutyAttendanceMarkerScreen extends StatefulWidget { + const DutyAttendanceMarkerScreen({super.key}); + + @override + State createState() => _DutyAttendanceMarkerScreenState(); +} + +class _DutyAttendanceMarkerScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Duty Attendance Marker"), + ), + body: SingleChildScrollView( + child: Container( + child: Column( + children: [ + DutyAttendanceMarker(), + ], + ), + ), + ), + + ); + } +} \ No newline at end of file diff --git a/campus/mobile/lib/avinya/attendance/lib/screens/duty_participants.dart b/campus/mobile/lib/avinya/attendance/lib/screens/duty_participants.dart new file mode 100644 index 00000000..764012ea --- /dev/null +++ b/campus/mobile/lib/avinya/attendance/lib/screens/duty_participants.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:attendance/widgets/assign_duty_for_participant.dart'; + + +class DutyParticipantsScreen extends StatefulWidget { + const DutyParticipantsScreen({super.key}); + + @override + State createState() => _DutyParticipantsScreenState(); +} + +class _DutyParticipantsScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Duty Participants"), + ), + body: SingleChildScrollView( + child: Container( + child:Column(children: [ + Container(child: AssignDutyForParticipant()), + ], + ) + ), + ), + + ); + } +} \ No newline at end of file diff --git a/campus/mobile/lib/avinya/attendance/lib/screens/scaffold.dart b/campus/mobile/lib/avinya/attendance/lib/screens/scaffold.dart index 35c4bf55..68c2493a 100644 --- a/campus/mobile/lib/avinya/attendance/lib/screens/scaffold.dart +++ b/campus/mobile/lib/avinya/attendance/lib/screens/scaffold.dart @@ -16,6 +16,7 @@ class SMSScaffold extends StatelessWidget { '/daily_attendance_report', // '/weekly_payment_report', // '/person_attendance_report', + '/duty_participants', ]; static const studentPageNames = [ @@ -23,6 +24,12 @@ class SMSScaffold extends StatelessWidget { '/person_attendance_report', ]; + static const leaderParticipantPageNames = [ + '/attendance_marker', + '/person_attendance_report', + '/duty_attendance_marker', + ]; + const SMSScaffold({ super.key, }); @@ -57,8 +64,31 @@ class SMSScaffold extends StatelessWidget { // title: 'Weekly Payment Report', // icon: Icons.summarize, // ), + AdaptiveScaffoldDestination( + title: 'Assign duties', + icon: Icons.work, + ), ]; - } else { + }else if(campusAppsPortalInstance.isStudent + && campusAppsPortalInstance.getLeaderParticipant().role == 'leader'){ + + destinations = const[ + AdaptiveScaffoldDestination( + title: 'Attendance Marker', + icon: Icons.person_outline, + ), + AdaptiveScaffoldDestination( + title: 'Payment Report', + icon: Icons.summarize, + ), + AdaptiveScaffoldDestination( + title: 'Duty Attendance Marker', + icon: Icons.people, + ), + + ]; + } + else { destinations = const [ AdaptiveScaffoldDestination( title: 'Attendance Marker', @@ -133,7 +163,12 @@ class SMSScaffold extends StatelessWidget { campusAppsPortalInstance.isSecurity || campusAppsPortalInstance.isFoundation) { routeState.go(pageNames[idx]); - } else { + }else if(campusAppsPortalInstance.isStudent + && campusAppsPortalInstance.getLeaderParticipant().role == 'leader'){ + + routeState.go(leaderParticipantPageNames[idx]); + + }else { routeState.go(studentPageNames[idx]); } }, @@ -160,7 +195,12 @@ class SMSScaffold extends StatelessWidget { campusAppsPortalInstance.isSecurity || campusAppsPortalInstance.isFoundation) { index = pageNames.indexOf(pathTemplate); - } else { + + }else if(campusAppsPortalInstance.isStudent + && campusAppsPortalInstance.getLeaderParticipant().role == 'leader'){ + + index = leaderParticipantPageNames.indexOf(pathTemplate); + }else { index = studentPageNames.indexOf(pathTemplate); } diff --git a/campus/mobile/lib/avinya/attendance/lib/screens/scaffold_body.dart b/campus/mobile/lib/avinya/attendance/lib/screens/scaffold_body.dart index 51789e40..0b30d0be 100644 --- a/campus/mobile/lib/avinya/attendance/lib/screens/scaffold_body.dart +++ b/campus/mobile/lib/avinya/attendance/lib/screens/scaffold_body.dart @@ -3,6 +3,8 @@ import 'package:attendance/screens/avinya_types.dart'; import 'package:attendance/screens/attendance_marker.dart'; import 'package:attendance/screens/bulk_attendance_marker.dart'; import 'package:attendance/screens/daily_attendance_report.dart'; +import 'package:attendance/screens/duty_participants.dart'; +import 'package:attendance/screens/duty_attendance_marker.dart'; import 'package:flutter/material.dart'; import 'package:attendance/screens/weekly_payment_report.dart'; @@ -75,6 +77,16 @@ class SMSScaffoldBody extends StatelessWidget { key: ValueKey('person_attendance_report'), child: PersonAttendanceReportScreen(), ) + else if (currentRoute.pathTemplate.startsWith('/duty_participants')) + const FadeTransitionPage( + key: ValueKey('duty_participants'), + child: DutyParticipantsScreen(), + ) + else if (currentRoute.pathTemplate.startsWith('/duty_attendance_marker')) + const FadeTransitionPage( + key: ValueKey('duty_participants'), + child: DutyAttendanceMarkerScreen(), + ) // Avoid building a Navigator with an empty `pages` list when the // RouteState is set to an unexpected path, such as /signin. // 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 new file mode 100644 index 00000000..6969adbe --- /dev/null +++ b/campus/mobile/lib/avinya/attendance/lib/widgets/assign_duty_for_participant.dart @@ -0,0 +1,760 @@ +import 'package:flutter/material.dart'; +import 'package:attendance/data.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:mobile/constants.dart'; +import 'package:intl/intl.dart'; + + +class AssignDutyForParticipant extends StatefulWidget { + const AssignDutyForParticipant({super.key}); + + @override + State createState() => _AssignDutyForParticipantState(); +} + +class _AssignDutyForParticipantState extends State { + + var _selectedClassValue; + var _selectedPersonValue; + Organization? _fetchedOrganization; + + late List> _dropDownPersonList; + late List _selectedClassValues; + late List _selectedPersonValues; + late List _selectedRoleValues; + + List _dutyParticipants = []; + List _activitiesByAvinyaType = []; + List _activitiesNames = []; + List _dutyRelatedParticipantsFilterAndStore = []; //filter And Store duty Relavant Participants + List _dropDownRoleList = ['leader','member']; + late DutyRotationMetaDetails _rotationMetaDetails; + + late TextEditingController _startDate; + late TextEditingController _endDate; + + bool _startDateSelected = true; + bool _endDateSelected = true; + + + @override + void initState(){ + super.initState(); + loadActivitiesByAvinyaType(); + loadRotationMetadetails(); + _startDate = TextEditingController(); + _endDate = TextEditingController(); + } + + @override + void dispose() { + _startDate.dispose(); + _endDate.dispose(); + super.dispose(); + } + + bool hasLeaderRoleWithActivity(String? activityName,String? allocatedRole){ + print('duty participants : ${_dutyParticipants}'); + bool hasLeaderRoleWithActivity; + + if(allocatedRole == "leader"){ + hasLeaderRoleWithActivity = _dutyParticipants.any((participant)=>participant.activity?.name == activityName && participant.role == 'leader'); + + if(hasLeaderRoleWithActivity){ + return true; + }else{ + return false; + } + }else{ + return false; + } + } + + Future> loadDutyParticipantsData(int organization_id) async{ + + print('organization id inside loadDutyParticipantsData() methos : ${organization_id}'); + 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{ + setState(() { + _startDateSelected = false; + _endDateSelected = false; + }); + } + + } + + 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(); + + _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); + + } + + + + @override + void didChangeDependencies(){ + super.didChangeDependencies(); + print(''); + print('execute did change dependencies'); + } + + @override + Widget build(BuildContext context) { + + return Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(left: 15.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + height: 10, + ), + Container( + width: 300, + child: TextField( + 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( + 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: 35), + child: _startDateSelected && _endDateSelected + ? SizedBox() + : Text( + 'Please select both start and end dates', + style: TextStyle(color: Colors.red), + ), + ), + ], + + ), + ), + SizedBox( + height: 20, + ), + 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, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + for (var org in campusAppsPortalInstance + .getUserPerson() + .organization! + .child_organizations) + + if (org.child_organizations.length > 0) + SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + Container( + margin: EdgeInsets.only(left: 14.0), + child: Row( + children: [ + Icon( + IconData(0xe6f2, fontFamily: 'MaterialIcons'), + size: 25, + color: Colors.blueAccent, + ), + SizedBox( + width: 10, + ), + Text( + '${_activitiesNames[tableIndex]}', + overflow: TextOverflow.clip, + style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold) + ) + ], + ), + ), + SizedBox( + height: 15, + ), + Row( + children:[ + SizedBox( + width: 15, + ), + 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.0, + ), + Container( + margin: EdgeInsets.only(left: 10.0), + width: 120, + child: buildClassDropDownButton(org,tableIndex,_dutyParticipants) + ), + ] + ), + SizedBox( + height: 25, + ), + Row( + children: [ + SizedBox( + width: 15, + ), + 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.0, + ), + ConstrainedBox( + constraints: BoxConstraints( + minWidth: 120, + maxWidth: 240, + ), + child: buildPersonDropDownButton(tableIndex) + + ), + ] + ), + SizedBox( + height: 20, + ), + Row( + children: [ + SizedBox( + width: 15, + ), + 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.0, + ), + Container( + margin: EdgeInsets.only(left: 10.0), + width: 120, + child: buildRoleDropDownButton(tableIndex) + ), + ], + ), + ], + ), + ), + buildTable(_dutyRelatedParticipantsFilterAndStore,tableIndex,_dutyParticipants), + SizedBox( + height: 30, + ) + ], + + ), + ); + }, + ), + ); + } + //} + return Container( + margin: EdgeInsets.only(top: 10), + child: SpinKitCircle( + color: (Colors + .blue), + size: 70, + ), + ); + }, + ), + ], + )); + } + + Widget buildTable(List dutyRelatedParticipantsFilterAndStore,int tableIndex,List dutyParticipants){ + return Card( + margin: EdgeInsets.only(left: 15.0), + child: Padding( + padding:const EdgeInsets.all(8.0), + child: Column( + children: [ + + SingleChildScrollView( + scrollDirection: Axis.horizontal, + 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'; + + 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,), + 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)); + + setState(() { + _selectedClassValues[tableIndex] = newValue; + _dropDownPersonList[tableIndex] = _fetchedOrganization!.people; + + }); + }, + ); + + } + + 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{ + + 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); + 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), + ), + 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 leader role participant is already added to this $activityName duty.", + textAlign: TextAlign.center, + ), + Text( + "You can't add another participant with a leader role.If you'd like to add this participant as a leader, please remove the current leader first.", + textAlign: TextAlign.center, + ), + ], + ), + 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(', ')}'; + + showDialog( + 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), + ), + content: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + Icons.close, + color: Colors.red, + size: 40, + ), + SizedBox(height: 10,), + Text( + 'Cannot add duty for participant.', + textAlign: TextAlign.center, + ), + Text( + errorMessage, + textAlign: TextAlign.center, + ) + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text('OK'), + ), + ], + ), + ); + }, + ); + } + }, + ); +} + +Future _selectStartDate(BuildContext context) async{ + final DateTime? picked = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1950), + lastDate: DateTime(2100), + ); + if(picked !=null){ + print(picked); + String formattedDate = DateFormat('yyyy-MM-dd').format(picked); + print(formattedDate); + + setState(() { + _startDate.text = formattedDate; + _startDateSelected= true; + }); + }else if(picked == null){ + setState(() { + String formattedDate = ''; + _startDate.text = formattedDate; + _startDateSelected = false; + }); + } +} + +Future _selectEndDate(BuildContext context) async{ + final DateTime? picked = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1950), + lastDate: DateTime(2100), + ); + 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 + }); + + 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){ + setState(() { + String formattedDate = ''; + _endDate.text = formattedDate; + _endDateSelected= false; + }); + } +} + + + +} + + 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 new file mode 100644 index 00000000..f89363e8 --- /dev/null +++ b/campus/mobile/lib/avinya/attendance/lib/widgets/duty_attendance_marker.dart @@ -0,0 +1,512 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:attendance/data/activity_attendance.dart'; +import 'package:flutter/src/widgets/placeholder.dart'; +import 'package:attendance/data.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:mobile/constants.dart'; +import '../data/activity_instance.dart'; +import 'package:attendance/data/evaluation.dart'; + + +class DutyAttendanceMarker extends StatefulWidget { + const DutyAttendanceMarker({super.key}); + + @override + State createState() => _DutyAttendanceMarkerState(); +} + +class _DutyAttendanceMarkerState extends State { + + +var workActivityId = 0; +var workActivityInstance = ActivityInstance(id: -1); + +List _dutyParticipants = []; +List _fetchedDutyAttendance = []; +List _fetchedEvaluations = []; +List selectedRows = []; + + + + @override + void initState(){ + super.initState(); + workActivityId = campusAppsPortalInstance.activityIds['work']!; + loadDutyParticipants(); + loadDutyAttendance(); + loadEvaluations(); + } + + + Future submitDutyAttendance(DutyParticipant dutyParticipant,TimeOfDay selectedTime) async{ + + if (workActivityInstance.id == -1) { + workActivityInstance = await campusAttendanceSystemInstance + .getCheckinActivityInstance(workActivityId); + } + + int index = -1; + + index = _fetchedDutyAttendance.indexWhere((attendance) => + attendance.person_id == dutyParticipant.person!.id && attendance.sign_in_time != null); + + print( + 'index: $index person_id: ${dutyParticipant.person!.id} _fetchedAttendance lenth ${_fetchedDutyAttendance.length}'); + + if (index == -1) { + index = _fetchedDutyAttendance + .indexWhere((attendance) => attendance.person_id == -1); + if (index == -1) { + print( + 'index is still -1 => index: $index person_id: ${dutyParticipant.person!.id} '); + // if index is still -1 then there is no empty slot + // so we need to create a new slot + _fetchedDutyAttendance.add(ActivityAttendance( + person_id: -1, sign_in_time: null, sign_out_time: null)); + index = _fetchedDutyAttendance.length - 1; + } + } + + ActivityAttendance activityAttendance = ActivityAttendance( + person_id: -1, sign_in_time: null, sign_out_time: null); + + activityAttendance = ActivityAttendance( + activity_instance_id: workActivityInstance.id, + person_id: dutyParticipant.person!.id, + sign_in_time: DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, selectedTime.hour, selectedTime.minute).toString(), + in_marked_by: campusAppsPortalInstance.getUserPerson().digital_id, + ); + + + createDutyActivityAttendance(activityAttendance); + + _fetchedDutyAttendance[index] = activityAttendance; + + } + + Future toggleAbsent(DutyParticipant dutyParticipant, bool value) async{ + + if (workActivityInstance.id == -1) { + + workActivityInstance = await campusAttendanceSystemInstance.getCheckinActivityInstance(workActivityId); + + } + + if(value == true){ + + final Evaluation evaluation = Evaluation( + evaluatee_id: dutyParticipant.person!.id, + evaluator_id: campusAppsPortalInstance.getUserPerson().id, + evaluation_criteria_id: 54, + activity_instance_id: workActivityInstance.id, + response: "absence", + notes: "", + grade: 0 + ); + await createEvaluation([evaluation]); + + }else if(value == false){ + + var evaluation = _fetchedEvaluations.firstWhere((evaluation) => + evaluation.evaluatee_id == + dutyParticipant.person!.id!); + await deleteEvaluation(evaluation.id!.toString()); + + } + + } + + + Future loadDutyParticipants() async{ + + int? parentOrganizationId = campusAppsPortalInstance.getUserPerson(). + organization!.parent_organizations[0].parent_organizations[0].id; + + + + final dutyParticipants = await fetchDutyParticipantsByDutyActivityId( + parentOrganizationId!,campusAppsPortalInstance.getLeaderParticipant().activity!.id!); + + setState(() { + _dutyParticipants = dutyParticipants; + }); + } + + Future loadDutyAttendance() async{ + + int? parentOrganizationId = campusAppsPortalInstance.getUserPerson(). + organization!.parent_organizations[0].parent_organizations[0].id; + + final dutyAttendance = await getDutyAttendanceToday( + parentOrganizationId!,workActivityId); + setState(() { + _fetchedDutyAttendance = dutyAttendance; + }); + } + + Future loadEvaluations() async{ + + if (workActivityInstance.id == -1) { + workActivityInstance = await campusAttendanceSystemInstance + .getCheckinActivityInstance( + workActivityId); + } + + final evaluations = await getActivityInstanceEvaluations(workActivityInstance.id!); + + setState(() { + _fetchedEvaluations = evaluations; + }); + + } + + + + + TimeOfDay? _getInitialTime(DutyParticipant participant) { + final attendance = _fetchedDutyAttendance.firstWhere( + (attendance) => + attendance.person_id == participant.person!.id! && + attendance.sign_in_time != null,); + + if (attendance.sign_in_time != null) { + + final dateTime = DateTime.parse(attendance.sign_in_time.toString()); + return TimeOfDay.fromDateTime(dateTime); + } else { + + return null; + } + } + + + @override + Widget build(BuildContext context) { + + return Container( + margin: EdgeInsets.only(left: 10.0), + child: Column( + children: [ + SizedBox( + height: 20, + ), + Row( + children: [ + + Icon( + IconData(0xe6f2, fontFamily: 'MaterialIcons'), + size: 25, + color: Colors.blueAccent, + ), + SizedBox( + width: 10, + ), + Text( + 'Duty :', + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 16,fontWeight: FontWeight.normal) + ), + SizedBox( + width: 20, + ), + + Text( + campusAppsPortalInstance.getLeaderParticipant().activity!.name!, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold) + ), + SizedBox( + height: 100, + ) + ], + ), + SizedBox( + height: 20, + ), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + + _dutyParticipants.isEmpty ? SizedBox(): buildTable(), + ], + ) + ), + ], + ), + ); + } + +Widget buildTable(){ + return Card( + child: Padding( + padding:const EdgeInsets.all(8.0), + child: Column( + children: [ + + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Container( + width: 1100, + 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( + "Status", + style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), + ), + ), + DataColumn( + label: Text( + "Time", + style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), + ), + ), + DataColumn( + label: Text( + "Absent", + style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold), + ), + ), + ], + + rows: _dutyParticipants.map((participant){ + + bool isAbsent = true; + if (_fetchedEvaluations + .firstWhere( + (evaluation) => + evaluation.evaluatee_id == + participant.person!.id!, + orElse: () => new Evaluation( + evaluatee_id: -1)) + .evaluatee_id != + -1) + isAbsent = false; + + 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( + _fetchedDutyAttendance + .firstWhere( + (attendance) => + attendance.person_id == + participant.person!.id! && + attendance.sign_in_time != + null, + orElse: () => + new ActivityAttendance( + sign_in_time: null) + ) + .sign_in_time != + null ? + Text( + "Present", + style: TextStyle( + color: Colors.green + ), + ): + Text( + "Absent", + style: TextStyle( + color: Colors.red + ), + ), + ), + + if(_fetchedDutyAttendance.firstWhere((attendance) => + attendance.person_id == participant.person!.id! + && attendance.sign_in_time != null, + orElse: () => + new ActivityAttendance( + person_id: -1) + ).person_id !=-1) + DataCell( + TimePickerCell( + onTimeSelected: (TimeOfDay selectedTime){ + // Handle the selected time here. + print('Selected Time: $selectedTime'); + }, + initialTime:_getInitialTime(participant), + isButtonEnabled:isAbsent, + ), + ) + else + DataCell( + TimePickerCell( + onTimeSelected: (TimeOfDay selectedTime) async{ + // Handle the selected time here. + print('Selected Time: $selectedTime'); + await submitDutyAttendance(participant,selectedTime); + + setState(() {}); + }, + initialTime:null, + isButtonEnabled:isAbsent, + ), + ), + + if (_fetchedEvaluations + .firstWhere( + (evaluation) => + evaluation.evaluatee_id == + participant.person!.id!, + orElse: () => new Evaluation( + evaluatee_id: -1)) + .evaluatee_id != + -1) + + DataCell(Checkbox( // Add a Checkbox to the cell + value: _fetchedEvaluations + .firstWhere((evaluation) => + evaluation.evaluatee_id == + participant.person!.id!) + .response!=null, + onChanged: (bool? value) async{ + await toggleAbsent(participant,value!); + + _fetchedEvaluations = + await getActivityInstanceEvaluations( + workActivityInstance.id!); + setState(() {}); + }, + ) + ) + else + DataCell(Checkbox( // Add a Checkbox to the cell + value: false, + onChanged: (bool? value) async{ + await toggleAbsent(participant,value!); + + _fetchedEvaluations = + await getActivityInstanceEvaluations( + workActivityInstance.id!); + setState(() {}); + }, + ) + ) + ], + ); + }).toList(), + ), + ), + ), + ], + ), + ), + ); + } + + +} + +class TimePickerCell extends StatefulWidget { + + final ValueChanged onTimeSelected; + final TimeOfDay? initialTime; + final bool isButtonEnabled; + + + TimePickerCell({required this.onTimeSelected,this.initialTime,required this.isButtonEnabled}); + + @override + State createState() => _TimePickerCellState(); +} + +class _TimePickerCellState extends State { + + TimeOfDay? _selectedTime; + + @override + void initState() { + super.initState(); + _selectedTime = widget.initialTime; + + // Initialize _selectedTime with initialTime + } + + + @override + Widget build(BuildContext context) { + + + + if(widget.initialTime !=null){ + _selectedTime = widget.initialTime; + }else if(widget.initialTime ==null){ + _selectedTime = widget.initialTime; + } + + + return Container( + width: 120, + height: 70, + child: Row( + children: [ + + if(_selectedTime !=null) + Text( + _selectedTime?.format(context) ?? '', + style: TextStyle( + color: _selectedTime != null ? Colors.black : Colors.grey, + ) + ), + + if(_selectedTime == null) + ElevatedButton( + onPressed: widget.isButtonEnabled ? () async{ + final selectedTime = await showTimePicker( + context: context, + initialTime: _selectedTime ?? TimeOfDay.now(), + ); + + if(selectedTime !=null){ + setState(() { + _selectedTime = selectedTime; + + }); + + widget.onTimeSelected(selectedTime); + } + }:null, + child: Text('Pick a Time'), + ) + ], + ), + ); + + } +} \ No newline at end of file diff --git a/campus/mobile/lib/data/campus_apps_portal.dart b/campus/mobile/lib/data/campus_apps_portal.dart index 4b704da7..042b98ef 100644 --- a/campus/mobile/lib/data/campus_apps_portal.dart +++ b/campus/mobile/lib/data/campus_apps_portal.dart @@ -1,5 +1,6 @@ import 'dart:developer'; +import 'package:mobile/avinya/attendance/lib/data/duty_participant.dart'; import 'package:mobile/data/person.dart'; import '../auth.dart'; @@ -34,6 +35,8 @@ class CampusAppsPortal { bool isFoundation = false; bool isGroupFetched = false; + DutyParticipant leaderParticipant = new DutyParticipant(); + final activityIds = { 'school-day': 1, 'arrival': 2, @@ -102,6 +105,14 @@ class CampusAppsPortal { return userPerson; } + void setLeaderParticipant(DutyParticipant dutyLeaderParticipant){ + leaderParticipant = dutyLeaderParticipant; + } + + DutyParticipant getLeaderParticipant(){ + return leaderParticipant; + } + // void setApplication(Application? application) { // this.application = application!; // } @@ -196,6 +207,16 @@ class CampusAppsPortal { if (isSecurity || isTeacher || isFoundation || isStudent) { isGroupFetched = true; } + + if(isStudent){ + DutyParticipant? dutyParticipant = await fetchDutyParticipant(person.id!); + + if( dutyParticipant !=null && dutyParticipant.role == 'leader'){ + campusAppsPortalInstance.setLeaderParticipant(dutyParticipant); + } + + } + } } } catch (e) { diff --git a/campus/mobile/lib/main.dart b/campus/mobile/lib/main.dart index 310c09cb..43cd5178 100644 --- a/campus/mobile/lib/main.dart +++ b/campus/mobile/lib/main.dart @@ -79,7 +79,9 @@ void main() async { log('signedIn 1: $signedIn! '); signedIn = await galleryApp._auth.getSignedIn(); + print("signed in real value : ${signedIn}"); campusAppsPortalInstance.setSignedIn(signedIn); + print("signed in 2 real value : ${signedIn}"); runApp(GalleryApp()); }