Skip to content

implement the home page#3

Merged
saikumarbt merged 1 commit into
mainfrom
home-page-implementation
Jun 23, 2026
Merged

implement the home page#3
saikumarbt merged 1 commit into
mainfrom
home-page-implementation

Conversation

@saikumarbt

Copy link
Copy Markdown
Owner

No description provided.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Summary by CodeRabbit

  • New Features

    • Redesigned home screen to display all subscriptions and upcoming renewals
    • Added expandable subscription cards to view detailed payment and renewal information
    • Displays user balance and next renewal date on the home screen
  • Chores

    • Added date utility library for improved date formatting

Walkthrough

The PR replaces the placeholder home tab screen with a subscriptions dashboard. It introduces global type interfaces, a lib/utils.ts formatting library (with dayjs), static fixture data in constants/data.ts, a centralized image constants file, and three new components (ListHeading, SubscriptionCard, UpcomingSubscriptionCard) that the rewritten home screen renders.

Changes

Subscriptions Home Screen

Layer / File(s) Summary
Global type contracts
type.d.ts
Adds AppTab, Subscription, SubscriptionCardProps, UpcomingSubscription, UpcomingSubscriptionCardProps, and ListHeadingProps as global interfaces alongside the existing TabIconProps.
Formatting utilities and dayjs dependency
lib/utils.ts, package.json
Adds formatCurrency (with Intl.NumberFormat and symbol fallback), formatSubscriptionDateTime (dayjs MM/DD/YYYY with null-guard), and formatStatusLabel (first-char capitalizer). Adds dayjs ^1.11.21 runtime dependency.
Fixture data and image constants
constants/data.ts, constants/images.ts
Exports avatar and splashPattern image assets centrally. Adds HOME_USER, HOME_BALANCE, UPCOMING_SUBSCRIPTIONS, and HOME_SUBSCRIPTIONS fixture arrays.
ListHeading, SubscriptionCard, UpcomingSubscriptionCard
components/ListHeading.tsx, components/SubscriptionCard.tsx, components/UpcomingSubscriptionCard.tsx
ListHeading renders a section title with a "View All" touchable. SubscriptionCard is a collapsible Pressable showing formatted price, dates, and status. UpcomingSubscriptionCard is a compact card with a days-left/last-day label and formatted price.
Home tab screen rewrite
app/(tabs)/index.tsx
Removes expo-router navigation links. Adds expandedSubscriptionId state. Renders a header with avatar and formatted balance, a horizontal FlatList of UpcomingSubscriptionCard items (with empty state), and a vertical FlatList of SubscriptionCard items with toggle-expand behavior wired via extraData.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant HomeScreen as app/(tabs)/index.tsx
    participant SubscriptionCard
    participant Utils as lib/utils.ts

    User->>HomeScreen: View home tab
    HomeScreen->>Utils: formatCurrency(HOME_BALANCE.amount)
    Utils-->>HomeScreen: formatted balance string
    HomeScreen->>HomeScreen: render horizontal FlatList(UPCOMING_SUBSCRIPTIONS)
    HomeScreen->>HomeScreen: render vertical FlatList(HOME_SUBSCRIPTIONS)
    User->>SubscriptionCard: tap card
    SubscriptionCard->>HomeScreen: onPress(item.id)
    HomeScreen->>HomeScreen: setExpandedSubscriptionId(toggle id)
    HomeScreen->>SubscriptionCard: re-render with expanded=true
    SubscriptionCard->>Utils: formatSubscriptionDateTime(startDate/renewalDate)
    SubscriptionCard->>Utils: formatStatusLabel(status)
    Utils-->>SubscriptionCard: formatted strings
    SubscriptionCard-->>User: display expanded details
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hop hop, the tabs have changed today,
No more links that led astray!
Cards expand with a single press,
Currencies formatted — nothing less.
Balance shown, renewals near,
The subscriptions dashboard is finally here! 🌟

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive No pull request description was provided by the author, making it impossible to assess whether a description is related to the changeset. Add a pull request description explaining the changes, their purpose, and any relevant context for reviewers.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'implement the home page' directly describes the main objective of the changeset, which transforms the index screen into a subscriptions home view with new components and data.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 home-page-implementation

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/`(tabs)/index.tsx:
- Around line 56-57: The ListHeading component for both the "Upcoming" section
and the other section (around line 72) has a visible "View All" CTA but no
navigation handler is connected to it. Add an onPress or onViewAllPress prop to
each ListHeading component that navigates to the appropriate detail screen
showing all items for that section, ensuring the tap affordance now has a
functional outcome that displays the full list of upcoming or relevant items.
- Around line 29-74: The ListHeaderComponent is defined inline as an arrow
function, which causes the entire header subtree (including the horizontal
FlatList for upcoming subscriptions) to remount unnecessarily whenever the
parent component re-renders, especially when expandedSubscriptionId changes.
Extract the ListHeaderComponent into a separate memoized component (either as a
standalone function component wrapped with React.memo or extracted to a separate
variable wrapped with useMemo) and reference it in the FlatList props instead of
defining it inline. This will preserve the header state and prevent unnecessary
remounts of child components.

In `@components/ListHeading.tsx`:
- Around line 7-9: The TouchableOpacity component with className "list-action"
is rendered as an interactive element but lacks an onPress handler, making the
"View All" button non-functional. Add an onPress prop to the TouchableOpacity
component that defines what action should occur when the user taps the button,
such as navigating to a full list view or expanding content. Ensure the handler
is properly defined and passed to make this CTA interactive and functional in
the dashboard flow.

In `@components/SubscriptionCard.tsx`:
- Line 109: The ternary operator on line 109 in the SubscriptionCard component
is preventing the formatStatusLabel function from handling undefined status
values with its built-in "Unknown" fallback. Remove the conditional ternary
operator and instead call formatStatusLabel directly with the status parameter,
allowing the function to handle missing or falsy values appropriately without
rendering an empty string.

In `@constants/data.ts`:
- Around line 29-32: The HOME_BALANCE constant in constants/data.ts has a
nextRenewalDate property set to March 18, 2026, which is in the past relative to
the current reference date of June 23, 2026. Update the nextRenewalDate value in
the HOME_BALANCE object to a date that is after June 23, 2026 to ensure the
"next renewal" label displays correctly in the home header.
- Around line 25-27: The HOME_USER constant in the file has a typo in the name
property where "Recurrly" should be corrected to "Recurly" (with a single 'r').
Locate the HOME_USER object and update the name property value to use the
correct spelling of Recurly.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 97027c3a-b62a-4307-a759-f1536d2e6acd

📥 Commits

Reviewing files that changed from the base of the PR and between 9c6c65c and f4ed0b4.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • app/(tabs)/index.tsx
  • components/ListHeading.tsx
  • components/SubscriptionCard.tsx
  • components/UpcomingSubscriptionCard.tsx
  • constants/data.ts
  • constants/images.ts
  • lib/utils.ts
  • package.json
  • type.d.ts

Comment thread app/(tabs)/index.tsx
Comment on lines +29 to +74
ListHeaderComponent={() => (
<>
<View className="home-header">
<View className="home-user">
<Image
source={images.avatar}
resizeMode="contain"
className="home-avatar"
/>
<Text className="home-user-name">{HOME_USER.name}</Text>
</View>
<Image source={icons.add} className="home-add-icon" />
</View>

<View className="home-balance-card">
<Text className="home-balance-label">Balance</Text>
<View className="home-balance-row">
<Text className="home-balance-amount">
{formatCurrency(HOME_BALANCE.amount)}
</Text>
<Text className="home-balance-date">
{dayjs(HOME_BALANCE.nextRenewalDate).format("MM/DD")}
</Text>
</View>
</View>

<View className="mb-5">
<ListHeading title="Upcoming" />
<FlatList
horizontal
showsHorizontalScrollIndicator={false}
data={UPCOMING_SUBSCRIPTIONS}
renderItem={({ item }) => (
<UpcomingSubscriptionCard {...item} />
)}
keyExtractor={(item) => item.id}
ListEmptyComponent={
<Text className="home-empty-state">
No upcoming renewals yet.
</Text>
}
/>
</View>
<ListHeading title="All Subscriptions" />
</>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Stabilize ListHeaderComponent to avoid unnecessary header subtree remounts.

Because the header is created inline, toggling expandedSubscriptionId recreates the entire header subtree (including the horizontal list). Extract/memoize the header component to preserve state and reduce render churn.

♻️ Suggested refactor
-import { useState } from "react";
+import { useMemo, useState } from "react";
@@
 export default function App() {
   const [expandedSubscriptionId, setExpandedSubscriptionId] = useState<
     string | null
   >(null);
+
+  const listHeader = useMemo(
+    () => (
+      <>
+        <View className="home-header">
+          <View className="home-user">
+            <Image source={images.avatar} resizeMode="contain" className="home-avatar" />
+            <Text className="home-user-name">{HOME_USER.name}</Text>
+          </View>
+          <Image source={icons.add} className="home-add-icon" />
+        </View>
+
+        <View className="home-balance-card">
+          <Text className="home-balance-label">Balance</Text>
+          <View className="home-balance-row">
+            <Text className="home-balance-amount">
+              {formatCurrency(HOME_BALANCE.amount)}
+            </Text>
+            <Text className="home-balance-date">
+              {dayjs(HOME_BALANCE.nextRenewalDate).format("MM/DD")}
+            </Text>
+          </View>
+        </View>
+
+        <View className="mb-5">
+          <ListHeading title="Upcoming" />
+          <FlatList
+            horizontal
+            showsHorizontalScrollIndicator={false}
+            data={UPCOMING_SUBSCRIPTIONS}
+            renderItem={({ item }) => <UpcomingSubscriptionCard {...item} />}
+            keyExtractor={(item) => item.id}
+            ListEmptyComponent={
+              <Text className="home-empty-state">No upcoming renewals yet.</Text>
+            }
+          />
+        </View>
+        <ListHeading title="All Subscriptions" />
+      </>
+    ),
+    [],
+  );
@@
-      <FlatList
-        ListHeaderComponent={() => (
-          <>
-            ...
-          </>
-        )}
+      <FlatList
+        ListHeaderComponent={listHeader}
         data={HOME_SUBSCRIPTIONS}

Also applies to: 88-88

🧰 Tools
🪛 React Doctor (0.5.8)

[warning] 30-30: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 31-31: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 32-32: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 33-33: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 38-38: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 40-40: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 43-43: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 44-44: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 45-45: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 46-46: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 49-49: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 55-55: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 56-56: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 57-57: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 62-62: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 66-66: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 72-72: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/`(tabs)/index.tsx around lines 29 - 74, The ListHeaderComponent is
defined inline as an arrow function, which causes the entire header subtree
(including the horizontal FlatList for upcoming subscriptions) to remount
unnecessarily whenever the parent component re-renders, especially when
expandedSubscriptionId changes. Extract the ListHeaderComponent into a separate
memoized component (either as a standalone function component wrapped with
React.memo or extracted to a separate variable wrapped with useMemo) and
reference it in the FlatList props instead of defining it inline. This will
preserve the header state and prevent unnecessary remounts of child components.

