Skip to content

feat(web): add stores discovery page#334

Merged
onerandomdevv merged 1 commit into
devfrom
feat/web-stores-discovery
May 26, 2026
Merged

feat(web): add stores discovery page#334
onerandomdevv merged 1 commit into
devfrom
feat/web-stores-discovery

Conversation

@onerandomdevv
Copy link
Copy Markdown
Collaborator

@onerandomdevv onerandomdevv commented May 26, 2026

Summary by CodeRabbit

  • New Features
    • Added a new Stores page where users can browse available stores
    • Store cards display verification status, follower counts, order information, and descriptions with images
    • Includes empty and error state messaging for better user experience

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 adds a new public Stores discovery page to the Next.js app. It fetches up to 24 verified stores from an API endpoint, validates the payload with type guards, formats store metadata (initials, follower counts), renders individual store cards with banners/logos and fallback states, and provides empty/error UI when data is unavailable or malformed.

Changes

Stores Page Feature

Layer / File(s) Summary
Page setup and payload validation
apps/web/src/app/(public)/stores/page.tsx (1–84)
Page exports dynamic = "force-dynamic" and page metadata with title and description. Type guards validate PublicStoreSummary and StoreCardFeedItem payloads, and unwrapFeedResponse() filters and normalizes the API response to extract only valid STORE_CARD items.
Store data fetching and normalization
apps/web/src/app/(public)/stores/page.tsx (86–133)
fetchStores() reads NEXT_PUBLIC_API_URL, fetches the feed with cache: "no-store", validates and unwraps the JSON, and returns a state shape with status (loaded / empty / error), stores array, or error message for missing API, non-OK response, malformed payload, or fetch exceptions.
Store cards and page rendering
apps/web/src/app/(public)/stores/page.tsx (135–308)
Formatting helpers generate store initials and format follower/order counts using en-NG locale. StoreDiscoveryCard renders a store with banner/logo fallbacks, verification badge, stats, bio, and conditional link to /stores/${handle}. StoresState renders empty/error messaging. StoresPage calls fetchStores(), wraps output in AppShell, and conditionally renders the stores grid, empty state, or error state.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A stores page hops to life so bright,
With cards that dance and grid so tight,
Type guards stand watch, feeds unwrap clean,
Fallback states keep all serene,
Discovery awaits, a merchant's delight!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author. The template requires multiple sections including 'What does this PR do?', type of change, area affected, testing instructions, and a pre-commit checklist, all of which are missing. Fill out the pull request description template with: a summary of changes, the type of change (mark 'New feature' and 'Web'), testing steps, verification of the pre-commit checklist items, and any relevant notes for reviewers.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(web): add stores discovery page' clearly and concisely summarizes the main change: adding a new stores discovery page to the web application.
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 feat/web-stores-discovery

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

🧹 Nitpick comments (1)
apps/web/src/app/(public)/stores/page.tsx (1)

235-238: Confirm store profile URL handling (/stores/${handle} vs /@${handle})

apps/web/src/app/(public)/stores/page.tsx links to /stores/${handle}, while apps/web/src/components/feed/FeedCard.tsx links to /@${store.handle}—both work because apps/web/src/middleware.ts rewrites "/@handle""/stores/handle", and apps/web/src/app/(public)/stores/[handle]/page.tsx reads params.handle from /stores/[handle].

