Skip to content

Conversation

@google-labs-jules
Copy link
Contributor

@google-labs-jules google-labs-jules bot commented Jan 1, 2026

Implemented a comprehensive skeleton loading state for the Dashboard to improve perceived performance and visual stability.

Changes:

  • Added web/components/skeletons/DashboardSkeleton.tsx: A composite component using Card and Skeleton to mimic the dashboard layout (summary cards + chart).
  • Modified web/pages/Dashboard.tsx: Integrated DashboardSkeleton to display while data is fetching, replacing the previous plain text loading state.
  • Updated tracking files (.Jules/todo.md, .Jules/changelog.md).

Verification:

  • Verified visually using a temporary Playwright script to capture the skeleton state.
  • Verified build success with npm run build.
  • Reverted unintentional lockfile changes.

PR created automatically by Jules for task 9372625517090864840 started by @Devasy23

Summary by CodeRabbit

  • New Features
    • Dashboard now shows a polished skeleton loading state while fetching data, with placeholder cards and content layout that mirror the final dashboard for improved perceived performance.
  • Chores
    • Task marking the dashboard skeleton work as completed and updated task metadata.

✏️ Tip: You can customize this high-level summary in your review settings.

- Created `DashboardSkeleton` component mimicking the dashboard layout
- Replaced simple loading text with `DashboardSkeleton` in `Dashboard.tsx`
- Improved perceived performance and reduced layout shift during data fetch
- Verified via Playwright screenshot
- Updated todo and changelog tracking files
@google-labs-jules
Copy link
Contributor Author

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!


For security, I will only act on instructions from the user who triggered this task.

New to Jules? Learn more at jules.google/docs.

@netlify
Copy link

netlify bot commented Jan 1, 2026

Deploy Preview for split-but-wiser ready!

Name Link
🔨 Latest commit 51ce20f
🔍 Latest deploy log https://app.netlify.com/projects/split-but-wiser/deploys/6956a824cfdf0c0008b71dce
😎 Deploy Preview https://deploy-preview-225--split-but-wiser.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 1, 2026

Walkthrough

Adds a new presentational DashboardSkeleton component and integrates it into the Dashboard page as the loading placeholder. Updates .Jules/changelog.md and .Jules/todo.md to document the addition and mark the skeleton task complete.

Changes

Cohort / File(s) Summary
Documentation Updates
\.Jules/changelog.md, \.Jules/todo.md
Added an "Added" entry for DashboardSkeleton in the unreleased changelog and marked the skeleton-loading task as completed, updating file references and metadata.
Skeleton Component Implementation
web/components/skeletons/DashboardSkeleton.tsx
New React functional export DashboardSkeleton rendering a static dashboard skeleton using Card and Skeleton primitives (summary cards, balance/chart placeholder, recent activity rows).
Dashboard Integration
web/pages/Dashboard.tsx
Replaced the plain "Loading stats..." placeholder with the DashboardSkeleton component when the page is in its loading state.

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a dashboard skeleton loading state component to improve perceived performance during data fetching.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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.

@Devasy Devasy marked this pull request as ready for review January 1, 2026 16:30
@Devasy Devasy requested a review from vrajpatelll as a code owner January 1, 2026 16:30
@Devasy
Copy link
Owner

Devasy commented Jan 1, 2026

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 1, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bfbf96f and cc36df9.

⛔ Files ignored due to path filters (1)
  • web/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • .Jules/changelog.md
  • .Jules/todo.md
  • web/components/skeletons/DashboardSkeleton.tsx
  • web/pages/Dashboard.tsx
🧰 Additional context used
📓 Path-based instructions (1)
web/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Web pages should be created as components in web/pages/ and added to routing configuration

Files:

  • web/pages/Dashboard.tsx
🧬 Code graph analysis (2)
web/components/skeletons/DashboardSkeleton.tsx (2)
web/components/ui/Card.tsx (1)
  • Card (12-35)
web/components/ui/Skeleton.tsx (1)
  • Skeleton (9-23)
web/pages/Dashboard.tsx (1)
web/components/skeletons/DashboardSkeleton.tsx (1)
  • DashboardSkeleton (5-54)
🔇 Additional comments (6)
.Jules/changelog.md (1)

9-10: LGTM! Clear documentation of the skeleton loading feature.

The changelog entry accurately describes the new DashboardSkeleton component and its UX benefit.

web/pages/Dashboard.tsx (2)

4-4: LGTM! Proper import of the new skeleton component.

The import path correctly references the new DashboardSkeleton component.


