Skip to content

fix(web): add loading and empty states across app#338

Merged
onerandomdevv merged 3 commits into
devfrom
fix/web-loading-states
May 26, 2026
Merged

fix(web): add loading and empty states across app#338
onerandomdevv merged 3 commits into
devfrom
fix/web-loading-states

Conversation

@onerandomdevv
Copy link
Copy Markdown
Collaborator

@onerandomdevv onerandomdevv commented May 26, 2026

What does this PR do?

This PR adds reusable loading, empty, error, retry, skeleton, and processing states across priority Twizrr web routes. It improves perceived performance and user clarity during API requests, form submissions, route loading, empty data states, and failed fetches without changing backend behavior.

Type of change

  • New feature
  • Bug fix
  • Refactor / cleanup
  • Database migration included
  • Chore / maintenance
  • Documentation

Area affected

  • Backend
  • Web
  • WhatsApp
  • Shared package
  • Database / Prisma
  • GitHub / CI / infrastructure

How to test this

  1. Checkout the branch and run web checks:

    git checkout fix/web-loading-states
    cd apps/web
    pnpm run lint
    npx tsc --noEmit
    pnpm run build```
    
  2. Start the web app
    pnpm run dev

  3. Smoke-test priority routes:
    /login
    /register
    /stores
    /explore
    /store/source
    /store/setup
    /admin/users
    /admin/stores
    /admin/disputes
    /admin/moderation

Expected result: pages render without crashes, loading/skeleton states appear while data is loading, forms show clear processing labels, empty/error states are polished, and retry states appear when API requests fail.

Pre-commit checklist

  • Backend lint/type/build pass when backend is affected
  • Web lint/type/build pass when web is affected
  • Shared package build passes when shared is affected
  • No console.log left in production code
  • No secrets or .env files committed
  • No new any types added
  • No non-MVP legacy features reintroduced
  • All money values are BigInt kobo, never float
  • Paystack webhook changes verify HMAC before processing
  • Database migrations are Prisma migrations, not db push
  • Database migrations are backward-compatible or risk is documented

Screenshots

Notes for reviewer

Pages/routes improved:

/stores
Added loading route
Added reusable empty/error/retry states
/explore
Added loading route
Added feed retry state
/store/source
Added reusable empty/error/retry states
Admin pages:
/admin/users
/admin/stores
/admin/disputes
/admin/moderation
Added processing button labels for admin actions
Auth forms:
Improved submission labels such as Signing in...
Store/product flows:
Store setup has clearer creating/submitting labels
Product publish/save draft has clearer processing labels

Audit findings:

Many shopper/store order/profile/cart/settings pages already had skeletons and form loading.
Missing or inconsistent states were found in:
/stores
route-level loading for /explore
shared empty/error/retry UI
admin action processing labels
auth form loading copy
source-products empty/error retry polish
product publish button processing labels

Branded loading follow-up

Additional commit:

  • 72c68d9

Added official Twizrr mark-based loading components using:

  • apps/web/public/logo/mark.svg
  • public path: /logo/mark.svg

New loading system:

  • apps/web/src/components/ui/brand-loader.tsx

Exports:

  • BrandLoader
  • PageLoadingState
  • SectionLoadingState
  • ButtonLoadingContent
  • InlineSpinner
  • CardSkeleton
  • TableSkeleton
  • StoreCardSkeleton
  • ProductCardSkeleton
  • FeedSkeleton

Usage updates:

  • Button loading now uses a tiny Twizrr mark instead of a generic spinner
  • Admin auth probe uses branded loading
  • Auth suspense fallbacks use branded loading
  • /stores loading states use branded/skeleton states
  • /explore loading states use branded/skeleton states
  • /stores/[handle] loading states use branded/skeleton states
  • Source-products catalogue loading states use branded/skeleton states

Validation after branded loader follow-up:

  • cd apps/web && pnpm run lint passed
  • cd apps/web && npx tsc --noEmit passed
  • cd apps/web && pnpm run build passed
  • cd apps/web && pnpm run dev booted successfully
  • Browser smoke passed for:
    • /
    • /login
    • /register
    • /stores
    • /explore
    • /stores/test-handle
    • /store/setup
    • /admin/dashboard

Runtime note:

  • Restarting next dev after next build briefly served stale .next chunks locally.
  • This was local cache behavior only; source checks and production build are clean.

Summary by CodeRabbit

  • New Features

    • Added loading skeleton screens for explore, store, and stores pages.
    • Introduced consistent empty and error state messaging across the app.
  • Improvements

    • Admin action buttons now display "Processing..." while operations are in progress.
    • Form submission buttons show contextual loading messages (e.g., "Signing in...", "Verifying...", "Creating account...").
    • Enhanced loading states and better visual feedback throughout authentication and admin workflows.

Review Change Stack

@codesandbox
Copy link
Copy Markdown

codesandbox Bot commented May 26, 2026

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

📝 Walkthrough

Walkthrough

This PR introduces a unified loading and skeleton component library for consistent UI feedback during async operations, then applies it across auth, admin, public, and catalog pages. The new brand-loader.tsx and State.tsx modules provide reusable primitives, while Button is enhanced to accept custom loading text.

Changes

Loading & State Component Migration

Layer / File(s) Summary
Brand loader and skeleton component library
src/components/ui/brand-loader.tsx
Core library exports BrandLoader with size variants, PageLoadingState, ButtonLoadingContent, InlineSpinner, and skeleton templates (CardSkeleton, StoreCardSkeleton, ProductCardSkeleton, FeedSkeleton, TableSkeleton).
Empty and error state components
src/components/ui/State.tsx
Introduces StateShell layout pattern, EmptyState with optional action, and ErrorState with conditional retry button/link; re-exports skeleton/spinner primitives.
Button loading text support
src/components/ui/Button.tsx
Adds loadingText?: string prop, replaces inline Loader2 with ButtonLoadingContent, preserves existing disabled/icon/children rendering rules.
Auth pages with loading text and states
src/app/(auth)/login/page.tsx, src/app/(auth)/register/page.tsx, src/app/(auth)/verify-email/page.tsx, src/app/(auth)/forgot-password/page.tsx
Login/register/verify-email/forgot-password pages now include loadingText on submit buttons and use PageLoadingState for Suspense fallbacks.
Admin pages with button loading feedback
src/app/(admin)/admin/_components/AdminShell.tsx, src/app/(admin)/admin/disputes/page.tsx, src/app/(admin)/admin/moderation/page.tsx, src/app/(admin)/admin/stores/page.tsx, src/app/(admin)/admin/users/page.tsx
Admin pages display conditional "Processing..." text on action buttons while busy; AdminShell uses PageLoadingState for initial auth verification loading.
Store and product creation pages with loading text
src/app/(store)/store/setup/StoreSetupClient.tsx, src/app/(store)/store/products/new/_components/ScreenFourSizeGuidePublish.tsx
Store setup and product publish buttons show custom loading text during form submission.
Public page loading skeletons
src/app/(public)/explore/loading.tsx, src/app/(public)/stores/loading.tsx, src/app/(public)/stores/[handle]/loading.tsx
New loading states for explore, stores list, and store detail pages render skeleton placeholders via FeedSkeleton, StoreCardSkeleton, and ProductCardSkeleton.
Stores page state UI refactor
src/app/(public)/stores/page.tsx
Replaces local StoresState helper with shared EmptyState and ErrorState components for consistent empty/error messaging and retry behavior.
Source products catalog UI with shared states and skeletons
src/app/(store)/store/source/SourceProductsClient.tsx
Updates to use EmptyState, ErrorState, and ProductCardSkeleton; simplifies skeleton rendering and wires onRetry handlers for store/catalogue error recovery.
Feed component error and loading states
src/components/feed/FeedClient.tsx
Replaces custom error/loading-more UI with ErrorState and InlineSpinner; introduces reloadKey state to trigger feed refetch on retry.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • coded-devs/twizrr#334: Follow-up refactor that swaps stores page's local empty/error UI (StoresState) for shared EmptyState/ErrorState components introduced here.
  • coded-devs/twizrr#294: Direct updates to auth pages (login, register, verify-email, forgot-password) for loadingText and PageLoadingState support.
  • coded-devs/twizrr#311: Builds on Source Products catalogue UI with shared EmptyState/ErrorState, skeleton rendering, and onRetry flow wiring.

Poem

🐰 A loader hops into the frame,
Skeletons dance in the loading game,
States aligned, both empty and true,
Processing... processing... shimmering through!
Buttons glow with consistent delight,
The UI's now unified and right.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: adding loading and empty states across the application's web interface.
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.
Description check ✅ Passed Pull request description covers all required template sections including what the PR does, type of change, affected areas, testing procedures, checklist verification, and detailed reviewer notes.

✏️ 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 fix/web-loading-states

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.

Copy link
Copy Markdown
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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/components/ui/brand-loader.tsx`:
- Around line 116-123: The InlineSpinner component currently renders BrandLoader
and an animated spinner which violates the guideline to use skeletons for
data-fetch loading; replace InlineSpinner's implementation so it outputs an
inline skeleton/text-skeleton pattern that matches the eventual content shape
instead of BrandLoader (e.g., a short gray rounded rectangle or animated shimmer
for the text width and optional small avatar/element), keep the component API
(exported name InlineSpinner and its label prop) or rename to InlineSkeleton if
preferred, and remove any direct BrandLoader usage so callers get a skeleton
primitive appropriate for data-fetch loading.
🪄 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: f28a3b5f-582b-4f3e-8332-1d75c5460c1a

