Skip to content

feat: donation form API wiring and shared marketing container - #139

Merged
Smartlify07 merged 20 commits into
mainfrom
feat/donation-form-api
Aug 8, 2026
Merged

feat: donation form API wiring and shared marketing container#139
Smartlify07 merged 20 commits into
mainfrom
feat/donation-form-api

Conversation

@Smartlify07

@Smartlify07 Smartlify07 commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Wire donation form to /api/donations\ (Stripe Checkout) with react-hook-form validation
  • Auto-select second donation amount () by default
  • Gate submit on confirmation checkbox
  • Add drop shadow to donation card
  • Add reusable .marketing-container\ utility class and apply across marketing page sections
  • Update course detail pages to use shared container; remove leftover \console.log/spinner CSS

Verification


  • px tsc --noEmit\ clean
  • Production build compiles (only pre-existing missing \RESEND_API_KEY\ env failure during page-data collection)

Summary by CodeRabbit

  • New Features

    • Added a validated donation form with 3% fee calculation, payment confirmation, checkout redirection, loading states, and error messages.
    • Renamed the marketing “Courses” heading to “Trainings.”
  • Improvements

    • Refreshed responsive layouts and spacing across marketing pages and the dashboard.
    • Improved course card sizing, button styling, and support-section presentation.
    • Donation totals now remain consistent throughout checkout and confirmation.
  • Bug Fixes

    • Improved server error logging for more reliable troubleshooting.

@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
modern-advocates Building Building Preview Aug 8, 2026 8:35pm

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9515e224-c1e8-478f-b30e-25a85b8d0e06

📥 Commits

Reviewing files that changed from the base of the PR and between 8008dc6 and b732cca.

📒 Files selected for processing (4)
  • src/app/(user)/dashboard/page.tsx
  • src/features/marketing/components/footer.tsx
  • src/features/user-dashboard/components/course-player-navbar.tsx
  • src/features/user-dashboard/components/dashboard-navbar.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/features/user-dashboard/components/dashboard-navbar.tsx
  • src/app/(user)/dashboard/page.tsx
  • src/features/marketing/components/footer.tsx

📝 Walkthrough

Walkthrough

The PR adds a shared marketing container class, updates donation pricing and checkout submission, and adjusts course, dashboard, and marketing presentation. It also logs unhandled API errors before Sentry capture.

Changes

Marketing layout and donation updates