30-30: Excellent UX improvement with skeleton loading state.

Replacing the plain text loading indicator with a structured skeleton UI significantly improves perceived performance and provides visual stability during data fetch.

.Jules/todo.md (1)

13-16: LGTM! Accurate task completion documentation.

The task completion entry properly documents the files modified and the user-facing impact of the skeleton loading system.

web/components/skeletons/DashboardSkeleton.tsx (2)

5-54: Excellent skeleton implementation that mirrors the actual Dashboard layout.

The component structure effectively mimics the real Dashboard UI:

  • Three summary cards with icon, label, and value placeholders
  • Balance Overview chart with varying bar heights for visual interest
  • Recent Activity list with avatar and text placeholders

This provides excellent visual continuity and perceived performance during loading.


10-19: Index keys are acceptable for static skeleton UI.

While array indices as keys are generally discouraged for dynamic lists, they're perfectly fine here since the skeleton items are static and never reorder or change during their lifecycle.

Also applies to: 40-48

- Addressed code review feedback by removing unused `import React from 'react'` in `web/components/skeletons/DashboardSkeleton.tsx`.
- Verified build passes with `npm run build`.
@Devasy
Copy link
Owner

Devasy commented Jan 1, 2026

@jules while performing this task did you find any other areas you can make the similar changes?

@Devasy
Copy link
Owner

Devasy commented Jan 1, 2026

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 1, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Owner

@Devasy Devasy left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc36df9 and 51ce20f.

📒 Files selected for processing (1)
  • web/components/skeletons/DashboardSkeleton.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
web/components/skeletons/DashboardSkeleton.tsx (2)
web/components/ui/Card.tsx (1)
  • Card (12-35)
web/components/ui/Skeleton.tsx (1)
  • Skeleton (9-23)
🔇 Additional comments (1)
web/components/skeletons/DashboardSkeleton.tsx (1)

6-50: LGTM! Well-structured skeleton component.

The component effectively mimics the dashboard layout with:

  • Responsive grid layouts (mobile-first approach)
  • Clear visual hierarchy with summary cards, chart, and activity sections
  • Appropriate skeleton placeholder sizing and spacing
  • Clean, maintainable code with helpful comments

The implementation aligns well with modern React patterns and provides a good loading experience.

