- Notifications
You must be signed in to change notification settings - Fork211
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
Uh oh!
There was an error while loading.Please reload this page.
Conversation
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) |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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', |
There was a problem hiding this comment.
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.
Uh oh!
There was an error while loading.Please reload this page.
<divstyleName="right-panel"> | ||
<divstyleName="type"> | ||
<span>{PROJECT_TYPE_LABELS[opportunity.type]}</span> |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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%; |
There was a problem hiding this comment.
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%; |
There was a problem hiding this comment.
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&&( |
There was a problem hiding this comment.
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> | ||
)} | ||
There was a problem hiding this comment.
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&&( |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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)){ |
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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()), |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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)) |
There was a problem hiding this comment.
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)}`; |
There was a problem hiding this comment.
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.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
apply consistent formatting and fix linting errors in all scss files to maintain code quality.no issue
/* 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', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
As this is hard-coded value we need to add it also inhttps://github.com/topcoder-platform/community-app/blob/develop/config/production.js
constsortedOpportunities=_.clone(opportunities); | ||
sortedOpportunities.sort(Sort[activeSort].func); | ||
// const filteredOpportunities = sortedOpportunities.filter( |
There was a problem hiding this comment.
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.
remove commented code, add prod copilots url.no issue
There was a problem hiding this 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.
03bcfff
intodevelopUh oh!
There was an error while loading.Please reload this page.
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.