Comment thread app/(tabs)/index.tsx
Comment on lines +56 to +57
<ListHeading title="Upcoming" />
<FlatList

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

“View All” is a dead action in this screen flow.

This screen renders ListHeading with a visible CTA, but no actionable path is wired for either section, so users get a tap affordance with no outcome.

Also applies to: 72-72

🧰 Tools
🪛 React Doctor (0.5.8)

[warning] 56-56: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 57-57: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/`(tabs)/index.tsx around lines 56 - 57, The ListHeading component for
both the "Upcoming" section and the other section (around line 72) has a visible
"View All" CTA but no navigation handler is connected to it. Add an onPress or
onViewAllPress prop to each ListHeading component that navigates to the
appropriate detail screen showing all items for that section, ensuring the tap
affordance now has a functional outcome that displays the full list of upcoming
or relevant items.

Comment on lines +7 to +9
<TouchableOpacity className="list-action">
<Text className="list-action-text">View All</Text>
</TouchableOpacity>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Dead CTA on Line 7 (“View All” is pressable but has no action).

TouchableOpacity is rendered as an interactive affordance, but no onPress is provided. This creates a non-functional action in the primary dashboard flow.

Proposed fix
-const ListHeading = ({ title }: ListHeadingProps) => {
+const ListHeading = ({ title, onViewAllPress }: ListHeadingProps) => {
   return (
     <View className="list-head">
       <Text className="list-title">{title}</Text>
-      <TouchableOpacity className="list-action">
+      <TouchableOpacity
+        className="list-action"
+        onPress={onViewAllPress}
+        disabled={!onViewAllPress}
+        accessibilityRole="button"
+        accessibilityState={{ disabled: !onViewAllPress }}
+      >
         <Text className="list-action-text">View All</Text>
       </TouchableOpacity>
     </View>
   );
 };
 interface ListHeadingProps {
   title: string;
+  onViewAllPress?: () => void;
 }
🧰 Tools
🪛 React Doctor (0.5.8)

[warning] 7-7: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)


[warning] 8-8: This JSX crashes because React isn't in scope.

If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.

(react-in-jsx-scope)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/ListHeading.tsx` around lines 7 - 9, The TouchableOpacity
component with className "list-action" is rendered as an interactive element but
lacks an onPress handler, making the "View All" button non-functional. Add an
onPress prop to the TouchableOpacity component that defines what action should
occur when the user taps the button, such as navigating to a full list view or
expanding content. Ensure the handler is properly defined and passed to make
this CTA interactive and functional in the dashboard flow.

