Skip to content

feat(PM-4203): Filter by skills in completed profiles page#1530

Open
hentrymartin wants to merge 3 commits intodevfrom
pm-4203
Open

feat(PM-4203): Filter by skills in completed profiles page#1530
hentrymartin wants to merge 3 commits intodevfrom
pm-4203

Conversation

@hentrymartin
Copy link
Collaborator

@hentrymartin hentrymartin commented Mar 12, 2026

Related JIRA Ticket:

https://topcoder.atlassian.net/browse/PM-4203

What's in this PR?

  • Implemented filter by skills in completed profiles page

Open with Devin

queryParams.set('openToWork', 'false')
}

if (Array.isArray(skillIds) && skillIds.length > 0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 maintainability]
Consider using skillIds.filter(Boolean) to remove falsy values before iterating. This simplifies the code by eliminating the need for the if (id) check inside the loop.

github-actions[bot]

This comment was marked as resolved.

value: String(skill.id),
}))
.filter((option: InputMultiselectOption) => !!option.value)
} catch {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
Filtering options with !!option.value might not be sufficient if value can be a falsy but valid value (e.g., 0). Ensure that this filtering logic aligns with the expected data structure.

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +44 to +71
const loadSkillOptions = async (query: string): Promise<InputMultiselectOption[]> => {
setSkillOptionsLoading(true)
try {
const baseUrl = `${EnvironmentConfig.API.V5}/standardized-skills`
const params = new URLSearchParams({
size: '25',
})
if (query && query.trim().length > 0) {
params.append('term', query.trim())
}

const url = `${baseUrl}/skills/autocomplete?${params.toString()}`
const response: any = await xhrGetAsync(url)

const skills = Array.isArray(response) ? response : []

return skills
.map((skill: any) => ({
label: skill.name,
value: String(skill.id),
}))
.filter((option: InputMultiselectOption) => !!option.value)
} catch {
return []
} finally {
setSkillOptionsLoading(false)
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Unstable loadSkillOptions reference causes AsyncSelect to re-fetch default options on every render

loadSkillOptions is defined as a plain arrow function inside the component body (ProfileCompletionPage.tsx:44-71), so it gets a new reference on every render. This reference is passed as onFetchOptions to InputMultiselect, which forwards it as loadOptions to react-select/async's AsyncSelect (InputMultiselect.tsx:156). In react-select v5, the useAsync hook has loadOptions in the dependency array of the useEffect that loads default options when defaultOptions={true} (InputMultiselect.tsx:154). Every time the function identity changes, the effect re-runs and calls loadOptions(''), triggering a new API request to /standardized-skills/skills/autocomplete?size=25. This means every state change in the parent component (SWR data arriving, member skills loading, filter changes) causes an unnecessary network request. The existing codebase avoids this: EngagementFilters.tsx:79 wraps fetchCountryOptions in useCallback, and InputSkillSelector.tsx:23 defines fetchSkills at module level.

Prompt for agents
In src/apps/customer-portal/src/pages/profile-completion/ProfileCompletionPage/ProfileCompletionPage.tsx, wrap the loadSkillOptions function (lines 44-71) in useCallback with an empty dependency array (setSkillOptionsLoading is a stable state setter and EnvironmentConfig.API.V5 is a constant). This ensures the function reference remains stable across renders, preventing AsyncSelect from re-fetching default options on every render. Add useCallback to the imports from react on line 4. Example:

const loadSkillOptions = useCallback(async (query: string): Promise<InputMultiselectOption[]> => {
    setSkillOptionsLoading(true)
    try {
        ... (same body)
    } catch {
        return []
    } finally {
        setSkillOptionsLoading(false)
    }
}, [])
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant