Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ workflows:
branches:
only:
- develop
- PM-4482
- security_july_2026
- PM-5460

# Production builds are exectuted only on tagged commits to the
# master branch.
Expand Down
12 changes: 8 additions & 4 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2489,11 +2489,12 @@ definitions:
properties:
skills:
type: boolean
gigAvailability:
engagementAvailability:
type: boolean
bio:
preferredRoles:
type: boolean
profilePicture:
description: True when the member has selected at least one preferred role.
bio:
type: boolean
workHistory:
type: boolean
Expand All @@ -2504,7 +2505,10 @@ definitions:
skillsLastUpdateDate:
type: date-time
description: 'ISO-8601 formatted date times (YYYY-MM-DDTHH:mm:ss.sssZ)'
gigAvailabilityLastUpdateDate:
engagementAvailabilityLastUpdateDate:
type: date-time
description: 'ISO-8601 formatted date times (YYYY-MM-DDTHH:mm:ss.sssZ)'
preferredRolesLastUpdateDate:
type: date-time
description: 'ISO-8601 formatted date times (YYYY-MM-DDTHH:mm:ss.sssZ)'
workHistoryLastUpdateDate:
Expand Down
53 changes: 47 additions & 6 deletions src/services/MemberService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,34 @@ function isEngagementAvailabilityComplete (member, openToWorkData) {
return hasAvailability || hasLegacyPreferredRoles
}

/**
* Determine whether the member has selected at least one preferred role.
* Prefers the top-level personalization.preferredRoles field (current model)
* and falls back to legacy openToWork.preferredRoles when the top-level key
* is absent.
* @param {Array} personalizationData personalization trait data entries
* @returns {Boolean} true when at least one preferred role is selected
*/
function hasPreferredRolesSelected (personalizationData) {
if (!Array.isArray(personalizationData) || personalizationData.length === 0) {
return false
}

const personalizationEntry = personalizationData.find(r =>
Object.prototype.hasOwnProperty.call(r, 'preferredRoles') ||
Object.prototype.hasOwnProperty.call(r, 'openToWork')
) || personalizationData[0] || {}

let preferredRoles
if (Object.prototype.hasOwnProperty.call(personalizationEntry, 'preferredRoles')) {
preferredRoles = personalizationEntry.preferredRoles
} else {
preferredRoles = personalizationEntry.openToWork && personalizationEntry.openToWork.preferredRoles
}

return Array.isArray(preferredRoles) && preferredRoles.length > 0
}

/**
* Resolve compact memberStats track/type UUIDs before deriving current
* maxRating labels for member profile responses.
Expand Down Expand Up @@ -617,6 +645,7 @@ async function getProfileCompleteness (currentUser, handle, query) {
// data.verified = false
data.skills = false
data.engagementAvailability = false
data.preferredRoles = false
data.bio = false
data.workHistory = false
data.education = false
Expand All @@ -626,6 +655,7 @@ async function getProfileCompleteness (currentUser, handle, query) {

data.skillsLastUpdateDate = undefined
data.engagementAvailabilityLastUpdateDate = undefined
data.preferredRolesLastUpdateDate = undefined
data.workHistoryLastUpdateDate = undefined
data.educationLastUpdateDate = undefined
data.locationLastUpdateDate = undefined
Expand All @@ -645,14 +675,22 @@ async function getProfileCompleteness (currentUser, handle, query) {
data.workHistoryLastUpdateDate = new Date(item.updatedAt).toISOString()
}

if (item.traitId === 'personalization' && item.traits.data.length > 0 && !data.engagementAvailability) {
const openToWorkTrait = item.traits.data.find(r => Object.keys(r).includes('openToWork')) || {}
const openToWorkData = openToWorkTrait.openToWork
if (item.traitId === 'personalization' && item.traits.data.length > 0) {
if (!data.engagementAvailability) {
const openToWorkTrait = item.traits.data.find(r => Object.keys(r).includes('openToWork')) || {}
const openToWorkData = openToWorkTrait.openToWork

if (isEngagementAvailabilityComplete(member, openToWorkData)) {
if (isEngagementAvailabilityComplete(member, openToWorkData)) {
completeItems += 1
data.engagementAvailability = true
data.engagementAvailabilityLastUpdateDate = new Date(item.updatedAt).toISOString()
}
}

if (!data.preferredRoles && hasPreferredRolesSelected(item.traits.data)) {
completeItems += 1
data.engagementAvailability = true
data.engagementAvailabilityLastUpdateDate = new Date(item.updatedAt).toISOString()
data.preferredRoles = true
data.preferredRolesLastUpdateDate = new Date(item.updatedAt).toISOString()
}
}
})
Expand All @@ -666,6 +704,9 @@ async function getProfileCompleteness (currentUser, handle, query) {
if (!data.engagementAvailability) {
showToast.push('engagementAvailability')
}
if (!data.preferredRoles) {
showToast.push('preferredRoles')
}

// TODO: Do we use the short bio or the "description" field of the member object?
if (member.description && !data.bio) {
Expand Down
Loading