mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
After sign-in, an account that has chosen no plan (none kept as onboarding.plan, Free included) and pays for none is sent straight to pay's plans (/pay/cart?welcome=1), after the terms if it owes them. The Personal or Business step is gone for it: the plans page has both tabs. `welcome` draws a Back to hanzo.ai there until a plan is chosen (hanzo-inc/pay#10). Every later sign-in opens the plans again until one is; an earlier Personal/Business answer (`use`) is not a plan. A SuperAdmin, a support session, an invited member, a checkout chosen before sign-in and Free chosen on /pricing go on as before, and an IAM read that fails is read as a plan chosen, so it never holds anyone there. Sign-in and sign-up no longer offer the phone or the wallet (OFFERED in components/auth/panel.tsx); their flows stay, to offer again. Testing: pnpm typecheck clean (0 errors); oxlint shows no new warnings in the three files; no e2e spec covers these screens. Risk: medium. Accounts that never chose a plan, including older ones, now land on the plans at sign-in until they pick one (Free is one tap). How to revert: revert this commit. Co-authored-by: Claude Opus 5.5 <[email protected]>
77 lines
3.0 KiB
TypeScript
77 lines
3.0 KiB
TypeScript
/**
|
|
* pay's two addresses on this site: its plans, where a plan is chosen, and its
|
|
* card step, the one address a plan is bought at.
|
|
*
|
|
* hanzo-inc/pay is mounted at /pay on this origin. `/pay/cart` is every plan the
|
|
* catalog sells, one card each, priced by commerce and with a link's coupon
|
|
* quoted on the plans it covers; its close control and a finished purchase come
|
|
* back to `returnUrl`. It takes the organization billed, the coupon and the
|
|
* campaign the link carried.
|
|
*
|
|
* `/pay/confirm/card` names the plan and its price and asks for the card, with
|
|
* no picker before it. It takes the plan's catalog slug, the term, the seats, a
|
|
* first-month coupon commerce quoted for the plan (lib/coupon), the
|
|
* organization billed, and the hanzo.ai address to return to once paid. A
|
|
* month and one seat are pay's defaults and are not written. The price never
|
|
* rides along: commerce reads it.
|
|
*/
|
|
|
|
import type { Interval } from '@hanzo/app/lib/plans'
|
|
|
|
/** What pay's card step is opened on. */
|
|
export interface Order {
|
|
/** The catalog slug. */
|
|
plan: string
|
|
interval?: Interval
|
|
/** Seats, for a per-seat plan. */
|
|
quantity?: number
|
|
coupon?: string
|
|
/** The organization the purchase bills. */
|
|
org?: string
|
|
/** The campaign the link carried (lib/campaign), kept on every hop inside pay. */
|
|
campaign?: [string, string][]
|
|
/** Where pay sends the buyer once paid: an absolute hanzo.ai address. */
|
|
returnUrl: string
|
|
}
|
|
|
|
/** The path of pay's card step for `order`. */
|
|
export function checkout({ plan, interval = 'month', quantity = 1, coupon, org, campaign = [], returnUrl }: Order): string {
|
|
const q = new URLSearchParams({ plan })
|
|
if (interval === 'year') q.set('interval', 'year')
|
|
if (quantity > 1) q.set('quantity', String(quantity))
|
|
if (coupon) q.set('coupon', coupon)
|
|
if (org) q.set('org', org)
|
|
for (const [k, v] of campaign) q.append(k, v)
|
|
q.set('returnUrl', returnUrl)
|
|
return `/pay/confirm/card?${q}`
|
|
}
|
|
|
|
/** What pay's plans are opened on. */
|
|
export interface Browse {
|
|
/** The organization a purchase bills. */
|
|
org?: string
|
|
/** A coupon the link carried: pay quotes it on each plan it covers and says when it covers none. */
|
|
coupon?: string
|
|
/** The campaign the link carried (lib/campaign), kept on every hop inside pay. */
|
|
campaign?: [string, string][]
|
|
/** Where the close control and a finished purchase return to: an absolute hanzo.ai address. */
|
|
returnUrl: string
|
|
/**
|
|
* An account that has chosen no plan yet, sent here by its sign-in
|
|
* (components/onboarding/flow): pay draws a Back to the site above the plans
|
|
* until one is chosen, Free included (hanzo-inc/pay routes/cart).
|
|
*/
|
|
welcome?: boolean
|
|
}
|
|
|
|
/** The path of pay's plans for `browse`. */
|
|
export function plans({ org, coupon, campaign = [], returnUrl, welcome }: Browse): string {
|
|
const q = new URLSearchParams()
|
|
if (org) q.set('org', org)
|
|
if (coupon) q.set('coupon', coupon)
|
|
for (const [k, v] of campaign) q.append(k, v)
|
|
q.set('returnUrl', returnUrl)
|
|
if (welcome) q.set('welcome', '1')
|
|
return `/pay/cart?${q}`
|
|
}
|