numberOfLines={1}
ellipsizeMode="tail"
>
{status ? formatStatusLabel(status) : ""}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Line 109 bypasses the “Unknown” fallback from formatStatusLabel.

Current logic renders an empty string when status is missing, even though formatStatusLabel already handles undefined safely.

Proposed fix
-                  {status ? formatStatusLabel(status) : ""}
+                  {formatStatusLabel(status)}
📝 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
{status ? formatStatusLabel(status) : ""}
{formatStatusLabel(status)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/SubscriptionCard.tsx` at line 109, The ternary operator on line
109 in the SubscriptionCard component is preventing the formatStatusLabel
function from handling undefined status values with its built-in "Unknown"
fallback. Remove the conditional ternary operator and instead call
formatStatusLabel directly with the status parameter, allowing the function to
handle missing or falsy values appropriately without rendering an empty string.

Comment thread constants/data.ts
Comment on lines +25 to +27
export const HOME_USER = {
name: "S.ai | Recurrly",
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix user-facing typo in display name.

"S.ai | Recurrly" looks like a typo (“Recurly”), and this string is rendered in the home header.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@constants/data.ts` around lines 25 - 27, The HOME_USER constant in the file
has a typo in the name property where "Recurrly" should be corrected to
"Recurly" (with a single 'r'). Locate the HOME_USER object and update the name
property value to use the correct spelling of Recurly.

Comment thread constants/data.ts
Comment on lines +29 to +32
export const HOME_BALANCE = {
amount: 2489.48,
nextRenewalDate: "2026-03-18T09:00:00.000Z",
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update fixture nextRenewalDate to a future date.

HOME_BALANCE.nextRenewalDate is set to March 18, 2026, which is already in the past relative to June 23, 2026. This makes the “next renewal” label incorrect in the home header.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@constants/data.ts` around lines 29 - 32, The HOME_BALANCE constant in
constants/data.ts has a nextRenewalDate property set to March 18, 2026, which is
in the past relative to the current reference date of June 23, 2026. Update the
nextRenewalDate value in the HOME_BALANCE object to a date that is after June
23, 2026 to ensure the "next renewal" label displays correctly in the home
header.

@saikumarbt
saikumarbt merged commit 9f154ad into main Jun 23, 2026
1 check passed
@coderabbitai coderabbitai Bot mentioned this pull request Jun 29, 2026
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