mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-27 17:42:15 +00:00
Subscription upgrade/downgrade + tier management (#3927)
## Summary - Tier upgrade/downgrade in the Store. The Subscriptions tab now shows all tiers including the user's current one. Other tiers swap "Subscribe" → "Switch" when the user already has a sub, and clicking them calls the new `POST /subscriptions/@me/change-tier` endpoint with a direction-aware confirm (upgrade charges prorated diff now, downgrade gives account credit). - Owned-tier card renders a **Current Plan** badge in place of the purchase button. Resolution logic in `resolveCosmetics` now reads `userMeResponse.player.subscription.tier` (with flare fallback) and marks that tier as `owned`. - AccountModal's `<subscription-panel>` reworked into a proper two-column layout: - **Left**: tier name, `$X.XX/mo` price, description, daily Pu/Caps amounts. - **Right**: status badge (Active / Renews date / Cancels date), `[Manage] [Change Tier]` button row, `[Cancel]` centered underneath. When `cancelAtPeriodEnd === true`, the row collapses to a single `[Reactivate]` button (opens the Stripe portal). - New `<o-button size="xs">` variant (`py-2 px-3 text-xs`) for the compact panel buttons. - Store dollar-purchase price label now supports an optional suffix (`/mo` for subs only) via a `priceSuffix` prop plumbed through `CosmeticContainer` → `PurchaseButton`. - `Api.ts` gains `changeSubscriptionTier(tierName)` with the same 401-handling pattern as the existing subscription helpers. <img width="1114" height="728" alt="Screenshot 2026-05-14 at 7 09 20 PM" src="https://github.com/user-attachments/assets/688f83d5-4010-4580-9214-6885af8ec98e" /> <img width="1038" height="276" alt="Screenshot 2026-05-14 at 7 09 33 PM" src="https://github.com/user-attachments/assets/458197f5-a0d4-4c32-bc55-31e5679629b5" /> <img width="887" height="286" alt="Screenshot 2026-05-14 at 7 09 55 PM" src="https://github.com/user-attachments/assets/8149ed82-89cc-4bbe-83de-3614f886b331" /> ## Discord evan
This commit is contained in:
@@ -196,6 +196,40 @@ export async function cancelSubscription(): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function changeSubscriptionTier(
|
||||
tierName: string,
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${getApiBase()}/subscriptions/@me/change-tier`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: await getAuthHeader(),
|
||||
},
|
||||
body: JSON.stringify({ tierName }),
|
||||
},
|
||||
);
|
||||
if (response.status === 401) {
|
||||
await logOut();
|
||||
return false;
|
||||
}
|
||||
if (!response.ok) {
|
||||
console.error(
|
||||
"changeSubscriptionTier: request failed",
|
||||
response.status,
|
||||
response.statusText,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error("changeSubscriptionTier: request failed", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function openSubscriptionPortal(): Promise<string | false> {
|
||||
try {
|
||||
const response = await fetch(`${getApiBase()}/subscriptions/@me/portal`, {
|
||||
|
||||
Reference in New Issue
Block a user