Skip to content

feat: implement Suspense-based loading states across application pages - #54

Merged
rushikesh-bobade merged 4 commits into
rushikesh-bobade:mainfrom
Abhinav1190P:main
Aug 27, 2026
Merged

feat: implement Suspense-based loading states across application pages#54
rushikesh-bobade merged 4 commits into
rushikesh-bobade:mainfrom
Abhinav1190P:main

Conversation

@Abhinav1190P

@Abhinav1190P Abhinav1190P commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Description

Implemented deferred data loading using Suspense and Await for the Dashboard, Inventory Management, and Sales Log pages. Added page-specific skeleton loaders to display placeholder content while data is being fetched, improving the overall loading experience and perceived performance.

Related Issues

Fixes #35

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings

Screenshots (if applicable)

N/A

@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the participationcorner2025-8967's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codesense Ai: This PR is too large to review automatically. A human maintainer will take a look!

@github-actions github-actions Bot added the ECSoC26 Required label for ECSOC Sentinel scoring label Jul 1, 2026
@rushikesh-bobade

Copy link
Copy Markdown
Owner

Hey @Abhinav1190P! Excellent work here. Using Suspense and Await to defer the data loading is exactly what we needed to improve the perceived performance, and the skeletons look great!

I just finished reviewing the code and everything looks perfect. However, we just merged PR #55 (HTTP Edge Caching) which added a headers export to the same files you modified, causing a minor merge conflict.

Could you please git fetch and git rebase origin/main to resolve the conflicts? You just need to keep both your new Suspense logic AND the new export const headers block.

Once you push the resolved branch, I will merge this immediately!

@rushikesh-bobade rushikesh-bobade changed the title Implement Suspense-based loading states across application pages feat: implement Suspense-based loading states across application pages Jul 2, 2026
@rushikesh-bobade

Copy link
Copy Markdown
Owner

Hey @Abhinav1190P, thanks for the PR! We recently made some massive changes to the main branch to generalize the database schema and UI components. As a result, this PR now has merge conflicts. Could you please fetch the latest main branch, rebase your changes (or merge main into your branch), and resolve the conflicts? Let me know once that's done!

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

📝 Summary

The provided pull request introduces new skeleton components for the dashboard, inventory management, and sales log pages. These components are designed to display a loading state while data is being fetched. The changes also update the respective route files to utilize these new skeleton components.

📂 Files Changed

  • app/blocks/dashboard/dashboard-skeleton.tsx: New file, introduces a skeleton component for the dashboard page.
  • app/blocks/inventory-management/inventory-table-skeleton.tsx: New file, introduces a skeleton component for the inventory table.
  • app/blocks/sales-log/sales-log-skeleton.tsx: New file, introduces a skeleton component for the sales log table.
  • app/routes/dashboard.tsx: Updated to use the new DashboardSkeleton component.
  • app/routes/inventory-management.tsx: Updated to use the new InventoryTableSkeleton component.
  • app/routes/sales-log.tsx: Updated to use the new SalesTableSkeleton component.

🎭 Code Poem

Skeletons born, to load with care,
Data fetching, while users wait there,
Dashboard, inventory, sales log too,
Loading states, for a better view.

🚨 Bugs & Architectural Violations * The code seems to follow the architectural rules, using Remix and Prisma as required. * The use of Vanilla CSS Modules is consistent throughout the changes. * All UI components are placed in the correct `app/blocks/` directory. * No Tailwind CSS classes are used, adhering to the rules. * However, it's worth noting that the `Skeleton` component is used extensively, and its implementation should be reviewed to ensure it follows the performance guidelines. * The `dashboard-skeleton.tsx` file uses inline styles, which might not be the best practice. Consider moving these styles to a separate CSS module file. * The `inventory-table-skeleton.tsx` and `sales-log-skeleton.tsx` files use CSS modules correctly. * No accessibility issues are immediately apparent, but a thorough review of the components' accessibility features, such as `aria-hidden` and `roles`, is recommended.
💡 Suggestions & Best Practices * Consider adding a `defer` function to the `Skeleton` component to improve performance. * Review the `Skeleton` component's implementation to ensure it uses `transform` or `opacity` for CSS animations, rather than triggering main-thread repaints. * Add accessibility features, such as `aria-hidden` and `roles`, to the skeleton components to improve their accessibility. * Consider using a more robust loading state management system, rather than relying on a simple `Skeleton` component. * Review the code for any potential performance bottlenecks, such as unnecessary re-renders or slow data fetching. * Consider adding error handling and edge cases to the skeleton components to ensure they behave correctly in unexpected situations.

@Abhinav1190P

Copy link
Copy Markdown
Contributor Author

Yeah i can add skeleton back later, since it is low priority

@rushikesh-bobade

Copy link
Copy Markdown
Owner

Hey @Abhinav1190P!

Thanks for pushing that merge! It looks like during the merge conflict resolution, the original code from main accidentally overwrote your new <Suspense> logic, which reverted the pages back to being synchronous and caused the TypeScript build to fail.

Don't worry, merge conflicts can be tricky! To fix this, you just need to wrap your Promise.all in the loaders and defer them, then use your skeletons as the fallback in the UI.

Here is exactly how you can update app/routes/dashboard.tsx to fix the build and restore the skeletons:

1. In the loader:

  const dashboardPromise = Promise.all([
    // ... your prisma queries ...
  ]).then(([inventoryStats, salesData, expensesData]) => {
     // ... your formatting logic ...
    return { inventoryStats: serializedStats, salesData: serializedSales, expensesData: serializedExpenses };
  });

  return { dashboardData: dashboardPromise };

