Skip to content

Conversation

@codebyNJ
Copy link

@codebyNJ codebyNJ commented Nov 14, 2025

Recording.2025-11-15.013830.mp4

fix: #155

  • Added newsletters dashboard.

  • Focused more towards the UI so the overall product feel would be uplifted.

  • Implement search and filter functionality.

  • Added sample newsletters for testing
    .

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a newsletter archive for pro users with search functionality and filtering by date.
    • Enabled image optimization from Unsplash.
  • Style

    • Updated navigation bar styling with semi-transparent, blurred appearance.
    • Enhanced blog header with improved sticky positioning and typography.
  • UI/UX

    • Reorganized landing page layout with refined navigation integration.
    • Unified blog and post views with enhanced filtering capabilities.

@vercel
Copy link

vercel bot commented Nov 14, 2025

@codebyNJ is attempting to deploy a commit to the AJEET PRATAP SINGH's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

Walkthrough

Implements a complete newsletter feature for pro users with data structures defining newsletter content types, new pages for listing and displaying individual newsletters with pro-only access control, rich content rendering component, shader-based visual header component, sidebar integration, and comprehensive documentation on implementation and usage.

Changes

Cohort / File(s) Summary
Newsletter Feature (Core)
apps/web/src/data/newsletters.ts, apps/web/src/components/newsletters/NewsletterContent.tsx, apps/web/src/app/(main)/dashboard/newsletters/page.tsx, apps/web/src/app/(main)/dashboard/newsletters/[id]/page.tsx
Adds newsletter data model with content types, rich content renderer supporting headings/bold/links/images, and two new pages for listing/searching newsletters and displaying individual newsletter details with pro-only redirects.
Newsletter Documentation
NEWSLETTER_IMPLEMENTATION.md, apps/web/src/data/NEWSLETTER_GUIDE.md
Provides implementation architecture, file structure overview, content organization guidance, and instructions for adding new newsletters.
Dashboard & UI Integration
apps/web/src/components/dashboard/Sidebar.tsx, apps/web/src/components/ui/FaultyTerminal.tsx
Adds newsletter route to sidebar with icon and nested route support; introduces WebGL shader-based terminal component for visual effects.
Landing Page Restructuring
apps/web/src/components/landing-sections/Hero.tsx, apps/web/src/components/landing-sections/navbar.tsx, apps/web/src/app/(main)/(landing)/layout.tsx, apps/web/src/app/(main)/(landing)/page.tsx
Moves Navbar to fixed position within Hero, updates navbar styling/animations, removes duplicate Navbar renders, and adjusts layout spacing.
Blog Page Refactoring
apps/web/src/app/(main)/blogs/page.tsx, apps/web/src/components/blogs/BlogHeader.tsx
Introduces UnifiedPost type for flexible post rendering, updates filtering/sorting logic, and enhances header styling with semi-transparent sticky behavior.
Configuration & Dependencies
apps/web/next.config.js, apps/web/package.json, apps/api/package.json
Adds Unsplash remote pattern for images, adds ogl dependency, updates postinstall script to Node.js inline check for prisma schema.
Middleware
apps/web/src/middleware.ts
Disables authentication middleware by returning NextResponse.next() unconditionally.

Sequence Diagram

sequenceDiagram
    participant User
    participant Browser
    participant NewslettersPage
    participant useSubscription
    participant PricingPage
    participant NewsletterDetail

    User->>Browser: Navigate to /dashboard/newsletters
    Browser->>NewslettersPage: Load page
    NewslettersPage->>useSubscription: Check subscription status
    alt User is Pro/Paid
        useSubscription-->>NewslettersPage: isPaidUser = true
        NewslettersPage->>NewslettersPage: Render newsletter list<br/>(filtered, sorted by date)
        NewslettersPage-->>Browser: Show newsletters
        User->>Browser: Click newsletter card
        Browser->>NewsletterDetail: Load /dashboard/newsletters/[id]
        NewsletterDetail->>useSubscription: Verify subscription
        useSubscription-->>NewsletterDetail: isPaidUser = true
        NewsletterDetail->>NewsletterDetail: Render header image<br/>+ FaultyTerminal + content
        NewsletterDetail-->>Browser: Display newsletter detail
    else User is not Pro
        useSubscription-->>NewslettersPage: isPaidUser = false
        NewslettersPage->>PricingPage: Redirect to /pricing
        PricingPage-->>Browser: Show pricing page
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • FaultyTerminal.tsx: WebGL shader implementation with GLSL code, uniform management, and resource cleanup requires careful review for correctness and performance.
  • NewslettersPage.tsx: Complex search/filter logic with state management, grouping by year/month, and animation integration needs verification of filtering accuracy.
  • middleware.ts: Complete disabling of authentication middleware warrants clarification of intent and security implications.
  • blogs/page.tsx refactoring: New unified type and filtering/sorting logic must be validated for correctness and data consistency.
  • Landing page restructuring: Multiple navbar/Hero changes across files with positioning/z-index updates need visual verification.

