Skip to content

feat: multi-step donate drawer with Stripe Elements#17

Merged
mlehotskylf merged 5 commits into
mainfrom
feat/donate-modal
May 14, 2026
Merged

feat: multi-step donate drawer with Stripe Elements#17
mlehotskylf merged 5 commits into
mainfrom
feat/donate-modal

Conversation

@emlimlf
Copy link
Copy Markdown
Contributor

@emlimlf emlimlf commented May 14, 2026

Summary

  • Extends LfxDrawer with position="bottom" and hide-close-button props to support bottom-sheet layout
  • Adds a 4-screen donate flow (amount → contact → payment → thank you) as a globally accessible bottom drawer
  • Wires the "Fund this initiative" button on the initiative detail header to open the drawer via a Pinia store
  • Integrates Stripe Elements (split cardNumber / cardExpiry / cardCvc) for PCI-compliant card entry — raw card data never touches the server; a paymentMethodId is sent to the backend instead
  • Adds a mock POST /api/donate server route that stores submissions in memory pending the Go backend
  • Fixes LfxCheckbox icon alignment and sizing
  • Fixes LfxFieldMessages TypeScript error (ValidationBaseValidation)

What's not yet wired

The frontend posts a paymentMethodId to /api/donate but no actual charge is made — that requires the Go backend to call POST /v1/payment_intents with the Stripe secret key. A small follow-up to
donate-drawer.vue will be needed to handle a clientSecret in the response (for 3D Secure) once the backend endpoint is ready.

Test plan

  • Open initiative detail page → click "Fund this initiative" → drawer slides up from bottom
  • Step 1: select a tier or enter a custom amount; Continue is disabled until a selection is made
  • Step 2: toggle Individual / Company; required fields enforce Continue button disabled state; email validates format on blur
  • Step 3: Stripe card fields match LfxInput visual style; "Donate" button is disabled until all three fields report complete; use test card 4242 4242 4242 4242, any future expiry, any CVC
  • Stripe dashboard → Developers → Logs shows POST /v1/payment_methods on each submission
  • Thank you screen shows correct amount, tier badge, and share buttons
  • Closing at any step resets the form; reopening starts fresh at step 1
  • Back button on steps 2 and 3 navigates to the previous step

emlimlf added 4 commits May 14, 2026 12:56
Signed-off-by: Efren Lim <elim@linuxfoundation.org>
Signed-off-by: Efren Lim <elim@linuxfoundation.org>
Signed-off-by: Efren Lim <elim@linuxfoundation.org>
Signed-off-by: Efren Lim <elim@linuxfoundation.org>
Copilot AI review requested due to automatic review settings May 14, 2026 08:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a globally accessible, multi-step donation bottom-drawer flow in the Nuxt frontend, including Stripe Elements-based card entry and a temporary server-side mock endpoint to accept donation submissions while the Go backend is pending.

Changes:

  • Extended LfxDrawer to support a bottom-sheet layout (position="bottom") and optional built-in close button suppression.
  • Added a 3-step donate flow (amount → contact → payment) plus a success screen, opened globally via a Pinia store and wired from the initiative detail header CTA.
  • Integrated Stripe Elements via a useStripe() composable and added a mock POST /api/donate endpoint for local submission capture.

Reviewed changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
frontend/shared/types/donate.types.ts Adds shared types for donation tiers, forms, and submission/record payloads.
frontend/setup/runtime-config.ts Adds a public runtime config entry intended for the Stripe publishable key.
frontend/server/api/donate/index.post.ts Introduces a mock donation POST route that validates and stores submissions in memory.
frontend/package.json Adds @stripe/stripe-js dependency.
frontend/pnpm-lock.yaml Locks @stripe/stripe-js dependency.
frontend/app/layouts/default.vue Mounts the global donate drawer at the app layout level.
frontend/app/composables/useStripe.ts Adds a singleton Stripe loader keyed by runtime-config publishable key.
frontend/app/components/uikit/field/field-messages.vue Fixes Vuelidate typing by switching to BaseValidation.
frontend/app/components/uikit/drawer/drawer.vue Adds bottom positioning, height support, and hideCloseButton prop.
frontend/app/components/uikit/drawer/drawer.scss Adds bottom-drawer styling and makes drawer content relative.
frontend/app/components/uikit/checkbox/checkbox.vue Wraps checkbox input/icon for improved alignment and sizing.
frontend/app/components/uikit/checkbox/checkbox.scss Updates checkbox layout/CSS to match the new structure.
frontend/app/components/modules/initiatives/components/initiative-detail-header.vue Wires “Fund this initiative” CTA to open the donate drawer via store.
frontend/app/components/modules/donate/store/donate-drawer.store.ts Adds Pinia store to control donate drawer open state + initiative context.
frontend/app/components/modules/donate/components/donate-drawer-global.vue Provides a single global mount point for the donate drawer.
frontend/app/components/modules/donate/components/donate-drawer.vue Implements the multi-step donate drawer UI, validation gating, and submission call.
frontend/app/components/modules/donate/components/donate-step-amount.vue Implements tier selection + custom amount entry.
frontend/app/components/modules/donate/components/donate-step-contact.vue Implements donor info collection with Vuelidate validation.
frontend/app/components/modules/donate/components/donate-step-payment.vue Implements Stripe Elements card input and payment method creation.
frontend/app/components/modules/donate/components/donate-step-success.vue Implements the post-submission success/thank-you screen.
.claude/skills/uikit/references/components.md Updates internal component reference docs for the new LfxDrawer API.
Files not reviewed (1)
  • frontend/pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

auth0ClientId: process.env.NUXT_PUBLIC_AUTH0_CLIENT_ID || '',
auth0RedirectUri: `${appUrl}/auth/callback`,
auth0Audience: `${appUrl}/api/`,
stripePublishableKey: '', // populated from NUXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
initiativeId: body.initiativeId,
tierId: body.tierId ?? null,
tierName: body.tierName ?? null,
amountCents: body.amountCents,
Comment on lines +269 to +273
submitted.value = true;
emit('submitted');
} catch {
// Payment step displays its own Stripe error; API errors surface via $fetch
} finally {
type="solid"
:size="9"
class="c-checkbox__check text-white"
@click.stop
Comment on lines +20 to +24
<p class="text-sm text-neutral-600">
Your {{ formattedAmount }} donation to
<span class="font-semibold text-accent-600">{{ initiativeName }}</span>
has been processed.
</p>
@mlehotskylf mlehotskylf merged commit 5107067 into main May 14, 2026
9 checks passed
@mlehotskylf mlehotskylf deleted the feat/donate-modal branch May 14, 2026 18:38
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.

4 participants