feat: handling subscription tier button link parameter (#7553)

## Summary

Discussion here:
https://comfy-organization.slack.com/archives/C0A0XANFJRE/p1764899027465379

Implement: Subscription tier query parameter for direct checkout flow

Example button link: `/cloud/subscribe?tier=standard`

`tier` could be `standard`, `creator` or `pro`
`cycle` could be `monthly` or `yearly`. it is optional, and `monthly` by
default.

<!-- One sentence describing what changed and why. -->

## Changes

- **What**: <!-- Core functionality added/modified -->
- Add a landing page called `CloudSubscriptionRedirectView.vue` to
handling the subscription tier button link parameter
  - Extract subscription handling logic from `PriceTable.vue`
 
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
  - Code change touched  `PriceTable.vue`
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->

## Review Focus
- link will redirect to login url, when cloud app not login
- after login, the cloud app will redirect to CloudSubscriptionRedirect
page
- wait for several seconds, the cloud app will be redirected to checkout
page

<!-- Critical design decisions or edge cases that need attention -->

<!-- If this PR fixes an issue, uncomment and update the line below -->
<!-- Fixes #ISSUE_NUMBER -->

## Screenshots (if applicable)

![Kapture 2025-12-16 at 18 43
28](https://github.com/user-attachments/assets/affbc18f-d45c-4953-b06a-fc797eba6804)


<!-- Add screenshots or video recording to help explain your changes -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7553-feat-handling-subscription-tier-button-link-parameter-2cb6d73d365081ee9580e89090248300)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Yourz
2026-01-15 08:57:51 +08:00
committed by GitHub
parent 97b1a48a25
commit 3069c24f81
15 changed files with 536 additions and 71 deletions

View File

@@ -28,6 +28,7 @@ export type CloudSubscriptionStatusResponse = NonNullable<
function useSubscriptionInternal() {
const subscriptionStatus = ref<CloudSubscriptionStatusResponse | null>(null)
const telemetry = useTelemetry()
const isInitialized = ref(false)
const isSubscribedOrIsNotCloud = computed(() => {
if (!isCloud || !window.__CONFIG__?.subscription_required) return true
@@ -200,10 +201,15 @@ function useSubscriptionInternal() {
() => isLoggedIn.value,
async (loggedIn) => {
if (loggedIn) {
await fetchSubscriptionStatus()
try {
await fetchSubscriptionStatus()
} finally {
isInitialized.value = true
}
} else {
subscriptionStatus.value = null
stopCancellationWatcher()
isInitialized.value = true
}
},
{ immediate: true }
@@ -244,6 +250,7 @@ function useSubscriptionInternal() {
return {
// State
isActiveSubscription: isSubscribedOrIsNotCloud,
isInitialized,
isCancelled,
formattedRenewalDate,
formattedEndDate,