Possibly related issues

  • [bounty-to-hire]: create ui for newsletter #155 ([bounty-to-hire]: create ui for newsletter) — This PR directly implements all core requirements from the bounty issue: newsletter listing by date, rich content support (text, headings, bold, links, images), pro-user gating with redirects, sidebar integration, code-based content management, and comprehensive documentation.

Possibly related PRs

  • fix: UI Responsiveness of Landing Page #142 — Both PRs modify Hero.tsx and navbar.tsx landing components with overlapping layout/navbar responsiveness and styling changes.
  • auto onboarding #131 — This PR depends on subscription/payment hooks and backend subscription APIs introduced in that PR for pro-user access control.
  • [feat] add blogs #147 — Both PRs modify blogs/page.tsx; this PR refactors blog filtering/sorting logic while that PR originally added the blogs page functionality.

Poem

📰 Through fiber-optic burrows I hop,
Where newsletters bloom and never stop,
Pro users gather 'round my markdown throne,
Rich content rendered, shader-bright and known,
A feast of data, styled with shader glow,
Listen, dear reader—the newsletter show! ✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Several changes appear out of scope: middleware disabling authentication, landing page navbar removal/relocation, blog posts unification, and navbar styling changes are unrelated to the newsletter feature requirements. Remove unrelated changes such as middleware modifications, landing page restructuring, and blog page updates to keep the PR focused on newsletter implementation.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Implementation of NewsLetter' is generic and lacks specificity about the main changes—it doesn't convey the UI/dashboard aspect or key features like search/filtering. Use a more specific title like 'Add newsletter dashboard for pro users with search and filtering' to better summarize the primary contribution.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR successfully implements all core requirements: newsletter listing with date organization [#155], rich content support with text/links/images [#155], sample newsletters for testing [#155], documentation on adding newsletters [#155], and search/filter functionality [#155].
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@cla-assistant
Copy link

cla-assistant bot commented Nov 14, 2025

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

1 similar comment
@cla-assistant
Copy link

cla-assistant bot commented Nov 14, 2025

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/src/app/(main)/(landing)/page.tsx (1)

8-8: Remove unused import.

The Navbar is imported but no longer used in this file (line 18 has its usage commented out). Remove this import to keep the code clean.

-import Navbar from '@/components/landing-sections/navbar'
apps/web/src/components/dashboard/Sidebar.tsx (1)

29-45: Gate the Newsletters sidebar item behind subscription to match the documented behavior

Right now the “Newsletters” item is rendered for everyone, even though:

  • You’re already calling useSubscription() and reading isPaidUser.
  • NEWSLETTER_GUIDE.md explicitly says “The newsletter link in the sidebar only appears for pro users.”

This is just a UI mismatch (users get redirected later), but it’s easy to align behavior with the docs by gating the route inside the map:

-        {SIDEBAR_ROUTES.map((route) => {
-          const isActive = pathname === route.path || pathname.startsWith(`${route.path}/`);
+        {SIDEBAR_ROUTES.map((route) => {
+          if (route.path === "/dashboard/newsletters" && !isPaidUser) {
+            return null;
+          }
+
+          const isActive =
+            pathname === route.path ||
+            pathname.startsWith(`${route.path}/`);
           const activeClass = isActive ? "text-ox-purple" : "text-ox-white";
           return (
             <Link href={route.path} className={activeClass} key={route.path}>
               <SidebarItem
                 itemName={route.label}
                 icon={route.icon}
                 collapsed={isCollapsed}
               />
             </Link>
           );
         })}

(Feel free to add a requiresPro flag on the route definition instead of hard‑coding the path if you prefer.)

Also, getSidebarLinkClassName is now unused and could be dropped in a later tidy‑up.

Also applies to: 57-57, 125-137

🧹 Nitpick comments (10)
apps/api/package.json (1)

11-11: Consider extracting the inline script to a separate file for maintainability.

While the inline Node script works, the complexity makes it difficult to read and modify. Extracting this to a separate scripts/postinstall.js file would improve maintainability and allow for better error logging if needed.

// scripts/postinstall.js
const fs = require('fs');
const { execSync } = require('child_process');

try {
  if (fs.existsSync('prisma/schema.prisma')) {
    execSync('prisma generate', { stdio: 'inherit' });
  }
} catch (e) {
  // Silent fail to match original behavior
}

Then in package.json:

-"postinstall": "node -e \"try { if (require('fs').existsSync('prisma/schema.prisma')) require('child_process').execSync('prisma generate', {stdio: 'inherit'}); } catch(e) {}\""
+"postinstall": "node scripts/postinstall.js"
apps/web/src/app/(main)/blogs/page.tsx (3)

16-17: Question the necessity of UnifiedPost abstraction.

The UnifiedPost type currently only wraps blog posts with a discriminator. This adds complexity without an obvious immediate benefit. Is this preparing to merge newsletters with blogs in the future? If not, consider simplifying by using BlogPost directly.

If the intent is to eventually show newsletters alongside blogs on this page, please document that intent in a comment or the PR description.


41-45: Consider extracting date parsing logic to a shared utility.

The parseDate function parses the "DD-MM-YY" date format. If this format is used elsewhere in the codebase (e.g., newsletter dates), consider extracting it to a shared utility function to avoid duplication.

Create a utility file apps/web/src/lib/dateUtils.ts:

export function parseBlogDate(dateStr: string): Date {
  const [day, month, year] = dateStr.split("-").map(Number);
  return new Date(2000 + year, month - 1, day);
}

Then use it in the component:

+import { parseBlogDate } from "@/lib/dateUtils";
+
 // Sort by date
 return filtered.sort((a, b) => {
-  const parseDate = (dateStr: string) => {
-    const [day, month, year] = dateStr.split("-").map(Number);
-    return new Date(2000 + year, month - 1, day);
-  };
-  return parseDate(b.date).getTime() - parseDate(a.date).getTime();
+  return parseBlogDate(b.date).getTime() - parseBlogDate(a.date).getTime();
 });

22-31: Simplified mapping adds unnecessary overhead.

The allPosts array currently just maps blogs into the same structure with an added type field. Since you're only using blogs here, this adds cognitive overhead without functional benefit.

apps/web/package.json (1)

33-33: New ogl dependency – confirm types and bundle impact

Adding ogl to back the FaultyTerminal component makes sense. Please just double‑check:

  • That you either have TypeScript typings for ogl or a small ambient declare module "ogl"; somewhere to keep TS happy.
  • That the bundle impact is acceptable; if this WebGL effect stays confined to the newsletter detail header, a future enhancement could be to lazy‑load it to keep the core dashboard bundle lighter.

Separately (not caused by this PR), next: "15.5.3" is currently paired with react/react-dom 18.2.0; Next 15’s docs expect React 19+. Worth verifying the overall app’s React version upgrade plan in a follow‑up.

apps/web/src/data/NEWSLETTER_GUIDE.md (1)

60-79: Inline content example doesn’t match the renderer’s paragraph grouping

With the current NewsletterContent logic, this example:

{ type: "heading", level: 1, content: "Welcome!" },
{ type: "paragraph", content: "This is a paragraph with " },
{ type: "bold", content: "bold text" },
{ type: "text", content: " and a " },
{ type: "link", text: "link", url: "https://opensox.ai" },
{ type: "text", content: "." },

will render as two separate paragraphs (the paragraph item becomes its own block; subsequent inline items are grouped into another block), not a single line of text.

To match how the renderer actually works and avoid confusing future authors, consider updating the example like:

-    { type: "paragraph", content: "This is a paragraph with " },
+    { type: "text", content: "This is a paragraph with " },

and/or explicitly stating that:

  • paragraph is for standalone block paragraphs, and
  • text/bold/link are intended to be combined within the same paragraph (typically ended with an empty paragraph item for spacing).

Also applies to: 83-86

apps/web/src/app/(main)/dashboard/newsletters/page.tsx (3)

55-66: Search helper is correct but non‑exhaustive for future content types

getNewsletterTextContent correctly pulls text from current block types and is used consistently in the search filter. However, if new NewsletterContentType variants are added later (e.g., lists, code blocks), they’ll silently be excluded from search results.

Consider either:

  • Centralizing “to plain text” logic next to the NewsletterContentType definition, or
  • Using a switch with an exhaustive check (and a fallback that logs when a new type is unhandled),

so new content variants automatically participate in search.

Also applies to: 68-82


46-52: Month filter options are global, not per year

availableMonths is computed from all newsletters once, and the month chips are rendered independently of the selected year. If your data eventually spans multiple years, picking a month plus a year with no newsletters will show a “No newsletters found” state even though that month might exist in other years.

If you intend the month filter to be contextual to the selected year, consider recomputing available months based on selectedYear (or showing only months that have data for the chosen year).

Also applies to: 301-335


339-347: Avoid recomputing the total results count twice

The total results count is computed via filteredAndGroupedNewsletters.reduce(...) twice in the same expression. It’s minor, but you can simplify and avoid duplicate work:

-  {(searchQuery || selectedYear !== null || selectedMonth !== null) && (
-    <div className="text-sm text-[#9b9a97]">
-      {filteredAndGroupedNewsletters.reduce(
-        (sum, group) => sum + group.newsletters.length,
-        0
-      )}{" "}
-      newsletter{filteredAndGroupedNewsletters.reduce((sum, group) => sum + group.newsletters.length, 0) !== 1 ? "s" : ""} found
-    </div>
-  )}
+  {(searchQuery || selectedYear !== null || selectedMonth !== null) && (() => {
+    const total = filteredAndGroupedNewsletters.reduce(
+      (sum, group) => sum + group.newsletters.length,
+      0
+    );
+    return (
+      <div className="text-sm text-[#9b9a97]">
+        {total} newsletter{total !== 1 ? "s" : ""} found
+      </div>
+    );
+  })()}

This keeps the JSX clearer and slightly reduces repeated work.

apps/web/src/data/newsletters.ts (1)

28-99: Seed data looks good; double‑check external assets and future extensibility

The two sample newsletters cover headings, paragraphs, bold text, links, and images, which is a good functional test set for the renderer and search. A couple of minor checks:

  • All date values use the documented YYYY-MM-DD format and appear consistent with the archive sorting logic in the page.
  • The headerImage and image.src fields all point to Unsplash; as noted in the page review, confirm these domains are whitelisted in your Next.js image config.
  • If you plan to actively use the optional category field in the UI later, consider adding at least one example here so downstream components have real data to exercise.

Nothing blocking, just small data/UX considerations.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5445fd9 and 43adae3.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (18)
  • NEWSLETTER_IMPLEMENTATION.md (1 hunks)
  • apps/api/package.json (1 hunks)
  • apps/web/next.config.js (1 hunks)
  • apps/web/package.json (1 hunks)
  • apps/web/src/app/(main)/(landing)/layout.tsx (1 hunks)
  • apps/web/src/app/(main)/(landing)/page.tsx (1 hunks)
  • apps/web/src/app/(main)/blogs/page.tsx (2 hunks)
  • apps/web/src/app/(main)/dashboard/newsletters/[id]/page.tsx (1 hunks)
  • apps/web/src/app/(main)/dashboard/newsletters/page.tsx (1 hunks)
  • apps/web/src/components/blogs/BlogHeader.tsx (1 hunks)
  • apps/web/src/components/dashboard/Sidebar.tsx (4 hunks)
  • apps/web/src/components/landing-sections/Hero.tsx (1 hunks)
  • apps/web/src/components/landing-sections/navbar.tsx (6 hunks)
  • apps/web/src/components/newsletters/NewsletterContent.tsx (1 hunks)
  • apps/web/src/components/ui/FaultyTerminal.tsx (1 hunks)
  • apps/web/src/data/NEWSLETTER_GUIDE.md (1 hunks)
  • apps/web/src/data/newsletters.ts (1 hunks)
  • apps/web/src/middleware.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
apps/web/src/components/newsletters/NewsletterContent.tsx (1)
apps/web/src/data/newsletters.ts (1)
  • NewsletterContentType (11-17)
apps/web/src/components/landing-sections/Hero.tsx (1)
apps/web/src/components/icons/icons.tsx (1)
  • Terminal (1-5)
apps/web/src/components/dashboard/Sidebar.tsx (1)
apps/web/src/hooks/useSubscription.ts (1)
  • useSubscription (11-75)
apps/web/src/app/(main)/dashboard/newsletters/page.tsx (4)
apps/web/src/data/newsletters.ts (2)
  • NewsletterPost (19-26)
  • newsletters (28-99)
apps/web/src/hooks/useSubscription.ts (1)
  • useSubscription (11-75)
apps/web/src/components/ui/SpinnerElm.tsx (1)
  • SpinnerElm (5-17)
apps/web/src/components/ui/FaultyTerminal.tsx (1)
  • FaultyTerminal (244-424)
apps/web/src/components/landing-sections/navbar.tsx (1)
apps/web/src/lib/utils.ts (1)
  • cn (4-6)
apps/web/src/app/(main)/dashboard/newsletters/[id]/page.tsx (4)
apps/web/src/hooks/useSubscription.ts (1)
  • useSubscription (11-75)
apps/web/src/data/newsletters.ts (1)
  • newsletters (28-99)
apps/web/src/components/ui/FaultyTerminal.tsx (1)
  • FaultyTerminal (244-424)
apps/web/src/components/newsletters/NewsletterContent.tsx (1)
  • NewsletterContent (11-165)
apps/web/src/app/(main)/blogs/page.tsx (1)
apps/web/src/data/blogs.ts (2)
  • BlogTag (1-6)
  • blogs (15-70)
🔇 Additional comments (17)
apps/api/package.json (2)

11-11: Cross-platform postinstall script improvement.

The change replaces Unix-specific shell syntax with a Node.js approach, making the postinstall script portable across Windows, macOS, and Linux. The {stdio: 'inherit'} option correctly preserves output visibility.


7-12: Clarify the relationship between this infrastructure change and the newsletter PR.

This postinstall script change appears orthogonal to the newsletter feature PR objectives (design/implementation of newsletter UI, content management, etc.). Please clarify whether this change is a prerequisite for the newsletter feature or should be submitted as a separate PR for better change isolation and review focus.

apps/web/next.config.js (1)

9-12: LGTM! Unsplash domain added for image optimization.

This correctly allows the Next.js Image component to optimize and serve images from Unsplash, which aligns with the newsletter feature's need for external images.

apps/web/src/components/blogs/BlogHeader.tsx (2)

7-7: LGTM! Improved header styling with sticky positioning and blur effect.

The sticky header with backdrop blur and semi-transparent background provides better visual hierarchy and modern UI polish.


11-11: LGTM! Consistent font weight for navigation links.

Adding font-medium to both navigation links improves visual consistency.

Also applies to: 17-17

NEWSLETTER_IMPLEMENTATION.md (1)

1-147: Comprehensive documentation provided.

The documentation thoroughly covers the newsletter feature implementation, including architecture, usage, testing checklist, and future enhancements. This fulfills the PR objective requirement for "documentation on how to add a blog."

apps/web/src/app/(main)/blogs/page.tsx (1)

76-77: Minor: Updated message text is more generic.

Changing from "No blog posts found." to "No posts found." is more generic, which aligns with the UnifiedPost abstraction if you plan to add other content types later.

apps/web/src/components/landing-sections/navbar.tsx (3)

32-34: Navbar now always visible (scroll-hide removed).

The scroll-responsive hiding behavior has been removed for non-pricing pages. The navbar now remains visible at all times. This is a UX change that may improve navigation discoverability but removes the immersive full-screen scroll experience.

If this change was intentional, consider documenting the reasoning. If not, the previous scroll-hide logic should be restored.


49-56: LGTM! Modern glassmorphism styling with improved entrance animation.

The updated styling (rounded corners, semi-transparent background with blur) provides a modern, polished appearance. The extended entrance animation with vertical offset creates a smoother initial render.


80-90: LGTM! Improved link styling with transitions.

The white/white-90 color scheme with transition-colors provides better contrast and smooth hover interactions.

apps/web/src/components/landing-sections/Hero.tsx (1)

8-87: Hero layout and fixed Navbar integration look good

The fixed Navbar, hero spacing, background image layering, and CTA setup are all consistent and should behave well across breakpoints. No changes needed here.

apps/web/src/components/newsletters/NewsletterContent.tsx (1)

11-163: Newsletter content grouping and rendering look solid

The useMemo block grouping plus renderInlineContent cleanly support headings, images, and inline text/bold/link segments, and the Notion‑style typography/spacing reads well. I don’t see any functional issues here.

apps/web/src/components/ui/FaultyTerminal.tsx (1)

244-399: WebGL lifecycle and FaultyTerminal component structure look well-managed

The component sets up the renderer/program/mesh inside useEffect, wires resize and mouse handlers, and fully cleans up (RAF, observer, DOM node, and GL context) on unmount. Given how stateful WebGL is, this is a solid pattern, and I don’t see correctness issues in the React lifecycle handling.

Also applies to: 421-423

apps/web/src/app/(main)/dashboard/newsletters/page.tsx (3)

22-36: Access control flow is sound for pro-only gating

The combination of subscription-based isLoading handling, early spinner return, redirect effect, and the final if (!isPaidUser) return null ensures non‑paid users never see newsletter content and get pushed to /pricing. This matches the “pro users only” requirement from useSubscription (apps/web/src/hooks/useSubscription.ts) and looks correct.

Also applies to: 138-148


155-183: Overall archive UI, grouping, and card layout look strong

The combination of the header visual (FaultyTerminal banner), year/month grouping, date‑sorted sections, and card layout with header images and clear titles delivers a readable, polished newsletter archive that aligns well with the “Notion‑like, readability‑focused” brief. The grouping and sorting logic (latest first per requirements) also matches the NewsletterPost dates correctly.

Also applies to: 352-441


393-408: Confirm remote image domains are configured for Next.js

Card headers use next/image with Unsplash URLs from newsletter.headerImage. Ensure the Next.js image configuration (likely in the root or app-specific next.config.*) includes images.unsplash.com (and any other domains you plan to use), otherwise images will fail to load at runtime.

apps/web/src/data/newsletters.ts (1)

1-27: Type definitions and inline documentation are clear and extensible

NewsletterContentType and NewsletterPost cleanly model the rich content you need (headings, bold, links, images, paragraphs), and the top comment concisely documents how to add new newsletters, including date format. This should be easy for the team to extend without over‑engineering.

@@ -1,10 +1,10 @@
import Navbar from '@/components/landing-sections/navbar'
// import Navbar from '@/components/landing-sections/navbar'
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Consider removing commented code or clarifying intent.

The Navbar import and rendering are commented out rather than removed. According to the AI summary, the Navbar has been moved to the Hero component, which is an unusual architectural choice since layouts typically house persistent navigation elements.

If this is a temporary change for testing, it should not be merged. If intentional, please remove the commented code and document why the Navbar belongs in the Hero component rather than at the layout level.

Also applies to: 7-7


I'll verify this review comment by examining the codebase structure and confirming the Navbar's actual location and usage.


🏁 Script executed:

#!/bin/bash
# Check the full content of the layout file to see commented code
cat "apps/web/src/app/(main)/(landing)/layout.tsx"

Length of output: 288


🏁 Script executed:

#!/bin/bash
# Search for Navbar usage in Hero component
find . -name "hero*" -type f | grep -i hero | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for imports and usage of Navbar in the codebase
rg -n "Navbar" --type=tsx --type=ts -C 2 | head -50

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check if there are other layouts or pages using the landing layout
rg -n "landing.*layout\|useLayout.*landing" --type=tsx --type=ts | head -20

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Look for any recent comments or documentation about Navbar changes
rg -n "Navbar.*moved\|Hero.*Navbar\|moved.*Hero" --type=tsx --type=ts -C 2

Length of output: 27


I need to correct the ripgrep syntax and search more broadly for the Hero component and Navbar usage.


---

🏁 Script executed:

```shell
#!/bin/bash
# Search for Navbar imports/usages with correct syntax
rg -n "Navbar" -g "*.tsx" -g "*.ts" -C 2 | head -60

Length of output: 3953


🏁 Script executed:

#!/bin/bash
# Find Hero component file(s)
fd -e tsx -e ts -i "hero" 

Length of output: 49


🏁 Script executed:

#!/bin/bash
# Check landing-sections directory for components
ls -la "apps/web/src/components/landing-sections/" 2>/dev/null || echo "Directory not found"

Length of output: 749


🏁 Script executed:

#!/bin/bash
# Search for all imports from navbar component
rg "from.*navbar|import.*[Nn]avbar" -g "*.tsx" -g "*.ts" -C 3

Length of output: 1563


🏁 Script executed:

#!/bin/bash
# Check directory structure of components
find "apps/web/src/components" -type f \( -name "*.tsx" -o -name "*.ts" \) | grep -i "hero\|navbar" | head -20

Length of output: 101


Remove commented code and clean up unused Navbar import.

The Navbar has been intentionally moved to the Hero component where it's rendered as a fixed/floating element—an appropriate architectural choice for landing-page-only navigation. However, commented code should be removed rather than left in the codebase.

Please remove:

  • layout.tsx lines 1 and 7 (commented Navbar import and usage)
  • page.tsx line 8 (unused Navbar import)
  • page.tsx line 18 (commented Navbar usage)
🤖 Prompt for AI Agents
In apps/web/src/app/(main)/(landing)/layout.tsx lines 1 and 7 and
apps/web/src/app/(main)/(landing)/page.tsx lines 8 and 18, remove the commented
Navbar import and commented usage plus the now-unused Navbar import in page.tsx;
delete the commented line "// import Navbar from
'@/components/landing-sections/navbar'" and the commented JSX usage in
layout.tsx, and remove the unused import statement in page.tsx so the codebase
is free of dead/commented Navbar references (Hero continues to render the
Navbar).

return (
<main className='min-h-screen w-full bg-[#101010] text-white font-sans overflow-hidden relative'>
<Navbar />
{/* <Navbar /> */}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove commented code.

Either restore the Navbar rendering or remove the commented line. Commented code should not be committed to version control.

-            {/* <Navbar />  */}
📝 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.

Suggested change
{/* <Navbar /> */}
🤖 Prompt for AI Agents
In apps/web/src/app/(main)/(landing)/page.tsx around line 18, there is a
commented-out Navbar JSX: remove the commented code or re-enable it;
specifically either restore the Navbar component call (<Navbar />) if it should
render on the page, or delete the commented line entirely so no commented code
remains in the committed file. Ensure imports remain consistent (remove unused
Navbar import if you delete the line, or keep/add the import if you re-enable
it).

Comment on lines +1 to +4
"use client";

import { use, useMemo } from "react";
import { newsletters } from "@/data/newsletters";
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Don’t use React use() for params in this client page; read params synchronously

This page is marked "use client", but it treats params as a Promise and uses the experimental use() API:

  • With the current setup (react/react-dom 18.2.0), use is not exported from "react", so this won’t type‑check or run.
  • For client pages in the app router, Next passes params synchronously; you don’t need (and shouldn’t use) use() here.

You can simplify and fix this by making params synchronous and dropping use entirely:

-"use client";
-
-import { use, useMemo } from "react";
+"use client";
+
+import { useMemo } from "react";

 export default function NewsletterDetailPage({
   params,
 }: {
-  params: Promise<{ id: string }>;
+  params: { id: string };
 }) {
-  const { id } = use(params);
+  const { id } = params;
   const { isPaidUser, isLoading } = useSubscription();

(Optionally, you can also simplify the date memo to depend on newsletter instead of newsletter?.date, but that’s non‑blocking.)

Everything else in the page—subscription gating, not‑found handling, header visual, and use of NewsletterContent—looks good.

Also applies to: 15-21, 33-40


I'll verify the review comment by checking the React version, investigating use() availability, and inspecting the actual file content.

Now I need to check the actual package.json and file content to verify which Next.js version is being used:


🏁 Script executed:

#!/bin/bash
# Check package.json for React and Next.js versions
cat package.json | grep -E '"(react|next)"'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Inspect the actual file
cat "apps/web/src/app/(main)/dashboard/newsletters/[id]/page.tsx"

Length of output: 6876


🏁 Script executed:

#!/bin/bash
# Check for any use of useParams hook
grep -r "useParams" "apps/web/src/app/(main)/dashboard/newsletters/[id]/" 2>/dev/null || echo "No useParams found"

Length of output: 18


🏁 Script executed:

#!/bin/bash
# Find all page.tsx files to understand the pattern
find "apps/web/src/app" -name "page.tsx" -type f | head -5

Length of output: 223


🏁 Script executed:

#!/bin/bash
# Check another similar page to see how params are handled
find "apps/web/src/app" -name "[id]" -o -name "[*]" -type d | head -3 | xargs -I {} find {} -name "page.tsx" -exec grep -l "use\|params" {} \; 2>/dev/null | head -3

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look at similar client component pages with params
rg -A5 "use client.*params.*Promise" apps/web/src/app --type ts --type tsx -C2 | head -20

Length of output: 27


Let me search for the package.json and verify the React/Next.js versions:


🏁 Script executed:

#!/bin/bash
# Look for package.json files
find . -maxdepth 2 -name "package.json" -type f

Length of output: 14


🏁 Script executed:

#!/bin/bash
# Check root or apps level for React/Next versions
if [ -f "package.json" ]; then cat package.json | grep -A 50 "dependencies"; fi

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check apps/web package.json
if [ -f "apps/web/package.json" ]; then cat "apps/web/package.json" | grep -A 50 "dependencies"; fi

Length of output: 1327


🏁 Script executed:

#!/bin/bash
# Look for other dynamic pages to see if they also use Promise params
rg -n "params.*Promise" apps/web/src/app --type js --type ts -C2 | head -30

Length of output: 399


🏁 Script executed:

#!/bin/bash
# Alternatively search for params pattern in pages
rg -n "params:" apps/web/src/app -C1 | grep -A 1 -B 1 "Promise\|params:" | head -40

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check if use() is used elsewhere in the codebase
rg -n "from.*react.*use" apps/web/src --type js --type ts | head -10

Length of output: 0


🌐 Web query:

What version of React introduced the `use()` hook?

💡 Result:

The use() API was introduced in React 19. [1][2]

Sources:
[1] React 19 release post (react.dev).
[2] React 19 upgrade guide (react.dev).


🌐 Web query:

In Next.js, do client components receive params as Promise or synchronously?

💡 Result:

Client components receive resolved (synchronous) values — not a Promise. The App Router's page/server component may receive params as a Promise (you await them on the server), but when you pass params down as props to a "use client" component they are serialized and delivered as normal values. [1][2]

Sources:
[1] Next.js App Router examples showing page params typed as Promise and awaited in a Server Component.
[2] Next.js docs on Server/Client Components and passing data (props) from Server → Client.


Remove use() import and treat params as synchronous—this code will crash with React 18.2.0

This page is marked "use client", but it incorrectly treats params as a Promise and uses the use() hook:

The problem:

  • Your codebase uses React 18.2.0, but use() was not introduced until React 19—the import will fail at runtime with TypeError: use is not a function
  • Next.js 15.5.3 client components receive params synchronously as normal props, not as a Promise; only server components receive Promise-typed params
  • This page is the only one in the app using this incorrect pattern

Fix:

-import { use, useMemo } from "react";
+import { useMemo } from "react";

 export default function NewsletterDetailPage({
   params,
 }: {
-  params: Promise<{ id: string }>;
+  params: { id: string };
 }) {
-  const { id } = use(params);
+  const { id } = params;

Everything else—subscription gating, routing, and layout—is correct.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/web/src/app/(main)/dashboard/newsletters/[id]/page.tsx around lines 1 to
4, the component is a client component but imports and calls React's use() and
treats params as a Promise which will fail on React 18.2.0 and Next.js client
components; remove the use import and any calls to use(), accept params
synchronously from the component props (function signature should read ( {
params } ) ), treat params.id as a plain string, look up the newsletter
synchronously from newsletters (no await), and remove any async/Promise handling
related to params so the page runs as a normal client component.

Comment on lines +5 to +6
// TEMPORARILY DISABLED FOR UI DEVELOPMENT - REMOVE THIS COMMENT AND UNCOMMENT BELOW WHEN DONE
return NextResponse.next();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

CRITICAL: Authentication is completely disabled.

The middleware immediately returns NextResponse.next() without any authentication checks, bypassing all protected route security. This means anyone can access the /dashboard routes without logging in, completely defeating the pro-user newsletter restrictions described in the PR objectives.

This temporary development workaround must be reverted before merging to main.

Apply this diff to restore authentication:

-  // TEMPORARILY DISABLED FOR UI DEVELOPMENT - REMOVE THIS COMMENT AND UNCOMMENT BELOW WHEN DONE
-  return NextResponse.next();
-  
-  /* ORIGINAL AUTH CODE - UNCOMMENT WHEN DONE WITH UI WORK
   const adaptedReq = {
     headers: req.headers,
     cookies: req.cookies,
   };
   const token = await getToken({
     req: adaptedReq as any,
     secret: process.env.NEXTAUTH_SECRET,
   });
   const protectedPaths = ["/dashboard"];
   if (protectedPaths.some((path) => req.nextUrl.pathname.startsWith(path))) {
     if (!token) {
       const signInUrl = new URL("/login", req.url);
       return NextResponse.redirect(signInUrl);
     }
   }
   return NextResponse.next();
-  */

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +33 to +36
4. **Pro User Protection**
- Newsletter pages are only accessible to pro users
- Non-pro users are automatically redirected to pricing page
- Newsletter link in sidebar only appears for pro users
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Documentation contradicts middleware implementation.

The documentation states that "Newsletter pages are only accessible to pro users" and "Non-pro users are automatically redirected to pricing page," but the middleware.ts file has authentication completely disabled. This means the documented security feature is not actually functioning.

Ensure the authentication middleware is re-enabled before merging, or update this documentation to reflect the actual implementation.

🤖 Prompt for AI Agents
In NEWSLETTER_IMPLEMENTATION.md around lines 33 to 36, the doc claims
"Newsletter pages are only accessible to pro users" and "Non-pro users are
automatically redirected to pricing page" but the middleware was disabled;
either re-enable the authentication/authorization middleware in middleware.ts so
it checks user subscription status and redirects non-pro users to the pricing
page (and gate the sidebar link rendering behind the same pro-check), or update
these lines to accurately reflect the current behavior; after making the change,
run relevant route/middleware tests and update any frontend conditional that
renders the newsletter sidebar link to match the enforced policy.

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.

[bounty-to-hire]: create ui for newsletter

1 participant