Skip to content

Speed review improvements#2207

Merged
anglilian merged 5 commits into
masterfrom
speed-review-improvements
Mar 28, 2026
Merged

Speed review improvements#2207
anglilian merged 5 commits into
masterfrom
speed-review-improvements

Conversation

@anglilian

Copy link
Copy Markdown
Contributor

Description

Issue

Fixes #

Developer checklist

Screenshot

📸 Before After
📱
🖥️

Changed the date filtering logic in fetchRounds to properly compare dates at midnight rather than using ISO string comparison. This ensures rounds are correctly filtered based on whether their discussion date is today or in the future, preventing potential timezone-related issues.
Add proper CSS classes to handle long text content that was causing layout issues. Applied break-words and overflow-hidden to application source fields and session complete components to prevent horizontal scrolling and maintain responsive layout.
Add keyboard shortcut (spacebar) to cycle through application details sections sequentially. When pressed, it closes the current open detail and opens the next one, with smooth scrolling to keep it in view. This improves keyboard navigation efficiency during the review process.
@render render Bot temporarily deployed to speed-review-improvements - bluedot-preview PR #2207 March 28, 2026 20:36 Destroyed
@coderabbitai

coderabbitai Bot commented Mar 28, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 96683e45-90a1-4e98-9cc6-d5d7b07655e7

📥 Commits

Reviewing files that changed from the base of the PR and between e1ea0b0 and e042cb4.

📒 Files selected for processing (4)
  • apps/speed-review/src/components/ApplicationCard.tsx
  • apps/speed-review/src/components/SessionComplete.tsx
  • apps/speed-review/src/lib/api/airtable.ts
  • apps/speed-review/src/pages/index.tsx

📝 Walkthrough

Walkthrough

This pull request updates the speed-review application across multiple components and API layers. The ApplicationCard and SessionComplete components receive Tailwind styling adjustments for improved text wrapping and overflow handling. The SessionComplete component's average duration display is refactored to show a minutes-and-seconds format rather than rounded seconds. The Airtable API layer changes the date filtering logic to use a local midnight timestamp instead of ISO date strings, and reorders fetched applications by prioritising those with aiSummary fields. A spacebar keyboard shortcut is added to enable sequential navigation through details elements during review.

Possibly related PRs

  • bluedot/bluedot#2201: Modifies the same UI components (ApplicationCard and SessionComplete) with overlapping changes to layout and rendering behaviour.
  • bluedot/bluedot#2189: Updates ApplicationCard and SessionComplete components with changes to layout, overflow, and responsive Tailwind classes.
  • bluedot/bluedot#2190: Modifies SessionComplete component layout and wrapping behaviour with similar overflow and container constraint adjustments.
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description contains only the template with no explanatory text, issue links, screenshots, or completed checklist items despite multiple substantial changes affecting UI, keyboard navigation, and API logic. Add explanatory text describing why changes were made, complete relevant checklist items, link to any related issue, and include before/after screenshots if there are visual changes.
Title check ❓ Inconclusive The title 'Speed review improvements' is vague and generic, using non-descriptive language that doesn't convey specific information about the changeset. Provide a more specific title highlighting the primary change, such as 'Add spacebar navigation and fix date filtering in speed review' or focus on the most significant improvement.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch speed-review-improvements

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Modified the application fetching logic to display applications with AI summaries first, followed by those without. Both groups are still shuffled randomly within their respective categories to maintain fairness while improving reviewer efficiency.
…rd handler

Add consistent spacing and formatting to the keyboard event handler for better code readability. Ensures proper line breaks after control flow statements and maintains consistent code style.
@greptile-apps

greptile-apps Bot commented Mar 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR brings a collection of UX improvements to the speed-review app: overflow/layout fixes across ApplicationCard and SessionComplete, a corrected avg-time display that now formats minutes properly, and a new spacebar keyboard shortcut to cycle through an applicant's expandable detail sections.

