-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Refactor PostCard and PostFilters components for improved UI #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughReplaces Prisma-backed PostCard with data-driven PostData models and mock data; adds SinglePostCard and PostsGallery, introduces TagRenderer, and reduces PostFilters to a search-only input. PostsList now renders PostFilters and PostsGallery; previous sorting, filtering UI and per-post rendering/infinite-scroll are removed. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant PostsList
participant PostFilters
participant PostsGallery
participant SinglePostCard
Note over PostsList,PostsGallery: New gallery-driven render flow (mock/default data)
User->>PostsList: Open posts page
PostsList->>PostFilters: Render({ search, onSearchChange })
User->>PostFilters: Type search
PostFilters-->>PostsList: onSearchChange(query)
PostsList->>PostsGallery: Render({ posts = mockPostsData })
PostsGallery->>SinglePostCard: map(posts)
loop per post
SinglePostCard-->>User: Render card (title, desc, sentiment badge, bar, sources, tags)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/PostComponents/PostCard.tsx (1)
212-229
: Guard empty lists and remove implicit mock fallback.
posts[0]
can throw whenposts
is empty. Also, defaulting tomockPostsData
hides real data. Makeposts
required (or return an empty state) and use stable keys.-export default function PostCard({ - posts = mockPostsData, - showMultiple = true, -}: PostCardProps) { - if (showMultiple) { - return ( - <div className="flex flex-row justify-center gap-6 p-2"> - {posts.map((post, index) => ( - <SinglePostCard key={index} post={post} /> - ))} - </div> - ); - } - - // Show only the first card if showMultiple is false - return <SinglePostCard post={posts[0]} />; -} +export default function PostCard({ posts = [], showMultiple = true }: PostCardProps) { + if (!posts.length) { + return null; // or a skeleton/empty-state component + } + if (showMultiple) { + return ( + <div className="flex flex-row justify-center gap-6 p-2"> + {posts.map((post) => ( + <SinglePostCard key={(post as any).id ?? post.title} post={post} /> + ))} + </div> + ); + } + return <SinglePostCard post={posts[0]} />; +}
🧹 Nitpick comments (10)
src/components/PostComponents/PostCard.tsx (4)
9-14
: Data should be JSON-friendly: move icon/color out of the data model.Embedding
ReactNode
in data prevents server/transport usage. KeepSource
serializable (name, count), derive icon/color at render.If you want, I can provide a small helper like
renderSourcePill(name, count)
that maps to icon/color without mutating the data model.
124-126
: Tailwind class likely invalid: w-54.Tailwind’s default scale has w-52 and w-56;
w-54
won’t apply unless custom-configured. Use a valid token or arbitrary value.- <Card className="w-54 h-60 font-sans"> + <Card className="w-56 h-60 font-sans"> {/* or w-[216px] */}
168-185
:Source.color
is unused; either remove it or use it consistently.You’re hardcoding pill colors by name. If you keep
color
in the model, apply it in the className; otherwise drop it from the type and mock data.
219-221
: Prefer stable keys over array indices.Use
post.id
or another stable identifier to prevent reconciliation issues on reorders.See the diff on Lines 212-229 where the key uses
post.id ?? post.title
.src/components/PostComponents/PostsList.tsx (3)
2-9
: Remove unused imports (SentimentBar, Spinner) to avoid lint noise.-import SentimentBar from "./SentimentBar"; -import { SortField, SortOrder } from "./PostSortSelect"; -import Spinner from "./Spinner"; +import { SortField, SortOrder } from "./PostSortSelect";
25-28
: Debounce the search input to reduce unnecessary requests.The current handler fires per keystroke; consider a 250–400ms debounce.
I can add a small
useDebouncedValue
hook if you want it in this PR.
29-73
: Abort in-flight fetches on param changes to avoid race conditions.Success of a slower previous request can overwrite newer results. Use
AbortController
per call and passsignal
tofetch
.Happy to provide a minimal diff using
AbortController
and cleanup inuseEffect
.src/components/PostComponents/PostFilters.tsx (3)
1-1
: Remove unused Select imports.-import { Select, SelectItem } from "@/components/ui/select";
3-3
: Remove unused PostSortSelect and type imports.-import { PostSortSelect, SortField, SortOrder } from "./PostSortSelect";
15-22
: Add an accessible label to the search input.- <Input + <Input + aria-label="Search posts" value={search} onChange={onSearchChange} placeholder="Search posts..." className="w-full max-w-md shadow-md rounded-lg border border-gray-200 focus:border-blue-400 focus:ring-2 focus:ring-blue-100 transition" />
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/components/PostComponents/PostCard.tsx
(1 hunks)src/components/PostComponents/PostFilters.tsx
(1 hunks)src/components/PostComponents/PostsList.tsx
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/components/PostComponents/PostsList.tsx (2)
src/components/PostComponents/PostFilters.tsx (1)
PostFilters
(10-26)src/components/PostComponents/PostCard.tsx (1)
PostCard
(212-228)
src/components/PostComponents/PostCard.tsx (1)
src/components/ui/card.tsx (4)
Card
(91-91)CardHeader
(92-92)CardTitle
(94-94)CardDescription
(96-96)
🔇 Additional comments (1)
src/components/PostComponents/PostCard.tsx (1)
16-25
: Export PostData (and include optional id) to enable typed adapters from API.
[ suggest_recommended_refactor ]-type PostData = { +export type PostData = { + id?: string; title: string; description: string; sentiment: "Bullish" | "Bearish" | "Neutral"; sentimentBar: { bullish: number; neutral: number; bearish: number }; postCount: number; sources: Source[]; categories: string[]; extraTags?: string; };
<CardDescription className="text-[8px] text-gray-600 mb-2 line-clamp-2"> | ||
{post.description} | ||
</CardDescription> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify line-clamp plugin is enabled.
line-clamp-2
requires the Tailwind plugin; otherwise truncation won’t apply.
Run this to confirm:
🏁 Script executed:
#!/bin/bash
fd -a 'tailwind.config.*' | xargs -I{} rg -n 'line-clamp' {}
Length of output: 0
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Finding tailwind config files ==="
fd -a 'tailwind.config*' --hidden --exclude node_modules || true
echo
echo "=== Searching repo for line-clamp plugin references and class usage ==="
rg -n --hidden --no-ignore-vcs --glob '!**/node_modules/**' "require\(\s*['\"]@tailwindcss/line-clamp['\"]\s*\)" || true
rg -n --hidden --no-ignore-vcs --glob '!**/node_modules/**' "@tailwindcss/line-clamp" || true
rg -n --hidden --no-ignore-vcs --glob '!**/node_modules/**' "lineClamp" || true
rg -n --hidden --no-ignore-vcs --glob '!**/node_modules/**' "line-clamp" || true
echo
echo "=== Showing contents of any tailwind config files found (first 300 lines) ==="
for f in $(fd -a 'tailwind.config*' --hidden --exclude node_modules || true); do
echo "----- $f -----"
sed -n '1,300p' "$f" || true
echo
done
echo "=== Scanning package.json files for @tailwindcss/line-clamp and tailwindcss ==="
for p in $(fd -a 'package.json' --hidden --exclude node_modules || true); do
echo "----- $p -----"
jq -c '{dependencies, devDependencies}' "$p" 2>/dev/null || sed -n '1,240p' "$p"
echo
done
Length of output: 1690
Enable @tailwindcss/line-clamp or remove the utility.
No tailwind.config.* found and repo root package.json lists tailwindcss but not @tailwindcss/line-clamp; src/components/PostComponents/PostCard.tsx (lines 130–133) uses class "line-clamp-2" — install the plugin and add require('@tailwindcss/line-clamp') to tailwind.config.js plugins, or replace with a CSS fallback.
🤖 Prompt for AI Agents
In src/components/PostComponents/PostCard.tsx around lines 130–133 the class
"line-clamp-2" is used but the repository either lacks a tailwind.config.js or
the @tailwindcss/line-clamp plugin is not installed/configured; fix by either
(A) installing the plugin (npm/yarn add -D @tailwindcss/line-clamp), ensure you
have a tailwind.config.js at repo root (create one if missing) and add
require('@tailwindcss/line-clamp') to the plugins array, then rebuild; or (B)
remove the "line-clamp-2" utility and replace with a CSS fallback on the
component such as overflow-hidden, display: -webkit-box, -webkit-line-clamp: 2
and -webkit-box-orient: vertical (added via a class or module stylesheet) to
achieve the same clamping without the plugin.
<div className="mt-8"> | ||
<PostFilters | ||
search={search} | ||
onSearchChange={onChangeHandler} | ||
/> | ||
<PostCard/> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UI ignores fetched posts and infinite scroll sentinel; search has no visible effect.
You fetch and paginate but render a PostCard with internal mock defaults. Also, no loadMoreRef
element exists, so the observer never fires. Wire real data into PostCard and add the sentinel.
- <div className="mt-8">
- <PostFilters
- search={search}
- onSearchChange={onChangeHandler}
- />
- <PostCard/>
- </div>
+ <div className="mt-8">
+ <PostFilters search={search} onSearchChange={onChangeHandler} />
+ {/* TODO: map API Post -> PostData. Placeholder passes empty array if not mapped yet */}
+ <PostCard posts={[]} showMultiple />
+ <div ref={loadMoreRef} />
+ </div>
Optionally, export PostData
(see PostCard.tsx comment) and add an adapter:
// near fetchPosts or above return
import type { PostData } from "./PostCard";
function mapPostsToPostData(posts: Post[]): PostData[] {
return posts.map((p) => ({
id: (p as any).id,
title: (p as any).title ?? "Untitled",
description: (p as any).summary ?? (p as any).content ?? "",
sentiment: ((p as any).sentiment ?? "Neutral") as PostData["sentiment"],
sentimentBar: (p as any).sentimentBar ?? { bullish: 0, neutral: 100, bearish: 0 },
postCount: (p as any).postCount ?? 0,
sources: ((p as any).sources ?? []).map((s: any) => ({ name: s.name, count: s.count })),
categories: (p as any).categories ?? [],
extraTags: (p as any).extraTags,
}));
}
🤖 Prompt for AI Agents
In src/components/PostComponents/PostsList.tsx around lines 99-105, the
component renders a single PostCard with mock/internal defaults and has no
sentinel for infinite-scroll, so fetched/paginated posts and the observer are
ignored; fix by importing/exporting the PostData type from PostCard, create a
mapPostsToPostData adapter (near the fetchPosts or above the return) to convert
fetched Post[] into PostData[], map the component's posts state through that
adapter, render a list of PostCard components (use post.id as key) passing the
mapped PostData props into each PostCard instead of a bare <PostCard/>, and add
a sentinel element (e.g., <div ref={loadMoreRef} />) after the list so the
intersection observer can fire to load more. Ensure onChangeHandler still wires
into PostFilters (already present) and remove any hardcoded defaults in PostCard
usage.
…nhance category/subcategory display
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
src/components/PostComponents/PostCard.tsx (2)
114-116
:line-clamp-2
requires plugin; add fallback or configure plugin.Previous review flagged missing
@tailwindcss/line-clamp
. Provide an inline fallback to avoid truncation regressions.- <CardDescription className="text-[8px] text-gray-600 mb-2 line-clamp-2"> + <CardDescription + className="text-[8px] text-gray-600 mb-2" + style={{ + display: '-webkit-box', + WebkitLineClamp: 2, + WebkitBoxOrient: 'vertical', + overflow: 'hidden', + }} + >Run to verify plugin config:
#!/bin/bash fd -a 'tailwind.config*' --hidden --exclude node_modules rg -nP --hidden --no-ignore-vcs --glob '!**/node_modules/**' "@tailwindcss/line-clamp|lineClamp" || true
25-91
: Don’t ship mocks by default; export for Storybook/dev and remove default prop.Defaulting to
mockPostsData
masks data‑flow issues and leaks demo content into prod. Export the mock for stories/dev only and require callers to pass real data.Apply:
-// Mock data array -const mockPostsData: PostData[] = [ +// Mock data array (exported for Storybook/dev usage only) +export const mockPostsData: PostData[] = [And:
-export default function PostCard({ - posts = mockPostsData, - showMultiple = true, -}: PostCardProps) { +export default function PostCard({ posts, showMultiple = true }: PostCardProps) {Also applies to: 221-224
🧹 Nitpick comments (6)
src/components/PostComponents/PostCard.tsx (6)
225-237
: Guard for empty/undefined posts; avoidposts[0]
crash and map on undefined.Without the mock default (previous comment),
posts
can be empty/undefined. Add a safe fallback.- if (showMultiple) { - return ( - <div className="flex flex-row justify-center gap-6 p-2"> - {posts.map((post, index) => ( - <SinglePostCard key={index} post={post} /> - ))} - </div> - ); - } - - // Show only the first card if showMultiple is false - return <SinglePostCard post={posts[0]} />; + const data = posts ?? []; + + if (showMultiple) { + return ( + <div className="flex flex-row justify-center gap-6 p-2"> + {data.map((post, index) => ( + <SinglePostCard key={`${post.title}-${index}`} post={post} /> + ))} + </div> + ); + } + + if (data.length === 0) return null; // or a Skeleton placeholder + return <SinglePostCard post={data[0]} />;
108-108
: Fix nonstandard Tailwind sizes (w-54
,h-66
).These classes don’t exist; use bracketed arbitrary values or scale tokens.
- <Card className="w-54 h-66 font-sans"> + <Card className="w-[216px] h-[264px] font-sans">
123-125
: Use a down icon for Bearish to avoid mixed signals.Swap icon based on sentiment for clearer UX.
-import { IoIosTrendingUp } from "react-icons/io"; +import { IoIosTrendingUp, IoIosTrendingDown } from "react-icons/io"; ... - <IoIosTrendingUp className="w-2 h-2" /> - {post.sentiment} + {post.sentiment === "Bearish" ? ( + <IoIosTrendingDown className="w-2 h-2" /> + ) : ( + <IoIosTrendingUp className="w-2 h-2" /> + )} + {post.sentiment}
132-148
: Add a11y text for the sentiment bar.Expose the distribution to screen readers.
- <div className="mb-2"> + <div + className="mb-2" + role="img" + aria-label={`Sentiment: ${post.sentimentBar.bullish}% bullish, ${post.sentimentBar.neutral}% neutral, ${post.sentimentBar.bearish}% bearish`} + > <div className="flex h-1 w-20 rounded overflow-hidden"> <div className="bg-green-500" style={{ flex: post.sentimentBar.bullish }} ></div> <div className="bg-gray-300" style={{ flex: post.sentimentBar.neutral }} ></div> <div className="bg-red-500" style={{ flex: post.sentimentBar.bearish }} ></div> </div> + <span className="sr-only"> + {`${post.sentimentBar.bullish}% bullish, ${post.sentimentBar.neutral}% neutral, ${post.sentimentBar.bearish}% bearish`} + </span> </div>
152-167
: Flatten the source styling logic with a map to reduce branching.Cleaner and easier to extend; avoids repeated class fragments.
- {post.sources.map((src, idx) => { - let pillClass = - "px-2 py-0.5 rounded-full flex items-center gap-1 border text-[9px] font-medium"; - let icon = null; - if (src.name === "Twitter") { - pillClass += " bg-blue-50 text-blue-600 border-blue-200"; - icon = <FaTwitter className="w-2 h-2" />; - } else if (src.name === "LinkedIn") { - pillClass += " bg-blue-50 text-blue-600 border-blue-200"; - icon = <FaLinkedin className="w-2 h-2" />; - } else if (src.name === "Reddit") { - pillClass += " bg-orange-50 text-orange-600 border-orange-200"; - icon = <FaReddit className="w-2 h-2" />; - } else { - pillClass += " bg-gray-50 text-gray-600 border-gray-200"; - } - return ( - <span key={src.name + idx} className={pillClass}> - {icon} - {src.name} <span className="font-semibold">({src.count})</span> - </span> - ); - })} + {post.sources.map((src, idx) => { + const base = "px-2 py-0.5 rounded-full flex items-center gap-1 border text-[9px] font-medium"; + const map: Record<string, { cls: string; icon: JSX.Element | null }> = { + Twitter: { cls: " bg-blue-50 text-blue-600 border-blue-200", icon: <FaTwitter className="w-2 h-2" /> }, + LinkedIn:{ cls: " bg-blue-50 text-blue-600 border-blue-200", icon: <FaLinkedin className="w-2 h-2" /> }, + Reddit: { cls: " bg-orange-50 text-orange-600 border-orange-200", icon: <FaReddit className="w-2 h-2" /> }, + }; + const { cls, icon } = map[src.name] ?? { cls: " bg-gray-50 text-gray-600 border-gray-200", icon: null }; + return ( + <span key={`${src.name}-${idx}`} className={base + cls}> + {icon} + {src.name} <span className="font-semibold">({src.count})</span> + </span> + ); + })}
227-231
: Prefer stable keys over array index.Indexes hinder reconciliation on re‑orders. Use a stable composite key if no id exists.
If titles are unique in your dataset:
- {data.map((post, index) => ( - <SinglePostCard key={`${post.title}-${index}`} post={post} /> + {data.map((post) => ( + <SinglePostCard key={post.title} post={post} /> ))}Otherwise, keep a composite including a stable source (id/slug) and verify uniqueness in the feed.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/PostComponents/PostCard.tsx
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/PostComponents/PostCard.tsx (1)
src/components/ui/card.tsx (4)
Card
(91-91)CardHeader
(92-92)CardTitle
(94-94)CardDescription
(96-96)
…splay and categorization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work on fixing all the reviews
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/components/PostComponents/PostsList.tsx (1)
8-8
: Fetched posts are ignored and infinite scroll cannot trigger; wire data into PostGallery and add sentinel.Right now PostGallery renders mock data and no sentinel exists, so pagination never fires. This mirrors a previously raised issue. Pass mapped posts and render the
loadMoreRef
element.-import PostGallery from "./PostGallery"; +import PostGallery, { type PostData } from "./PostGallery";return ( - <div className="mt-8"> - <PostFilters - search={search} - onSearchChange={onChangeHandler} - /> - <PostGallery/> - </div> + <div className="mt-8"> + <PostFilters search={search} onSearchChange={onChangeHandler} /> + <PostGallery posts={mappedPosts} /> + <div ref={loadMoreRef} aria-hidden="true" className="h-px" /> + </div> );Add the adapter and mapping before the return:
// keep near other hooks or above return const mappedPosts: PostData[] = mapPostsToPostData(info); function mapPostsToPostData(posts: Post[]): PostData[] { return posts.map((p: any) => ({ title: p.title ?? "Untitled", description: p.summary ?? p.content ?? "", sentiment: (p.sentiment ?? "NEUTRAL") as PostData["sentiment"], sentimentBar: p.sentimentBar ?? { bullish: 0, neutral: 100, bearish: 0 }, postCount: p.postCount ?? 0, sources: (p.sources ?? []).map((s: any) => ({ name: s.name, count: s.count })), categories: p.categories ?? [], subcategories: p.subcategories ?? [], })); }Also, guard the observer against duplicate page loads:
// inside IntersectionObserver callback (around Line 88) if (entries[0].isIntersecting && hasMore && !loading && !loadingMore && nextCursor) { fetchPosts(nextCursor); }Also applies to: 99-105
🧹 Nitpick comments (6)
src/components/PostComponents/TagRenderer.tsx (2)
25-27
: Avoid magic number and prevent negative "+N more".Compute remaining count robustly and name the constant.
- const visibleTags = allTags.slice(0, 5); - const remainingCount = allTags.length - 5; + const MAX_VISIBLE = 5; + const visibleTags = allTags.slice(0, MAX_VISIBLE); + const remainingCount = Math.max(0, allTags.length - visibleTags.length);
33-37
: 7px text is not readable; bump for a11y.At this size the chips will fail basic readability. Suggest 10–12px.
- className={`px-1 py-0.5 text-[7px] font-medium rounded-full ${ + className={`px-1 py-0.5 text-[10px] font-medium rounded-full ${ ... - <span className="px-1 py-0.5 text-[7px] font-medium text-gray-700 bg-gray-100 rounded-full"> + <span className="px-1 py-0.5 text-[10px] font-medium text-gray-700 bg-gray-100 rounded-full">Also applies to: 43-45
src/components/PostComponents/PostsList.tsx (1)
8-8
: Type‑only imports; drop unused runtime imports.
SortField
/SortOrder
should be type-only to avoid bundling UI you removed; also remove unusedSentimentBar
/Spinner
imports.// replace import { SortField, SortOrder } from "./PostSortSelect"; // with import type { SortField, SortOrder } from "./PostSortSelect"; // and remove unused: // import SentimentBar from "./SentimentBar"; // import Spinner from "./Spinner";src/components/PostComponents/PostGallery.tsx (3)
16-25
: Export PostData for reuse in PostsList mapping.This enables typed adapters and prevents
any
.-type PostData = { +export type PostData = { title: string; description: string; sentiment: Sentiment; sentimentBar: { bullish: number; neutral: number; bearish: number }; postCount: number; sources: Source[]; categories: string[]; subcategories?: string[]; };
109-109
: Tailwind sizesw-54
/h-66
aren’t standard; likely no‑ops.Use standard scale or configured tokens.
- <Card className="w-54 h-66 font-sans"> + <Card className="w-56 h-64 font-sans">
195-197
: Prefer stable keys over array index.If the order changes, index keys can cause visual glitches. Consider adding an
id
toPostData
and using it here.Example:
export type PostData = { id: string; /* ... */ }; // ... <SinglePostCard key={post.id} post={post} />
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/components/PostComponents/PostGallery.tsx
(1 hunks)src/components/PostComponents/PostsList.tsx
(2 hunks)src/components/PostComponents/TagRenderer.tsx
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/PostComponents/PostsList.tsx (1)
src/components/PostComponents/PostFilters.tsx (1)
PostFilters
(10-26)
|
||
import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card"; | ||
import TagRenderer from "./TagRenderer"; | ||
import { Sentiment } from "@prisma/client"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Do not import Prisma on the client; use a type‑only import.
Importing from @prisma/client
in a client component can bloat/break the bundle. Use import type
.
-import { Sentiment } from "@prisma/client";
+import type { Sentiment } from "@prisma/client";
To verify no runtime Prisma leaks in client code:
🏁 Script executed:
#!/bin/bash
# Find client components importing @prisma/client as a value (not type-only)
rg -nP --type tsx -C2 '@prisma/client' src/components
Length of output: 27
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Searching for @prisma/client imports in src..."
rg -n --hidden -S "@prisma/client" src || true
echo
echo "Showing matches with 2 lines of context:"
rg -n --hidden -S -C2 "@prisma/client" src || true
echo
if [ -f src/components/PostComponents/PostGallery.tsx ]; then
echo "Contents of src/components/PostComponents/PostGallery.tsx (first 200 lines):"
sed -n '1,200p' src/components/PostComponents/PostGallery.tsx || true
else
echo "File not found: src/components/PostComponents/PostGallery.tsx"
fi
Length of output: 8492
Replace value import with a type-only import for Sentiment in this client component
This is a client component (has "use client" at the top); importing from @prisma/client as a value will pull Prisma runtime into the client bundle — use a type-only import.
Location: src/components/PostComponents/PostGallery.tsx — line 9
-import { Sentiment } from "@prisma/client";
+import type { Sentiment } from "@prisma/client";
📝 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.
import { Sentiment } from "@prisma/client"; | |
import type { Sentiment } from "@prisma/client"; |
🤖 Prompt for AI Agents
In src/components/PostComponents/PostGallery.tsx around line 9, the file
currently imports Sentiment from @prisma/client as a value which will pull
Prisma runtime into the client bundle; change that import to a type-only import
so Sentiment is erased at runtime (use the TypeScript "import type" form),
ensuring the component remains a client component without including Prisma
runtime.
posts = mockPostsData, | ||
}: PostsGalleryProps) { | ||
return ( | ||
<div className="flex flex-row justify-center gap-6 p-2"> | ||
{posts.map((post, index) => ( | ||
<SinglePostCard key={index} post={post} /> | ||
))} | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid shipping mock data by default.
Defaulting posts
to mockPostsData
risks mock UI in production. Make posts
explicit and fallback inside only when truly needed.
-export default function PostsGallery({
- posts = mockPostsData,
-}: PostsGalleryProps) {
- return (
- <div className="flex flex-row justify-center gap-6 p-2">
- {posts.map((post, index) => (
+export default function PostsGallery({ posts }: PostsGalleryProps) {
+ const data = posts ?? mockPostsData;
+ return (
+ <div className="flex flex-row justify-center gap-6 p-2">
+ {data.map((post, index) => (
<SinglePostCard key={index} post={post} />
))}
</div>
);
📝 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.
posts = mockPostsData, | |
}: PostsGalleryProps) { | |
return ( | |
<div className="flex flex-row justify-center gap-6 p-2"> | |
{posts.map((post, index) => ( | |
<SinglePostCard key={index} post={post} /> | |
))} | |
</div> | |
export default function PostsGallery({ posts }: PostsGalleryProps) { | |
const data = posts ?? mockPostsData; | |
return ( | |
<div className="flex flex-row justify-center gap-6 p-2"> | |
{data.map((post, index) => ( | |
<SinglePostCard key={index} post={post} /> | |
))} | |
</div> | |
); | |
} |
🤖 Prompt for AI Agents
In src/components/PostComponents/PostGallery.tsx around lines 191 to 198, the
component currently defaults the posts prop to mockPostsData which can leak mock
UI to production; remove the default assignment from the function signature so
posts must be passed in (or make the prop required in the PostsGalleryProps
type), and if a safe fallback is needed inside the component use a non-mock
fallback like posts = postsProp || [] or explicitly use mockPostsData only in
story/test code — update types and callers accordingly to ensure production code
never ships with mock data by default.
Description:
PostFilters.tsx
, leaving only the search bar.PostsList.tsx
to render only the search bar viaPostFilters
.Summary by CodeRabbit
New Features
Refactor