From 30528409bf5bb033578ead4bf7b1114da46fb2db Mon Sep 17 00:00:00 2001 From: Ginza Hatemi Date: Wed, 17 Sep 2025 02:25:23 -0600 Subject: [PATCH 1/5] feat: Refactor Post and PostGroup models, update seed script, and modify PostGallery component --- .../migration.sql | 52 +++++++++++++++++++ .../migration.sql | 9 ++++ prisma/schema.prisma | 14 ++--- prisma/seed.ts | 22 ++++---- src/components/PostComponents/PostGallery.tsx | 28 +++++----- 5 files changed, 93 insertions(+), 32 deletions(-) create mode 100644 prisma/migrations/20250917074232_rename_to_post_group_and_post_model/migration.sql create mode 100644 prisma/migrations/20250917075310_update_post_group_model/migration.sql diff --git a/prisma/migrations/20250917074232_rename_to_post_group_and_post_model/migration.sql b/prisma/migrations/20250917074232_rename_to_post_group_and_post_model/migration.sql new file mode 100644 index 0000000..218522b --- /dev/null +++ b/prisma/migrations/20250917074232_rename_to_post_group_and_post_model/migration.sql @@ -0,0 +1,52 @@ +/* + Warnings: + + - You are about to drop the column `bearishSummary` on the `Post` table. All the data in the column will be lost. + - You are about to drop the column `bullishSummary` on the `Post` table. All the data in the column will be lost. + - You are about to drop the column `neutralSummary` on the `Post` table. All the data in the column will be lost. + - You are about to drop the column `title` on the `Post` table. All the data in the column will be lost. + - You are about to drop the column `totalSubposts` on the `Post` table. All the data in the column will be lost. + - You are about to drop the `Subpost` table. If the table is not empty, all the data it contains will be lost. + - Added the required column `content` to the `Post` table without a default value. This is not possible if the table is not empty. + - Added the required column `postGroupId` to the `Post` table without a default value. This is not possible if the table is not empty. + - Added the required column `sentiment` to the `Post` table without a default value. This is not possible if the table is not empty. + - Added the required column `source` to the `Post` table without a default value. This is not possible if the table is not empty. + - Added the required column `updatedAt` to the `Post` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropForeignKey +ALTER TABLE "public"."Subpost" DROP CONSTRAINT "Subpost_postId_fkey"; + +-- AlterTable +ALTER TABLE "public"."Post" DROP COLUMN "bearishSummary", +DROP COLUMN "bullishSummary", +DROP COLUMN "neutralSummary", +DROP COLUMN "title", +DROP COLUMN "totalSubposts", +ADD COLUMN "categories" TEXT[] DEFAULT ARRAY[]::TEXT[], +ADD COLUMN "content" TEXT NOT NULL, +ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, +ADD COLUMN "link" TEXT, +ADD COLUMN "postGroupId" TEXT NOT NULL, +ADD COLUMN "sentiment" "public"."Sentiment" NOT NULL, +ADD COLUMN "source" "public"."Source" NOT NULL, +ADD COLUMN "subcategories" TEXT[] DEFAULT ARRAY[]::TEXT[], +ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL; + +-- DropTable +DROP TABLE "public"."Subpost"; + +-- CreateTable +CREATE TABLE "public"."PostGroup" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "totalSubposts" INTEGER NOT NULL DEFAULT 0, + "bullishSummary" TEXT, + "bearishSummary" TEXT, + "neutralSummary" TEXT, + + CONSTRAINT "PostGroup_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "public"."Post" ADD CONSTRAINT "Post_postGroupId_fkey" FOREIGN KEY ("postGroupId") REFERENCES "public"."PostGroup"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20250917075310_update_post_group_model/migration.sql b/prisma/migrations/20250917075310_update_post_group_model/migration.sql new file mode 100644 index 0000000..4651aae --- /dev/null +++ b/prisma/migrations/20250917075310_update_post_group_model/migration.sql @@ -0,0 +1,9 @@ +/* + Warnings: + + - You are about to drop the column `totalSubposts` on the `PostGroup` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "public"."PostGroup" DROP COLUMN "totalSubposts", +ADD COLUMN "totalposts" INTEGER NOT NULL DEFAULT 0; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 81a5845..39dc82d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -48,17 +48,17 @@ enum Source { FARCASTER } -model Post { - id String @id @default(uuid()) +model PostGroup { + id String @id @default(uuid()) title String - subposts Subpost[] - totalSubposts Int @default(0) + posts Post[] + totalposts Int @default(0) bullishSummary String? bearishSummary String? neutralSummary String? } -model Subpost { +model Post { id String @id @default(uuid()) content String sentiment Sentiment @@ -66,8 +66,8 @@ model Subpost { categories String[] @default([]) subcategories String[] @default([]) link String? - postId String - post Post @relation(fields: [postId], references: [id]) + postGroupId String + postGroup PostGroup @relation(fields: [postGroupId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } diff --git a/prisma/seed.ts b/prisma/seed.ts index 6bf074a..91f8b5b 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -9,15 +9,15 @@ const prisma = new PrismaClient(); async function main() { // Delete existing data to prevent stacking - await prisma.subpost.deleteMany({}); await prisma.post.deleteMany({}); + await prisma.postGroup.deleteMany({}); await prisma.user.deleteMany({}); // Seed Users const MAX_USERS = 5; - const MAX_POSTS = 10; - const MIN_SUBPOSTS = 5; - const MAX_SUBPOSTS = 20; + const MAX_POSTGROUP = 10; + const MIN_POSTS = 5; + const MAX_POSTS = 20; for (let i = 0; i < MAX_USERS; i++) { await prisma.user.create({ @@ -31,19 +31,19 @@ async function main() { }); } - // Seed Posts with Subposts - for (let i = 0; i < MAX_POSTS; i++) { - const subpostCount = faker.number.int({ min: MIN_SUBPOSTS, max: MAX_SUBPOSTS }); - await prisma.post.create({ + // Seed PostGroups with Posts + for (let i = 0; i < MAX_POSTGROUP; i++) { + const postCount = faker.number.int({ min: MIN_POSTS, max: MAX_POSTS }); + await prisma.postGroup.create({ data: { title: faker.lorem.sentence(), bullishSummary: faker.helpers.maybe(() => faker.lorem.paragraph(), { probability: 0.7 }), bearishSummary: faker.helpers.maybe(() => faker.lorem.paragraph(), { probability: 0.7 }), neutralSummary: faker.helpers.maybe(() => faker.lorem.paragraph(), { probability: 0.7 }), - totalSubposts: subpostCount, - subposts: { + totalposts: postCount, + posts: { createMany: { - data: Array.from({ length: subpostCount }).map(() => ({ + data: Array.from({ length: postCount }).map(() => ({ content: faker.lorem.paragraph({ min: 3, max: 5 }), sentiment: faker.helpers.arrayElement([ Sentiment.BULLISH, diff --git a/src/components/PostComponents/PostGallery.tsx b/src/components/PostComponents/PostGallery.tsx index c75ab9a..4f3f0a8 100644 --- a/src/components/PostComponents/PostGallery.tsx +++ b/src/components/PostComponents/PostGallery.tsx @@ -13,27 +13,27 @@ type Source = { count: number; }; -type PostData = { +type PostGroup = { title: string; - description: string; + content: string; sentiment: Sentiment; sentimentBar: { bullish: number; neutral: number; bearish: number }; postCount: number; - sources: Source[]; + source: Source[]; categories: string[]; subcategories?: string[]; }; // Mock data array -const mockPostsData: PostData[] = [ +const mockPostsData: PostGroup[] = [ { title: "Bitcoin Institutional Adoption & Market Sentiment", - description: + content: "Major financial institutions showing increased interest in Bitcoin with positive analyst reports...", sentiment: "BULLISH", sentimentBar: { bullish: 60, neutral: 25, bearish: 15 }, postCount: 24, - sources: [ + source: [ { name: "Twitter", count: 12, @@ -52,12 +52,12 @@ const mockPostsData: PostData[] = [ }, { title: "Ethereum DeFi Protocol Updates", - description: + content: "New developments in decentralized finance protocols showing promising growth patterns...", sentiment: "NEUTRAL", sentimentBar: { bullish: 30, neutral: 50, bearish: 20 }, postCount: 18, - sources: [ + source: [ { name: "Twitter", count: 10, @@ -72,12 +72,12 @@ const mockPostsData: PostData[] = [ }, { title: "Market Volatility Analysis", - description: + content: "Recent market downturn showing concerning trends across major cryptocurrencies...", sentiment: "BEARISH", sentimentBar: { bullish: 15, neutral: 25, bearish: 60 }, postCount: 32, - sources: [ + source: [ { name: "LinkedIn", count: 15, @@ -93,11 +93,11 @@ const mockPostsData: PostData[] = [ ]; type PostsGalleryProps = { - posts?: PostData[]; + posts?: PostGroup[]; }; // Single card component -export function SinglePostCard({ post }: { post: PostData }) { +export function SinglePostCard({ post }: { post: PostGroup }) { const sentimentColor = post.sentiment === "BULLISH" ? "text-green-700 bg-green-100" @@ -113,7 +113,7 @@ export function SinglePostCard({ post }: { post: PostData }) { - {post.description} + {post.content} {/* Sentiment indicators */} @@ -150,7 +150,7 @@ export function SinglePostCard({ post }: { post: PostData }) { {/* Source Tags */}
- {post.sources.map((src, idx) => { + {post.source.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; From ade745d73d5e117f48e42dddc67df9d69119ca9a Mon Sep 17 00:00:00 2001 From: Ginza Hatemi Date: Wed, 17 Sep 2025 02:44:19 -0600 Subject: [PATCH 2/5] feat: Update Post table schema: add new columns, backfill data, and remove obsolete columns --- .../migration.sql | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/prisma/migrations/20250917074232_rename_to_post_group_and_post_model/migration.sql b/prisma/migrations/20250917074232_rename_to_post_group_and_post_model/migration.sql index 218522b..4bcca09 100644 --- a/prisma/migrations/20250917074232_rename_to_post_group_and_post_model/migration.sql +++ b/prisma/migrations/20250917074232_rename_to_post_group_and_post_model/migration.sql @@ -17,21 +17,42 @@ -- DropForeignKey ALTER TABLE "public"."Subpost" DROP CONSTRAINT "Subpost_postId_fkey"; --- AlterTable -ALTER TABLE "public"."Post" DROP COLUMN "bearishSummary", -DROP COLUMN "bullishSummary", -DROP COLUMN "neutralSummary", -DROP COLUMN "title", -DROP COLUMN "totalSubposts", +-- AlterTable - Step 1: Add new columns as nullable first +ALTER TABLE "public"."Post" ADD COLUMN "categories" TEXT[] DEFAULT ARRAY[]::TEXT[], -ADD COLUMN "content" TEXT NOT NULL, -ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, +ADD COLUMN "content" TEXT, +ADD COLUMN "createdAt" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, ADD COLUMN "link" TEXT, -ADD COLUMN "postGroupId" TEXT NOT NULL, -ADD COLUMN "sentiment" "public"."Sentiment" NOT NULL, -ADD COLUMN "source" "public"."Source" NOT NULL, +ADD COLUMN "postGroupId" TEXT, +ADD COLUMN "sentiment" "public"."Sentiment", +ADD COLUMN "source" "public"."Source", ADD COLUMN "subcategories" TEXT[] DEFAULT ARRAY[]::TEXT[], -ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL; +ADD COLUMN "updatedAt" TIMESTAMP(3); + +-- Step 2: Backfill data for new columns +UPDATE "public"."Post" SET + "content" = COALESCE("title", 'Migrated content'), + "sentiment" = 'NEUTRAL', + "source" = 'REDDIT', + "updatedAt" = CURRENT_TIMESTAMP, + "createdAt" = COALESCE("createdAt", CURRENT_TIMESTAMP) +WHERE "content" IS NULL; + +-- Step 3: Set NOT NULL constraints after backfill +ALTER TABLE "public"."Post" +ALTER COLUMN "content" SET NOT NULL, +ALTER COLUMN "createdAt" SET NOT NULL, +ALTER COLUMN "sentiment" SET NOT NULL, +ALTER COLUMN "source" SET NOT NULL, +ALTER COLUMN "updatedAt" SET NOT NULL; + +-- Step 4: Drop old columns +ALTER TABLE "public"."Post" +DROP COLUMN "bearishSummary", +DROP COLUMN "bullishSummary", +DROP COLUMN "neutralSummary", +DROP COLUMN "title", +DROP COLUMN "totalSubposts"; -- DropTable DROP TABLE "public"."Subpost"; From 03444ecbcd8c00671bb6c83701bc318ec3fa2462 Mon Sep 17 00:00:00 2001 From: Ginza Hatemi Date: Wed, 17 Sep 2025 03:25:13 -0600 Subject: [PATCH 3/5] feat: Refactor PostGallery component to use PostGroup structure, enhance sentiment display, and improve data handling --- src/components/PostComponents/PostGallery.tsx | 262 ++++++++++-------- 1 file changed, 154 insertions(+), 108 deletions(-) diff --git a/src/components/PostComponents/PostGallery.tsx b/src/components/PostComponents/PostGallery.tsx index 4f3f0a8..a5a568b 100644 --- a/src/components/PostComponents/PostGallery.tsx +++ b/src/components/PostComponents/PostGallery.tsx @@ -1,185 +1,231 @@ "use client"; -import { IoIosTrendingUp } from "react-icons/io"; import { CiChat1 } from "react-icons/ci"; import { FaTwitter, FaLinkedin, FaReddit } from "react-icons/fa"; import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card"; import TagRenderer from "./TagRenderer"; -import { Sentiment } from "@prisma/client"; - -type Source = { - name: string; - count: number; -}; +import { Sentiment, Source } from "@prisma/client"; type PostGroup = { + id: string; title: string; + posts: Post[]; + totalposts: number; + bullishSummary?: string | null; + bearishSummary?: string | null; + neutralSummary?: string | null; +}; + +type Post = { + id: string; content: string; sentiment: Sentiment; - sentimentBar: { bullish: number; neutral: number; bearish: number }; - postCount: number; - source: Source[]; + source: Source; categories: string[]; - subcategories?: string[]; + subcategories: string[]; + link?: string | null; + createdAt: string; + updatedAt: string; }; // Mock data array -const mockPostsData: PostGroup[] = [ +const mockPostGroup: PostGroup[] = [ { - title: "Bitcoin Institutional Adoption & Market Sentiment", - content: - "Major financial institutions showing increased interest in Bitcoin with positive analyst reports...", - sentiment: "BULLISH", - sentimentBar: { bullish: 60, neutral: 25, bearish: 15 }, - postCount: 24, - source: [ + id: "group1", + title: "Bitcoin Historical Milestones & Market Impact", + totalposts: 3, + bullishSummary: + "Bitcoin's journey from pizza transactions to trillion-dollar adoption shows incredible growth potential", + bearishSummary: + "Historical volatility and speculative nature raise concerns about sustainable growth", + neutralSummary: + "Bitcoin's evolution reflects both opportunities and challenges in the cryptocurrency space", + posts: [ { - name: "Twitter", - count: 12, + id: "post1", + content: + "Empery Digital\n@EMPD_BTC\n·\n11m\nBitcoin Firsts that changed everything:\n- $4B Pizza\n- A nation bets on BTC\n- Wall Street embraces it\n- The Trillion-Dollar Club\nFrom a pizza order to reshaping global finance.\n#Bitcoin #BTC #Blockchain #EmperyDigital", + sentiment: "BULLISH", + source: "TWITTER", + categories: ["Cryptocurrency", "Market Analysis"], + subcategories: ["Bitcoin", "Milestones", "Adoption"], + link: null, + createdAt: "2025-09-16T12:00:00.000Z", + updatedAt: "2025-09-16T12:00:00.000Z", }, { - name: "LinkedIn", - count: 8, + id: "post2", + content: + "Empery Digital\n@EMPD_BTC\n·\n11m\nSome notable events in Bitcoin's history include:\n- The purchase of pizza with Bitcoin\n- A country adopting BTC\n- Increased interest from Wall Street\n- Joining the Trillion-Dollar Club\nThese milestones reflect Bitcoin's evolving role in finance.\n#Bitcoin #BTC #Blockchain #EmperyDigital", + sentiment: "NEUTRAL", + source: "TWITTER", + categories: ["Cryptocurrency", "Market Analysis"], + subcategories: ["Bitcoin", "Milestones", "Adoption"], + link: null, + createdAt: "2025-09-16T12:00:00.000Z", + updatedAt: "2025-09-16T12:00:00.000Z", }, { - name: "Reddit", - count: 4, + id: "post3", + content: + "Empery Digital\n@EMPD_BTC\n·\n11m\nRecent events in Bitcoin's history have raised concerns:\n- The infamous $4B pizza purchase\n- A nation risking its economy on BTC\n- Wall Street's speculative involvement\n- Entering the Trillion-Dollar Club amid volatility\nFrom a simple transaction to ongoing financial uncertainty.\n#Bitcoin #BTC #Blockchain #EmperyDigital", + sentiment: "BEARISH", + source: "TWITTER", + categories: ["Cryptocurrency", "Market Analysis"], + subcategories: ["Bitcoin", "Milestones", "Risks"], + link: null, + createdAt: "2025-09-16T12:00:00.000Z", + updatedAt: "2025-09-16T12:00:00.000Z", }, ], - categories: ["Bitcoin", "Institutional"], - subcategories: ["ETF", "Regulation", "Spot", "Futures"], }, { - title: "Ethereum DeFi Protocol Updates", - content: - "New developments in decentralized finance protocols showing promising growth patterns...", - sentiment: "NEUTRAL", - sentimentBar: { bullish: 30, neutral: 50, bearish: 20 }, - postCount: 18, - source: [ + id: "group2", + title: "Ethereum DeFi Ecosystem Updates", + totalposts: 2, + bullishSummary: + "DeFi protocols showing strong innovation and growth in the Ethereum ecosystem", + bearishSummary: + "Regulatory concerns and high gas fees continue to challenge DeFi adoption", + neutralSummary: + "DeFi development continues with mixed signals from market and regulatory fronts", + posts: [ { - name: "Twitter", - count: 10, + id: "post4", + content: + "Major DeFi protocol announces new lending features with improved yield opportunities for users", + sentiment: "BULLISH", + source: "REDDIT", + categories: ["Ethereum", "DeFi"], + subcategories: ["Lending", "Yield", "Innovation"], + link: "https://reddit.com/r/ethereum/defi-update", + createdAt: "2025-09-16T14:00:00.000Z", + updatedAt: "2025-09-16T14:00:00.000Z", }, { - name: "Reddit", - count: 8, + id: "post5", + content: + "Gas fees on Ethereum network surge to new highs, affecting DeFi transaction costs", + sentiment: "BEARISH", + source: "TWITTER", + categories: ["Ethereum", "DeFi"], + subcategories: ["Gas Fees", "Network Congestion"], + link: null, + createdAt: "2025-09-16T15:00:00.000Z", + updatedAt: "2025-09-16T15:00:00.000Z", }, ], - categories: ["Ethereum"], - subcategories: ["Lending", "DEX", "Staking", "Yield", "Bridge"], - }, - { - title: "Market Volatility Analysis", - content: - "Recent market downturn showing concerning trends across major cryptocurrencies...", - sentiment: "BEARISH", - sentimentBar: { bullish: 15, neutral: 25, bearish: 60 }, - postCount: 32, - source: [ - { - name: "LinkedIn", - count: 15, - }, - { - name: "Reddit", - count: 17, - }, - ], - categories: ["Market", "Volatility"], - subcategories: ["Crash", "Recovery", "Bear", "Bull"], }, ]; type PostsGalleryProps = { - posts?: PostGroup[]; + postGroups: PostGroup[]; }; -// Single card component -export function SinglePostCard({ post }: { post: PostGroup }) { - const sentimentColor = - post.sentiment === "BULLISH" - ? "text-green-700 bg-green-100" - : post.sentiment === "BEARISH" - ? "text-red-700 bg-red-100" - : "text-gray-700 bg-gray-100"; +// Single card component for PostGroup +export function PostCard({ postGroup }: { postGroup: PostGroup }) { + // Calculate sentiment distribution from posts + const sentimentCounts = postGroup.posts.reduce( + (acc, post) => { + acc[post.sentiment.toLowerCase() as keyof typeof acc]++; + return acc; + }, + { bullish: 0, neutral: 0, bearish: 0 } + ); + + const totalPosts = postGroup.posts.length; + const sentimentBar = { + bullish: (sentimentCounts.bullish / totalPosts) * 100, + neutral: (sentimentCounts.neutral / totalPosts) * 100, + bearish: (sentimentCounts.bearish / totalPosts) * 100, + }; + + // Get source counts + const sourceCounts = postGroup.posts.reduce((acc, post) => { + acc[post.source] = (acc[post.source] || 0) + 1; + return acc; + }, {} as Record); + + // Get all categories and subcategories + const allCategories = [ + ...new Set(postGroup.posts.flatMap((post) => post.categories)), + ]; + const allSubcategories = [ + ...new Set(postGroup.posts.flatMap((post) => post.subcategories)), + ]; return ( - - - - {post.title} + + + + {postGroup.title} - - {post.content} + + {postGroup.bullishSummary || + postGroup.neutralSummary || + postGroup.bearishSummary} - {/* Sentiment indicators */} -
- - - {post.sentiment} - -
- - {post.postCount} + {/* Post count indicator */} +
+
+ + {postGroup.totalposts} posts
{/* Sentiment Bar */} -
-
+
+
{/* Source Tags */} -
- {post.source.map((src, idx) => { +
+ {Object.entries(sourceCounts).map(([source, count]) => { let pillClass = - "px-2 py-0.5 rounded-full flex items-center gap-1 border text-[9px] font-medium"; + "px-2 py-1 rounded-full flex items-center gap-1 border text-xs font-medium"; let icon = null; - if (src.name === "Twitter") { + if (source === "TWITTER") { pillClass += " bg-blue-50 text-blue-600 border-blue-200"; - icon = ; - } else if (src.name === "LinkedIn") { + icon = ; + } else if (source === "LINKEDIN") { pillClass += " bg-blue-50 text-blue-600 border-blue-200"; - icon = ; - } else if (src.name === "Reddit") { + icon = ; + } else if (source === "REDDIT") { pillClass += " bg-orange-50 text-orange-600 border-orange-200"; - icon = ; + icon = ; } else { pillClass += " bg-gray-50 text-gray-600 border-gray-200"; } return ( - + {icon} - {src.name} ({src.count}) + {source} ({count}) ); })}
{/* Category/Subcategory Tags */} -
+
@@ -188,12 +234,12 @@ export function SinglePostCard({ post }: { post: PostGroup }) { } export default function PostsGallery({ - posts = mockPostsData, + postGroups = mockPostGroup, }: PostsGalleryProps) { return (
- {posts.map((post, index) => ( - + {postGroups.map((postGroup, index) => ( + ))}
); From 93f6e561cd653e20f857836ca8d592f096631821 Mon Sep 17 00:00:00 2001 From: Ginza Hatemi Date: Wed, 17 Sep 2025 03:52:47 -0600 Subject: [PATCH 4/5] feat: Enhance PostCard component with dominant sentiment display and update TagRenderer for improved styling --- src/components/PostComponents/PostGallery.tsx | 58 +++++++++++++++++-- src/components/PostComponents/TagRenderer.tsx | 2 +- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/components/PostComponents/PostGallery.tsx b/src/components/PostComponents/PostGallery.tsx index a5a568b..941841b 100644 --- a/src/components/PostComponents/PostGallery.tsx +++ b/src/components/PostComponents/PostGallery.tsx @@ -2,6 +2,8 @@ import { CiChat1 } from "react-icons/ci"; import { FaTwitter, FaLinkedin, FaReddit } from "react-icons/fa"; +import { IoIosTrendingUp, IoIosTrendingDown } from "react-icons/io"; +import { FiMinus } from "react-icons/fi"; import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card"; import TagRenderer from "./TagRenderer"; @@ -141,6 +143,39 @@ export function PostCard({ postGroup }: { postGroup: PostGroup }) { bearish: (sentimentCounts.bearish / totalPosts) * 100, }; + // Determine dominant sentiment and description + const getDominantSentiment = () => { + const max = Math.max( + sentimentCounts.bullish, + sentimentCounts.neutral, + sentimentCounts.bearish + ); + + if ( + sentimentCounts.bullish === sentimentCounts.neutral && + sentimentCounts.neutral === sentimentCounts.bearish + ) { + return { sentiment: "NEUTRAL", description: postGroup.neutralSummary }; + } + + if (sentimentCounts.bullish === max) { + return { sentiment: "BULLISH", description: postGroup.bullishSummary }; + } else if (sentimentCounts.bearish === max) { + return { sentiment: "BEARISH", description: postGroup.bearishSummary }; + } else { + return { sentiment: "NEUTRAL", description: postGroup.neutralSummary }; + } + }; + + const dominantSentiment = getDominantSentiment(); + + const sentimentColor = + dominantSentiment.sentiment === "BULLISH" + ? "text-green-700 bg-green-100" + : dominantSentiment.sentiment === "BEARISH" + ? "text-red-700 bg-red-100" + : "text-gray-700 bg-gray-100"; + // Get source counts const sourceCounts = postGroup.posts.reduce((acc, post) => { acc[post.source] = (acc[post.source] || 0) + 1; @@ -163,13 +198,26 @@ export function PostCard({ postGroup }: { postGroup: PostGroup }) { - {postGroup.bullishSummary || - postGroup.neutralSummary || - postGroup.bearishSummary} + {dominantSentiment.description} - {/* Post count indicator */} -
+ {/* Sentiment tag and post count */} +
+ + {dominantSentiment.sentiment === "BULLISH" && ( + + )} + {dominantSentiment.sentiment === "BEARISH" && ( + + )} + {dominantSentiment.sentiment === "NEUTRAL" && ( + + )} + {dominantSentiment.sentiment.charAt(0) + + dominantSentiment.sentiment.slice(1).toLowerCase()} +
{postGroup.totalposts} posts diff --git a/src/components/PostComponents/TagRenderer.tsx b/src/components/PostComponents/TagRenderer.tsx index 03f76cf..6825fa1 100644 --- a/src/components/PostComponents/TagRenderer.tsx +++ b/src/components/PostComponents/TagRenderer.tsx @@ -30,7 +30,7 @@ export default function TagRenderer({ {visibleTags.map((tag, idx) => ( Date: Wed, 17 Sep 2025 04:09:20 -0600 Subject: [PATCH 5/5] feat: Update sentiment bar calculation in PostCard component to handle zero posts scenario --- src/components/PostComponents/PostGallery.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/PostComponents/PostGallery.tsx b/src/components/PostComponents/PostGallery.tsx index 941841b..6372fd7 100644 --- a/src/components/PostComponents/PostGallery.tsx +++ b/src/components/PostComponents/PostGallery.tsx @@ -7,7 +7,7 @@ import { FiMinus } from "react-icons/fi"; import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card"; import TagRenderer from "./TagRenderer"; -import { Sentiment, Source } from "@prisma/client"; +import type { Sentiment, Source } from "@prisma/client"; type PostGroup = { id: string; @@ -137,11 +137,14 @@ export function PostCard({ postGroup }: { postGroup: PostGroup }) { ); const totalPosts = postGroup.posts.length; - const sentimentBar = { - bullish: (sentimentCounts.bullish / totalPosts) * 100, - neutral: (sentimentCounts.neutral / totalPosts) * 100, - bearish: (sentimentCounts.bearish / totalPosts) * 100, - }; + const sentimentBar = + totalPosts > 0 + ? { + bullish: (sentimentCounts.bullish / totalPosts) * 100, + neutral: (sentimentCounts.neutral / totalPosts) * 100, + bearish: (sentimentCounts.bearish / totalPosts) * 100, + } + : { bullish: 0, neutral: 0, bearish: 0 }; // Determine dominant sentiment and description const getDominantSentiment = () => {