@@ -23,6 +23,8 @@ import {
2323 SquadSource ,
2424 User ,
2525} from '../entity' ;
26+ import { UserExperience } from '../entity/user/experiences/UserExperience' ;
27+ import { UserExperienceType } from '../entity/user/experiences/types' ;
2628import { DatasetLocation } from '../entity/dataset/DatasetLocation' ;
2729import {
2830 getPermissionsForMember ,
@@ -45,6 +47,7 @@ import {
4547 StorageKey ,
4648 StorageTopic ,
4749} from '../config' ;
50+
4851import {
4952 ONE_DAY_IN_SECONDS ,
5053 base64 ,
@@ -148,6 +151,7 @@ export type LoggedInBoot = BaseBoot & {
148151 balance : GetBalanceResult ;
149152 coresRole : CoresRole ;
150153 location ?: TLocation | null ;
154+ profileCompletion ?: ProfileCompletion | null ;
151155 } ;
152156 accessToken ?: AccessToken ;
153157 marketingCta : MarketingCta | null ;
@@ -525,6 +529,80 @@ const getLocation = async (
525529 return location ;
526530} ;
527531
532+ export type ProfileCompletion = {
533+ percentage : number ;
534+ hasProfileImage : boolean ;
535+ hasHeadline : boolean ;
536+ hasExperienceLevel : boolean ;
537+ hasWork : boolean ;
538+ hasEducation : boolean ;
539+ } ;
540+
541+ type ProfileExperienceFlags = {
542+ hasWork : boolean ;
543+ hasEducation : boolean ;
544+ } ;
545+
546+ const getProfileExperienceFlags = async (
547+ con : DataSource | QueryRunner ,
548+ userId : string ,
549+ ) : Promise < ProfileExperienceFlags > => {
550+ const result = await con . manager
551+ . createQueryBuilder ( UserExperience , 'ue' )
552+ . select ( `MAX(CASE WHEN ue.type = :workType THEN 1 ELSE 0 END)` , 'hasWork' )
553+ . addSelect (
554+ `MAX(CASE WHEN ue.type = :educationType THEN 1 ELSE 0 END)` ,
555+ 'hasEducation' ,
556+ )
557+ . where ( 'ue.userId = :userId' , { userId } )
558+ . andWhere ( 'ue.type IN (:...types)' , {
559+ types : [ UserExperienceType . Work , UserExperienceType . Education ] ,
560+ } )
561+ . setParameters ( {
562+ workType : UserExperienceType . Work ,
563+ educationType : UserExperienceType . Education ,
564+ } )
565+ . getRawOne ( ) ;
566+
567+ const hasWork = result ?. hasWork == 1 ;
568+ const hasEducation = result ?. hasEducation == 1 ;
569+
570+ return { hasWork, hasEducation } ;
571+ } ;
572+
573+ const calculateProfileCompletion = (
574+ user : User | null ,
575+ experienceFlags : ProfileExperienceFlags | null ,
576+ ) : ProfileCompletion | null => {
577+ if ( ! user || ! experienceFlags ) {
578+ return null ;
579+ }
580+
581+ // Calculate completion based on 5 items (each worth 20%)
582+ const hasProfileImage = ! ! user . image && user . image !== '' ;
583+ const hasHeadline = ! ! user . bio && user . bio . trim ( ) !== '' ;
584+ const hasExperienceLevel = ! ! user . experienceLevel ;
585+ const { hasWork, hasEducation } = experienceFlags ;
586+
587+ const completedItems = [
588+ hasProfileImage ,
589+ hasHeadline ,
590+ hasExperienceLevel ,
591+ hasWork ,
592+ hasEducation ,
593+ ] . filter ( Boolean ) . length ;
594+
595+ const percentage = Math . round ( ( completedItems / 5 ) * 100 ) ;
596+ return {
597+ percentage,
598+ hasProfileImage,
599+ hasHeadline,
600+ hasExperienceLevel,
601+ hasWork,
602+ hasEducation,
603+ } ;
604+ } ;
605+
528606const loggedInBoot = async ( {
529607 con,
530608 req,
@@ -546,6 +624,7 @@ const loggedInBoot = async ({
546624 const geo = geoSection ( req ) ;
547625
548626 const { log } = req ;
627+
549628 const [
550629 visit ,
551630 roles ,
@@ -559,6 +638,7 @@ const loggedInBoot = async ({
559638 feeds ,
560639 unreadNotificationsCount ,
561640 location ,
641+ experienceFlags ,
562642 ] ,
563643 balance ,
564644 clickbaitTries ,
@@ -582,11 +662,15 @@ const loggedInBoot = async ({
582662 getFeeds ( { con : queryRunner , userId } ) ,
583663 getUnreadNotificationsCount ( queryRunner , userId ) ,
584664 getLocation ( queryRunner , userId ) ,
665+ getProfileExperienceFlags ( queryRunner , userId ) ,
585666 ] ) ;
586667 } ) ,
587668 getBalanceBoot ( { userId } ) ,
588669 getClickbaitTries ( { userId } ) ,
589670 ] ) ;
671+
672+ const profileCompletion = calculateProfileCompletion ( user , experienceFlags ) ;
673+
590674 if ( ! user ) {
591675 return handleNonExistentUser ( con , req , res , middleware ) ;
592676 }
@@ -641,6 +725,7 @@ const loggedInBoot = async ({
641725 clickbaitTries,
642726 hasLocationSet,
643727 location,
728+ profileCompletion,
644729 } ,
645730 visit,
646731 alerts : {
0 commit comments