Key changes:

  • ApplicationCard.tsx: Adds break-words overflow-hidden to the source/UTM block to prevent long strings from breaking the card layout.
  • SessionComplete.tsx: Fixes "Avg per app" to show Xm Ys format instead of raw seconds; adds overflow-hidden / min-w-0 to prevent grid children from overflowing on narrow viewports.
  • airtable.ts: Refactors round date filtering from a string comparison to a Date object comparison. The new approach mixes local-midnight (setHours(0,0,0,0)) with UTC-parsed date-only strings (new Date('YYYY-MM-DD')), which would incorrectly exclude today's rounds on servers running in a timezone behind UTC.
  • index.tsx: Adds a spacebar keyboard shortcut to sequentially open/close <details> sections on the current application card. The handler uses a global document.querySelectorAll('details') query which is fragile but currently safe given page structure.

Confidence Score: 4/5

Safe to merge for UTC-hosted deployments (e.g. Vercel); the date comparison regression only surfaces on non-UTC server environments.

The date filtering change introduces a real behavioral regression (today's rounds being excluded) on non-UTC servers. In practice Vercel runs in UTC so production is likely unaffected, but the logic is demonstrably wrong for local development in non-UTC timezones. All other changes are clean layout and UX improvements with no correctness issues.

apps/speed-review/src/lib/api/airtable.ts — the date timezone mismatch warrants attention before merging.

Important Files Changed

Filename Overview
apps/speed-review/src/lib/api/airtable.ts Date filtering refactored from string comparison to Date objects, but introduces a timezone mismatch: local midnight vs UTC-parsed date strings could exclude today's rounds on non-UTC servers.
apps/speed-review/src/pages/index.tsx Adds spacebar keyboard shortcut to cycle through <details> sections; uses a global document.querySelectorAll('details') which is fragile but harmless today given current page structure.
apps/speed-review/src/components/SessionComplete.tsx Average time display now correctly shows minutes and seconds (e.g. "1m 23s") instead of raw seconds; layout fixes with overflow-hidden and min-w-0 are correct.
apps/speed-review/src/components/ApplicationCard.tsx Minor layout improvement: adds break-words overflow-hidden to the source/UTM section to prevent long strings from overflowing the card.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Spacebar pressed] --> B{Target is input/textarea/select?}
    B -- Yes --> Z[Ignore]
    B -- No --> C[e.preventDefault]
    C --> D[querySelectorAll 'details' globally]
    D --> E{Any section open?}
    E -- No --> F[nextIndex = 0]
    E -- Yes --> G[openIndex = index of open section]
    G --> H[Close all sections]
    H --> I[nextIndex = openIndex + 1]
    F --> J{nextIndex < details.length?}
    I --> J
    J -- No --> K[All closed — cycle complete]
    J -- Yes --> L[Open details at nextIndex]
    L --> M[scrollIntoView smooth]
Loading

Reviews (1): Last reviewed commit: "feat(speed-review): add spacebar navigat..." | Re-trigger Greptile

