Phase8: Auto bill credit card
All checks were successful
Build and Push / build (push) Successful in 1m45s
All checks were successful
Build and Push / build (push) Successful in 1m45s
This commit is contained in:
@@ -1,26 +1,6 @@
|
|||||||
import { redirect, notFound } from "next/navigation";
|
import { redirect, notFound } from "next/navigation";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import { getSessionUser } from "@/lib/session";
|
import { getSessionUser } from "@/lib/session";
|
||||||
import { getOrgBilling } from "@/lib/db";
|
|
||||||
import { BillingSettingsForm } from "@/components/settings/billing-form";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* /settings/billing — customer-side billing details management.
|
|
||||||
*
|
|
||||||
* Owner-only by visibility: non-owner members get a 404 (same
|
|
||||||
* response as if the page didn't exist). The link to this page
|
|
||||||
* is also hidden from non-owners on /billing and elsewhere, but
|
|
||||||
* the page itself enforces too — a non-owner who learns the URL
|
|
||||||
* still gets 404, not 403, so the page's existence doesn't leak.
|
|
||||||
*
|
|
||||||
* First-time visitors see an empty form. Subsequent visits see
|
|
||||||
* the current values, editable. Save creates or updates via the
|
|
||||||
* shared upsert path; the row's existence drives whether the
|
|
||||||
* monthly issuance cron will pick this org up.
|
|
||||||
*/
|
|
||||||
import { redirect, notFound } from "next/navigation";
|
|
||||||
import { getTranslations } from "next-intl/server";
|
|
||||||
import { getSessionUser } from "@/lib/session";
|
|
||||||
import { getOrgBilling, getOrgBillingConfig } from "@/lib/db";
|
import { getOrgBilling, getOrgBillingConfig } from "@/lib/db";
|
||||||
import { BillingSettingsForm } from "@/components/settings/billing-form";
|
import { BillingSettingsForm } from "@/components/settings/billing-form";
|
||||||
import { SavedCardSection } from "@/components/settings/saved-card-section";
|
import { SavedCardSection } from "@/components/settings/saved-card-section";
|
||||||
@@ -40,9 +20,9 @@ import { SavedCardSection } from "@/components/settings/saved-card-section";
|
|||||||
* monthly issuance cron will pick this org up.
|
* monthly issuance cron will pick this org up.
|
||||||
*
|
*
|
||||||
* Phase 9: also renders the saved-card section (Set up auto-pay /
|
* Phase 9: also renders the saved-card section (Set up auto-pay /
|
||||||
* Visa •••• 4242, expires 05/27 / Update card / Disable auto-pay /
|
* Visa dot-dot-dot 4242, expires MM/YY / Update card / Disable
|
||||||
* Remove card) when billing info is on file, plus a footer note
|
* auto-pay / Remove card) when billing info is on file, plus a
|
||||||
* explaining that bank transfer is available on request.
|
* footer note explaining that bank transfer is available on request.
|
||||||
*/
|
*/
|
||||||
export default async function BillingSettingsPage() {
|
export default async function BillingSettingsPage() {
|
||||||
const user = await getSessionUser();
|
const user = await getSessionUser();
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ const MIGRATION_SQL = `
|
|||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
);
|
);
|
||||||
-- Phase 9: saved-card columns. The PaymentMethod id (`pm_xxx`)
|
-- Phase 9: saved-card columns. The PaymentMethod id ('pm_xxx')
|
||||||
-- is the handle for off-session charges; brand/last4/exp are
|
-- is the handle for off-session charges; brand/last4/exp are
|
||||||
-- display fields. No PAN, CVV, or anything PCI-scope — Stripe
|
-- display fields. No PAN, CVV, or anything PCI-scope — Stripe
|
||||||
-- holds those. The columns are nullable because a fresh org has
|
-- holds those. The columns are nullable because a fresh org has
|
||||||
|
|||||||
Reference in New Issue
Block a user