feat: Enhance AnalysisPage with recent events summary and API integration - #98
Conversation
…tion - Added functionality to fetch and display recent crisis events on the AnalysisPage. - Introduced a new API client method `getRecentEvents` to retrieve recent events based on selected filters. - Implemented loading states and conditional rendering for event summaries, improving user experience. - Added a link to view all events, enhancing navigation within the dashboard.
WalkthroughThe pull request adds event-driven features to the dashboard and introduces a new design system showcase page. Changes include a new API helper function for fetching recent events, integration of that function into the dashboard with state management and effects, and a comprehensive design system page with interactive color/component demonstrations and asset downloads. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✨ Version Bump PredictionWhen this PR is merged to 1.48.1 → 1.49.0 ( 💡 How to change the version bump typeThe version bump is determined by your commit messages and PR title:
What I analyzed:
Edit your PR title or commit messages to change the bump type. |
🚀 Preview Deployment Ready!Backend: https://api-geeth-br-143-frontend-add-quic.private.bluerelief.app Commit: 🔐 AuthenticationDemo Login: Click "Google Sign In" → Use demo auth (no Google account needed) ✨ Version Bump PredictionWhen this PR is merged to main, the version will be bumped: 1.48.1 → 1.49.0 (minor) 💡 How to change the version bump type
Preview will be automatically deleted when PR is closed or merged. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
client/app/design-system/page.tsx (1)
470-485: Consolidate duplicate color computation logic.The functions
getComputedHex(line 470) andgetHexFromElement(line 572) share nearly identical canvas-based color computation logic. The only difference is thatgetHexFromElementaccepts apropertyparameter to read different CSS properties.Refactor to use a single, parameterized helper function:
-function getComputedHex(element: HTMLElement): string { +function getComputedHex(element: HTMLElement, property: 'backgroundColor' | 'color' = 'backgroundColor'): string { const canvas = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; const ctx = canvas.getContext('2d'); if (!ctx) return '#000000'; const computedStyle = getComputedStyle(element); - ctx.fillStyle = computedStyle.backgroundColor; + ctx.fillStyle = computedStyle[property]; ctx.fillRect(0, 0, 1, 1); const data = ctx.getImageData(0, 0, 1, 1).data; return '#' + [data[0], data[1], data[2]] .map(x => x.toString(16).padStart(2, '0')) .join(''); }Then in
SeveritySwatch, remove thegetHexFromElementfunction and use:React.useEffect(() => { if (bgRef.current && textRef.current) { setHexColors({ - bg: getHexFromElement(bgRef.current, 'backgroundColor'), - text: getHexFromElement(textRef.current, 'color') + bg: getComputedHex(bgRef.current, 'backgroundColor'), + text: getComputedHex(textRef.current, 'color') }); } }, [bgVar, textVar]);Also applies to: 572-587
client/app/dashboard/analysis/page.tsx (2)
334-353: Consider adding error state for recent events fetching.The
fetchRecentEventsfunction logs errors to the console but provides no user-facing feedback when the API call fails. While this might be acceptable for a non-critical feature, users would benefit from knowing why the events section is empty.Consider adding an error state for better user feedback:
const [recentEvents, setRecentEvents] = useState<Array<{...}>>([]); const [eventsLoading, setEventsLoading] = useState(true); + const [eventsError, setEventsError] = useState<string | null>(null); useEffect(() => { const fetchRecentEvents = async () => { try { setEventsLoading(true); + setEventsError(null); const country = selectedCountry || undefined; const disasterType = selectedDisasterTypes.length > 0 ? selectedDisasterTypes.join(',') : undefined; const eventsData = await getRecentEvents(8, country, disasterType); setRecentEvents(eventsData.crises); } catch (e) { console.error('Failed to fetch recent events:', e); + setEventsError('Unable to load recent events. Please try again later.'); } finally { setEventsLoading(false); } }; fetchRecentEvents(); }, [selectedCountry, selectedDisasterTypes]);Then update the CardContent to show the error state before the empty state check.
692-737: Remove redundant array slice operation.Line 694 slices
recentEventsto 8 items, butgetRecentEventsis already called with a limit of 8 (line 343), making this slice operation redundant.- {recentEvents.slice(0, 8).map((event) => ( + {recentEvents.map((event) => ( <div
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
client/app/dashboard/analysis/page.tsx(4 hunks)client/app/design-system/page.tsx(1 hunks)client/lib/api-client.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
client/app/dashboard/analysis/page.tsx (3)
client/lib/api-client.ts (1)
getRecentEvents(224-257)client/components/lordicon.tsx (1)
Lordicon(15-113)client/lib/lordicon-config.ts (2)
LORDICON_SOURCES(6-41)LORDICON_SIZES(66-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build (frontend, client, Dockerfile.prod, bluerelief/frontend)
🔇 Additional comments (2)
client/app/dashboard/analysis/page.tsx (1)
650-761: Well-implemented Active Events Summary section.The implementation demonstrates good UX practices:
- Loading skeletons provide visual feedback during data fetch
- Empty states adapt messaging based on whether filters are active
- Event cards display comprehensive information with appropriate formatting
- Navigation link to the full data feed is clearly accessible
- Responsive grid layout works well across screen sizes
client/app/design-system/page.tsx (1)
14-22: Verify logo asset availability.The download function assumes logo files exist at
/bluerelief-logo.pngand/bluerelief-logo.svg. Ensure these files are present in the public directory to avoid 404 errors when users attempt downloads.
| export async function getRecentEvents(limit = 10, country?: string, disasterType?: string) { | ||
| const params = new URLSearchParams(); | ||
| params.append('days', '30'); | ||
| params.append('page', '1'); | ||
| params.append('page_size', limit.toString()); | ||
|
|
||
| if (country) params.append('country', country); | ||
| if (disasterType) params.append('disaster_type', disasterType); | ||
|
|
||
| return apiGet<{ | ||
| crises: Array<{ | ||
| id: number; | ||
| crisis_name: string; | ||
| date: string; | ||
| region: string; | ||
| severity: string; | ||
| tweets_analyzed: number; | ||
| status: string; | ||
| description: string; | ||
| sentiment?: string | null; | ||
| sentiment_score?: number | null; | ||
| disaster_type: string; | ||
| bluesky_url: string | null; | ||
| }>; | ||
| pagination: { | ||
| page: number; | ||
| page_size: number; | ||
| total_count: number; | ||
| total_pages: number; | ||
| has_next: boolean; | ||
| has_prev: boolean; | ||
| } | ||
| }>(`/api/data-feed/weekly-crises?${params.toString()}`); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Reduce code duplication with existing getWeeklyCrises function.
The new getRecentEvents function is essentially a specialized wrapper around the same endpoint used by getWeeklyCrises (line 95), with hardcoded days=30 and page=1. The return type structure is also duplicated.
Refactor to reuse the existing function and eliminate duplication:
-export async function getRecentEvents(limit = 10, country?: string, disasterType?: string) {
- const params = new URLSearchParams();
- params.append('days', '30');
- params.append('page', '1');
- params.append('page_size', limit.toString());
-
- if (country) params.append('country', country);
- if (disasterType) params.append('disaster_type', disasterType);
-
- return apiGet<{
- crises: Array<{
- id: number;
- crisis_name: string;
- date: string;
- region: string;
- severity: string;
- tweets_analyzed: number;
- status: string;
- description: string;
- sentiment?: string | null;
- sentiment_score?: number | null;
- disaster_type: string;
- bluesky_url: string | null;
- }>;
- pagination: {
- page: number;
- page_size: number;
- total_count: number;
- total_pages: number;
- has_next: boolean;
- has_prev: boolean;
- }
- }>(`/api/data-feed/weekly-crises?${params.toString()}`);
+export async function getRecentEvents(limit = 10, country?: string, disasterType?: string) {
+ // Reuse getWeeklyCrises with 30-day window
+ return getWeeklyCrises(30, 1, limit, '', country, disasterType);
}Note: You'll need to update getWeeklyCrises signature to accept optional country and disasterType parameters for this refactor to work.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In client/lib/api-client.ts around lines 224 to 257, getRecentEvents duplicates
logic and types from getWeeklyCrises (around line 95); change getWeeklyCrises to
accept optional parameters country?: string and disasterType?: string (and keep
existing params for days, page, page_size) so it can build the same URL based on
those inputs, then replace getRecentEvents with a thin wrapper that calls
getWeeklyCrises({ days: 30, page: 1, page_size: limit, country, disasterType })
and returns its result so the endpoint construction and return type are reused
instead of duplicated.
getRecentEventsto retrieve recent events based on selected filters.Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.