Layer / File(s) Summary
Shared container migration
src/app/globals.css, src/shared/ui/marketing-container.tsx, src/features/marketing/components/*, src/app/(user)/dashboard/page.tsx, src/features/user-dashboard/components/*, src/features/courses/components/*
Adds a shared container utility and applies it across marketing, dashboard, course, and contact layouts.
Donation pricing and checkout flow
src/features/marketing/lib/donation-pricing.ts, src/features/marketing/components/donation-form.tsx, src/features/marketing/components/donation-support-section.tsx, src/app/api/donations/route.ts, src/app/(marketing)/donation/success/page.tsx
Adds donation fee and total helpers, validated donation form state, checkout submission, and consistent charged and displayed totals.
Course and marketing presentation updates
src/features/courses/components/*, src/features/marketing/components/course-detail-*.tsx, src/features/marketing/components/courses-hero-section.tsx, src/features/marketing/components/donation-hero-section.tsx, src/features/marketing/components/footer.tsx, src/features/marketing/components/contact-hero-section.tsx, src/shared/ui/marketing-button.tsx, src/features/user-dashboard/components/*
Updates widths, labels, spacing, content, and JSX formatting across course, marketing, and dashboard UI.
Unhandled error logging
src/shared/lib/api-handler.ts
Logs unhandled API errors before Sentry capture and the generic 500 response.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Donor
  participant DonationForm
  participant DonationsAPI
  participant Checkout
  Donor->>DonationForm: Enter validated donation details
  DonationForm->>DonationsAPI: Submit donation data
  DonationsAPI-->>DonationForm: Return checkout URL
  DonationForm->>Checkout: Redirect to checkout URL
Loading

Possibly related PRs

Poem

A rabbit counts each coin with care,
Then hops to checkout путь?
Shared containers line the path,
While totals add without any wrath.
One neat form, and off it goes!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two primary changes: donation form API integration and the shared marketing container.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/donation-form-api

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.

# Conflicts:
#	src/features/marketing/components/donation-support-section.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Nitpick comments (6)
src/features/marketing/components/donation-hero-section.tsx (1)

12-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Two line-height utilities conflict on the heading.

text-[28px]/[100%] already sets line-height: 100%. leading-[1.16] sets it again on the same element. This class list is a plain string, so cn/twMerge does not resolve the conflict and the applied value depends on stylesheet order. Keep one.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-hero-section.tsx` at line 12,
Remove the conflicting leading-[1.16] utility from the h1 class list, keeping
the line height defined by text-[28px]/[100%] and the existing responsive
sm:leading-[70px] and lg:text-[60px]/[70px] rules.
src/features/marketing/components/donation-form.tsx (2)

257-267: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider keeping the submit button enabled and showing the reason.

The button is disabled until the checkbox is checked. A user who misses the checkbox sees no explanation. If you enforce confirmation in the schema, you can drop !isConfirmed from disabled and let the field error explain the block.

Add aria-busy={submitting} so assistive technology announces the pending state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-form.tsx` around lines 257 - 267,
Update the submit Button in the donation form to disable only while submitting,
allowing schema validation to surface the confirmation field error when
unchecked. Add aria-busy={submitting} to expose the pending state to assistive
technology, preserving the existing loading indicator and submission behavior.

224-242: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Render the validation message for the confirmation field.

The Field for confirmation has no FieldError. If you tighten the schema as suggested at lines 38-46, the failure produces no visible message.

🔧 Proposed fix
-            render={({ field }) => (
+            render={({ field, fieldState }) => (
               <Field orientation="horizontal">
                 <Checkbox
                   id="donation-confirmation"
                   checked={field.value}
                   onCheckedChange={(checked) =>
                     field.onChange(checked === true)
                   }
                   className="data-checked:border-ma-admin-primary data-checked:bg-ma-admin-primary"
                 />
                 <FieldLabel htmlFor="donation-confirmation" className="w-fit">
                   Authorize payment processing at the checkout page
                 </FieldLabel>
+                <FieldError errors={[fieldState.error]} />
               </Field>
             )}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-form.tsx` around lines 224 - 242,
Add a FieldError for the confirmation Controller’s Field so validation failures
from the confirmation schema are visibly rendered, while preserving the existing
Checkbox and FieldLabel behavior.
src/features/marketing/components/about-hero-section.tsx (1)

13-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Marketing sections apply the raw marketing-container class instead of the shared component. src/shared/ui/marketing-container.tsx exists for this purpose and adds data-slot="marketing-container". Each migrated section hand-writes the class on a plain div, which duplicates the component and drops the data attribute.

  • src/features/marketing/components/about-hero-section.tsx#L13-L14: replace the div.marketing-container with <MarketingContainer> and close it at line 89.
  • src/features/marketing/components/faq.tsx#L47-L48: replace the div.marketing-container with <MarketingContainer> and close it at line 98.
  • src/features/marketing/components/stories-from-our-community-section.tsx#L74-L75: replace the div.marketing-container with <MarketingContainer> and close it at line 139.

As per coding guidelines: "Reuse shared UI components from shared/ui and marketing components from features/marketing/components instead of creating duplicates."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/about-hero-section.tsx` around lines 13 -
14, Replace each raw marketing-container div with the shared MarketingContainer
component, preserving its existing children and closing the component around the
same content. Apply this in
src/features/marketing/components/about-hero-section.tsx lines 13-14 through 89,
src/features/marketing/components/faq.tsx lines 47-48 through 98, and
src/features/marketing/components/stories-from-our-community-section.tsx lines
74-75 through 139; import MarketingContainer from shared UI where needed.

Source: Coding guidelines

src/features/marketing/components/invest-in-hope-section.tsx (2)

6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Both donation sections hard-code the arbitrary hex #ECE8FF. No design token exists for this surface color, so each section inlines the value. Add the token once, then reference it.

  • src/features/marketing/components/invest-in-hope-section.tsx#L6-L6: replace bg-[#ECE8FF] with the new token class.
  • src/features/marketing/components/donation-support-section.tsx#L5-L5: replace bg-[#ECE8FF] with the same token class.

Define the token in the @theme block of src/app/globals.css.

As per coding guidelines: "Do not use arbitrary hex colors or spacing; use the repository's design tokens."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/invest-in-hope-section.tsx` at line 6, Add
a named surface-color token for `#ECE8FF` in the `@theme` block of
src/app/globals.css, then replace the arbitrary bg-[`#ECE8FF`] class in
InvestInHopeSection at
src/features/marketing/components/invest-in-hope-section.tsx:6-6 and
DonationSupportSection at
src/features/marketing/components/donation-support-section.tsx:5-5 with the
shared token class.

Source: Coding guidelines


4-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate the duplicate donation sections.

InvestInHopeSection and DonationSupportSection both render the same "Invest in Hope" copy, background, and <DonationForm />, with the main difference being heading/spacing variants. Keep one component and remove the duplicate, or extract a shared section wrapper.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/invest-in-hope-section.tsx` around lines 4
- 24, Consolidate the duplicated donation-section implementation by reusing a
single shared component between InvestInHopeSection and DonationSupportSection.
Preserve the existing “Invest in Hope” copy, background styling, DonationForm
rendering, and each section’s required heading or spacing variant; remove the
redundant implementation rather than maintaining two equivalent sections.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/marketing/components/course-detail-content-section.tsx`:
- Around line 25-42: Move the shared CourseContentData type from
course-detail-content-section.tsx into a common module, then import and reuse it
in both CourseDetailContentSection and CourseInformationCard. Remove the
duplicate local definition from course-information-card.tsx while preserving the
existing payload shape.

In `@src/features/marketing/components/course-detail-hero-section.tsx`:
- Line 30: Update the Image component’s sizes configuration in the course detail
hero section to reflect the responsive grid: add a breakpoint for the two-column
sm layout and retain matching entries for lg and 2xl, with the default covering
widths below sm. Ensure each sizes value represents the image’s actual container
width at its breakpoint.

In `@src/features/marketing/components/donation-form.tsx`:
- Around line 66-80: Align the donation submission and displayed summary in
onSubmit with the intended administration-fee behavior: if donors are charged
the fee, submit total instead of data.amount and ensure the summary remains
amount plus fee; otherwise remove the fee from the Total calculation and
display. Keep the amount used for the API request and the value shown to donors
consistent.
- Around line 119-137: Update the preset buttons in the Controller render to use
field.onChange(price.amount) instead of form.setValue, and add
aria-pressed={watchedAmount === price.amount} so assistive technology exposes
the selected amount while preserving the existing visual selection logic.
- Around line 96-98: Change the card title heading in DonationForm from h1 to
the next appropriate lower-level heading, preserving its existing text and
styling so pages with an existing h1 maintain a valid heading hierarchy.
- Around line 38-46: Update donationFormSchema so amount enforces the API’s
minimum of 0.5 with an appropriate validation message, and replace
confirmation’s boolean schema with a literal true requirement using the
specified authorization error. Preserve the existing positive amount and other
field validations.
- Line 82: Guard the donation submission redirect around result.url before
calling window.location.assign in the form submit handler. Treat a missing or
null checkout URL as an error and route it through the existing catch/error
path, while preserving the redirect behavior for valid URLs and aligning the
response type with the nullable session.url value.

In `@src/features/marketing/components/donation-hero-section.tsx`:
- Around line 24-31: Update the alt text on the Image using melanie-and-will.png
to describe both founders, matching the “Melanie And Will” and “Founders” naming
used by the adjacent card instead of naming only Melanie as a singular founder.

In `@src/features/marketing/components/donation-support-section.tsx`:
- Line 19: Update DonationForm to use React.useId() for the form and each
related field id instead of hard-coded donation-form, donation-amount,
donor-name, and donor-email values. Ensure every label htmlFor and corresponding
input id uses the generated identifiers, so multiple DonationForm instances
rendered by DonationSupportSection and InvestInHopeSection remain independent.

In `@src/features/marketing/components/footer.tsx`:
- Line 16: Update the footer grid container’s xl gap in the surrounding JSX to
use an existing spacing or named repository design token instead of the
arbitrary 140px value, while preserving the current responsive grid layout.

---

Nitpick comments:
In `@src/features/marketing/components/about-hero-section.tsx`:
- Around line 13-14: Replace each raw marketing-container div with the shared
MarketingContainer component, preserving its existing children and closing the
component around the same content. Apply this in
src/features/marketing/components/about-hero-section.tsx lines 13-14 through 89,
src/features/marketing/components/faq.tsx lines 47-48 through 98, and
src/features/marketing/components/stories-from-our-community-section.tsx lines
74-75 through 139; import MarketingContainer from shared UI where needed.

In `@src/features/marketing/components/donation-form.tsx`:
- Around line 257-267: Update the submit Button in the donation form to disable
only while submitting, allowing schema validation to surface the confirmation
field error when unchecked. Add aria-busy={submitting} to expose the pending
state to assistive technology, preserving the existing loading indicator and
submission behavior.
- Around line 224-242: Add a FieldError for the confirmation Controller’s Field
so validation failures from the confirmation schema are visibly rendered, while
preserving the existing Checkbox and FieldLabel behavior.

In `@src/features/marketing/components/donation-hero-section.tsx`:
- Line 12: Remove the conflicting leading-[1.16] utility from the h1 class list,
keeping the line height defined by text-[28px]/[100%] and the existing
responsive sm:leading-[70px] and lg:text-[60px]/[70px] rules.

In `@src/features/marketing/components/invest-in-hope-section.tsx`:
- Line 6: Add a named surface-color token for `#ECE8FF` in the `@theme` block of
src/app/globals.css, then replace the arbitrary bg-[`#ECE8FF`] class in
InvestInHopeSection at
src/features/marketing/components/invest-in-hope-section.tsx:6-6 and
DonationSupportSection at
src/features/marketing/components/donation-support-section.tsx:5-5 with the
shared token class.
- Around line 4-24: Consolidate the duplicated donation-section implementation
by reusing a single shared component between InvestInHopeSection and
DonationSupportSection. Preserve the existing “Invest in Hope” copy, background
styling, DonationForm rendering, and each section’s required heading or spacing
variant; remove the redundant implementation rather than maintaining two
equivalent sections.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a2654df9-0a7b-4000-ab93-014dbd64b74a

📥 Commits

Reviewing files that changed from the base of the PR and between dd000ca and c17e01f.

⛔ Files ignored due to path filters (6)
  • public/figma-home/downloaded-node-2800-19876.png is excluded by !**/*.png
  • public/figma-home/downloaded-node-2800-19884.png is excluded by !**/*.png
  • public/figma-home/downloaded-node-2800-19886.png is excluded by !**/*.png
  • public/figma-home/downloaded-node-2800-19890.png is excluded by !**/*.png
  • public/figma-home/downloaded-node-2800-19892.png is excluded by !**/*.png
  • public/figma-home/downloaded-node-2863-17140.png is excluded by !**/*.png
📒 Files selected for processing (29)
  • src/app/globals.css
  • src/features/courses/components/course-card.tsx
  • src/features/courses/components/enroll-now-button.tsx
  • src/features/marketing/components/about-hero-section.tsx
  • src/features/marketing/components/about-our-values-section.tsx
  • src/features/marketing/components/about-support-mission-section.tsx
  • src/features/marketing/components/community-section.tsx
  • src/features/marketing/components/course-detail-content-section.tsx
  • src/features/marketing/components/course-detail-hero-section.tsx
  • src/features/marketing/components/course-information-card.tsx
  • src/features/marketing/components/courses-hero-section.tsx
  • src/features/marketing/components/cta-section.tsx
  • src/features/marketing/components/donation-cta-section.tsx
  • src/features/marketing/components/donation-form.tsx
  • src/features/marketing/components/donation-hero-section.tsx
  • src/features/marketing/components/donation-support-section.tsx
  • src/features/marketing/components/empowerment-section.tsx
  • src/features/marketing/components/faq.tsx
  • src/features/marketing/components/footer.tsx
  • src/features/marketing/components/how-can-we-help.tsx
  • src/features/marketing/components/how-can-we-support.tsx
  • src/features/marketing/components/invest-in-hope-section.tsx
  • src/features/marketing/components/mission-sections.tsx
  • src/features/marketing/components/our-vision-section.tsx
  • src/features/marketing/components/practical-pathways-section.tsx
  • src/features/marketing/components/stories-from-our-community-section.tsx
  • src/features/marketing/components/testimonials.tsx
  • src/shared/lib/api-handler.ts
  • src/shared/ui/marketing-container.tsx

Comment on lines +25 to +42
modules: {
id: string
title: string
sortOrder: number
topics: {
id: string
title: string
format: string
content: string | null
}[]
}[]
reviews: {
id: string
body: string | null
rating: number
studentName: string | null
studentImage: string | null
}[]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Move CourseContentData to one shared type definition.

CourseContentData is duplicated in src/features/marketing/components/course-information-card.tsx. Move the course payload type to one shared module and import it from both components.

As per coding guidelines, do not redefine DTOs or query keys in multiple places.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/course-detail-content-section.tsx` around
lines 25 - 42, Move the shared CourseContentData type from
course-detail-content-section.tsx into a common module, then import and reuse it
in both CourseDetailContentSection and CourseInformationCard. Remove the
duplicate local definition from course-information-card.tsx while preserving the
existing payload shape.

Source: Coding guidelines

return (
<section className="bg-ma-surface-2 py-10 text-ma-text sm:py-[90px] lg:py-16">
<div className="mx-auto grid gap-5 rounded-card-2 px-4 lg:max-w-7xl lg:grid-cols-2 lg:px-25 2xl:max-w-360 2xl:px-50">
<div className="marketing-container grid gap-5 py-0! sm:grid-cols-2 sm:py-0">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

hero="src/features/marketing/components/course-detail-hero-section.tsx"
globals="src/app/globals.css"

rg -n 'sm:grid-cols-2|sizes=' "$hero"
rg -n -A2 -B1 '\.marketing-container' "$globals"

if ! rg -q 'min-width: 640px' "$hero"; then
  echo "Missing an sm-specific Image.sizes entry" >&2
  exit 1
fi

Repository: Smartlify07/Modern-Advocates

Length of output: 507


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "Changed files/stat:"
git diff --stat || true

echo
echo "Relevant source:"
sed -n '1,70p' src/features/marketing/components/course-detail-hero-section.tsx

echo
echo "globals marketing-container:"
sed -n '180,200p' src/app/globals.css

echo
echo "Tailwind/config size hints for marketing and spacing:"
rg -n "\bmarketing-container\b|\.marketing-container|1024px|--breakpoints|screens:|spacing" -S . --glob 'tailwind.config.*' --glob '*.config.*' --glob '*.css' --glob '*.jsx' --glob '*.tsx' --glob '*.ts' | sed -n '1,200p'

Repository: Smartlify07/Modern-Advocates

Length of output: 8516


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "Tailwind config files:"
fd -a 'tailwind\.config\.(js|cjs|mjs|ts)$' .

echo
echo "Relevant Tailwind config snippets:"
for f in $(fd 'tailwind\.config\.(js|cjs|mjs|ts)$' .); do
  echo "--- $f ---"
  sed -n '1,220p' "$f"
done

echo
echo "CSS custom properties / spacing definitions:"
rg -n 'spacing\[0-9]|spacing-\d+|--spacing|`@theme`|--tw-content-box|`@property`' src --glob '*.css' --glob '*.ts' --glob '*.tsx' --glob '*.js' | sed -n '1,220p'

echo
echo "Global tailwind/theme imports/options:"
rg -n 'tailwind|`@tailwind`|`@config`|designTokens|plugin\(function|function \(\$|const.*breakpoints|--spacing|gap-5' src tailwind.config.* 2>/dev/null | sed -n '1,220p'

echo
echo "JavaScript/static probe for current sizes at selected viewport widths;" \
    "container styles derived from src/app/globals.css"
python3 - <<'PY'
from dataclasses import dataclass
import re

css = open("src/app/globals.css", encoding="utf-8").read()
styles = {}
m = re.search(r'\.marketing-container\s*\{([^}]+)\}', css, re.S)
if m:
    for stmt in re.findall(r'(--?[\w-]+)\s*:\s*([^;]+);', m.group(1)):
        styles[stmt[0]] = stmt[1].strip()

def calc(value, vw):
    for pat in (r'calc\((.+)\)', r'env\((.+)\)'):
        m = re.search(pat, value)
        if m:
            return eval(m.group(1).replace('100vw', f'{vw}'))
    if m := re.search(r'env\(([^)]+)\)', value):
        return eval(m.group(1).replace('100vw', f'{vw}'))
    m = re.search(r'rem\(([^)]+)\)', value)
    if m:
        return float(m.group(1)) * 16
    if value.isdigit():
        return int(value)
    return value

size_expr = '(min-width: 1024px) 510px, calc(100vw - 48px)'
viewport_widths = [320, 640, 1023, 1024, 1280, 1536]
for vw in viewport_widths:
    active = 1024
    if vw >= active:
        sizes = [1024, float('inf')]
        width_hints = [510, f'calc(100vw - 48px)']
    else:
        sizes = [float('-inf'), 1024]
        width_hints = [f'calc(100vw - 48px)']
    # current expression default is calc(100vw - 48px)
    sizes = [float('-inf'), 1024]
    width_hints = [f'calc(100vw - 48px)', 510]
    breakpoint = sizes[1]
except Exception as e:
    breakpoint = vw
except Exception as e:
PY

Repository: Smartlify07/Modern-Advocates

Length of output: 11303


🌐 Web query:

Tailwind CSS v4 default breakpoints px 640 768 1024 1280 1536

💡 Result:

Tailwind CSS v4 uses five default responsive breakpoints, all defined using rem units [1][2][3]. Although these map to common pixel values, Tailwind recommends maintaining the use of rem units for consistency [1][4]. The default breakpoints are as follows [1][2][3]: | Breakpoint prefix | Rem value | Pixel value (approx.) | Media query | | --- | --- | --- | --- | | sm | 40rem | 640px | (width >= 40rem) | | md | 48rem | 768px | (width >= 48rem) | | lg | 64rem | 1024px | (width >= 64rem) | | xl | 80rem | 1280px | (width >= 80rem) | | 2xl | 96rem | 1536px | (width >= 96rem) | In Tailwind CSS v4, you can customize or remove these breakpoints using the @theme directive in your CSS [1][5][6]. To override or add breakpoints, define them within the @theme block using the --breakpoint-* namespace [1][7]: @theme { --breakpoint-xs: 30rem; --breakpoint-3xl: 120rem; } To remove default breakpoints, you can set them to initial [1][8]: @theme { --breakpoint-2xl: initial; }

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "globals `@theme` block:"
sed -n '80,195p' src/app/globals.css

echo
echo "Lockfile/package versions:"
rg -n '"tailwindcss"|"next"|tailwindcss-next|tailwindcss@|next@' package-lock.json package.json . --glob 'package*json' --glob 'pnpm-lock.yaml' --glob 'yarn.lock' --glob '*.css' | sed -n '1,220p'

echo
echo "Calculate image source width hints at selected viewport widths using current Image.sizes"
python3 - <<'PY'
from pathlib import Path
import re, math

css = Path("src/app/globals.css").read_text()
expr = '(min-width: 1024px) 510px, calc(100vw - 48px)'

def calc_size(width, value):
    return eval(value.replace("100vw", str(width)))

choices = []
# Next.js sorts by breakpoint ascending and picks the largest matching breakpoint.
# The expression's largest matching breakpoint at vw >= 1024 is 1024px, with size 510px.
# For vw < 1024px, no mq matches, so the default expression is used.
if width >= 1024:
    size = 510
elif True:
    size = calc_size(width, "100vw - 48")
choices.append((width, size))

# Show the browser-visible hint range for current sizes across viewport widths.
for width in [640, 767, 1023, 1024, 1200, 1280, 1500, 1536]:
    current_hint = 510 if width >= 1024 else calc_size(width, "100vw - 48")
    print(f"{width}px -> current hint {current_hint}px")
PY

Repository: Smartlify07/Modern-Advocates

Length of output: 8643


Update Image.sizes for the new sm grid breakpoint.

sm:grid-cols-2 makes the image one grid column starting at sm. The current sizes defaults to calc(100vw - 48px) below 1024px, so browsers can select a source sized for the full-width case instead of the half-width image. Add breakpoints before lg that match the container layout for sm, lg, and 2xl.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/course-detail-hero-section.tsx` at line 30,
Update the Image component’s sizes configuration in the course detail hero
section to reflect the responsive grid: add a breakpoint for the two-column sm
layout and retain matching entries for lg and 2xl, with the default covering
widths below sm. Ensure each sizes value represents the image’s actual container
width at its breakpoint.

Comment on lines +38 to +46
const donationFormSchema = z.object({
donationType: z.enum(["fixed", "tier", "monthly"]),
amount: z
.number({ message: "Enter a donation amount" })
.positive("Amount must be greater than 0"),
donorName: z.string().min(1, "Full name is required"),
donorEmail: z.email("Please enter a valid email address"),
confirmation: z.boolean(),
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Zod 4 z.literal(true) custom error message API

💡 Result:

In Zod 4, you can customize the error message for z.literal(true) (or any literal) by passing an options object with an error parameter as the second argument to the z.literal() call [1][2]. This unified error parameter is a key feature of Zod 4, replacing the fragmented and inconsistent error customization APIs found in Zod 3 [3]. Here is the implementation syntax: const schema = z.literal(true, { error: "Your custom error message here" }); Additionally, the error parameter accepts a function (an error map) if you require dynamic error messages based on the validation issue: const schema = z.literal(true, { error: (issue) => { // You can access issue details here, such as issue.code or issue.input return "Custom dynamic error message"; } }); In Zod 4, virtually all Zod APIs accept this standard error parameter [1][2][4]. This replaces legacy approaches such as separate invalid_type_error or required_error parameters, which have been deprecated or dropped [3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate relevant files =="
fd -a 'donation-form\.tsx|route\.ts$' . | sed 's#^\./##' | rg 'src/(features/marketing/components/donation-form\.tsx|app/api/donations/route\.ts)$' || true

echo
echo "== donation form outline =="
if [ -f src/features/marketing/components/donation-form.tsx ]; then
  wc -l src/features/marketing/components/donation-form.tsx
  ast-grep outline src/features/marketing/components/donation-form.tsx || true
  cat -n src/features/marketing/components/donation-form.tsx | sed -n '1,140p'
fi

echo
echo "== donations route snippets =="
if [ -f src/app/api/donations/route.ts ]; then
  wc -l src/app/api/donations/route.ts
  ast-grep outline src/app/api/donations/route.ts || true
  rg -n "amount|0\.5|min|400|schema|body|parse|donation" src/app/api/donations/route.ts -C 3
fi

echo
echo "== package zod version =="
if [ -f package.json ]; then
  node -e 'const p=require("./package.json"); console.log(JSON.stringify({dependencies:p.dependencies?.zod, devDependencies:p.devDependencies?.zod}, null, 2))'
fi

Repository: Smartlify07/Modern-Advocates

Length of output: 8820


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== donation form submit and confirmation UI =="
cat -n src/features/marketing/components/donation-form.tsx | sed -n '140,220p'

echo
echo "== read-only schema validation check =="
node - <<'JS'
const z = require("zod");
const current = z.object({
  amount: z.number().positive("Amount must be greater than 0"),
  confirmation: z.boolean(),
});
const amounts = [0.1, 0.49, 0.5, 1];
for (const [name, schema] of [
  ["current", current],
]) {
  console.log(name + " schema accepts:");
  for (const amount of amounts) {
    const result = schema.safeParse({ amount, confirmation: false });
    console.log(JSON.stringify({ amount, confirmation: false, ok: result.success }));
  }
}
const proposedConfirmation = z.boolean().and(z.literal(true, { error: "Authorize payment processing to continue" }));
console.log("proposed confirmation schema accepts true:", proposedConfirmation.safeParse(true).success);
console.log("proposed confirmation schema accepts false:", proposedConfirmation.safeParse(false).success);
JS

Repository: Smartlify07/Modern-Advocates

Length of output: 4952


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== remainder of donation-form =="
cat -n src/features/marketing/components/donation-form.tsx | sed -n '220,272p'

echo
echo "== route validation implementation =="
cat -n src/app/api/donations/route.ts | sed -n '1,35p'

echo
echo "== package manager manifests =="
for f in package.json src/features/marketing/components/donation-form.tsx src/app/api/donations/route.ts; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    sed -n '1,80p' "$f"
  fi
done

Repository: Smartlify07/Modern-Advocates

Length of output: 11314


Enforce the API amount floor and make the confirmation required in the schema.

src/app/api/donations/route.ts rejects values below 0.5, but donationFormSchema only rejects non-positive amounts. Add .min(0.5, ...) before the network call. confirmation: z.boolean() also accepts false; use z.literal(true, { error: "Authorize payment processing to continue" }) so disabled submission is only UI-level, not validation-level.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-form.tsx` around lines 38 - 46,
Update donationFormSchema so amount enforces the API’s minimum of 0.5 with an
appropriate validation message, and replace confirmation’s boolean schema with a
literal true requirement using the specified authorization error. Preserve the
existing positive amount and other field validations.

Comment on lines +66 to +80
const fee = watchedAmount * 0.03
const total = watchedAmount + fee

async function onSubmit(data: DonationFormValues) {
setSubmitting(true)
try {
const result = await apiFetch<{ url: string }>("/api/donations", {
method: "POST",
body: {
amount: data.amount,
donorName: data.donorName,
donorEmail: data.donorEmail,
donationType: data.donationType,
},
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

The charged amount excludes the administration fee shown in the summary.

Lines 246-254 display a "3% Administration fee" and a Total of amount + fee. The submission at lines 74-79 sends only data.amount. Stripe therefore charges the base amount, not the displayed total. The donor sees one number and pays another.

Decide the intended behavior and make both sides agree. If the fee is charged, send total. If the fee is absorbed, remove it from the Total row.

🔧 Proposed fix if the fee is charged
-          amount: data.amount,
+          amount: Number(total.toFixed(2)),

Also applies to: 246-254

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-form.tsx` around lines 66 - 80,
Align the donation submission and displayed summary in onSubmit with the
intended administration-fee behavior: if donors are charged the fee, submit
total instead of data.amount and ensure the summary remains amount plus fee;
otherwise remove the fee from the Total calculation and display. Keep the amount
used for the API request and the value shown to donors consistent.

},
})

window.location.assign(result.url)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Stripe Checkout Session url property nullable type

💡 Result:

In the Stripe Checkout Session object, the url property is indeed nullable [1]. It is defined as a string or null type [1]. The url property is only present when the Checkout Session is in an active state [1]. When a Session is no longer active—such as when it has been completed, expired, or canceled—the url property will be null [1]. This ensures that once a session is closed, customers can no longer be redirected to the hosted payment page.

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate donation form and donations api =="
fd -a 'donation-form\.tsx$|donations|routes|app' . | sed 's#^\./##' | head -200

echo
echo "== relevant files from index =="
git ls-files | rg '(^|/)donation-form\.tsx$|donations|api|donation' || true

echo
echo "== donation form outline and relevant lines =="
FILE="$(git ls-files | rg '(^|/)donation-form\.tsx$' | head -1 || true)"
if [ -n "${FILE:-}" ]; then
  wc -l "$FILE"
  ast-grep outline "$FILE" || true
  sed -n '1,140p' "$FILE" | cat -n
fi

echo
echo "== search donations api handlers and route definitions =="
rg -n '"/api/donations"|/api/donations|donations|Checkout\.Session|createCheckoutSession|session\.url|url: session\.url|NextResponse\.json\(\{ url' . --glob '!node_modules' --glob '!dist' --glob '!build' --glob '!public' || true

Repository: Smartlify07/Modern-Advocates

Length of output: 29049


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== donations route implementation =="
sed -n '1,160p' src/app/api/donations/route.ts | cat -n

echo
echo "== exact window.location.assign calls with result.url =="
rg -n 'window\.location\.assign|\.url' src/features/marketing/components/donation-form.tsx src/app/api/donations/route.ts

echo
echo "== static JS/TS semantics for assign(null) in browser-like globals =="
node - <<'JS'
const url = new URL('https://example.org/checkout?x=1');
url.href = null;
console.log({ type: typeof url.href, value: url.href });
JS

Repository: Smartlify07/Modern-Advocates

Length of output: 4773


🌐 Web query:

mdn window.location.assign null does not navigate /null

💡 Result:

When calling window.location.assign(null) in JavaScript, the behavior is that the browser treats null as the string "null" and navigates to a URL path of /null relative to the current origin [1][2]. This occurs because the URL parameter passed to location.assign is implicitly converted to a string via the ToString abstract operation [1][3]. Since String(null) results in "null", the browser attempts to load the resource located at that path [4]. If you were expecting this call to do nothing or throw an error, note the following: - Method Signature: The assign method expects a URL-like string [1][5]. - Type Conversion: Because it performs an implicit conversion, passing non-string types like null, undefined, or numbers will result in them being converted to their string representations (e.g., "null", "undefined", "123") and appended to the current origin [1][3]. - Error Handling: A SyntaxError is only thrown if the final resulting string is not a valid URL (though most browsers are very permissive with what they accept as a relative path string) [1][2]. If your goal is to prevent navigation, you must add an explicit check to ensure the value is a valid, non-null string before calling assign [1].

Citations:


Guard against a missing checkout URL.

POST /api/donations returns session.url, and Stripe’s Checkout.Session.url can be null when the session is not open. Declaring { url: string } does not cover that response, and window.location.assign(null) directs the submitter to /null under the catch.

🛡️ Proposed fix
-      const result = await apiFetch<{ url: string }>("/api/donations", {
+      const result = await apiFetch<{ url: string | null }>("/api/donations", {
         method: "POST",
         body: {
           amount: data.amount,
           donorName: data.donorName,
           donorEmail: data.donorEmail,
           donationType: data.donationType,
         },
       })
 
-      window.location.assign(result.url)
+      if (!result.url) {
+        throw new Error("Checkout is unavailable. Please try again.")
+      }
+      window.location.assign(result.url)
📝 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
window.location.assign(result.url)
if (!result.url) {
throw new Error("Checkout is unavailable. Please try again.")
}
window.location.assign(result.url)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-form.tsx` at line 82, Guard the
donation submission redirect around result.url before calling
window.location.assign in the form submit handler. Treat a missing or null
checkout URL as an error and route it through the existing catch/error path,
while preserving the redirect behavior for valid URLs and aligning the response
type with the nullable session.url value.

Comment on lines +96 to +98
<h1 className="mb-5 text-lg font-semibold sm:text-2xl">
Make a Donation
</h1>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use a lower heading level for the card title.

DonationForm renders inside DonationHeroSection and DonationSupportSection pages that already define an <h1> (see donation-hero-section.tsx line 12). Two <h1> elements on one page break the heading outline for screen readers.

🔧 Proposed fix
-        <h1 className="mb-5 text-lg font-semibold sm:text-2xl">
+        <h2 className="mb-5 text-lg font-semibold sm:text-2xl">
           Make a Donation
-        </h1>
+        </h2>
📝 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
<h1 className="mb-5 text-lg font-semibold sm:text-2xl">
Make a Donation
</h1>
<h2 className="mb-5 text-lg font-semibold sm:text-2xl">
Make a Donation
</h2>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-form.tsx` around lines 96 - 98,
Change the card title heading in DonationForm from h1 to the next appropriate
lower-level heading, preserving its existing text and styling so pages with an
existing h1 maintain a valid heading hierarchy.

Comment on lines +119 to +137
{prices.map((price) => (
<button
type="button"
key={price.id}
onClick={() =>
form.setValue("amount", price.amount, {
shouldValidate: true,
})
}
className={cn(
"rounded-none px-5 py-2.5 text-base font-medium transition-colors",
watchedAmount === price.amount
? "bg-ma-admin-primary text-white"
: "bg-ma-bg text-primary"
)}
>
${price.amount}
</button>
))}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Expose the selected preset amount to assistive technology.

The preset buttons show selection through background color only. A screen reader user cannot tell which amount is active. Add aria-pressed.

Also prefer field.onChange over form.setValue inside the Controller render, because field is already bound to amount.

♿ Proposed fix
                     <button
                       type="button"
                       key={price.id}
-                      onClick={() =>
-                        form.setValue("amount", price.amount, {
-                          shouldValidate: true,
-                        })
-                      }
+                      aria-pressed={watchedAmount === price.amount}
+                      onClick={() => field.onChange(price.amount)}
📝 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
{prices.map((price) => (
<button
type="button"
key={price.id}
onClick={() =>
form.setValue("amount", price.amount, {
shouldValidate: true,
})
}
className={cn(
"rounded-none px-5 py-2.5 text-base font-medium transition-colors",
watchedAmount === price.amount
? "bg-ma-admin-primary text-white"
: "bg-ma-bg text-primary"
)}
>
${price.amount}
</button>
))}
{prices.map((price) => (
<button
type="button"
key={price.id}
aria-pressed={watchedAmount === price.amount}
onClick={() => field.onChange(price.amount)}
className={cn(
"rounded-none px-5 py-2.5 text-base font-medium transition-colors",
watchedAmount === price.amount
? "bg-ma-admin-primary text-white"
: "bg-ma-bg text-primary"
)}
>
${price.amount}
</button>
))}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-form.tsx` around lines 119 - 137,
Update the preset buttons in the Controller render to use
field.onChange(price.amount) instead of form.setValue, and add
aria-pressed={watchedAmount === price.amount} so assistive technology exposes
the selected amount while preserving the existing visual selection logic.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 10

🧹 Nitpick comments (6)
src/features/marketing/components/donation-hero-section.tsx (1)

12-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Two line-height utilities conflict on the heading.

text-[28px]/[100%] already sets line-height: 100%. leading-[1.16] sets it again on the same element. This class list is a plain string, so cn/twMerge does not resolve the conflict and the applied value depends on stylesheet order. Keep one.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-hero-section.tsx` at line 12,
Remove the conflicting leading-[1.16] utility from the h1 class list, keeping
the line height defined by text-[28px]/[100%] and the existing responsive
sm:leading-[70px] and lg:text-[60px]/[70px] rules.
src/features/marketing/components/donation-form.tsx (2)

257-267: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider keeping the submit button enabled and showing the reason.

The button is disabled until the checkbox is checked. A user who misses the checkbox sees no explanation. If you enforce confirmation in the schema, you can drop !isConfirmed from disabled and let the field error explain the block.

Add aria-busy={submitting} so assistive technology announces the pending state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-form.tsx` around lines 257 - 267,
Update the submit Button in the donation form to disable only while submitting,
allowing schema validation to surface the confirmation field error when
unchecked. Add aria-busy={submitting} to expose the pending state to assistive
technology, preserving the existing loading indicator and submission behavior.

224-242: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Render the validation message for the confirmation field.

The Field for confirmation has no FieldError. If you tighten the schema as suggested at lines 38-46, the failure produces no visible message.

🔧 Proposed fix
-            render={({ field }) => (
+            render={({ field, fieldState }) => (
               <Field orientation="horizontal">
                 <Checkbox
                   id="donation-confirmation"
                   checked={field.value}
                   onCheckedChange={(checked) =>
                     field.onChange(checked === true)
                   }
                   className="data-checked:border-ma-admin-primary data-checked:bg-ma-admin-primary"
                 />
                 <FieldLabel htmlFor="donation-confirmation" className="w-fit">
                   Authorize payment processing at the checkout page
                 </FieldLabel>
+                <FieldError errors={[fieldState.error]} />
               </Field>
             )}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-form.tsx` around lines 224 - 242,
Add a FieldError for the confirmation Controller’s Field so validation failures
from the confirmation schema are visibly rendered, while preserving the existing
Checkbox and FieldLabel behavior.
src/features/marketing/components/about-hero-section.tsx (1)

13-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Marketing sections apply the raw marketing-container class instead of the shared component. src/shared/ui/marketing-container.tsx exists for this purpose and adds data-slot="marketing-container". Each migrated section hand-writes the class on a plain div, which duplicates the component and drops the data attribute.

  • src/features/marketing/components/about-hero-section.tsx#L13-L14: replace the div.marketing-container with <MarketingContainer> and close it at line 89.
  • src/features/marketing/components/faq.tsx#L47-L48: replace the div.marketing-container with <MarketingContainer> and close it at line 98.
  • src/features/marketing/components/stories-from-our-community-section.tsx#L74-L75: replace the div.marketing-container with <MarketingContainer> and close it at line 139.

As per coding guidelines: "Reuse shared UI components from shared/ui and marketing components from features/marketing/components instead of creating duplicates."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/about-hero-section.tsx` around lines 13 -
14, Replace each raw marketing-container div with the shared MarketingContainer
component, preserving its existing children and closing the component around the
same content. Apply this in
src/features/marketing/components/about-hero-section.tsx lines 13-14 through 89,
src/features/marketing/components/faq.tsx lines 47-48 through 98, and
src/features/marketing/components/stories-from-our-community-section.tsx lines
74-75 through 139; import MarketingContainer from shared UI where needed.

Source: Coding guidelines

src/features/marketing/components/invest-in-hope-section.tsx (2)

6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Both donation sections hard-code the arbitrary hex #ECE8FF. No design token exists for this surface color, so each section inlines the value. Add the token once, then reference it.

  • src/features/marketing/components/invest-in-hope-section.tsx#L6-L6: replace bg-[#ECE8FF] with the new token class.
  • src/features/marketing/components/donation-support-section.tsx#L5-L5: replace bg-[#ECE8FF] with the same token class.

Define the token in the @theme block of src/app/globals.css.

As per coding guidelines: "Do not use arbitrary hex colors or spacing; use the repository's design tokens."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/invest-in-hope-section.tsx` at line 6, Add
a named surface-color token for `#ECE8FF` in the `@theme` block of
src/app/globals.css, then replace the arbitrary bg-[`#ECE8FF`] class in
InvestInHopeSection at
src/features/marketing/components/invest-in-hope-section.tsx:6-6 and
DonationSupportSection at
src/features/marketing/components/donation-support-section.tsx:5-5 with the
shared token class.

Source: Coding guidelines


4-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate the duplicate donation sections.

InvestInHopeSection and DonationSupportSection both render the same "Invest in Hope" copy, background, and <DonationForm />, with the main difference being heading/spacing variants. Keep one component and remove the duplicate, or extract a shared section wrapper.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/invest-in-hope-section.tsx` around lines 4
- 24, Consolidate the duplicated donation-section implementation by reusing a
single shared component between InvestInHopeSection and DonationSupportSection.
Preserve the existing “Invest in Hope” copy, background styling, DonationForm
rendering, and each section’s required heading or spacing variant; remove the
redundant implementation rather than maintaining two equivalent sections.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/marketing/components/course-detail-content-section.tsx`:
- Around line 25-42: Move the shared CourseContentData type from
course-detail-content-section.tsx into a common module, then import and reuse it
in both CourseDetailContentSection and CourseInformationCard. Remove the
duplicate local definition from course-information-card.tsx while preserving the
existing payload shape.

In `@src/features/marketing/components/course-detail-hero-section.tsx`:
- Line 30: Update the Image component’s sizes configuration in the course detail
hero section to reflect the responsive grid: add a breakpoint for the two-column
sm layout and retain matching entries for lg and 2xl, with the default covering
widths below sm. Ensure each sizes value represents the image’s actual container
width at its breakpoint.

In `@src/features/marketing/components/donation-form.tsx`:
- Around line 66-80: Align the donation submission and displayed summary in
onSubmit with the intended administration-fee behavior: if donors are charged
the fee, submit total instead of data.amount and ensure the summary remains
amount plus fee; otherwise remove the fee from the Total calculation and
display. Keep the amount used for the API request and the value shown to donors
consistent.
- Around line 119-137: Update the preset buttons in the Controller render to use
field.onChange(price.amount) instead of form.setValue, and add
aria-pressed={watchedAmount === price.amount} so assistive technology exposes
the selected amount while preserving the existing visual selection logic.
- Around line 96-98: Change the card title heading in DonationForm from h1 to
the next appropriate lower-level heading, preserving its existing text and
styling so pages with an existing h1 maintain a valid heading hierarchy.
- Around line 38-46: Update donationFormSchema so amount enforces the API’s
minimum of 0.5 with an appropriate validation message, and replace
confirmation’s boolean schema with a literal true requirement using the
specified authorization error. Preserve the existing positive amount and other
field validations.
- Line 82: Guard the donation submission redirect around result.url before
calling window.location.assign in the form submit handler. Treat a missing or
null checkout URL as an error and route it through the existing catch/error
path, while preserving the redirect behavior for valid URLs and aligning the
response type with the nullable session.url value.

In `@src/features/marketing/components/donation-hero-section.tsx`:
- Around line 24-31: Update the alt text on the Image using melanie-and-will.png
to describe both founders, matching the “Melanie And Will” and “Founders” naming
used by the adjacent card instead of naming only Melanie as a singular founder.

In `@src/features/marketing/components/donation-support-section.tsx`:
- Line 19: Update DonationForm to use React.useId() for the form and each
related field id instead of hard-coded donation-form, donation-amount,
donor-name, and donor-email values. Ensure every label htmlFor and corresponding
input id uses the generated identifiers, so multiple DonationForm instances
rendered by DonationSupportSection and InvestInHopeSection remain independent.

In `@src/features/marketing/components/footer.tsx`:
- Line 16: Update the footer grid container’s xl gap in the surrounding JSX to
use an existing spacing or named repository design token instead of the
arbitrary 140px value, while preserving the current responsive grid layout.

---

Nitpick comments:
In `@src/features/marketing/components/about-hero-section.tsx`:
- Around line 13-14: Replace each raw marketing-container div with the shared
MarketingContainer component, preserving its existing children and closing the
component around the same content. Apply this in
src/features/marketing/components/about-hero-section.tsx lines 13-14 through 89,
src/features/marketing/components/faq.tsx lines 47-48 through 98, and
src/features/marketing/components/stories-from-our-community-section.tsx lines
74-75 through 139; import MarketingContainer from shared UI where needed.

In `@src/features/marketing/components/donation-form.tsx`:
- Around line 257-267: Update the submit Button in the donation form to disable
only while submitting, allowing schema validation to surface the confirmation
field error when unchecked. Add aria-busy={submitting} to expose the pending
state to assistive technology, preserving the existing loading indicator and
submission behavior.
- Around line 224-242: Add a FieldError for the confirmation Controller’s Field
so validation failures from the confirmation schema are visibly rendered, while
preserving the existing Checkbox and FieldLabel behavior.

In `@src/features/marketing/components/donation-hero-section.tsx`:
- Line 12: Remove the conflicting leading-[1.16] utility from the h1 class list,
keeping the line height defined by text-[28px]/[100%] and the existing
responsive sm:leading-[70px] and lg:text-[60px]/[70px] rules.

In `@src/features/marketing/components/invest-in-hope-section.tsx`:
- Line 6: Add a named surface-color token for `#ECE8FF` in the `@theme` block of
src/app/globals.css, then replace the arbitrary bg-[`#ECE8FF`] class in
InvestInHopeSection at
src/features/marketing/components/invest-in-hope-section.tsx:6-6 and
DonationSupportSection at
src/features/marketing/components/donation-support-section.tsx:5-5 with the
shared token class.
- Around line 4-24: Consolidate the duplicated donation-section implementation
by reusing a single shared component between InvestInHopeSection and
DonationSupportSection. Preserve the existing “Invest in Hope” copy, background
styling, DonationForm rendering, and each section’s required heading or spacing
variant; remove the redundant implementation rather than maintaining two
equivalent sections.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a2654df9-0a7b-4000-ab93-014dbd64b74a

📥 Commits

Reviewing files that changed from the base of the PR and between dd000ca and c17e01f.

⛔ Files ignored due to path filters (6)
  • public/figma-home/downloaded-node-2800-19876.png is excluded by !**/*.png
  • public/figma-home/downloaded-node-2800-19884.png is excluded by !**/*.png
  • public/figma-home/downloaded-node-2800-19886.png is excluded by !**/*.png
  • public/figma-home/downloaded-node-2800-19890.png is excluded by !**/*.png
  • public/figma-home/downloaded-node-2800-19892.png is excluded by !**/*.png
  • public/figma-home/downloaded-node-2863-17140.png is excluded by !**/*.png
📒 Files selected for processing (29)
  • src/app/globals.css
  • src/features/courses/components/course-card.tsx
  • src/features/courses/components/enroll-now-button.tsx
  • src/features/marketing/components/about-hero-section.tsx
  • src/features/marketing/components/about-our-values-section.tsx
  • src/features/marketing/components/about-support-mission-section.tsx
  • src/features/marketing/components/community-section.tsx
  • src/features/marketing/components/course-detail-content-section.tsx
  • src/features/marketing/components/course-detail-hero-section.tsx
  • src/features/marketing/components/course-information-card.tsx
  • src/features/marketing/components/courses-hero-section.tsx
  • src/features/marketing/components/cta-section.tsx
  • src/features/marketing/components/donation-cta-section.tsx
  • src/features/marketing/components/donation-form.tsx
  • src/features/marketing/components/donation-hero-section.tsx
  • src/features/marketing/components/donation-support-section.tsx
  • src/features/marketing/components/empowerment-section.tsx
  • src/features/marketing/components/faq.tsx
  • src/features/marketing/components/footer.tsx
  • src/features/marketing/components/how-can-we-help.tsx
  • src/features/marketing/components/how-can-we-support.tsx
  • src/features/marketing/components/invest-in-hope-section.tsx
  • src/features/marketing/components/mission-sections.tsx
  • src/features/marketing/components/our-vision-section.tsx
  • src/features/marketing/components/practical-pathways-section.tsx
  • src/features/marketing/components/stories-from-our-community-section.tsx
  • src/features/marketing/components/testimonials.tsx
  • src/shared/lib/api-handler.ts
  • src/shared/ui/marketing-container.tsx
🛑 Comments failed to post (3)
src/features/marketing/components/donation-hero-section.tsx (1)

24-31: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the image alt text.

The image now shows both founders (melanie-and-will.png), and the card at lines 35-38 names "Melanie And Will" as "Founders". The alt text still names one person and uses the singular "founder".

🔧 Proposed fix
           <Image
             src="/figma-home/melanie-and-will.png"
-            alt="Melanie Reyes, founder of ModernAdvocates Inc."
+            alt="Melanie and Will, founders of ModernAdvocates Inc."
             priority
📝 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.

          <Image
            src="/figma-home/melanie-and-will.png"
            alt="Melanie and Will, founders of ModernAdvocates Inc."
            priority
            className="rounded-card-2 object-cover sm:h-full"
            width={510}
            height={560}
          />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-hero-section.tsx` around lines 24
- 31, Update the alt text on the Image using melanie-and-will.png to describe
both founders, matching the “Melanie And Will” and “Founders” naming used by the
adjacent card instead of naming only Melanie as a singular founder.
src/features/marketing/components/donation-support-section.tsx (1)

19-19: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether any route renders both donation sections.
rg -n 'InvestInHopeSection|DonationSupportSection|DonationHeroSection' --glob '*.tsx'

Repository: Smartlify07/Modern-Advocates

Length of output: 166


🏁 Script executed:

#!/bin/bash
set -u

echo "== repo files (top-level names) =="
git ls-files | sed 's#/.*##' | sort -u | sed -n '1,200p'

echo "== locate donation related files =="
fd -i 'donation|support|investment|invest' . --type f | sed -n '1,200p'

echo "== search donation identifiers broadly =="
rg -n 'donation-form|DonationForm|donation-amount|donor-name|donor-email|donation-confirmation|InvestInHopeSection|DonationSupportSection|DonationHeroSection|Invest.*Hope' . --glob '*.{ts,tsx}' || true

Repository: Smartlify07/Modern-Advocates

Length of output: 5044


Generate unique form ids in DonationForm.

DonationForm has hard-coded id="donation-form" and IDs such as donation-amount, donor-name, and donor-email, while DonationSupportSection and InvestInHopeSection both render DonationForm on /(marketing)/donation/page.tsx. If both sections render in one document, the second form is disabled and labels may target the wrong inputs. Use React.useId() for the form and related field ids.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-support-section.tsx` at line 19,
Update DonationForm to use React.useId() for the form and each related field id
instead of hard-coded donation-form, donation-amount, donor-name, and
donor-email values. Ensure every label htmlFor and corresponding input id uses
the generated identifiers, so multiple DonationForm instances rendered by
DonationSupportSection and InvestInHopeSection remain independent.
src/features/marketing/components/footer.tsx (1)

16-16: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Replace the arbitrary footer spacing with a design token.

Line [16] introduces xl:gap-[140px]. Use an existing spacing token or a named repository token instead.

As per coding guidelines, do not use arbitrary hex colors or spacing; use the repository's design tokens.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/footer.tsx` at line 16, Update the footer
grid container’s xl gap in the surrounding JSX to use an existing spacing or
named repository design token instead of the arbitrary 140px value, while
preserving the current responsive grid layout.

Source: Coding guidelines

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/features/marketing/components/donation-form.tsx (1)

95-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a design-token shadow.

The new shadow-[0_-6px_40px_0_rgba(0,0,0,0.08)] hard-codes shadow spacing in the component. Reuse an existing named shadow token or define one in the design-token layer.

As per coding guidelines: “Do not use arbitrary hex colors or spacing; use the repository's design tokens.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-form.tsx` at line 95, Replace the
arbitrary shadow value on the donation form container with an existing named
design-token shadow, or add the shadow to the design-token layer and reference
it here. Update only the container’s shadow styling and preserve the surrounding
layout classes.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/`(user)/dashboard/page.tsx:
- Line 80: Update the loading card class in the dashboard page to replace
sm:max-w-[300px] with the repository’s existing named 300px width design token;
if no such token exists, define it in the appropriate design-token configuration
before referencing it.

---

Nitpick comments:
In `@src/features/marketing/components/donation-form.tsx`:
- Line 95: Replace the arbitrary shadow value on the donation form container
with an existing named design-token shadow, or add the shadow to the
design-token layer and reference it here. Update only the container’s shadow
styling and preserve the surrounding layout classes.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b22f0ab3-a7a1-46a0-b03d-5f4529e8578f

📥 Commits

Reviewing files that changed from the base of the PR and between c17e01f and 123073c.

📒 Files selected for processing (9)
  • src/app/(marketing)/donation/success/page.tsx
  • src/app/(user)/dashboard/page.tsx
  • src/app/api/donations/route.ts
  • src/features/marketing/components/contact-hero-section.tsx
  • src/features/marketing/components/donation-form.tsx
  • src/features/marketing/components/footer.tsx
  • src/features/marketing/lib/donation-pricing.ts
  • src/features/user-dashboard/components/dashboard-navbar.tsx
  • src/shared/ui/marketing-button.tsx

<div
key={i}
className="flex w-full flex-col gap-5 sm:max-w-[334px]"
className="flex w-full flex-col gap-5 sm:max-w-[300px]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use a design-token width for the loading card.

Line 80 changes the card width to another bracketed arbitrary value, sm:max-w-[300px]. Replace it with the repository’s named width token for 300px, or define that token before using it.

As per coding guidelines: “Do not use arbitrary hex colors or spacing; use the repository's design tokens.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`(user)/dashboard/page.tsx at line 80, Update the loading card class
in the dashboard page to replace sm:max-w-[300px] with the repository’s existing
named 300px width design token; if no such token exists, define it in the
appropriate design-token configuration before referencing it.

Source: Coding guidelines

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/marketing/components/donation-hero-section.tsx`:
- Around line 28-31: Update the image sizing classes in the donation hero
section’s image element so the auto-width and full-height overrides begin at the
lg breakpoint, matching lg:grid-cols-2; keep w-full active through the
single-column sm-to-tablet range.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6de04d1d-9757-4dd1-a9d3-b611a4b9eeeb

📥 Commits

Reviewing files that changed from the base of the PR and between 123073c and 8008dc6.

📒 Files selected for processing (4)
  • src/app/(user)/dashboard/page.tsx
  • src/features/marketing/components/donation-hero-section.tsx
  • src/features/marketing/components/footer.tsx
  • src/features/user-dashboard/components/dashboard-navbar.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/features/user-dashboard/components/dashboard-navbar.tsx
  • src/app/(user)/dashboard/page.tsx
  • src/features/marketing/components/footer.tsx

Comment on lines +28 to 31
className="w-full rounded-card-2 object-cover sm:h-full sm:w-auto"
width={510}
height={560}
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Align the image breakpoint with the grid breakpoint.

lg:grid-cols-2 keeps this section single-column from sm through the tablet range. sm:w-auto switches the image to its intrinsic width during that range, so it may stop filling the .marketing-container. Apply the height and auto-width overrides at lg, or keep w-full through lg.

Proposed fix
-            className="w-full rounded-card-2 object-cover sm:h-full sm:w-auto"
+            className="w-full rounded-card-2 object-cover lg:h-full lg:w-auto"
📝 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
className="w-full rounded-card-2 object-cover sm:h-full sm:w-auto"
width={510}
height={560}
/>
className="w-full rounded-card-2 object-cover lg:h-full lg:w-auto"
width={510}
height={560}
/>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/marketing/components/donation-hero-section.tsx` around lines 28
- 31, Update the image sizing classes in the donation hero section’s image
element so the auto-width and full-height overrides begin at the lg breakpoint,
matching lg:grid-cols-2; keep w-full active through the single-column
sm-to-tablet range.

@Smartlify07
Smartlify07 merged commit 64fc2ea into main Aug 8, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant