Skip to content

[jules] refactor: Use generic Skeleton component in FriendsScreen#305

Open
Devasy wants to merge 1 commit intomainfrom
jules-ux-friends-skeleton-6500990729041499595
Open

[jules] refactor: Use generic Skeleton component in FriendsScreen#305
Devasy wants to merge 1 commit intomainfrom
jules-ux-friends-skeleton-6500990729041499595

Conversation

@Devasy
Copy link
Owner

@Devasy Devasy commented Mar 23, 2026

Extracted the inline skeleton animation logic from FriendsScreen into a highly reusable Skeleton primitive in mobile/components/ui/. Refactored FriendsScreen to import and utilize the new generic component to produce a consistent and visually identical loading state while supporting light and dark themes out-of-the-box.


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

Summary by CodeRabbit

  • New Features

    • Introduced a reusable skeleton loading placeholder component for consistent loading state UI.
  • Refactor

    • Updated the Friends screen to use the new skeleton component for loading placeholders, improving code maintainability.

Extracted the inline skeleton animation logic from FriendsScreen into a highly reusable `Skeleton` primitive in `mobile/components/ui/`. Refactored `FriendsScreen` to import and utilize the new generic component to produce a consistent and visually identical loading state while supporting light and dark themes out-of-the-box.

Co-authored-by: Devasy23 <110348311+Devasy23@users.noreply.github.com>
@Devasy Devasy requested a review from vrajpatelll as a code owner March 23, 2026 20:20
@google-labs-jules
Copy link
Contributor

👋 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!

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


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

@netlify
Copy link

netlify bot commented Mar 23, 2026

Deploy Preview for split-but-wiser canceled.

Name Link
🔨 Latest commit 4136f3b
🔍 Latest deploy log https://app.netlify.com/projects/split-but-wiser/deploys/69c1a07eac829900080edaa9

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 23, 2026

Walkthrough

A new reusable Skeleton component is introduced in the mobile UI library with animated opacity effects using React Native's Animated API. The component is then integrated into FriendsScreen.js, replacing an inline shimmer skeleton implementation with instances of the new component.

Changes

Cohort / File(s) Summary
Skeleton Component Implementation
mobile/components/ui/Skeleton.js
New React Native component for animated placeholder UI with configurable width, height, and border radius. Uses useTheme from react-native-paper and Animated API to create infinite opacity loop effect (1 to 0.3) with native driver optimization.
Skeleton Integration
mobile/screens/FriendsScreen.js
Refactored to use the new Skeleton component for avatar and text placeholders, removing inline animation logic and associated style definitions. Simplified imports by removing Animated and useRef dependencies.

Suggested reviewers

  • vrajpatelll
🚥 Pre-merge checks | ✅ 3
✅ 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 and specifically describes the main change: extracting and using a new generic Skeleton component in FriendsScreen.
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.


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.

@codecov
Copy link

codecov bot commented Mar 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@9404621). Learn more about missing BASE report.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #305   +/-   ##
=======================================
  Coverage        ?   74.43%           
=======================================
  Files           ?       17           
  Lines           ?     1635           
  Branches        ?      144           
=======================================
  Hits            ?     1217           
  Misses          ?      367           
  Partials        ?       51           
Components Coverage Δ
Authentication System 76.80% <ø> (?)
Expense Management 69.58% <ø> (?)
Group Management 76.68% <ø> (?)
User Management 97.16% <ø> (?)
Backend Core 69.41% <ø> (?)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@mobile/components/ui/Skeleton.js`:
- Around line 7-27: The Skeleton component currently creates its own
Animated.loop via the opacityAnim useRef and useEffect, causing many concurrent
loops; change Skeleton to accept an optional shared animated value prop (e.g.,
sharedOpacityAnim) and, in the component (identify opacityAnim and useEffect
that calls Animated.loop/loop.start/loop.stop), use the passed sharedOpacityAnim
when provided and only create the local Animated.Value and loop when no shared
value is supplied; ensure the shared loop is started/stopped in a single central
place (or lazily once in a module-level initializer) while keeping the current
local fallback behavior so existing usage still works.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b0418a4b-f54d-425a-8328-a901094571d2

📥 Commits

Reviewing files that changed from the base of the PR and between 9404621 and 4136f3b.

📒 Files selected for processing (2)
  • mobile/components/ui/Skeleton.js
  • mobile/screens/FriendsScreen.js

Comment on lines +7 to +27
const opacityAnim = useRef(new Animated.Value(0.3)).current;

useEffect(() => {
const loop = Animated.loop(
Animated.sequence([
Animated.timing(opacityAnim, {
toValue: 1,
duration: 700,
useNativeDriver: true,
}),
Animated.timing(opacityAnim, {
toValue: 0.3,
duration: 700,
useNativeDriver: true,
}),
])
);
loop.start();

return () => loop.stop();
}, [opacityAnim]);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C3 'new Animated\.Value|Animated\.loop|useEffect' mobile/components/ui/Skeleton.js
rg -n -C2 '<Skeleton' mobile/screens/FriendsScreen.js
rg -n -C2 'Array\.from\(\{ length: 5 \}\)' mobile/screens/FriendsScreen.js

Repository: Devasy/splitwiser

Length of output: 1255


🏁 Script executed:

rg -n 'import.*Skeleton|<Skeleton' mobile/screens/ --type js

Repository: Devasy/splitwiser

Length of output: 537


Share animation state instead of starting one pulse loop per Skeleton instance.

Each mounted Skeleton starts its own infinite Animated.loop. In FriendsScreen's loading state, 5 rows render 3 Skeleton components each, resulting in 15 concurrent animation loops. This adds avoidable animation overhead and can impact smoothness on lower-end devices.

⚙️ Proposed refactor (allow shared animated value, keep local fallback)
-const Skeleton = ({ width, height, borderRadius, style }) => {
+const Skeleton = ({ width, height, borderRadius, style, animatedOpacity }) => {
   const theme = useTheme();
-  const opacityAnim = useRef(new Animated.Value(0.3)).current;
+  const localOpacityAnim = useRef(new Animated.Value(0.3)).current;
+  const opacityAnim = animatedOpacity ?? localOpacityAnim;

   useEffect(() => {
+    if (animatedOpacity) return undefined;
     const loop = Animated.loop(
       Animated.sequence([
         Animated.timing(opacityAnim, {
           toValue: 1,
           duration: 700,
           useNativeDriver: true,
         }),
         Animated.timing(opacityAnim, {
           toValue: 0.3,
           duration: 700,
           useNativeDriver: true,
         }),
       ])
     );
     loop.start();

     return () => loop.stop();
-  }, [opacityAnim]);
+  }, [animatedOpacity, localOpacityAnim]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mobile/components/ui/Skeleton.js` around lines 7 - 27, The Skeleton component
currently creates its own Animated.loop via the opacityAnim useRef and
useEffect, causing many concurrent loops; change Skeleton to accept an optional
shared animated value prop (e.g., sharedOpacityAnim) and, in the component
(identify opacityAnim and useEffect that calls
Animated.loop/loop.start/loop.stop), use the passed sharedOpacityAnim when
provided and only create the local Animated.Value and loop when no shared value
is supplied; ensure the shared loop is started/stopped in a single central place
(or lazily once in a module-level initializer) while keeping the current local
fallback behavior so existing usage still works.

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