feat: donation form API wiring and shared marketing container - #139
Conversation
…into ch/donation-page-ui-updtes
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughThe 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. ChangesMarketing layout and donation updates
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
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
# Conflicts: # src/features/marketing/components/donation-support-section.tsx
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (6)
src/features/marketing/components/donation-hero-section.tsx (1)
12-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTwo line-height utilities conflict on the heading.
text-[28px]/[100%]already setsline-height: 100%.leading-[1.16]sets it again on the same element. This class list is a plain string, socn/twMergedoes 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 valueConsider 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
confirmationin the schema, you can drop!isConfirmedfromdisabledand 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 valueRender the validation message for the confirmation field.
The
Fieldforconfirmationhas noFieldError. 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 winMarketing sections apply the raw
marketing-containerclass instead of the shared component.src/shared/ui/marketing-container.tsxexists for this purpose and addsdata-slot="marketing-container". Each migrated section hand-writes the class on a plaindiv, which duplicates the component and drops the data attribute.
src/features/marketing/components/about-hero-section.tsx#L13-L14: replace thediv.marketing-containerwith<MarketingContainer>and close it at line 89.src/features/marketing/components/faq.tsx#L47-L48: replace thediv.marketing-containerwith<MarketingContainer>and close it at line 98.src/features/marketing/components/stories-from-our-community-section.tsx#L74-L75: replace thediv.marketing-containerwith<MarketingContainer>and close it at line 139.As per coding guidelines: "Reuse shared UI components from
shared/uiand marketing components fromfeatures/marketing/componentsinstead 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 winBoth 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: replacebg-[#ECE8FF]with the new token class.src/features/marketing/components/donation-support-section.tsx#L5-L5: replacebg-[#ECE8FF]with the same token class.Define the token in the
@themeblock ofsrc/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 winConsolidate the duplicate donation sections.
InvestInHopeSectionandDonationSupportSectionboth 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
⛔ Files ignored due to path filters (6)
public/figma-home/downloaded-node-2800-19876.pngis excluded by!**/*.pngpublic/figma-home/downloaded-node-2800-19884.pngis excluded by!**/*.pngpublic/figma-home/downloaded-node-2800-19886.pngis excluded by!**/*.pngpublic/figma-home/downloaded-node-2800-19890.pngis excluded by!**/*.pngpublic/figma-home/downloaded-node-2800-19892.pngis excluded by!**/*.pngpublic/figma-home/downloaded-node-2863-17140.pngis excluded by!**/*.png
📒 Files selected for processing (29)
src/app/globals.csssrc/features/courses/components/course-card.tsxsrc/features/courses/components/enroll-now-button.tsxsrc/features/marketing/components/about-hero-section.tsxsrc/features/marketing/components/about-our-values-section.tsxsrc/features/marketing/components/about-support-mission-section.tsxsrc/features/marketing/components/community-section.tsxsrc/features/marketing/components/course-detail-content-section.tsxsrc/features/marketing/components/course-detail-hero-section.tsxsrc/features/marketing/components/course-information-card.tsxsrc/features/marketing/components/courses-hero-section.tsxsrc/features/marketing/components/cta-section.tsxsrc/features/marketing/components/donation-cta-section.tsxsrc/features/marketing/components/donation-form.tsxsrc/features/marketing/components/donation-hero-section.tsxsrc/features/marketing/components/donation-support-section.tsxsrc/features/marketing/components/empowerment-section.tsxsrc/features/marketing/components/faq.tsxsrc/features/marketing/components/footer.tsxsrc/features/marketing/components/how-can-we-help.tsxsrc/features/marketing/components/how-can-we-support.tsxsrc/features/marketing/components/invest-in-hope-section.tsxsrc/features/marketing/components/mission-sections.tsxsrc/features/marketing/components/our-vision-section.tsxsrc/features/marketing/components/practical-pathways-section.tsxsrc/features/marketing/components/stories-from-our-community-section.tsxsrc/features/marketing/components/testimonials.tsxsrc/shared/lib/api-handler.tssrc/shared/ui/marketing-container.tsx
| 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 | ||
| }[] |
There was a problem hiding this comment.
🗄️ 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"> |
There was a problem hiding this comment.
🚀 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
fiRepository: 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:
PYRepository: 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:
- 1: https://tailwindcss.com/docs/responsive-design
- 2: https://tailkits.com/blog/tailwind-media-queries/
- 3: https://llmbestpractices.com/frontend/tailwind-responsive
- 4: https://stackoverflow.com/questions/79599447/how-to-add-and-use-custom-breakpoint-tailwindcss-v4
- 5: https://tailwindcss.com/docs/functions-and-directives
- 6: https://tailwindcss.com/docs/adding-custom-styles
- 7: https://tailwindcss.com/docs/theme
- 8: [v4] In a production environment, the theme does not contain breakpoint variables tailwindlabs/tailwindcss#18902
🏁 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")
PYRepository: 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.
| 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(), | ||
| }) |
There was a problem hiding this comment.
🗄️ 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:
- 1: https://zod.dev/error-customization
- 2: https://github.com/colinhacks/zod/blob/v4.4.3/packages/docs/content/error-customization.mdx
- 3: https://zod.dev/v4/changelog
- 4: https://github.com/colinhacks/zod/blob/912f0f51/packages/docs/content/error-customization.mdx
🏁 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))'
fiRepository: 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);
JSRepository: 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
doneRepository: 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.
| 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, | ||
| }, | ||
| }) |
There was a problem hiding this comment.
🗄️ 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) |
There was a problem hiding this comment.
🩺 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' || trueRepository: 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 });
JSRepository: 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:
- 1: https://developer.mozilla.org/en-US/docs/Web/API/Location/assign
- 2: https://github.com/mdn/content/blob/main/files/en-us/web/api/location/assign/index.md
- 3: https://devdoc.net/web/developer.mozilla.org/en-US/docs/Web/API/Window/location.html
- 4: Url has some undocumented formats mdn/content#30017
- 5: https://www.w3schools.com/jsref/met_loc_assign.asp
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.
| 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.
| <h1 className="mb-5 text-lg font-semibold sm:text-2xl"> | ||
| Make a Donation | ||
| </h1> |
There was a problem hiding this comment.
📐 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.
| <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.
| {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> | ||
| ))} |
There was a problem hiding this comment.
📐 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.
| {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.
There was a problem hiding this comment.
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 valueTwo line-height utilities conflict on the heading.
text-[28px]/[100%]already setsline-height: 100%.leading-[1.16]sets it again on the same element. This class list is a plain string, socn/twMergedoes 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 valueConsider 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
confirmationin the schema, you can drop!isConfirmedfromdisabledand 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 valueRender the validation message for the confirmation field.
The
Fieldforconfirmationhas noFieldError. 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 winMarketing sections apply the raw
marketing-containerclass instead of the shared component.src/shared/ui/marketing-container.tsxexists for this purpose and addsdata-slot="marketing-container". Each migrated section hand-writes the class on a plaindiv, which duplicates the component and drops the data attribute.
src/features/marketing/components/about-hero-section.tsx#L13-L14: replace thediv.marketing-containerwith<MarketingContainer>and close it at line 89.src/features/marketing/components/faq.tsx#L47-L48: replace thediv.marketing-containerwith<MarketingContainer>and close it at line 98.src/features/marketing/components/stories-from-our-community-section.tsx#L74-L75: replace thediv.marketing-containerwith<MarketingContainer>and close it at line 139.As per coding guidelines: "Reuse shared UI components from
shared/uiand marketing components fromfeatures/marketing/componentsinstead 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 winBoth 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: replacebg-[#ECE8FF]with the new token class.src/features/marketing/components/donation-support-section.tsx#L5-L5: replacebg-[#ECE8FF]with the same token class.Define the token in the
@themeblock ofsrc/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 winConsolidate the duplicate donation sections.
InvestInHopeSectionandDonationSupportSectionboth 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
⛔ Files ignored due to path filters (6)
public/figma-home/downloaded-node-2800-19876.pngis excluded by!**/*.pngpublic/figma-home/downloaded-node-2800-19884.pngis excluded by!**/*.pngpublic/figma-home/downloaded-node-2800-19886.pngis excluded by!**/*.pngpublic/figma-home/downloaded-node-2800-19890.pngis excluded by!**/*.pngpublic/figma-home/downloaded-node-2800-19892.pngis excluded by!**/*.pngpublic/figma-home/downloaded-node-2863-17140.pngis excluded by!**/*.png
📒 Files selected for processing (29)
src/app/globals.csssrc/features/courses/components/course-card.tsxsrc/features/courses/components/enroll-now-button.tsxsrc/features/marketing/components/about-hero-section.tsxsrc/features/marketing/components/about-our-values-section.tsxsrc/features/marketing/components/about-support-mission-section.tsxsrc/features/marketing/components/community-section.tsxsrc/features/marketing/components/course-detail-content-section.tsxsrc/features/marketing/components/course-detail-hero-section.tsxsrc/features/marketing/components/course-information-card.tsxsrc/features/marketing/components/courses-hero-section.tsxsrc/features/marketing/components/cta-section.tsxsrc/features/marketing/components/donation-cta-section.tsxsrc/features/marketing/components/donation-form.tsxsrc/features/marketing/components/donation-hero-section.tsxsrc/features/marketing/components/donation-support-section.tsxsrc/features/marketing/components/empowerment-section.tsxsrc/features/marketing/components/faq.tsxsrc/features/marketing/components/footer.tsxsrc/features/marketing/components/how-can-we-help.tsxsrc/features/marketing/components/how-can-we-support.tsxsrc/features/marketing/components/invest-in-hope-section.tsxsrc/features/marketing/components/mission-sections.tsxsrc/features/marketing/components/our-vision-section.tsxsrc/features/marketing/components/practical-pathways-section.tsxsrc/features/marketing/components/stories-from-our-community-section.tsxsrc/features/marketing/components/testimonials.tsxsrc/shared/lib/api-handler.tssrc/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}' || trueRepository: Smartlify07/Modern-Advocates
Length of output: 5044
Generate unique form ids in
DonationForm.
DonationFormhas hard-codedid="donation-form"and IDs such asdonation-amount,donor-name, anddonor-email, whileDonationSupportSectionandInvestInHopeSectionboth renderDonationFormon/(marketing)/donation/page.tsx. If both sections render in one document, the second form is disabled and labels may target the wrong inputs. UseReact.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
… to remaining pages
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/features/marketing/components/donation-form.tsx (1)
95-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse 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
📒 Files selected for processing (9)
src/app/(marketing)/donation/success/page.tsxsrc/app/(user)/dashboard/page.tsxsrc/app/api/donations/route.tssrc/features/marketing/components/contact-hero-section.tsxsrc/features/marketing/components/donation-form.tsxsrc/features/marketing/components/footer.tsxsrc/features/marketing/lib/donation-pricing.tssrc/features/user-dashboard/components/dashboard-navbar.tsxsrc/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]" |
There was a problem hiding this comment.
📐 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
There was a problem hiding this comment.
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
📒 Files selected for processing (4)
src/app/(user)/dashboard/page.tsxsrc/features/marketing/components/donation-hero-section.tsxsrc/features/marketing/components/footer.tsxsrc/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
| className="w-full rounded-card-2 object-cover sm:h-full sm:w-auto" | ||
| width={510} | ||
| height={560} | ||
| /> |
There was a problem hiding this comment.
🎯 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.
| 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.
Summary
Verification
px tsc --noEmit\ clean
Summary by CodeRabbit
New Features
Improvements
Bug Fixes