98 lines
3.0 KiB
TypeScript
98 lines
3.0 KiB
TypeScript
import { createSignal } from "solid-js"
|
|
import { updateActiveTenant } from "@/lib/hooks"
|
|
import { createInvoiceCheckout, createPortalSession } from "@/lib/api"
|
|
import { account } from "@/lib/state"
|
|
|
|
// Lightning/NWC save state machine, shared by the combined and focused setup
|
|
// dialogs. `onSaved` fires once the wallet URL is persisted.
|
|
export function useNwcSetup(onSaved?: () => void) {
|
|
const [nwcUrl, setNwcUrl] = createSignal("")
|
|
const [saving, setSaving] = createSignal(false)
|
|
const [saved, setSaved] = createSignal(false)
|
|
const [error, setError] = createSignal("")
|
|
|
|
async function save() {
|
|
const url = nwcUrl().trim()
|
|
if (!url) return
|
|
setSaving(true)
|
|
setError("")
|
|
try {
|
|
await updateActiveTenant({ nwc_url: url })
|
|
setSaved(true)
|
|
onSaved?.()
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e.message : "Failed to save wallet connection")
|
|
} finally {
|
|
setSaving(false)
|
|
}
|
|
}
|
|
|
|
function reset() {
|
|
setNwcUrl("")
|
|
setSaved(false)
|
|
setError("")
|
|
}
|
|
|
|
return { nwcUrl, setNwcUrl, saving, saved, error, save, reset }
|
|
}
|
|
|
|
export type NwcSetup = ReturnType<typeof useNwcSetup>
|
|
|
|
// Card setup is a full-page redirect to the Stripe billing portal (which returns
|
|
// to wherever it was opened from), so there's no local "saved" state — only the
|
|
// in-flight redirect and any failure to open the portal.
|
|
export function useCardPortal() {
|
|
const [redirecting, setRedirecting] = createSignal(false)
|
|
const [error, setError] = createSignal("")
|
|
|
|
async function openPortal() {
|
|
setRedirecting(true)
|
|
setError("")
|
|
try {
|
|
const { url } = await createPortalSession(account()!.pubkey, window.location.href)
|
|
window.location.href = url
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e.message : "Failed to open billing portal")
|
|
setRedirecting(false)
|
|
}
|
|
}
|
|
|
|
function reset() {
|
|
setError("")
|
|
}
|
|
|
|
return { redirecting, error, openPortal, reset }
|
|
}
|
|
|
|
export type CardPortal = ReturnType<typeof useCardPortal>
|
|
|
|
// Paying one specific invoice by card is a full-page redirect to a Stripe
|
|
// Checkout session scoped to that invoice (so a 3D Secure challenge can be
|
|
// completed) — distinct from the billing-portal redirect that manages the
|
|
// recurring card on file. Like the portal, there's no local "saved" state, only
|
|
// the in-flight redirect and any failure to open the session.
|
|
export function useInvoiceCheckout(invoiceId: () => string) {
|
|
const [redirecting, setRedirecting] = createSignal(false)
|
|
const [error, setError] = createSignal("")
|
|
|
|
async function openCheckout() {
|
|
setRedirecting(true)
|
|
setError("")
|
|
try {
|
|
const { url } = await createInvoiceCheckout(invoiceId())
|
|
window.location.href = url
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e.message : "Failed to open checkout")
|
|
setRedirecting(false)
|
|
}
|
|
}
|
|
|
|
function reset() {
|
|
setError("")
|
|
}
|
|
|
|
return { redirecting, error, openCheckout, reset }
|
|
}
|
|
|
|
export type InvoiceCheckout = ReturnType<typeof useInvoiceCheckout>
|