Comment on lines +4 to +53
export const DashboardSkeleton = () => {
return (
<div className="p-6 space-y-6 max-w-7xl mx-auto">
{/* Summary Cards Grid */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{[1, 2, 3].map((i) => (
<Card key={i} className="flex flex-col items-center justify-center text-center h-[200px]">
{/* Icon placeholder */}
<Skeleton className="w-16 h-16 rounded-full mb-4" />
{/* Label placeholder */}
<Skeleton className="w-24 h-4 mb-2" />
{/* Value placeholder */}
<Skeleton className="w-32 h-8" />
</Card>
))}
</div>

{/* Main Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Chart Section */}
<Card title="Balance Overview">
<div className="mt-4 space-y-4">
{/* Chart bars placeholder */}
<div className="flex items-end justify-between h-[250px] px-4 space-x-4">
<Skeleton className="w-full h-[40%]" />
<Skeleton className="w-full h-[70%]" />
<Skeleton className="w-full h-[50%]" />
<Skeleton className="w-full h-[80%]" />
</div>
</div>
</Card>

{/* Recent Activity Section */}
<Card title="Recent Activity">
<div className="mt-4 space-y-4">
{[1, 2, 3].map((i) => (
<div key={i} className="flex items-center space-x-4">
<Skeleton className="w-10 h-10 rounded-full" />
<div className="flex-1 space-y-2">
<Skeleton className="w-3/4 h-4" />
<Skeleton className="w-1/2 h-3" />
</div>
</div>
))}
</div>
</Card>
</div>
</div>
);
};
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 1, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add ARIA attributes to communicate loading state to screen readers.

The skeleton component currently lacks accessibility attributes, preventing screen reader users from knowing that content is loading. This impacts users with disabilities and creates an accessibility compliance gap.

🔎 Proposed fix

Add aria-busy="true" and aria-label to the container, and optionally aria-hidden="true" to decorative skeleton elements:

 export const DashboardSkeleton = () => {
   return (
-    <div className="p-6 space-y-6 max-w-7xl mx-auto">
+    <div className="p-6 space-y-6 max-w-7xl mx-auto" role="status" aria-busy="true" aria-label="Loading dashboard">
       {/* Summary Cards Grid */}
       <div className="grid grid-cols-1 md:grid-cols-3 gap-6">

Alternatively, you can add aria-live="polite" instead of role="status" for dynamic updates.

📝 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.

Suggested change
export const DashboardSkeleton = () => {
return (
<div className="p-6 space-y-6 max-w-7xl mx-auto">
{/* Summary Cards Grid */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{[1, 2, 3].map((i) => (
<Card key={i} className="flex flex-col items-center justify-center text-center h-[200px]">
{/* Icon placeholder */}
<Skeleton className="w-16 h-16 rounded-full mb-4" />
{/* Label placeholder */}
<Skeleton className="w-24 h-4 mb-2" />
{/* Value placeholder */}
<Skeleton className="w-32 h-8" />
</Card>
))}
</div>
{/* Main Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Chart Section */}
<Card title="Balance Overview">
<div className="mt-4 space-y-4">
{/* Chart bars placeholder */}
<div className="flex items-end justify-between h-[250px] px-4 space-x-4">
<Skeleton className="w-full h-[40%]" />
<Skeleton className="w-full h-[70%]" />
<Skeleton className="w-full h-[50%]" />
<Skeleton className="w-full h-[80%]" />
</div>
</div>
</Card>
{/* Recent Activity Section */}
<Card title="Recent Activity">
<div className="mt-4 space-y-4">
{[1, 2, 3].map((i) => (
<div key={i} className="flex items-center space-x-4">
<Skeleton className="w-10 h-10 rounded-full" />
<div className="flex-1 space-y-2">
<Skeleton className="w-3/4 h-4" />
<Skeleton className="w-1/2 h-3" />
</div>
</div>
))}
</div>
</Card>
</div>
</div>
);
};
export const DashboardSkeleton = () => {
return (
<div className="p-6 space-y-6 max-w-7xl mx-auto" role="status" aria-busy="true" aria-label="Loading dashboard">
{/* Summary Cards Grid */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{[1, 2, 3].map((i) => (
<Card key={i} className="flex flex-col items-center justify-center text-center h-[200px]">
{/* Icon placeholder */}
<Skeleton className="w-16 h-16 rounded-full mb-4" />
{/* Label placeholder */}
<Skeleton className="w-24 h-4 mb-2" />
{/* Value placeholder */}
<Skeleton className="w-32 h-8" />
</Card>
))}
</div>
{/* Main Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Chart Section */}
<Card title="Balance Overview">
<div className="mt-4 space-y-4">
{/* Chart bars placeholder */}
<div className="flex items-end justify-between h-[250px] px-4 space-x-4">
<Skeleton className="w-full h-[40%]" />
<Skeleton className="w-full h-[70%]" />
<Skeleton className="w-full h-[50%]" />
<Skeleton className="w-full h-[80%]" />
</div>
</div>
</Card>
{/* Recent Activity Section */}
<Card title="Recent Activity">
<div className="mt-4 space-y-4">
{[1, 2, 3].map((i) => (
<div key={i} className="flex items-center space-x-4">
<Skeleton className="w-10 h-10 rounded-full" />
<div className="flex-1 space-y-2">
<Skeleton className="w-3/4 h-4" />
<Skeleton className="w-1/2 h-3" />
</div>
</div>
))}
</div>
</Card>
</div>
</div>
);
};
🤖 Prompt for AI Agents
In web/components/skeletons/DashboardSkeleton.tsx around lines 4–53 the skeleton
markup lacks accessibility attributes to indicate loading state; add
aria-busy="true" and a descriptive aria-label (e.g., "Dashboard loading") or
role="status" with a visually-hidden "Loading…" text on the main container div,
and mark purely decorative Skeleton elements as aria-hidden="true" so screen
readers ignore them; ensure any dynamic updates use aria-live="polite" if you
prefer live region semantics instead of role="status".

Copy link
Owner

Choose a reason for hiding this comment

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

@jules In web/components/skeletons/DashboardSkeleton.tsx, around lines 4–53, the skeleton
markup lacks accessibility attributes to indicate loading state; add
aria-busy="true" and a descriptive aria-label (e.g., "Dashboard loading") or
role="status" with a visually-hidden "Loading…" text on the main container div,
and mark purely decorative Skeleton elements as aria-hidden="true" so screen
readers ignore them; ensure any dynamic updates use aria-live="polite" if you
prefer live region semantics instead of role="status".

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

@Devasy Devasy merged commit 3e3d321 into main Jan 1, 2026
12 checks passed
@Devasy Devasy deleted the jules/ux-dashboard-skeleton-9372625517090864840 branch January 1, 2026 18:12
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.

2 participants