🤖 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 `@apps/web/src/app/`(public)/stores/page.tsx around lines 235 - 238,
Inconsistent store URL formats are used: one Link uses `/stores/${handle}`
(page.tsx) while FeedCard uses `/@${store.handle}`; pick a canonical URL (use
`/stores/${handle}` to match the stores/[handle]/page component) and update all
Link usages to that pattern (update FeedCard's Link href to
`/stores/${store.handle}` and any other occurrences). Also verify middleware
rewrite still maps `/@handle` → `/stores/handle` if you want backwards
compatibility and ensure the stores/[handle]/page component continues to read
params.handle correctly.
🤖 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/app/`(public)/stores/page.tsx:
- Around line 86-112: The fetchStores function currently uses raw fetch and
should use the shared api helper to centralize base URL, credentials and
envelope unwrapping: in fetchStores replace the fetch(...) call with
api.get<FeedResponse>("/feed/stores?limit=24") (or first extend the api client
to accept Next fetch options like cache: "no-store" if you need to preserve that
behavior), then consume response.data and pass it to unwrapFeedResponse instead
of awaiting response.json(); keep the same error-path checks but base them on
the api client's response and status.

---

Nitpick comments:
In `@apps/web/src/app/`(public)/stores/page.tsx:
- Around line 235-238: Inconsistent store URL formats are used: one Link uses
`/stores/${handle}` (page.tsx) while FeedCard uses `/@${store.handle}`; pick a
canonical URL (use `/stores/${handle}` to match the stores/[handle]/page
component) and update all Link usages to that pattern (update FeedCard's Link
href to `/stores/${store.handle}` and any other occurrences). Also verify
middleware rewrite still maps `/@handle` → `/stores/handle` if you want
backwards compatibility and ensure the stores/[handle]/page component continues
to read params.handle correctly.
🪄 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: a06a6fb9-ab75-4e28-9ab8-1b11dbc2113f

📥 Commits

Reviewing files that changed from the base of the PR and between 31ffb98 and 54807cd.

📒 Files selected for processing (1)
  • apps/web/src/app/(public)/stores/page.tsx

Comment on lines +86 to +112
async function fetchStores(): Promise<StoreLoadState> {
const apiBase = process.env.NEXT_PUBLIC_API_URL?.replace(/\/$/, "");

if (!apiBase) {
return {
status: "error",
message: "Store discovery is not configured for this environment.",
};
}

try {
const response = await fetch(`${apiBase}/feed/stores?limit=24`, {
cache: "no-store",
headers: {
Accept: "application/json",
},
});

if (!response.ok) {
return {
status: "error",
message: "Verified stores could not be loaded right now.",
};
}

const parsed = unwrapFeedResponse(await response.json());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that a shared Axios client with response unwrapping exists and is the expected frontend standard.
fd -i 'api*.ts' apps/web/src
rg -n -C3 'axios\.create|baseURL|withCredentials|interceptors\.response|success.*data' apps/web/src
rg -n -C3 '\bfetch\s*\(' apps/web/src/app/(public)/stores/page.tsx

Repository: coded-devs/twizrr

Length of output: 2105


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show shared API client implementation (if any)
echo "---- apps/web/src/lib/api.ts (head) ----"
wc -l apps/web/src/lib/api.ts
sed -n '1,220p' apps/web/src/lib/api.ts | cat -n

echo "---- apps/web/src/lib/api.ts (tail) ----"
sed -n '220,520p' apps/web/src/lib/api.ts | cat -n || true

# Inspect the stores discovery page around the reported lines
echo "---- apps/web/src/app/(public)/stores/page.tsx (region) ----"
wc -l "apps/web/src/app/(public)/stores/page.tsx"
sed -n '60,160p' "apps/web/src/app/(public)/stores/page.tsx" | cat -n

# Re-run a safe search for fetch usage in that page
echo "---- fetch usage in stores page ----"
rg -n '\bfetch\s*\(' "apps/web/src/app/(public)/stores/page.tsx" || true

# Check whether /stores/[handle] exists
echo "---- routes under apps/web/src/app/(public)/stores ----"
fd -e ts -e tsx "apps/web/src/app/(public)/stores" -a | sort || true
fd -e ts -e tsx "apps/web/src/app/(public)" | rg '/stores/' | head -n 50 || true

# Search for links that use /stores/${handle}
echo "---- link patterns for /stores/ ----"
rg -n '\/stores\/\$\{.*handle.*\}' apps/web/src | head -n 50 || true
rg -n '\/stores\/' apps/web/src/app/(public)/stores/page.tsx || true

Repository: coded-devs/twizrr

Length of output: 9632


Use the shared api client instead of raw fetch in fetchStores()

  • apps/web/src/app/(public)/stores/page.tsx calls fetch(...) directly, bypassing apps/web/src/lib/api.ts (api helper) that centralizes NEXT_PUBLIC_API_URL, credentials: "include", and { data } envelope unwrapping. Replace the direct call with api.get<FeedResponse>("/feed/stores?limit=24") (or extend the helper to accept Next fetch options like cache: "no-store" to preserve current semantics).
🤖 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 `@apps/web/src/app/`(public)/stores/page.tsx around lines 86 - 112, The
fetchStores function currently uses raw fetch and should use the shared api
helper to centralize base URL, credentials and envelope unwrapping: in
fetchStores replace the fetch(...) call with
api.get<FeedResponse>("/feed/stores?limit=24") (or first extend the api client
to accept Next fetch options like cache: "no-store" if you need to preserve that
behavior), then consume response.data and pass it to unwrapFeedResponse instead
of awaiting response.json(); keep the same error-path checks but base them on
the api client's response and status.

@onerandomdevv onerandomdevv merged commit 15ad5fe into dev May 26, 2026
8 checks passed
@onerandomdevv onerandomdevv deleted the feat/web-stores-discovery branch May 26, 2026 01:29
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