Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

PM-1188 copilot opportunities on challenge feed#7094

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
kkartunov merged 5 commits intodevelopfromPM-1188
May 19, 2025
Merged

Conversation

himaniraghav3
Copy link
Collaborator

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

Add support for fetching and displaying copilot opportunities within the challenge feed, including dynamic sorting and pagination handling.

This excludes search over opportunities. We have added sorting over title, project track, and status.
Deafult sort prioritises active oportunities and sorts them on created Date.

add support for fetching and displaying copilot opportunities within the challenge feed, including dynamic sorting and pagination handling.refs pm-1188
*@return {Promise<{uuid: string, loaded: object}>} Action result
*/
functiongetCopilotOpportunitiesDone(uuid,page){
returngetCopilotOpportunities(page,COPILOT_OPPORTUNITY_PAGE_SIZE)

Choose a reason for hiding this comment

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

Consider handling the case wheregetCopilotOpportunities might return a non-object or unexpected data structure. This could prevent potential runtime errors if the API response changes.

returngetCopilotOpportunities(page,COPILOT_OPPORTUNITY_PAGE_SIZE)
.then(loaded=>({ uuid, loaded}))
.catch((error)=>{
fireErrorMessage('Error Getting Copilot Opportunities',error.content||error);

Choose a reason for hiding this comment

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

ThefireErrorMessage function is called witherror.content || error. Ensure thaterror.content is a valid property and consider logging the entire error object for better debugging information.

import'./style.scss';

constPROJECT_TYPE_LABELS={
dev:'Development',

Choose a reason for hiding this comment

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

Consider adding a default label for project types that are not listed inPROJECT_TYPE_LABELS to handle unexpected values gracefully.


<divstyleName="right-panel">
<divstyleName="type">
<span>{PROJECT_TYPE_LABELS[opportunity.type]}</span>

Choose a reason for hiding this comment

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

Consider adding a fallback forPROJECT_TYPE_LABELS[opportunity.type] in caseopportunity.type is not a key inPROJECT_TYPE_LABELS to prevent renderingundefined.

}

CopilotOpportunityCard.propTypes={
opportunity:PT.shape().isRequired,

Choose a reason for hiding this comment

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

Theopportunity prop type should be more specific. Define the shape with expected properties and their types to improve type safety and documentation.

font-size:12px;
color:$tc-gray-60;
margin-right:$challenge-space-10;
line-height: ($challenge-space-10)+2;

Choose a reason for hiding this comment

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

The line-height calculation($challenge-space-10) + 2 might not work as intended. Consider usingcalc() for arithmetic operations in CSS, likecalc(#{$challenge-space-10} + 2px).

color:green;
line-height:$challenge-space-20;
margin-right:$challenge-space-20;
min-width:$challenge-space-50+2;

Choose a reason for hiding this comment

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

Themin-width property value$challenge-space-50 + 2 might not be calculated correctly. Consider usingcalc() for arithmetic operations, likecalc(#{$challenge-space-50} + 2px).


functionCopilotOpportunityHeader(){
return(
<divstyleName="copilotOpportunityHeader">

Choose a reason for hiding this comment

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

Consider using a more descriptive class name forcopilotOpportunityHeader to avoid potential conflicts with other styles and to improve readability.

functionCopilotOpportunityHeader(){
return(
<divstyleName="copilotOpportunityHeader">
<divstyleName="left-panel">

Choose a reason for hiding this comment

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

Theleft-panel class name could be more descriptive to better convey its purpose or content.

</div>
</div>

<divstyleName="right-panel">

Choose a reason for hiding this comment

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

Consider using a more descriptive class name forright-panel to improve clarity and maintainability.

</div>

<divstyleName="right-panel">
<divstyleName="type">

Choose a reason for hiding this comment

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

Thetype class name is quite generic. Consider using a more specific name to avoid potential conflicts and improve readability.

<divstyleName="type">
<span>Type</span>
</div>
<divstyleName="status">

Choose a reason for hiding this comment

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

Thestatus class name is very generic. Consider using a more descriptive name to avoid potential conflicts and improve maintainability.

<divstyleName="status">
<span>Status</span>
</div>
<divstyleName="numHours">

Choose a reason for hiding this comment

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

Consider using a more descriptive class name fornumHours to better convey its purpose and improve code readability.

@@ -0,0 +1,93 @@
@import'~styles/mixins';

$challenge-space-20:$base-unit*4;

Choose a reason for hiding this comment

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

Consider renaming$challenge-space-20 to something more descriptive, such as$challenge-padding-small, to better convey its purpose.

@import'~styles/mixins';

$challenge-space-20:$base-unit*4;
$challenge-space-30:$base-unit*6;

Choose a reason for hiding this comment

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

Consider renaming$challenge-space-30 to something more descriptive, such as$challenge-padding-large, to better convey its purpose.

.copilotOpportunityHeader {
@includeroboto-medium;

display:flex;

Choose a reason for hiding this comment

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

Thejustify-content: flex-start; property is redundant here sinceflex-start is the default value forjustify-content. Consider removing it for cleaner code.

padding:$challenge-space-200;
color:$tc-gray-60;
font-size:12px;
margin-left:24px;

Choose a reason for hiding this comment

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

Themargin-left: 24px; might cause alignment issues on smaller screens. Ensure this is the intended behavior or consider using a responsive unit.

.left-panel {
display:flex;
justify-content:flex-start;
width:45.5%;

Choose a reason for hiding this comment

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

The width of45.5% for.left-panel might lead to layout issues when combined with the50% width of.right-panel. Ensure this is the intended design or adjust the widths to fit within 100%.

.challenge-details {
display:inline-block;
vertical-align:baseline;
width:82%;

Choose a reason for hiding this comment

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

The width of82% for.challenge-details might cause layout issues when combined with the margin-right. Ensure this is the intended design or adjust the width to fit within the container.

/>
</div>
</div>
{!isCopilotOpportunitiesBucket&&(

Choose a reason for hiding this comment

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

It seems like the closing parenthesis for the conditional rendering is missing. Ensure that the JSX block is properly closed with a parenthesis to avoid syntax errors.

</div>
</div>
)}

Choose a reason for hiding this comment

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

The closing parenthesis for the conditional rendering block seems to be misplaced. Ensure that the conditional logic is correctly structured to avoid rendering issues.

}
</div>

{!isCopilotOpportunitiesBucket&&(

Choose a reason for hiding this comment

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

The condition!isCopilotOpportunitiesBucket is added here to wrap the buttons div. Ensure that this condition is necessary and correctly implemented to avoid hiding buttons unintentionally whenisCopilotOpportunitiesBucket is true.

// import { challenge as challengeUtils } from 'topcoder-react-lib';
importCopilotOpportunityHeaderfrom'components/challenge-listing/CopilotOpportunityHeader';
importCardPlaceholderfrom'../../placeholders/ChallengeCard';
importCopilotOpportunityCardfrom'../../CopilotOpportunityCard';// <== Replace with your actual Copilot Card component

Choose a reason for hiding this comment

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

The comment// <== Replace with your actual Copilot Card component suggests thatCopilotOpportunityCard might be a placeholder or temporary component. Ensure that this is the intended component for production use.

sort,
setSearchText,
}){
if(!opportunities.length&&!loadMore)returnnull;

Choose a reason for hiding this comment

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

The conditionif (!opportunities.length && !loadMore) return null; might cause the component to returnnull even whenloading istrue. Consider revising this logic if you want to show a loading state when there are no opportunities but data is still being fetched.

{cards}
{!loading&&filteredOpportunities.length===0&&(
<div>
<divstyleName="copilot-opportunity-bucket">

Choose a reason for hiding this comment

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

The nestedSortingSelectBar within the!loading && filteredOpportunities.length === 0 condition seems redundant since a similar component is rendered above. Consider removing this duplication unless there is a specific reason to render it twice.

CopilotOpportunityBucket.propTypes={
bucket:PT.string.isRequired,
challengesUrl:PT.string.isRequired,
expandedTags:PT.arrayOf(PT.number),

Choose a reason for hiding this comment

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

TheexpandedTags prop is defined asPT.arrayOf(PT.number), but it defaults to an empty array. Ensure that this type definition aligns with the expected data structure, especially ifexpandedTags might contain non-numeric values.

expandedTags:PT.arrayOf(PT.number),
expandTag:PT.func,
// filterState: PT.shape().isRequired,
opportunities:PT.arrayOf(PT.shape()).isRequired,

Choose a reason for hiding this comment

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

Theopportunities prop is defined asPT.arrayOf(PT.shape()).isRequired, which lacks specific shape details. Consider defining the expected shape of the objects within theopportunities array for better type checking and documentation.

margin-left:0;
}
}
} No newline at end of file

Choose a reason for hiding this comment

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

It is a good practice to ensure that files end with a newline character. This can prevent issues with certain tools and improve readability when concatenating files.

setSearchText={setSearchText}
/>
);
}elseif(isCopilotOpportunitiesBucket(bucket)){

Choose a reason for hiding this comment

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

The functionisCopilotOpportunitiesBucket is used here, but it's not clear from the diff whether this function is defined elsewhere or imported. Ensure that this function is properly defined or imported to avoid runtime errors.

needLoad={needLoad}
loading={loadingCopilotOpportunities}
loadMore={loadMoreCopilotOpportunities}
opportunities={copilotOpportunities}

Choose a reason for hiding this comment

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

The variableloadMoreCopilotOpportunities is used here, but it's not clear from the diff whether this variable is defined elsewhere or imported. Ensure that this variable is properly defined or imported to avoid runtime errors.

needLoad={needLoad}
loading={loadingCopilotOpportunities}
loadMore={loadMoreCopilotOpportunities}
opportunities={copilotOpportunities}

Choose a reason for hiding this comment

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

Consider renamingloadMoreCopilotOpportunities toloadMoreOpportunities for consistency with the naming convention used forloadMoreReviewOpportunities.

filterState={filterState}
keepPlaceholders={keepPastPlaceholders}
needLoad={needLoad}
loading={loadingCopilotOpportunities}

Choose a reason for hiding this comment

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

The variableloadingCopilotOpportunities is used here, but it's not clear from the diff whether this variable is defined elsewhere or imported. Ensure that this variable is properly defined or imported to avoid runtime errors.

needLoad={needLoad}
loading={loadingCopilotOpportunities}
loadMore={loadMoreCopilotOpportunities}
opportunities={copilotOpportunities}

Choose a reason for hiding this comment

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

The variablecopilotOpportunities is used here, but it's not clear from the diff whether this variable is defined elsewhere or imported. Ensure that this variable is properly defined or imported to avoid runtime errors.

needLoad:PT.bool.isRequired,
loadingCopilotOpportunities:PT.bool.isRequired,
loadMoreCopilotOpportunities:PT.func,
copilotOpportunities:PT.arrayOf(PT.shape()),

Choose a reason for hiding this comment

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

Consider specifying the shape of the objects within thecopilotOpportunities array for better type checking and clarity. This will help ensure that all necessary properties are present and correctly typed.

allChallengesLoaded:cl.allChallengesLoaded,
allPastChallengesLoaded:cl.allPastChallengesLoaded,
allOpenForRegistrationChallengesLoaded:cl.allOpenForRegistrationChallengesLoaded,
// allCopilotOpportunitiesLoaded: cl.allCopilotOpportunitiesLoaded,

Choose a reason for hiding this comment

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

The line forallCopilotOpportunitiesLoaded is commented out. If this is intentional, consider removing it if it's not needed, or uncommenting it if it should be part of the functionality.

);
}

letloadMoreCopilotOpportunities;

Choose a reason for hiding this comment

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

Consider renamingloadMoreCopilotOpportunities tohandleLoadMoreCopilotOpportunities to better convey that this is a function handling an action.


letloadMoreCopilotOpportunities;
if(!allCopilotOpportunitiesLoaded){
loadMoreCopilotOpportunities=()=>getCopilotOpportunities(

Choose a reason for hiding this comment

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

It's unclear what the argument1 + lastRequestedPageOfCopilotOpportunities represents. Ensure that the logic for incrementing the page number is correct and consider using a named constant or variable for clarity.

loadingUuid:PT.string.isRequired,
timestamp:PT.number.isRequired,
}).isRequired,
copilotOpportunities:PT.arrayOf(PT.shape()).isRequired,

Choose a reason for hiding this comment

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

ThePT.shape() used forcopilotOpportunities is currently empty. Consider defining the expected shape of the objects within thecopilotOpportunities array to ensure proper type checking and validation.

lastRequestedPageOfAllChallenges:cl.lastRequestedPageOfAllChallenges,
lastRequestedPageOfPastChallenges:cl.lastRequestedPageOfPastChallenges,
lastRequestedPageOfReviewOpportunities:cl.lastRequestedPageOfReviewOpportunities,
lastRequestedPageOfCopilotOpportunities:cl.lastRequestedPageOfCopilotOpportunities,

Choose a reason for hiding this comment

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

Consider verifying iflastRequestedPageOfCopilotOpportunities is correctly initialized and used throughout the application to prevent potential undefined behavior.

lastRequestedPageOfCopilotOpportunities:cl.lastRequestedPageOfCopilotOpportunities,
// lastUpdateOfActiveChallenges: cl.lastUpdateOfActiveChallenges,
loadingActiveChallengesUUID:cl.loadingActiveChallengesUUID,
loadingCopilotOpportunitiesUUID:cl.loadingCopilotOpportunitiesUUID,

Choose a reason for hiding this comment

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

Ensure thatloadingCopilotOpportunitiesUUID is properly managed and updated in the application state to avoid any inconsistencies or errors during data fetching.

||Boolean(cl.loadingMyChallengesUUID)||Boolean(cl.loadingAllChallengesUUID)
||Boolean(cl.loadingPastChallengesUUID)||cl.loadingReviewOpportunitiesUUID,
||Boolean(cl.loadingPastChallengesUUID)||cl.loadingReviewOpportunitiesUUID
||cl.loadingCopilotOpportunitiesUUID,

Choose a reason for hiding this comment

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

Consider checking ifcl.loadingCopilotOpportunitiesUUID needs to be wrapped withBoolean() for consistency with the other loading flags.

getCopilotOpportunities:(page)=>{
constuuid=shortId();
dispatch(a.getCopilotOpportunitiesInit(uuid,page));
dispatch(a.getCopilotOpportunitiesDone(uuid,page));

Choose a reason for hiding this comment

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

It seems that thegetCopilotOpportunitiesDone function is being dispatched without atoken argument, unlikegetReviewOpportunitiesDone which includes it. If authentication is required for fetching copilot opportunities, consider adding thetoken parameter.

*@return {Object} New state
*/
functiononGetCopilotOpportunitiesDone(state,{ payload, error}){
if(error)returnstate;

Choose a reason for hiding this comment

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

Consider handling the error case more explicitly rather than returning the current state. This could involve logging the error or updating the state to reflect the error condition.

if(uuid!==state.loadingCopilotOpportunitiesUUID)returnstate;

constids=newSet();
loaded.forEach(item=>ids.add(item.id));

Choose a reason for hiding this comment

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

Using aSet to track IDs is efficient for ensuring uniqueness. However, consider adding a comment explaining why this approach is chosen, especially if the order of items is important.

constids=newSet();
loaded.forEach(item=>ids.add(item.id));
constcopilotOpportunities=state.copilotOpportunities
.filter(item=>!ids.has(item.id))

Choose a reason for hiding this comment

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

Thefilter andconcat operations could be optimized by using a singlereduce operation to build the new array, which might improve performance slightly if the arrays are large.

*@returns {Promise<Object>} The fetched data.
*/
exportdefaultfunctiongetCopilotOpportunities(page,pageSize=20,sort='createdAt desc'){
consturl=`${v5ApiUrl}/projects/copilots/opportunities?page=${page}&pageSize=${pageSize}&sort=${encodeURIComponent(sort)}`;

Choose a reason for hiding this comment

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

Consider adding error handling for the fetch request to manage potential network errors or unsuccessful responses. This will improve the robustness of the function.

apply consistent formatting and fix linting errors in all scss files to maintain code quality.no issue
@kkartunovkkartunov requested a review fromjmgasperMay 15, 2025 15:46
/* This is the same value as above, but it is used by topcoder-react-lib,
* as a more verbose name for the param. */
COMMUNITY_APP:'https://community-app.topcoder-dev.com',
COPILOTS_URL:'https://copilots.topcoder-dev.com',
Copy link
Collaborator

Choose a reason for hiding this comment

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

himaniraghav3 reacted with thumbs up emoji
constsortedOpportunities=_.clone(opportunities);
sortedOpportunities.sort(Sort[activeSort].func);

// const filteredOpportunities = sortedOpportunities.filter(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need this?
Let's remove commented out code for going upstream with this.

himaniraghav3 reacted with thumbs up emoji
kkartunovand others added2 commitsMay 19, 2025 09:32
remove commented code, add prod copilots url.no issue
@kkartunovkkartunov self-requested a reviewMay 19, 2025 10:45
Copy link
Collaborator

@kkartunovkkartunov left a comment

Choose a reason for hiding this comment

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

Looks good. Merging this.

@kkartunovkkartunov merged commit03bcfff intodevelopMay 19, 2025
6 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@github-actionsgithub-actions[bot]github-actions[bot] left review comments

@kkartunovkkartunovkkartunov approved these changes

@vas3avas3aAwaiting requested review from vas3a

@hentrymartinhentrymartinAwaiting requested review from hentrymartin

@ajeftsajeftsAwaiting requested review from ajeftsajefts is a code owner

@luizrrodriguesluizrrodriguesAwaiting requested review from luizrrodriguesluizrrodrigues is a code owner

@jmgasperjmgasperAwaiting requested review from jmgasper

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

2 participants
@himaniraghav3@kkartunov

[8]ページ先頭

©2009-2025 Movatter.jp