feat(signup): unify cadence UX across accept-invite, join, and account
Extract shared SignupFlowOverlay component. Static "Monthly Contribution" label on all three contribution inputs (was misleadingly dynamic). "Per Year"/"Per Month" toggle copy; Per Year default on accept-invite, Per Month default on join. Live billing-summary card on both signup flows. Welcome-heading on dashboard via ?welcome=1 for new signups. $0-member polish on account page (hide payment-history + Solidarity Fund prompts). State-aware contribution-change hint. Invite accept now creates Helcim customer and sets auth cookie server-side for both free and paid branches. Pre-registrant invite + /join signup flows manually verified against Cleo Nguyen preReg and $0-$50 variants.
This commit is contained in:
parent
493be2f3bc
commit
a80728f0a8
10 changed files with 553 additions and 321 deletions
|
|
@ -2,7 +2,9 @@ import jwt from 'jsonwebtoken'
|
|||
import PreRegistration from '../../models/preRegistration.js'
|
||||
import Member from '../../models/member.js'
|
||||
import { connectDB } from '../../utils/mongoose.js'
|
||||
import { setAuthCookie } from '../../utils/auth.js'
|
||||
import { assignMemberNumber } from '../../utils/memberNumber.js'
|
||||
import { createHelcimCustomer } from '../../utils/helcim.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await validateBody(event, inviteAcceptSchema)
|
||||
|
|
@ -36,6 +38,18 @@ export default defineEventHandler(async (event) => {
|
|||
throw createError({ statusCode: 409, statusMessage: 'A member with this email already exists' })
|
||||
}
|
||||
|
||||
// For paid invites, create the Helcim customer up front so we can store the ID
|
||||
// on the Member at creation time. Done before Member.create so a Helcim failure
|
||||
// doesn't leave us with an orphan Member doc.
|
||||
let helcimCustomer = null
|
||||
if (body.contributionAmount > 0) {
|
||||
helcimCustomer = await createHelcimCustomer({
|
||||
customerType: 'PERSON',
|
||||
contactName: body.name,
|
||||
email: preReg.email,
|
||||
})
|
||||
}
|
||||
|
||||
// Create the member
|
||||
const member = await Member.create({
|
||||
email: preReg.email,
|
||||
|
|
@ -46,6 +60,7 @@ export default defineEventHandler(async (event) => {
|
|||
contributionAmount: body.contributionAmount,
|
||||
bio: body.motivation || undefined,
|
||||
status: body.contributionAmount === 0 ? 'active' : 'pending_payment',
|
||||
helcimCustomerId: helcimCustomer?.id,
|
||||
agreement: { acceptedAt: new Date() },
|
||||
})
|
||||
|
||||
|
|
@ -65,22 +80,12 @@ export default defineEventHandler(async (event) => {
|
|||
preRegistrationId: preReg._id,
|
||||
})
|
||||
|
||||
// For free tier, issue session and redirect to welcome
|
||||
// Issue session cookie so the member is authenticated for any follow-up calls
|
||||
// (Helcim initialize-payment for paid flow, dashboard fetches for free flow).
|
||||
setAuthCookie(event, member)
|
||||
|
||||
// For free tier, redirect to welcome
|
||||
if (body.contributionAmount === 0) {
|
||||
const sessionToken = jwt.sign(
|
||||
{ memberId: member._id, email: member.email, tv: member.tokenVersion },
|
||||
config.jwtSecret,
|
||||
{ expiresIn: '7d' },
|
||||
)
|
||||
|
||||
setCookie(event, 'auth-token', sessionToken, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
maxAge: 60 * 60 * 24 * 7,
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
requiresPayment: false,
|
||||
|
|
@ -96,10 +101,12 @@ export default defineEventHandler(async (event) => {
|
|||
}
|
||||
}
|
||||
|
||||
// For paid tiers, return member info so frontend can proceed to Helcim payment
|
||||
// For paid tiers, return member + Helcim customer so frontend can proceed to payment
|
||||
return {
|
||||
success: true,
|
||||
requiresPayment: true,
|
||||
customerId: helcimCustomer.id,
|
||||
customerCode: helcimCustomer.customerCode,
|
||||
member: {
|
||||
id: member._id,
|
||||
email: member.email,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue