Phase8: Auto bill credit card
All checks were successful
Build and Push / build (push) Successful in 1m44s

This commit is contained in:
2026-05-28 21:49:59 +02:00
parent 3fe3597553
commit d78f9f2696
6 changed files with 33 additions and 93 deletions

View File

@@ -192,11 +192,6 @@ export function OnboardingWizard({
const [step, setStep] = useState<Step>(isEditing ? "configure" : "welcome");
const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState("");
// Phase 9b: 402 from the onboarding endpoint indicates the org
// needs to set up auto-pay before ordering. We render a tailored
// error block with a clickable link to /settings/billing rather
// than the generic red message.
const [autoPayRequired, setAutoPayRequired] = useState(false);
const [advancedOpen, setAdvancedOpen] = useState(false);
// In edit mode we already have soulMd/agentsMd from the request;
// skip the workspace-defaults round trip that would overwrite them.
@@ -444,7 +439,6 @@ export function OnboardingWizard({
setSubmitting(true);
setError("");
setAutoPayRequired(false);
try {
// Build secrets payload — only for packages that require them
@@ -491,19 +485,6 @@ export function OnboardingWizard({
}),
});
// Phase 9b (revised): 402 means the org needs a saved card
// before ordering. There's no "enable auto-pay" step anymore
// — a card on file is all that's required.
if (res.status === 402) {
const data = await res.json().catch(() => ({}));
if (data?.code === "card_required" || data?.code === "auto_pay_required") {
setAutoPayRequired(true);
setError(t("cardRequiredError"));
return;
}
throw new Error(data.error || "Submission failed");
}
if (!res.ok) {
const data = await res.json();
throw new Error(data.error || "Submission failed");
@@ -811,8 +792,16 @@ export function OnboardingWizard({
</div>
</button>
{/* Inline credential inputs — expand when selected + requires secrets */}
{isSelected && pkg.requiresSecrets && (
{/* Inline expansion when selected — shows
instructions (if any), credential inputs
(if requiresSecrets), and the disclaimer
checkbox (if any). Threema for example
has no customer-entered secrets but has
instructions + a disclaimer to accept. */}
{isSelected &&
(pkg.requiresSecrets ||
pkg.instructionsKey ||
pkg.disclaimerKey) && (
<div className="border-t border-border px-3 py-3 space-y-3 bg-surface-1/50">
{pkg.instructionsKey && (
<div className="bg-surface-2 border border-border rounded-lg p-3 text-xs text-text-secondary leading-relaxed whitespace-pre-line">
@@ -1275,17 +1264,6 @@ export function OnboardingWizard({
{error && (
<div className="text-xs text-red-400 bg-red-400/10 border border-red-400/20 rounded-lg px-3 py-2 mt-4">
{error}
{autoPayRequired && (
<>
{" "}
<a
href="/settings/billing"
className="underline font-medium text-red-300 hover:text-red-200"
>
{t("autoPaySetupLink")}
</a>
</>
)}
</div>
)}