2. In the DashboardPage component:

import { DashboardSkeleton } from "~/blocks/dashboard/dashboard-skeleton";

export default function DashboardPage() {
  const { dashboardData } = useLoaderData<typeof loader>();

  return (
    <div className={styles.page}>
      <DashboardHeader />
      <AIInsightsPanel />
      <Suspense fallback={<DashboardSkeleton />}>
        <Await resolve={dashboardData}>
          {({ inventoryStats, salesData, expensesData }) => (
            <>
              {/* ... render the charts and tables using the destructured data here ... */}
            </>
          )}
        </Await>
      </Suspense>
    </div>
  );
}

You'll just need to apply this same pattern to inventory-management.tsx and sales-log.tsx as well. Give that a shot and let me know if you run into any issues—I'm happy to help you get this across the finish line!

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions!

@rushikesh-bobade

Copy link
Copy Markdown
Owner

Hey @Abhinav1190P, thanks for continuing the great work from Part 1! The skeleton components themselves are well-built and reuse your Skeleton component perfectly. However, the Suspense/Await wiring — which is the core purpose of this PR — is incomplete. The skeletons were created but never actually connected to the UI. Here is the full breakdown:

✅ What's Great

  • Skeleton components are clean, well-structured, and correctly placed in app/blocks/:
    • DashboardSkeleton — mirrors the real dashboard layout (4 stat cards, chart, 3-column grid, tables)
    • InventoryTableSkeleton — real table headers with shimmer rows, reuses inventory-table.module.css styles
    • SalesTableSkeleton — same pattern for sales
  • All three properly import from ~/blocks/__global/skeleton (your Part 1 component)
  • Correctly scoped PR — only 6 files changed, all directly related

🔴 Critical Issues — Must Fix Before Merge

1. <Suspense> / <Await> is Never Used in the JSX (All 3 Routes)

This is the biggest issue. You imported Suspense and Await into all three route files, but you never actually wrapped any components with them. The skeletons are never rendered anywhere.

For example, in dashboard.tsx:

  • You changed the loader to return { dashboardData: Promise.resolve(...) }
  • You destructured const { dashboardData } = useLoaderData()
  • But then the component still directly references inventoryStats, salesData, and expensesData — which no longer exist! This will crash at runtime with ReferenceError: inventoryStats is not defined.

The JSX needs to be wrapped like this:

<Suspense fallback={<DashboardSkeleton />}>
  <Await resolve={dashboardData}>
    {({ inventoryStats, salesData, expensesData }) => (
      <>
        <StatsCardsRow stats={inventoryStats} sales={salesData} expenses={expensesData} />
        {/* ... rest of the dashboard ... */}
      </>
    )}
  </Await>
</Suspense>

The same problem exists in inventory-management.tsx and sales-log.tsx — you imported the skeletons but never used <Suspense fallback={<InventoryTableSkeleton />}> anywhere.

2. Dashboard Loader Still Awaits Everything Synchronously

Even though you wrapped the return in Promise.resolve(), the loader still has await Promise.all([...]) on line 107, which means all three database queries finish before the response is sent. The data arrives fully resolved, so <Suspense> will never show the fallback.

To actually get streaming, you need to return the un-awaited promise:

const dashboardData = Promise.all([inventoryQuery, salesQuery, expenseQuery])
  .then(([inventoryStats, salesData, expensesData]) => ({
    inventoryStats: serialize(inventoryStats),
    salesData: serialize(salesData),
    expensesData: serialize(expensesData),
  }));

return { dashboardData }; // Don't await it!

3. Stray Character in sales-log-skeleton.tsx Line 8

<table className={styles.table}>ß   // <-- stray "ß" character

This ß (German eszett) will render as visible text inside the table. Delete it.

🟡 Minor

4. Inline styles in DashboardSkeleton: The grid layouts use inline style={{}} instead of CSS Modules. This works, but for consistency with the rest of the codebase, consider creating a dashboard-skeleton.module.css file.

5. Missing newlines at EOF: dashboard.tsx, inventory-management.tsx, and sales-log.tsx all lost their trailing newline. Minor, but our linter may flag it.

6. Unrelated formatting change in inventory-management.tsx: The create action's data object was reformatted from multi-line to single-line (sku, name, brand, size, purchasePrice). Please revert this to keep the diff focused.

Summary

Area Verdict
Skeleton components ✅ Excellent
<Suspense> / <Await> wiring 🔴 Not implemented
Loader streaming (defer) 🔴 Not implemented
Stray character in sales skeleton 🔴 Must fix
Inline styles 🟡 Should use CSS Modules
Unrelated formatting 🟡 Please revert

The skeleton components are beautifully designed, but the core deliverable of this PR — making the pages stream data with <Suspense> fallbacks — hasn't been wired up yet. Once you connect the skeletons to the actual render paths, rebase on main, and fix the stray ß, this will be an incredible feature. Let me know if you need any help with the <Await> pattern!

@github-actions github-actions Bot removed the stale label Aug 10, 2026
@rushikesh-bobade
rushikesh-bobade merged commit 6990418 into rushikesh-bobade:main Aug 27, 2026
1 of 2 checks passed
@github-actions

Copy link
Copy Markdown

🎉 Congratulations @Abhinav1190P! 🎉

Your Pull Request has been successfully merged! Thank you so much for your hard work and contribution to FlipTrack. We really appreciate it! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ECSoC26-L2 ECSoC26 Required label for ECSOC Sentinel scoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Loading Skeletons for All Data Pages

2 participants