-
Notifications
You must be signed in to change notification settings - Fork 31
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
QA feedback on the chart and card names on truncations #2219
Conversation
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (1)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including You can disable this status message by setting the 📝 Walkthrough📝 WalkthroughWalkthroughThe changes in this pull request involve enhancements to several components, including Changes
Possibly related PRs
Suggested labels
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
New next-platform changes available for preview here |
1 similar comment
New next-platform changes available for preview 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.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (5)
platform/src/common/components/AQNumberCard/index.jsx (3)
83-103
: Consider optimizing the truncation detection.While the implementation is solid, there are two potential performance improvements:
- The resize event listener could benefit from debouncing to reduce unnecessary recalculations
- The effect's dependency on
windowWidth
might cause extra rechecks when the window size changes but doesn't affect the truncation statusConsider applying this optimization:
useEffect(() => { + const debounce = (fn, ms) => { + let timer; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => fn.apply(this, args), ms); + }; + }; + const checkTruncation = () => { const el = nameRef.current; if (el) { setIsTruncated(el.scrollWidth > el.clientWidth); } }; + + const debouncedCheck = debounce(checkTruncation, 250); // Initial check checkTruncation(); // Re-check on window resize - window.addEventListener('resize', checkTruncation); + window.addEventListener('resize', debouncedCheck); return () => { - window.removeEventListener('resize', checkTruncation); + window.removeEventListener('resize', debouncedCheck); }; -}, [site.name, windowWidth]); +}, [site.name]);
Line range hint
105-131
: Enhance accessibility for truncated text.The truncation implementation works well visually, but could be more accessible for screen readers.
Consider adding ARIA attributes:
const siteNameElement = ( <div ref={nameRef} className="text-gray-800 text-lg font-medium capitalize text-left w-full max-w-[185px] md:max-w-full lg:max-w-[185px] overflow-hidden text-ellipsis whitespace-nowrap" + aria-label={site.name || 'No Location Data'} + title={site.name || 'No Location Data'} > {site.name || '---'} </div> );
174-183
: Enhance PropTypes validation.The PropTypes implementation is good, but could be more specific for better type safety.
Consider these enhancements:
SiteCard.propTypes = { site: PropTypes.shape({ _id: PropTypes.string.isRequired, name: PropTypes.string, country: PropTypes.string, }).isRequired, onOpenModal: PropTypes.func.isRequired, windowWidth: PropTypes.number.isRequired, - pollutantType: PropTypes.string.isRequired, + pollutantType: PropTypes.oneOf(['pm2_5', 'pm10']).isRequired, }; AQNumberCard.propTypes = { - className: PropTypes.string, + className: PropTypes.string.isRequired, };Also applies to: 290-292
platform/src/common/components/Charts/components/index.jsx (2)
Line range hint
209-227
: LGTM! Nice improvements to the legend rendering logic.The changes look good:
- Clean destructuring of props
- Smart conditional truncation based on payload length
- Efficient memoization of the sorted payload
- Safe copying of the payload array using spread operator
Consider extracting the color-to-grayscale conversion into a separate utility function since it might be useful elsewhere:
const colorToGrayscale = (color) => { if (!color) return 0; const hex = color.replace('#', ''); const r = parseInt(hex.slice(0, 2), 16); const g = parseInt(hex.slice(2, 4), 16); const b = parseInt(hex.slice(4, 6), 16); return 0.2126 * r + 0.7152 * g + 0.0722 * b; // ITU-R BT.709 formula };
231-258
: Consider enhancing accessibility for the tooltip implementation.The tooltip implementation is clean and follows good practices. However, we could improve accessibility for screen readers.
Consider adding these ARIA attributes:
<span className={`${shouldTruncate ? 'truncate max-w-[100px] group' : ''}`} title={shouldTruncate ? entry.value : null} + role="tooltip" + aria-label={entry.value} > {entry.value} </span> {shouldTruncate && ( <div className="absolute bottom-full mb-1 hidden group-hover:flex flex-col items-center" + role="tooltip" + aria-hidden={true} >
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
platform/src/common/components/AQNumberCard/index.jsx
(8 hunks)platform/src/common/components/Charts/components/index.jsx
(2 hunks)platform/src/common/components/TopBar/index.jsx
(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- platform/src/common/components/TopBar/index.jsx
🔇 Additional comments (2)
platform/src/common/components/AQNumberCard/index.jsx (1)
1-1
: LGTM! Good addition of necessary imports.
The addition of useRef
and PropTypes
imports aligns well with the implementation of text truncation detection and type checking.
Also applies to: 8-8
platform/src/common/components/Charts/components/index.jsx (1)
Line range hint 1-1
: Verify complete removal of truncate2 function.
The AI summary mentioned the removal of the truncate2
function. Let's verify there are no remaining references to it.
✅ Verification successful
The previous command failed because the file type wasn't recognized. Let's try with explicit file pattern matching and also use AST-based search to be thorough.
truncate2
function has been successfully removed
The comprehensive search across all JavaScript and TypeScript files, including both string-based and AST-based searches, found no remaining references to the truncate2
function. This confirms its complete removal from the codebase.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for any remaining references to truncate2 function
rg "truncate2" --type js --type jsx
Length of output: 63
Script:
#!/bin/bash
# Search for any remaining references to truncate2 function, using ripgrep with all possible extensions
rg "truncate2" -g "*.{js,jsx,ts,tsx}"
# Also search using ast-grep to catch any function declarations or references
ast-grep --pattern 'truncate2($_)'
Length of output: 74
New next-platform changes available for preview 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.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (1)
platform/src/common/components/Modal/dataDownload/modules/DataDownload.jsx (1)
153-153
: Document the purpose of the 'minimum' flag.The addition of
minimum: true
to the API request could have significant implications on the data returned. Please add a comment explaining:
- The purpose of this flag
- How it affects the response data
- When it should be used
Add documentation above the apiData object:
// Prepare data for API + // minimum: true reduces the response payload by returning only essential fields const apiData = {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
platform/src/common/components/Modal/dataDownload/modules/DataDownload.jsx
(2 hunks)platform/src/pages/Home/index.jsx
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- platform/src/pages/Home/index.jsx
🔇 Additional comments (2)
platform/src/common/components/Modal/dataDownload/modules/DataDownload.jsx (2)
121-121
: LGTM! Clean error state management.
The error state reset is well-placed at the beginning of form submission, ensuring a clean slate for new validation checks.
144-145
: 🛠️ Refactor suggestion
Consider timezone handling in date conversions.
The current implementation using toISOString()
converts dates to UTC, which might not reflect the user's local timezone context. This could lead to unexpected date shifts, especially for users in different timezones.
Let's verify the impact:
Consider using a date library like date-fns or moment.js for proper timezone handling:
- startDateTime: new Date(formData.duration.name.start).toISOString(),
- endDateTime: new Date(formData.duration.name.end).toISOString(),
+ startDateTime: zonedTimeToUtc(new Date(formData.duration.name.start), Intl.DateTimeFormat().resolvedOptions().timeZone).toISOString(),
+ endDateTime: zonedTimeToUtc(new Date(formData.duration.name.end), Intl.DateTimeFormat().resolvedOptions().timeZone).toISOString(),
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.
Actionable comments posted: 3
🧹 Outside diff range and nitpick comments (5)
platform/src/common/components/Charts/ChartContainer.jsx (4)
Line range hint
64-106
: Consider enhancing error handling in the export functionalityThe
exportChart
function could benefit from more specific error handling and format validation:
- Add format validation before processing
- Handle specific export errors (e.g., canvas creation, PDF generation)
- Provide more detailed error messages to users
Here's a suggested improvement:
const exportChart = useCallback(async (format) => { if (!chartRef.current) return; + const supportedFormats = ['png', 'jpg', 'pdf']; + if (!supportedFormats.includes(format)) { + CustomToast({ + message: `Unsupported format: ${format}. Please use: ${supportedFormats.join(', ')}`, + type: 'error' + }); + return; + } setDownloadComplete(null); setLoadingFormat(format); try { const canvas = await html2canvas(chartRef.current, { scale: 2, useCORS: true, backgroundColor: '#fff', }); - if (['png', 'jpg'].includes(format)) { + if (format === 'png' || format === 'jpg') { const imgData = canvas.toDataURL(`image/${format}`, 0.8); const link = document.createElement('a'); link.href = imgData; link.download = `airquality-data.${format}`; document.body.appendChild(link); link.click(); document.body.removeChild(link); } else if (format === 'pdf') { const pdf = new jsPDF({ orientation: 'landscape', unit: 'px', format: [canvas.width, canvas.height], }); const imgData = canvas.toDataURL('image/png', 0.8); pdf.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height); pdf.save('airquality-data.pdf'); - } else { - throw new Error('Unsupported format'); } setDownloadComplete(format); CustomToast({ message: `Chart exported as ${format.toUpperCase()} successfully!`, type: 'success', }); } catch (error) { + const errorMessage = error.message || `Failed to export chart as ${format.toUpperCase()}`; console.error('Error exporting chart:', error); CustomToast({ - message: `Failed to export chart as ${format.toUpperCase()}.`, + message: errorMessage, type: 'error', }); } finally { setLoadingFormat(null); } }, []);
Line range hint
1-249
: Consider splitting this component for better maintainabilityThe
ChartContainer
component has multiple responsibilities:
- Chart rendering
- Export functionality
- Dropdown handling
- Error handling
Consider extracting these into separate components:
ChartExporter
: Handle export functionalityChartDropdown
: Handle dropdown menuChartError
: Handle error displayThis would improve:
- Code maintainability
- Testing capabilities
- Reusability
- Component complexity
Would you like me to help create a detailed plan for this refactoring?
Line range hint
171-184
: Extract ErrorOverlay into a separate componentThe
ErrorOverlay
component could be moved to its own file for better organization and reusability.Consider creating a new file
components/ErrorOverlay.jsx
:const ErrorOverlay = ({ onRetry }) => ( <div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center bg-gray-300 bg-opacity-50 z-10 p-4"> <p className="text-red-500 font-semibold mb-2"> Something went wrong. Please try again. </p> <button onClick={onRetry} className="mt-2 px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600" > Try Again </button> </div> ); export default ErrorOverlay;
Line range hint
107-166
: Optimize dropdown content memoizationThe
renderDropdownContent
callback could be optimized by:
- Moving the button components outside the callback
- Memoizing the export options separately
Here's a suggested approach:
const ExportButton = memo(({ format, loading, complete, onExport }) => ( <button onClick={() => onExport(format)} className="flex justify-between items-center w-full px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" > <span>Export as {format.toUpperCase()}</span> <span className="-mr-2 flex items-center"> {loading === format && ( <div className="animate-spin h-4 w-4 border-2 border-t-blue-500 border-gray-300 rounded-full" /> )} {complete === format && <CheckIcon fill="#1E40AF" width={20} height={20} />} </span> </button> )); const EXPORT_FORMATS = ['png', 'jpg', 'pdf']; const renderDropdownContent = useCallback( () => ( <> <button onClick={handleRefreshChart} className="flex justify-between items-center w-full px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" > Refresh </button> <hr className="border-gray-200" /> {EXPORT_FORMATS.map((format) => ( <ExportButton key={format} format={format} loading={loadingFormat} complete={downloadComplete} onExport={exportChart} /> ))} {/* ... rest of the content ... */} </> ), [exportChart, loadingFormat, downloadComplete, handleRefreshChart] );platform/src/pages/analytics/_components/OverView.jsx (1)
135-144
: Consider handling errors after retry attempts are exhaustedAfter the retry mechanism has reached its limit, it would be prudent to handle the scenario where data cannot be fetched successfully. This could involve displaying a user-friendly error message or logging the error for further investigation.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
platform/yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (5)
platform/next-env.d.ts
(1 hunks)platform/package.json
(1 hunks)platform/src/common/components/Charts/ChartContainer.jsx
(1 hunks)platform/src/pages/analytics/_components/OverView.jsx
(5 hunks)platform/tsconfig.json
(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- platform/next-env.d.ts
- platform/tsconfig.json
🔇 Additional comments (1)
platform/src/common/components/Charts/ChartContainer.jsx (1)
53-54
: Nice simplification of the skeleton loader state! 👍
The direct derivation of showSkeleton
from chartLoading
is a cleaner approach that:
- Eliminates unnecessary state management
- Removes the need for useEffect and timers
- Maintains the same visual behavior
Let's verify the skeleton loader behavior in other components:
✅ Verification successful
Skeleton loader behavior is consistent across the codebase ✅
The verification shows that the SkeletonLoader
component is used consistently across the codebase:
- In
MoreInsights.jsx
: Direct loading state usage - In
ChartContainer.jsx
: Our simplified loading state - In
reports/home/page.tsx
: Direct loading state usage
All implementations follow the same pattern of showing the skeleton based on a direct loading state, confirming that our simplification aligns with the codebase's patterns.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for other components using SkeletonLoader to ensure consistent behavior
# Search for SkeletonLoader usage
rg "SkeletonLoader" -A 3
# Search for similar loading state patterns
ast-grep --pattern 'const showSkeleton = $_;'
Length of output: 3275
@@ -89,6 +89,7 @@ | |||
"eslint-plugin-react-hooks": "^4.6.2", | |||
"globals": "^15.9.0", | |||
"prettier": "^3.3.3", | |||
"typescript": "5.6.3", |
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.
Fix invalid TypeScript version
The specified TypeScript version 5.6.3
is invalid. The latest stable version as of April 2024 is 5.3.3.
Apply this diff to fix the version:
- "typescript": "5.6.3",
+ "typescript": "5.3.3",
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"typescript": "5.6.3", | |
"typescript": "5.3.3", |
🛠️ Refactor suggestion
Add missing TypeScript type definitions
Since you're adding TypeScript support, you'll need type definitions for your existing dependencies. Several key packages in your dependencies require separate @types/*
packages.
Add these essential type definitions:
"typescript": "5.3.3",
+ "@types/react": "^18.2.0",
+ "@types/react-dom": "^18.2.0",
+ "@types/node": "^20.0.0",
+ "@types/mapbox-gl": "^2.7.19",
+ "@types/pako": "^2.0.3",
+ "@types/papaparse": "^5.3.14",
+ "@types/underscore": "^1.11.15",
"webpack": "^5.74.0"
This will provide proper type checking and better IDE support for your core dependencies.
Committable suggestion skipped: line range outside the PR's diff.
dateRange: chartData.chartDataRange, | ||
frequency: chartData.timeFrame, | ||
pollutant: chartData.pollutionType, | ||
organisationName: chartData.organizationName, |
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.
Inconsistent spelling of 'organizationName'
There's a discrepancy in the spelling of 'organizationName' when passing it to useFetchAnalyticsData
. The parameter name uses 'organisationName' (with an 's'), but the variable is chartData.organizationName
(with a 'z'). This inconsistency could lead to the organisationName
parameter being undefined in the hook.
Apply this diff to correct the spelling:
- organisationName: chartData.organizationName,
+ organizationName: chartData.organizationName,
Ensure that the useFetchAnalyticsData
hook accepts organizationName
as a parameter.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
organisationName: chartData.organizationName, | |
organizationName: chartData.organizationName, |
New next-platform changes available for preview here |
Summary of Changes (What does this PR do?)
Status of maturity (all need to be checked before merging):
How should this be manually tested?
What are the relevant tickets?
Screenshots (optional)
Summary by CodeRabbit
New Features
AQNumberCard
component to display site names with tooltips when truncated, improving user experience.OverView
component, simplifying data retrieval and error handling.Bug Fixes
Chores
TopBar
component while maintaining modal access.Documentation
SiteCard
,AddLocationCard
, andAQNumberCard
components to ensure proper prop usage.DataDownload
component for API requests.