11import { filterComplianceMembers } from '@/lib/compliance' ;
2+ import { HIPAA_TRAINING_ID } from '@/lib/data/hipaa-training-content' ;
23import { trainingVideos as trainingVideosData } from '@/lib/data/training-videos' ;
34import { serverApi } from '@/lib/server-api-client' ;
45import type { Invitation , Member , User } from '@db' ;
@@ -15,6 +16,14 @@ export interface TeamMembersData {
1516 pendingInvitations : Invitation [ ] ;
1617}
1718
19+ export interface TaskCompletion {
20+ completed : number ;
21+ total : number ;
22+ policies : { completed : number ; total : number } ;
23+ training : { completed : number ; total : number } ;
24+ hipaa ?: { completed : number ; total : number } ;
25+ }
26+
1827export interface TeamMembersProps {
1928 canManageMembers : boolean ;
2029 canInviteUsers : boolean ;
@@ -51,7 +60,7 @@ export async function TeamMembers(props: TeamMembersProps) {
5160 const employeeSyncData = await getEmployeeSyncConnections ( organizationId ) ;
5261
5362 // Build task completion map for employees/contractors
54- const taskCompletionMap : Record < string , { completed : number ; total : number } > = { } ;
63+ const taskCompletionMap : Record < string , TaskCompletion > = { } ;
5564
5665 const employeeMembers = await filterComplianceMembers ( members , organizationId ) ;
5766
@@ -69,10 +78,17 @@ export async function TeamMembers(props: TeamMembersProps) {
6978 ] ;
7079
7180 if ( employeeMembers . length > 0 ) {
72- const org = await db . organization . findUnique ( {
73- where : { id : organizationId } ,
74- select : { securityTrainingStepEnabled : true } ,
75- } ) ;
81+ const [ org , hipaaInstance ] = await Promise . all ( [
82+ db . organization . findUnique ( {
83+ where : { id : organizationId } ,
84+ select : { securityTrainingStepEnabled : true } ,
85+ } ) ,
86+ db . frameworkInstance . findFirst ( {
87+ where : { organizationId, framework : { name : 'HIPAA' } } ,
88+ select : { id : true } ,
89+ } ) ,
90+ ] ) ;
91+ const hasHipaaFramework = ! ! hipaaInstance ;
7692
7793 const policies = await db . policy . findMany ( {
7894 where : {
@@ -92,20 +108,40 @@ export async function TeamMembers(props: TeamMembersProps) {
92108
93109 const totalPolicies = policies . length ;
94110 const totalTrainingVideos = org ?. securityTrainingStepEnabled ? trainingVideosData . length : 0 ;
95- const totalTasks = totalPolicies + totalTrainingVideos ;
111+ const totalHipaaTraining = hasHipaaFramework ? 1 : 0 ;
112+ const totalTasks = totalPolicies + totalTrainingVideos + totalHipaaTraining ;
96113
97114 for ( const employee of employeeMembers ) {
98115 const policiesCompleted = policies . filter ( ( p ) => p . signedBy . includes ( employee . id ) ) . length ;
99116
100117 const trainingsCompleted = org ?. securityTrainingStepEnabled
101118 ? trainingCompletions . filter (
102- ( tc ) => tc . memberId === employee . id && tc . completedAt !== null ,
119+ ( tc ) =>
120+ tc . memberId === employee . id &&
121+ tc . completedAt !== null &&
122+ tc . videoId !== HIPAA_TRAINING_ID ,
103123 ) . length
104124 : 0 ;
105125
126+ const hipaaCompleted =
127+ hasHipaaFramework &&
128+ trainingCompletions . some (
129+ ( tc ) =>
130+ tc . memberId === employee . id &&
131+ tc . videoId === HIPAA_TRAINING_ID &&
132+ tc . completedAt !== null ,
133+ )
134+ ? 1
135+ : 0 ;
136+
106137 taskCompletionMap [ employee . id ] = {
107- completed : policiesCompleted + trainingsCompleted ,
138+ completed : policiesCompleted + trainingsCompleted + hipaaCompleted ,
108139 total : totalTasks ,
140+ policies : { completed : policiesCompleted , total : totalPolicies } ,
141+ training : { completed : trainingsCompleted , total : totalTrainingVideos } ,
142+ ...( hasHipaaFramework && {
143+ hipaa : { completed : hipaaCompleted , total : 1 } ,
144+ } ) ,
109145 } ;
110146 }
111147 }
0 commit comments