📥 Commits

Reviewing files that changed from the base of the PR and between 7338fcc and 72c68d9.

📒 Files selected for processing (20)
  • apps/web/src/app/(admin)/admin/_components/AdminShell.tsx
  • apps/web/src/app/(admin)/admin/disputes/page.tsx
  • apps/web/src/app/(admin)/admin/moderation/page.tsx
  • apps/web/src/app/(admin)/admin/stores/page.tsx
  • apps/web/src/app/(admin)/admin/users/page.tsx
  • apps/web/src/app/(auth)/forgot-password/page.tsx
  • apps/web/src/app/(auth)/login/page.tsx
  • apps/web/src/app/(auth)/register/page.tsx
  • apps/web/src/app/(auth)/verify-email/page.tsx
  • apps/web/src/app/(public)/explore/loading.tsx
  • apps/web/src/app/(public)/stores/[handle]/loading.tsx
  • apps/web/src/app/(public)/stores/loading.tsx
  • apps/web/src/app/(public)/stores/page.tsx
  • apps/web/src/app/(store)/store/products/new/_components/ScreenFourSizeGuidePublish.tsx
  • apps/web/src/app/(store)/store/setup/StoreSetupClient.tsx
  • apps/web/src/app/(store)/store/source/SourceProductsClient.tsx
  • apps/web/src/components/feed/FeedClient.tsx
  • apps/web/src/components/ui/Button.tsx
  • apps/web/src/components/ui/State.tsx
  • apps/web/src/components/ui/brand-loader.tsx

Comment thread apps/web/src/components/ui/brand-loader.tsx
@onerandomdevv onerandomdevv merged commit 5b92d6b into dev May 26, 2026
8 checks passed
@onerandomdevv onerandomdevv deleted the fix/web-loading-states branch May 26, 2026 08:52
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