@render render Bot temporarily deployed to speed-review-improvements - bluedot-preview PR #2207 March 28, 2026 20:39 Destroyed
Comment on lines 148 to +162
@@ -155,7 +156,11 @@ export const fetchRounds = async (): Promise<Round[]> => {
firstDiscussion: str(r.fields['First discussion']),
}))
.filter((r) => r.name !== '')
.filter((r) => !!r.firstDiscussion && r.firstDiscussion >= today)
.filter((r) => {
if (!r.firstDiscussion) return false;
const discussionDate = new Date(r.firstDiscussion);
return discussionDate >= todayStart;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Timezone mismatch in date comparison

todayStart.setHours(0, 0, 0, 0) sets midnight in the server's local timezone, but new Date(r.firstDiscussion) where r.firstDiscussion is a date-only string like "2025-04-01" is parsed as UTC midnight per the ECMAScript spec.

If the server runs in a timezone behind UTC (e.g., UTC-5), todayStart is 2025-04-01T05:00:00Z while new Date('2025-04-01') is 2025-04-01T00:00:00Z, so discussionDate >= todayStart evaluates to false — meaning today's rounds would be excluded from the list.

The old string comparison approach (r.firstDiscussion >= today on two YYYY-MM-DD strings) was actually correct and timezone-safe for pure calendar-date comparisons. The new approach only works correctly when the server is running in UTC.

A consistent fix would be to stay in UTC throughout:

const todayUTC = new Date().toISOString().slice(0, 10); // "YYYY-MM-DD" UTC

return records
  ...
  .filter((r) => {
    if (!r.firstDiscussion) return false;
    return r.firstDiscussion >= todayUTC;
  })

Comment on lines +352 to +363
case ' ': {
e.preventDefault();
const details = Array.from(document.querySelectorAll('details'));
const openIndex = details.findIndex((d) => d.open);
details.forEach((d) => {
d.open = false;
});
const nextIndex = openIndex === -1 ? 0 : openIndex + 1;

if (nextIndex < details.length) {
details[nextIndex]!.open = true;
details[nextIndex]!.scrollIntoView({ behavior: 'smooth', block: 'nearest' });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Global DOM query for <details> elements is fragile

document.querySelectorAll('details') queries the entire document, not just the current application card. This works today because <details> elements only appear inside ApplicationCard, but if any other component (e.g. SummaryCard, a modal, or a nav component) ever adds a <details> element, those would silently be included in the cycle, causing unexpected behaviour.

A more robust approach would be to scope the query to the card container using a ref or a specific data attribute on the card's wrapper <div>:

// In the JSX, add a data attribute:
// <div data-app-details-container ...>

// In the keyboard handler:
const container = document.querySelector('[data-app-details-container]');
const details = Array.from(container?.querySelectorAll('details') ?? []);

Comment on lines +352 to +363
case ' ': {
e.preventDefault();
const details = Array.from(document.querySelectorAll('details'));
const openIndex = details.findIndex((d) => d.open);
details.forEach((d) => {
d.open = false;
});
const nextIndex = openIndex === -1 ? 0 : openIndex + 1;

if (nextIndex < details.length) {
details[nextIndex]!.open = true;
details[nextIndex]!.scrollIntoView({ behavior: 'smooth', block: 'nearest' });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 No tests for the new spacebar shortcut

The spacebar cycling behaviour (open first section → cycle to next → close all → wrap around) is non-trivial logic. Consider adding a unit or integration test that verifies the cycle order, the wrap-around when reaching the last section, and that e.preventDefault() is called to suppress browser scrolling.

Rule Used: Consider adding tests for any new functionality in... (source)

Learnt From
bluedotimpact/bluedot#956
bluedotimpact/bluedot#969
bluedotimpact/bluedot#958

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/speed-review/src/lib/api/airtable.ts (1)

148-163: Consider timezone consistency for server-side date filtering.

The change correctly parses dates and compares against local midnight, which is an improvement over raw ISO string comparison. However, todayStart is set to the server's local midnight, which may differ from users' local dates depending on the server's timezone configuration.

If users in different timezones should see the same rounds based on a consistent reference (e.g., UTC), consider using UTC-based comparison:

const todayStart = new Date();
todayStart.setUTCHours(0, 0, 0, 0);
// and compare using UTC-based parsing

If server-local time is the intended behaviour (e.g., the organisation operates in a single timezone), the current implementation is appropriate.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/speed-review/src/lib/api/airtable.ts` around lines 148 - 163, The
current filtering uses server-local midnight via todayStart which can yield
inconsistent results across user timezones; update the logic in the
mapping/filter block (symbols: todayStart, firstDiscussion, and the final
.filter that constructs discussionDate) to use a UTC-based start-of-day when you
need timezone-consistent results: create todayStart using UTC
(setUTCHours(0,0,0,0)) and compare discussionDate using UTC-aware parsing/values
(e.g., use Date UTC timestamps or ensure discussionDate is parsed/normalized to
UTC) so the comparison discussionDate >= todayStart is done in the same timezone
reference.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/speed-review/src/pages/index.tsx`:
- Around line 352-363: In the keyboard navigation switch case (case ' '), fix
ESLint brace-style and spacing: change the inline block in details.forEach((d)
=> { d.open = false; }); to a multiline block so the statement is on the next
line (e.g. details.forEach((d) => { newline d.open = false; newline });) and add
a blank line immediately before the break statement so there is an empty line
separating the last statement and break; update the code in the case ' ' block
where details.forEach and break are used.

---

Nitpick comments:
In `@apps/speed-review/src/lib/api/airtable.ts`:
- Around line 148-163: The current filtering uses server-local midnight via
todayStart which can yield inconsistent results across user timezones; update
the logic in the mapping/filter block (symbols: todayStart, firstDiscussion, and
the final .filter that constructs discussionDate) to use a UTC-based
start-of-day when you need timezone-consistent results: create todayStart using
UTC (setUTCHours(0,0,0,0)) and compare discussionDate using UTC-aware
parsing/values (e.g., use Date UTC timestamps or ensure discussionDate is
parsed/normalized to UTC) so the comparison discussionDate >= todayStart is done
in the same timezone reference.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e047424c-3a8f-4982-9f5d-0241ca99365f

📥 Commits

Reviewing files that changed from the base of the PR and between e1ea0b0 and a9184d5.

📒 Files selected for processing (4)
  • apps/speed-review/src/components/ApplicationCard.tsx
  • apps/speed-review/src/components/SessionComplete.tsx
  • apps/speed-review/src/lib/api/airtable.ts
  • apps/speed-review/src/pages/index.tsx

Comment on lines +352 to +363
case ' ': {
e.preventDefault();
const details = Array.from(document.querySelectorAll('details'));
const openIndex = details.findIndex((d) => d.open);
details.forEach((d) => { d.open = false; });
const nextIndex = openIndex === -1 ? 0 : openIndex + 1;
if (nextIndex < details.length) {
details[nextIndex]!.open = true;
details[nextIndex]!.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
break;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix ESLint brace-style violations causing CI failure.

The pipeline is failing due to style violations flagged by ESLint:

  • Line 356: Statement inside curly braces should be on the next line
  • Line 362: Expected blank line before break statement

The navigation logic itself is sound.

🔧 Proposed fix for ESLint violations
         case ' ': {
           e.preventDefault();
           const details = Array.from(document.querySelectorAll('details'));
           const openIndex = details.findIndex((d) => d.open);
-          details.forEach((d) => { d.open = false; });
+          details.forEach((d) => {
+            d.open = false;
+          });
           const nextIndex = openIndex === -1 ? 0 : openIndex + 1;
           if (nextIndex < details.length) {
             details[nextIndex]!.open = true;
             details[nextIndex]!.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
           }
+
           break;
         }
🧰 Tools
🪛 GitHub Actions: ci_cd

[error] 356-356: ESLint (@stylistic/brace-style): 356:34 error - Statement inside of curly braces should be on next line.

🪛 GitHub Check: ci

[failure] 362-362:
Expected blank line before this statement


[failure] 356-356:
Closing curly brace should be on the same line as opening curly brace or on the line after the previous block


[failure] 356-356:
This line has 2 statements. Maximum allowed is 1


[failure] 356-356:
Statement inside of curly braces should be on next line

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/speed-review/src/pages/index.tsx` around lines 352 - 363, In the
keyboard navigation switch case (case ' '), fix ESLint brace-style and spacing:
change the inline block in details.forEach((d) => { d.open = false; }); to a
multiline block so the statement is on the next line (e.g. details.forEach((d)
=> { newline d.open = false; newline });) and add a blank line immediately
before the break statement so there is an empty line separating the last
statement and break; update the code in the case ' ' block where details.forEach
and break are used.

@anglilian anglilian merged commit 735ad97 into master Mar 28, 2026
8 of 9 checks passed
@anglilian anglilian deleted the speed-review-improvements branch March 28, 2026 20:43
@coderabbitai coderabbitai Bot mentioned this pull request Mar 30, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant