-
Notifications
You must be signed in to change notification settings - Fork 51
Feat/challenge reviewer v6 #1673
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/components/ChallengeEditor/ChallengeReviewer-Field/ChallengeReviewer-Field.module.scss
Outdated
Show resolved
Hide resolved
src/components/ChallengeEditor/ChallengeReviewer-Field/ChallengeReviewer-Field.module.scss
Outdated
Show resolved
Hide resolved
src/components/ChallengeEditor/ChallengeReviewer-Field/ChallengeReviewer-Field.module.scss
Outdated
Show resolved
Hide resolved
| throw new Error('Failed to load scorecards') | ||
| } | ||
| } catch (error) { | ||
| console.error('Error loading scorecards:', 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.
Consider handling specific error cases more explicitly instead of using a generic error message. This can help in debugging and provide more context to the user.
| // only load default reviewers if we have typeId and trackId | ||
| if (!challenge.typeId || !challenge.trackId) { | ||
| console.log('Cannot load default reviewers: missing typeId or trackId') | ||
| this.setState({ defaultReviewer: [] }) |
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.
There is a typo in the state update. It should be defaultReviewers instead of defaultReviewer.
| throw new Error('Failed to load default reviewers') | ||
| } | ||
| } catch (error) { | ||
| console.error('Error loading default reviewers:', 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.
Consider handling specific error cases more explicitly instead of using a generic error message. This can help in debugging and provide more context to the user.
| const fieldUpdate = {} | ||
| fieldUpdate[field] = value | ||
| updatedReviewers[index] = Object.assign({}, updatedReviewers[index], fieldUpdate) | ||
| onUpdateOthers({ field: 'reviewers', value: updatedReviewers }) |
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 Object.assign here is fine, but consider using the spread operator for a more modern approach: updatedReviewers[index] = { ...updatedReviewers[index], [field]: value }.
| onUpdateMultiSelect: () => {}, | ||
| readOnly: false | ||
| readOnly: false, | ||
| showReviewerField: false, |
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 addition of showReviewerField as a default prop is not accompanied by any explanation or usage in the surrounding code. Ensure that this prop is utilized appropriately in the component logic or remove it if unnecessary.
| readOnly: false | ||
| readOnly: false, | ||
| showReviewerField: false, | ||
| onUpdateOthers: () => {} |
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 onUpdateOthers function is added as a default prop but lacks context or usage in the component. Verify its necessity and ensure it is integrated into the component's functionality or remove it if not needed.
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.
please be more specific in the props naming. onUpdateOthers doesn't mean much. onUpdateOtherReviewers or onUpdateReviewers provides a better view over what it's supposed to mean.
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.
@rishabhtc this change should be handled, and you should rename onUpdateOthers to onUpdateOtherReviewers everywhere.
| shouldShowPrivateDescription: PropTypes.bool, | ||
| readOnly: PropTypes.bool | ||
| readOnly: PropTypes.bool, | ||
| showReviewerField: PropTypes.bool, |
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 showReviewerField prop is added but there is no context or usage shown in this diff. Ensure that this prop is utilized correctly in the component logic.
| readOnly: PropTypes.bool | ||
| readOnly: PropTypes.bool, | ||
| showReviewerField: PropTypes.bool, | ||
| onUpdateOthers: PropTypes.func |
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 onUpdateOthers prop is added but there is no context or usage shown in this diff. Ensure that this function is implemented and used appropriately within the component.
| onUpdateMultiSelect={this.onUpdateMultiSelect} | ||
| onUpdateMetadata={this.onUpdateMetadata} | ||
| showReviewerField | ||
| onUpdateOthers={this.onUpdateOthers} |
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 onUpdateOthers prop is added. Verify that the function this.onUpdateOthers is defined and implemented correctly to handle updates as expected.
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.
@vas3a onUpdateOthers in this component was present earlier as well. I can skip renaming it right ?
| // Add challenge track if available | ||
| if (challenge.trackId) { | ||
| // Map track ID to track name for the API | ||
| const trackMapping = { |
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 have the track data in the API? if so, you should fetch it from API rather than hardcode it in here.
| scorecards: [], | ||
| defaultReviewers: [], | ||
| isLoadingScorecards: false, | ||
| isLoadingDefaults: false, |
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.
please rename to isLoadingDefaultReviewers
| this.setState({ defaultReviewer: [] }) | ||
| return | ||
| } | ||
| const response = await axios.get('https://api.topcoder-dev.com/v6/challenges/default-reviewers', { |
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.
please use src\services\challenges.js (add missing method as needed) to fetch default reviewers. make sure to follow the same code style as it's already in there.
| readOnly: false | ||
| readOnly: false, | ||
| showReviewerField: false, | ||
| onUpdateOthers: () => {} |
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.
please be more specific in the props naming. onUpdateOthers doesn't mean much. onUpdateOtherReviewers or onUpdateReviewers provides a better view over what it's supposed to mean.
| } catch (error) { | ||
| console.error('Error loading default reviewers:', error) | ||
| // Use mock data for development/testing | ||
| const mockDefaultReviewers = [ |
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.
please move this to other file and keep track to remove it when you're done with it.
| } catch (error) { | ||
| console.error('Error loading scorecards:', error) | ||
| // Use mock data for development/testing | ||
| // const mockScorecards = [ |
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.
cleanup
…cted payment logic
src/actions/challenges.js
Outdated
|
|
||
| if (status !== 'all') { | ||
| filters['status'] = !status ? undefined : status | ||
| filters['status'] = !status ? undefined : _.startCase(status.toLowerCase()) |
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 _.capitalize(status.toLowerCase()) instead of _.startCase(status.toLowerCase()) if the intention is to only capitalize the first letter of the status. _.startCase will capitalize the first letter of each word, which might not be necessary if status is a single word.
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.
@vas3a
I have added this logic and also changed the ACTIVE to active due to challenge API expecting first letter of the status as uppercase Please verify it and let me know if needs to revert it.
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.
Is it not expecting all uppercase letters?
| metadataValue: scorecards.scoreCards || [] | ||
| }) | ||
| } catch (error) { | ||
| console.error('Error loading scorecards:', 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.
Using console.error for error logging is fine for development, but consider using a more robust logging mechanism for production environments.
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.
@vas3a Do I need to remove console.error ?
| metadataValue: defaultReviewers | ||
| }) | ||
| } catch (error) { | ||
| console.error('Error loading default reviewers:', 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.
Using console.error for error logging is fine for development, but consider using a more robust logging mechanism for production environments.
src/components/ChallengeEditor/ChallengeReviewer-Field/ChallengeReviewer-Field.module.scss
Show resolved
Hide resolved
|
|
||
| componentDidMount () { | ||
| this.loadScorecards() | ||
| this.isLoadingDefaultReviewers() |
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 method name isLoadingDefaultReviewers suggests it returns a boolean indicating loading status, but it actually initiates loading reviewers. Consider renaming it to better reflect its functionality, such as loadDefaultReviewers.
|
|
||
| renderReviewerForm (reviewer, index) { | ||
| const { challenge, metadata } = this.props | ||
| const { scorecards = [] } = metadata |
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 scorecards variable is being destructured from metadata with a default value of an empty array. Ensure that metadata is always defined to avoid potential runtime errors.
| const validationErrors = this.validateReviewer(reviewer) | ||
|
|
||
| return ( | ||
| <div key={`reviewer-${index}`} className={styles.reviewerForm}> |
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 key prop for the div element has been changed to use a template string with index. Ensure that index is unique and consistent across renders to prevent potential issues with React's reconciliation process.
| const currentReviewers = challenge.reviewers || [] | ||
| const updatedReviewers = currentReviewers.slice() | ||
|
|
||
| // Update both fields atomically to ensure XOR constraint is satisfied |
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 removing the comment about updating fields atomically, as comments are not encouraged in this context.
| const updatedReviewers = currentReviewers.slice() | ||
|
|
||
| // Update both fields atomically to ensure XOR constraint is satisfied | ||
| // Maintain correct field order as expected by API schema |
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 removing the comment about maintaining field order, as comments are not encouraged in this context.
| // Update both fields atomically to ensure XOR constraint is satisfied | ||
| // Maintain correct field order as expected by API schema | ||
| const currentReviewer = updatedReviewers[index] | ||
| updatedReviewers[index] = { |
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 that updatedReviewers[index] is not undefined before attempting to access its properties to avoid potential runtime errors.
| } | ||
|
|
||
| render () { | ||
| const { challenge, metadata, isLoading } = this.props |
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 metadata prop is being destructured, but it is not clear if it is always provided. Consider adding a default value or a check to ensure metadata is defined before destructuring.
| const { scorecards = [], defaultReviewers = [] } = metadata | ||
| const reviewers = challenge.reviewers || [] | ||
|
|
||
| if (isLoading) { |
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 for loading has been changed to isLoading. Ensure that this new prop accurately reflects the loading state for both scorecards and defaults, as the previous condition checked two separate loading states.
| } | ||
|
|
||
| // Only show error if there's a real error, not just missing data | ||
| if (error && !scorecards.length && !defaultReviewers.length) { |
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 code has been updated to use scorecards and defaultReviewers directly instead of this.state.scorecards and this.state.defaultReviewers. Ensure that scorecards and defaultReviewers are defined and accessible in the current scope to avoid potential reference errors.
src/components/ChallengeEditor/ChallengeReviewer-Field/index.js
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| const mapStateToProps = (state) => ({ | ||
| metadata: state.challenges.metadata, |
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 that state.challenges.metadata is correctly initialized in the Redux store to avoid potential issues with accessing properties on undefined.
|
|
||
| const mapStateToProps = (state) => ({ | ||
| metadata: state.challenges.metadata, | ||
| isLoading: state.challenges.isLoading |
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 that state.challenges.isLoading is correctly managed in the Redux store to reflect the loading state accurately.
| </div> | ||
| )} | ||
|
|
||
| {readOnly && reviewers.length === 0 && ( |
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 conditional check to ensure reviewers is defined before accessing its length property to prevent potential runtime errors.
| readOnly: PropTypes.bool | ||
| readOnly: PropTypes.bool, | ||
| showReviewerField: PropTypes.bool, | ||
| onUpdateReviewers: PropTypes.func |
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 prop name has been changed from onUpdateOthers to onUpdateReviewers. Ensure that all instances where this prop is used throughout the codebase are updated accordingly to prevent any potential errors or mismatches.
| onUpdateMultiSelect={this.onUpdateMultiSelect} | ||
| onUpdateMetadata={this.onUpdateMetadata} | ||
| showReviewerField | ||
| onUpdateReviewers={this.onUpdateOthers} |
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 function name onUpdateReviewers suggests that it updates reviewers, but it is still calling this.onUpdateOthers. Ensure that the function being called matches the intended functionality implied by the name change.
| scorecardId: (defaultReviewer && defaultReviewer.scorecardId) || '', | ||
| isMemberReview: true, | ||
| memberReviewerCount: (defaultReviewer && defaultReviewer.memberReviewerCount) || 1, | ||
| phaseId: (defaultReviewer && defaultReviewer.phaseId) || (firstPhase ? (firstPhase.id || firstPhase.phaseId) : ''), |
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 consistent type for basePayment. The change from a number to a string ('0') might lead to type-related issues elsewhere in the code where basePayment is expected to be a number.
| basePayment: (defaultReviewer && defaultReviewer.basePayment) || '0', | ||
| incrementalPayment: (defaultReviewer && defaultReviewer.incrementalPayment) || 0, | ||
| type: (defaultReviewer && defaultReviewer.opportunityType) || REVIEW_OPPORTUNITY_TYPES.REGULAR_REVIEW, | ||
| isAIReviewer: Boolean((defaultReviewer && defaultReviewer.isAIReviewer) || false) |
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 use of Boolean() is unnecessary here. The expression (defaultReviewer && defaultReviewer.isAIReviewer) || false already evaluates to a boolean value. Consider simplifying this line by removing Boolean().
| errors.push('Number of reviewers must be a positive integer') | ||
| } | ||
|
|
||
| const basePayment = convertDollarToInteger(reviewer.basePayment, '') |
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 convertDollarToInteger function is used here, but it's not clear if this function handles all edge cases, such as invalid input or currency formatting issues. Ensure that this function is robust and handles all potential input scenarios.
| return ( | ||
| <div key={`reviewer-${index}`} className={styles.reviewerForm}> | ||
| <div className={styles.reviewerHeader}> | ||
| {index > 0 && <h4>Reviewer {index + 1}</h4>} |
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.
Suggestion
Consider explaining why the header is conditionally rendered only when index > 0. If this is intentional to hide the header for the first reviewer, ensure that this logic aligns with the overall design requirements.
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.
Yes. I am implemented it because when number of reviewer value set to more than 1 , then it will not look nice as Reviewer 1 so removed it for first reviewer. @vas3a open for suggestions here
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.
you could hide it based on count. eg. if there are more than 1 reviewers render it, if there's a single reviewer hide it. BUT. let's leave it as is for now. it's pretty minor, we need to get this to QA.
| {validationErrors.length > 0 && ( | ||
| <div className={styles.validationErrors}> | ||
| {validationErrors.map((error, i) => ( | ||
| <div key={`error-${index}-${i}-${error}`} className={styles.validationError}>{error}</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.
Using index in the key generation suggests that index should be defined or imported in the current scope. Ensure that index is correctly defined or imported to avoid reference errors.
| updatedReviewers[index] = { | ||
| scorecardId: currentReviewer.scorecardId, | ||
| isMemberReview: !isAI, | ||
| memberReviewerCount: currentReviewer.memberReviewerCount || 1, |
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 if currentReviewer.memberReviewerCount should default to 1. This change might affect logic that relies on the original value.
| isMemberReview: !isAI, | ||
| memberReviewerCount: currentReviewer.memberReviewerCount || 1, | ||
| phaseId: currentReviewer.phaseId, | ||
| basePayment: currentReviewer.basePayment || '0', |
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 that defaulting currentReviewer.basePayment to '0' does not cause issues where a numeric value is expected, as this could lead to type mismatches.
| memberReviewerCount: currentReviewer.memberReviewerCount || 1, | ||
| phaseId: currentReviewer.phaseId, | ||
| basePayment: currentReviewer.basePayment || '0', | ||
| incrementalPayment: currentReviewer.incrementalPayment || 0, |
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.
Check if defaulting currentReviewer.incrementalPayment to 0 is appropriate, as it might affect calculations that assume a different default value.
| basePayment: currentReviewer.basePayment || '0', | ||
| incrementalPayment: currentReviewer.incrementalPayment || 0, | ||
| type: currentReviewer.type, | ||
| isAIReviewer: Boolean(isAI) |
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 Boolean(isAI) ensures a boolean value, but verify if this change aligns with the intended logic, especially if isAI can have non-boolean values that need specific handling.
| <span> | ||
| {(() => { | ||
| const phase = challenge.phases && challenge.phases.find(p => | ||
| (p.id === reviewer.phaseId) || (p.phaseId === reviewer.phaseId) |
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 (p.phaseId === reviewer.phaseId) seems redundant if p.id and p.phaseId are intended to represent the same identifier. Consider verifying if both are necessary or if they can be consolidated into a single check.
| {challenge.phases && challenge.phases | ||
| .filter(phase => { | ||
| const isReviewPhase = phase.name && phase.name.toLowerCase().includes('review') | ||
| const isCurrentlySelected = (phase.id === reviewer.phaseId) || (phase.phaseId === reviewer.phaseId) |
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 the variable isCurrentlySelected to isSelectedPhase for better clarity, as it checks if the phase is currently selected.
| return isReviewPhase || isCurrentlySelected | ||
| }) | ||
| .map(phase => ( | ||
| <option key={phase.id || phase.phaseId} value={phase.phaseId || phase.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.
The logic for key and value attributes in the <option> element is slightly inconsistent. Consider using a consistent order for phase.id and phase.phaseId to avoid confusion.
| min='1' | ||
| value={reviewer.memberReviewerCount || 1} | ||
| onChange={(e) => { | ||
| const validatedValue = validateValue(e.target.value, VALIDATION_VALUE_TYPE.INTEGER) |
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 function validateValue is used here, but it's not clear from the context if it handles all potential edge cases or errors. Ensure that validateValue is robust and returns a valid integer string or a default value that can be safely parsed.
| value={reviewer.memberReviewerCount || 1} | ||
| onChange={(e) => { | ||
| const validatedValue = validateValue(e.target.value, VALIDATION_VALUE_TYPE.INTEGER) | ||
| const parsedValue = parseInt(validatedValue) || 1 |
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 if validatedValue is a valid number before parsing it with parseInt. This will help avoid potential issues with unexpected input.
| step='0.01' | ||
| value={reviewer.basePayment || '0'} | ||
| onChange={(e) => { | ||
| const validatedValue = validateValue(e.target.value, VALIDATION_VALUE_TYPE.INTEGER) |
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 function validateValue is being used here, but it is not clear if it handles all edge cases for a number input, such as empty strings or non-numeric characters. Ensure that validateValue properly validates and sanitizes the input to prevent potential issues.
| step='0.01' | ||
| value={reviewer.basePayment || '0'} | ||
| onChange={(e) => { | ||
| const validatedValue = validateValue(e.target.value, VALIDATION_VALUE_TYPE.INTEGER) |
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 VALIDATION_VALUE_TYPE.INTEGER constant is used here, but the input field allows decimal values due to step='0.01'. Consider using a validation type that supports decimal numbers if decimals are intended to be allowed.
| } | ||
|
|
||
| render () { | ||
| const { challenge, metadata = {}, isLoading, readOnly = false } = this.props |
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 providing a default value for challenge to prevent potential errors if challenge is undefined.
| </div> | ||
| )} | ||
|
|
||
| {!readOnly && reviewers && reviewers.length === 0 && ( |
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 reviewers && reviewers.length === 0 is checking if reviewers is truthy before checking its length. Ensure that reviewers is always initialized to an array to avoid potential issues if reviewers is null or undefined. Consider initializing reviewers to an empty array by default if not already done.
| <h4>Review Summary</h4> | ||
| <div className={styles.summaryRow}> | ||
| <span>Total Member Reviewers:</span> | ||
| <span>{reviewers.filter(r => Boolean(r.isAIReviewer) === false).reduce((sum, r) => sum + (parseInt(r.memberReviewerCount) || 0), 0)}</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 using Number.isInteger() to check if r.memberReviewerCount is a valid integer before parsing it with parseInt() to avoid potential issues with invalid inputs.
| const base = convertDollarToInteger(r.basePayment, '') | ||
| const count = parseInt(r.memberReviewerCount) || 1 | ||
| return sum + (base * count) | ||
| }, 0)}</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.
The .toFixed(2) method was removed from the total review cost calculation. If the intention is to maintain a fixed decimal format for currency display, consider re-adding .toFixed(2) to ensure the cost is displayed with two decimal places.
| reviewerTotal = challenge.reviewers | ||
| .filter(r => Boolean(r.isAIReviewer) === false) | ||
| .reduce((sum, r) => { | ||
| const base = convertDollarToInteger(r.basePayment, '') |
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 function convertDollarToInteger is used here, but it is unclear from the context whether this function handles cases where r.basePayment might be undefined or not a valid dollar amount. Ensure that convertDollarToInteger has proper error handling for such cases to prevent unexpected behavior.
| .filter(r => Boolean(r.isAIReviewer) === false) | ||
| .reduce((sum, r) => { | ||
| const base = convertDollarToInteger(r.basePayment, '') | ||
| const count = parseInt(r.memberReviewerCount) || 1 |
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 parseInt without specifying a radix can lead to unexpected results if r.memberReviewerCount is a string with leading zeros. Consider using parseInt(r.memberReviewerCount, 10) to ensure the number is parsed as a decimal.
| <input | ||
| type='number' | ||
| min='0' | ||
| value={reviewer.basePayment || '0'} |
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.
Removing the step='0.01' attribute from the input field changes the behavior of the number input, potentially affecting user experience when entering decimal values. If the intention is to restrict input to whole numbers, consider updating the type attribute to reflect this change, or ensure that the validation logic handles decimal inputs appropriately.
| basePayment: currentReviewer.basePayment || '0', | ||
| incrementalPayment: currentReviewer.incrementalPayment || 0, | ||
| type: currentReviewer.type, | ||
| isAIReviewer: isAI |
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 isAIReviewer property is being set directly to isAI instead of using Boolean(isAI). If isAI is not already a boolean, this change could lead to unexpected behavior. Consider ensuring isAI is a boolean before assigning it to isAIReviewer.
| <span>Total Review Cost:</span> | ||
| <span>${reviewers.filter(r => !r.isAIReviewer).reduce((sum, r) => { | ||
| const base = convertDollarToInteger(r.basePayment || '0', '') | ||
| const count = parseInt(r.memberReviewerCount) || 1 |
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 providing a default value for r.basePayment directly in the convertDollarToInteger function if applicable, to centralize the handling of default values and avoid repetition.
| const base = convertDollarToInteger(r.basePayment || '0', '') | ||
| const count = parseInt(r.memberReviewerCount) || 1 | ||
| return sum + (base * count) | ||
| }, 0).toFixed(2)}</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.
The use of .toFixed(2) ensures that the total review cost is formatted to two decimal places, which is generally good for currency representation. However, ensure that this formatting does not interfere with any subsequent calculations or display requirements elsewhere in the application.
| reviewerTotal = challenge.reviewers | ||
| .filter(r => !r.isAIReviewer) | ||
| .reduce((sum, r) => { | ||
| const base = convertDollarToInteger(r.basePayment || '0', '') |
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 where r.basePayment is not a valid number string. Using || '0' ensures a default value, but it might be better to validate the input or handle potential errors more explicitly.
| .filter(r => !r.isAIReviewer) | ||
| .reduce((sum, r) => { | ||
| const base = convertDollarToInteger(r.basePayment || '0', '') | ||
| const count = parseInt(r.memberReviewerCount) || 1 |
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 use of parseInt(r.memberReviewerCount) || 1 assumes that memberReviewerCount is either a valid number string or undefined/null. If memberReviewerCount can be other invalid values, consider adding validation to ensure correct parsing.
vas3a
left a comment
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.
you can merge this. let's get it to qa.
| return ( | ||
| <div key={`reviewer-${index}`} className={styles.reviewerForm}> | ||
| <div className={styles.reviewerHeader}> | ||
| {index > 0 && <h4>Reviewer {index + 1}</h4>} |
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.
you could hide it based on count. eg. if there are more than 1 reviewers render it, if there's a single reviewer hide it. BUT. let's leave it as is for now. it's pretty minor, we need to get this to QA.
No description provided.