Conversation
Visitors regularly ask how to support Saba beyond their trip; the site had no canonical answer. Adds a server-rendered /donate page with a typed DONATION_RECIPIENTS registry (empty pending owner-approved content — a graceful in-progress state renders instead of fabricated organizations), the repo-documented marine-park conservation contribution, and a trust note clarifying that donations go directly to each organization. Entry points stay out of the primary nav: footer Explore column, the /partners conservation section, and the /plan-your-trip island section. Sitemap, llms.txt, and every route inventory updated; new donation_click analytics event for outbound recipient CTAs. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Reviewer's GuideThis PR adds a statically rendered Flow diagram for the empty Support Saba recipient stateflowchart TD
Start[Visitor opens /donate] --> Load[Load DONATION_RECIPIENTS]
Load --> Empty{Recipients approved?}
Empty -->|No| InProgress[Show list-in-progress message]
InProgress --> Contact[Link to /contact to ask Sea Saba]
Empty -->|Yes| Cards[Render organization cards]
Cards --> Donation{Direct donation URL exists?}
Donation -->|Yes| Direct[Donate directly on organization website]
Donation -->|No| Website[Visit organization website]
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="components/donations/donations-section.tsx" line_range="62" />
<code_context>
+ {recipient.image && (
+ <Image
+ src={recipient.image}
+ alt={recipient.imageAlt ?? ""}
+ width={160}
+ height={48}
</code_context>
<issue_to_address>
**issue (bug_risk):** When a recipient has an `image` but omits `imageAlt`, `DonationCard` renders `alt=""`, causing the organization image to be treated as decorative and hiding potentially meaningful content from screen-reader users. The interface comment says alt text is required, but the optional property does not enforce that contract.
**Triggers:** When a future registry entry supplies `image` without `imageAlt`.
**Suggested fix:** Make `imageAlt` required whenever `image` is present using a discriminated union, or provide a meaningful fallback alt value before rendering the image.
```suggestion
alt={recipient.imageAlt ?? recipient.name}
```
</issue_to_address>Sourcery assessment
Approval pending. 1 finding to address first.
Blocking findings: components/donations/donations-section.tsx:62
| {recipient.image && ( | ||
| <Image | ||
| src={recipient.image} | ||
| alt={recipient.imageAlt ?? ""} |
There was a problem hiding this comment.
issue (bug_risk): When a recipient has an image but omits imageAlt, DonationCard renders alt="", causing the organization image to be treated as decorative and hiding potentially meaningful content from screen-reader users. The interface comment says alt text is required, but the optional property does not enforce that contract.
Triggers: When a future registry entry supplies image without imageAlt.
Suggested fix: Make imageAlt required whenever image is present using a discriminated union, or provide a meaningful fallback alt value before rendering the image.
| alt={recipient.imageAlt ?? ""} | |
| alt={recipient.imageAlt ?? recipient.name} |
The page now serves both audiences: visitors looking for vetted island organizations to support directly, and Saba organizations/projects/events requesting a donation or sponsorship from Sea Saba — the second half was missing and is a major purpose of the feature. - data/community-support.ts: editable DRAFT policy content (who may ask, request categories, support types, review standards, process steps, no-guarantee note) — wording changes never touch JSX - lib/support-request.ts: typed request draft, per-field limits, shared validation, and mailto/wa.me handoff builders — same visitor-sends-it mechanism as the contact form, so Respond.io files requests under the requester's real address (no shared-sender collapse, #104) and no server endpoint or third-party form service is introduced - components/donations/: CommunitySupportSection renders the standards from data; SupportRequestForm collects name/org/contact, category, support types, conditional amount, request/description/beneficiaries/ timeline/use, direct-supplier-payment option, optional reference URL, and a required accuracy acknowledgement - Privacy page covers support-request details; analytics gain generic donation_request_started/submitted events that never carry field values Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
Heads-up on the failing |
The form's FieldError spacer rendered a min-h-5 line under every field, inflating each row gap to ~42px; collapse it when empty and group the trailing consent/submit cluster. Rewrite em-dash prose naturally across the new /donate copy, and recalibrate the resize-scroll 'just above footer' scenario against the footer's top edge instead of a fixed pixel threshold so it survives footer geometry changes. Add a page-level assertion that customer-facing copy contains no em/en dashes. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Fold the responsible-party and specific-purpose ground rules into one
("A clear project and someone responsible") and merge financial +
sponsorship into a single "financial" support type, so both grids render
as full 2x3 on desktop instead of leaving an orphan card. The merged type
keeps the "financial" slug so the required-amount gate and any existing
drafts are unaffected.
Card padding/gap reduced (py-3->py-2.5, gap-3->gap-2.5). Footer gets a
restrained density pass (pt-16->pt-10, grid gap-12->gap-8/10, nav
gap-3->gap-2, heading mt-4->mt-3, bottom bar mt-12/pt-8->mt-6/pt-6): ~15%
shorter on mobile, ~17% on desktop, launcher clearance and safe-area
padding unchanged. Adds Visiting Yachts to the Explore column.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Groups the donation entry point with the visitor-oriented trip-planning links and balances Plan/Explore at seven links each after the Visiting Yachts addition — no other footer changes. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Closes #171
Revision (head
9dbc331)The original implementation covered only the visitor-donation direction. This revision makes
/donatethe public home of Sea Saba's community giving program, serving both audiences:data/donations.ts, still empty/fail-safe until the owner approves organizations), donations route directly to each organization's own site.Polish pass (head
a41a56c)Owner-review visual/content pass:
"financial"slug, so the required-amount gate and any existing drafts are unaffected; the form hint and email serialization use the new label.py-3→py-2.5, gridgap-3→gap-2.5on both grids.pt-16→pt-10, gridgap-12→gap-8(sm:gap-10), navgap-3→gap-2, headingmt-4→mt-3, bottom barmt-12/pt-8→mt-6/pt-6. Measured ~15% shorter at mobile widths, ~14.5% at 768, ~17% at ≥1024. Thepb-[calc(5.5rem+env(safe-area-inset-bottom))]launcher clearance is unchanged and the footer-widgets clearance test still passes at all nine probe widths./visiting-yachts.Revised page structure
/donateremains the canonical URL (already wired into sitemap, llms.txt, entry points). Title "Support Saba" covers both audiences — recommended over "Donate" or renaming the route.Standards/policy architecture
All program content lives in
data/community-support.ts(typedSupportRequestCategory/SupportType/SupportStandardstructures +WHO_CAN_REQUEST,SUPPORT_REQUEST_STEPS,SUPPORT_REQUEST_NO_GUARANTEE). All copy is DRAFT pending owner review — clearly marked in the file header; editing wording never touches JSX. No dollar caps, budgets, deadlines, or funding guarantees anywhere.The six draft standards encode the anti-abuse controls in positive language: community benefit, a clear project with an identifiable responsible party, visibility into where money goes (proportional — "we may ask" for budget/quote/invoice/proof, not mandatory documents), no unrestricted personal cash gifts, preference for paying suppliers directly / purchasing goods / providing Sea Saba services over cash, and proportional follow-up (receipt/photo/short update).
Request form
components/donations/support-request-form.tsxcollects: name*, organization (optional), email*, phone/WhatsApp (optional), category* (Community/Youth/Education/Conservation/Animal welfare/Sports/Culture/Events/Other), support types* (multi-select: financial support or sponsorship, goods, prize/raffle, Sea Saba services, staff time, in-kind), amount (required only when "financial" selected), request*, description*, beneficiaries*, timing*, use-of-support*, "Sea Saba may pay a supplier directly" opt-in checkbox, optional reference URL, and a required accuracy acknowledgement*.Submission mechanism — why it's safe vs. #104
There is no approved server-side submission path today, and building one from a shared verified sender is exactly what collapsed all visitors into one Respond.io contact (#104). The form therefore uses the same architecture as the contact form: it builds a structured request and opens it in the requester's own email app (
mailto:info@seasaba.com) or WhatsApp (wa.me) — the requester's real From address reaches the inbox, so Respond.io attaches it to the correct contact. No new email service, database, SaaS, or file-upload machinery; requesters can attach supporting documents in their own email app. If #104's Custom Channel lands later,lib/support-request.tsis a pure data contract that can feed a server endpoint unchanged.Privacy & analytics
donation_request_started(first field focus, once) anddonation_request_submitted(handoff;method= email/whatsapp). A dedicated integration test fills the form with sentinel values and asserts no field content appears in anytrack()call ordataLayerpush; mailto/wa.me URLs are sanitized to bare addresses before enteringlink_url.Files changed (this revision)
data/community-support.ts,lib/support-request.ts,components/donations/{community-support-section,support-request-form}.tsx(new);app/(en)/(content)/donate/page.tsx,app/(en)/(content)/privacy/page.tsx,components/footer.tsx,lib/analytics.ts,docs/{ANALYTICS_SEO,OPERATIONS}.md,public/llms.txt,tests/{unit/support-request.test.ts,integration/{donate,internal-links}.test.tsx,e2e/accessibility.spec.ts}.Tests
support-request.test.ts): validation rules, conditional amount, acknowledgement, subject/body contract, optional-field omission, vendor-payment honesty, mailto/wa.me encoding.startedfires once, PII never reaches analytics./visiting-yachtsassertion added./donateadded to mobile axe scans + desktop axe scan of the form with validation errors shown; smoke/link-integrity/locale-routing already cover the route; footer-widgets launcher clearance and resize-scroll preservation remain green.Validation
check✓ ·lint✓ ·typecheck✓ ·vitest392/392 ✓ ·build:test✓ (/donatestatic) · e2e 124 passed: donate axe (desktop+mobile+error state), smoke, link-integrity, navigation, footer-widgets clearance at 320–1440, resize-scroll. Geometric verification at 320/375/390/768/1024/1280/1440: both card grids render balanced (2×3 at ≥768), equal card heights per row, no horizontal overflow, footer ~15–17% shorter.Still needs Chad's review
data/community-support.tsis DRAFT — standards, categories, support types, process steps, who-can-ask list./donateURL (kept — canonical, already indexed surfaces).data/donations.ts(unchanged dependency).Generated with Devin
Summary by Sourcery
Launch
/donateas Sea Saba’s public community-giving hub for supporting Saba and requesting support from Sea Saba.New Features:
/donateSupport Saba page for visitor giving and Sea Saba community-support requests.Enhancements:
Documentation:
Tests: