chore: Add auto-refresh and self-hosted redirect logic to the billing page (#12615)

# Pull Request Template

## Description

This PR includes billing page improvements with the following updates:

### Self-hosted Users

* Automatically redirected to the dashboard when accessing the billing
page.

### Cloud Users – No Billing Plan (First Visit)

* Shows a loading spinner with the `Your billing account is being
configured. Please refresh the page and try again.` message.
* Automatically refreshes the page after 5 seconds to check for billing
setup.

### Cloud Users – No Billing Plan (After Refresh)

* Prevents infinite refresh loops using `sessionStorage` tracking.
* Displays the standard `Your billing account is being configured.
Please refresh the page and try again.` message without further refresh
attempts.
* Cleans up session flags for future visits.

### Cloud Users – With Billing Plan

* Displays the existing billing page normally with no refresh or
redirection logic.


Fixes
https://linear.app/chatwoot/issue/CW-5559/your-billing-page-is-being-set-up-message-on-billing-page-is-confusing

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

### Loom video

https://www.loom.com/share/d0ea13d6b90b4ab1acbc581b524f6382?sid=d3dd19f3-85aa-4127-9233-7eecb1be0884

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
Sivin Varghese
2025-10-09 23:27:30 +05:30
committed by GitHub
parent d8da1f5bf3
commit cb65d615ea

View File

@@ -1,9 +1,11 @@
<script setup>
import { computed, onMounted } from 'vue';
import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useMapGetter, useStore } from 'dashboard/composables/store.js';
import { useAccount } from 'dashboard/composables/useAccount';
import { useCaptain } from 'dashboard/composables/useCaptain';
import { format } from 'date-fns';
import sessionStorage from 'shared/helpers/sessionStorage';
import BillingMeter from './components/BillingMeter.vue';
import BillingCard from './components/BillingCard.vue';
@@ -13,7 +15,8 @@ import BaseSettingsHeader from '../components/BaseSettingsHeader.vue';
import SettingsLayout from '../SettingsLayout.vue';
import ButtonV4 from 'next/button/Button.vue';
const { currentAccount } = useAccount();
const router = useRouter();
const { currentAccount, isOnChatwootCloud } = useAccount();
const {
captainEnabled,
captainLimits,
@@ -24,6 +27,12 @@ const {
const uiFlags = useMapGetter('accounts/getUIFlags');
const store = useStore();
const BILLING_REFRESH_ATTEMPTED = 'billing_refresh_attempted';
// State for handling refresh attempts and loading
const isWaitingForBilling = ref(false);
const customAttributes = computed(() => {
return currentAccount.value.custom_attributes || {};
});
@@ -61,11 +70,45 @@ const hasABillingPlan = computed(() => {
const fetchAccountDetails = async () => {
if (!hasABillingPlan.value) {
store.dispatch('accounts/subscription');
await store.dispatch('accounts/subscription');
fetchLimits();
}
};
const handleBillingPageLogic = async () => {
// If self-hosted, redirect to dashboard
if (!isOnChatwootCloud.value) {
router.push({ name: 'home' });
return;
}
// Check if we've already attempted a refresh for billing setup
const billingRefreshAttempted = sessionStorage.get(BILLING_REFRESH_ATTEMPTED);
// If cloud user, fetch account details first
await fetchAccountDetails();
// If still no billing plan after fetch
if (!hasABillingPlan.value) {
// If we haven't attempted refresh yet, do it once
if (!billingRefreshAttempted) {
isWaitingForBilling.value = true;
sessionStorage.set(BILLING_REFRESH_ATTEMPTED, true);
setTimeout(() => {
window.location.reload();
}, 5000);
} else {
// We've already tried refreshing, so just show the no billing message
// Clear the flag for future visits
sessionStorage.remove(BILLING_REFRESH_ATTEMPTED);
}
} else {
// Billing plan found, clear any existing refresh flag
sessionStorage.remove(BILLING_REFRESH_ATTEMPTED);
}
};
const onClickBillingPortal = () => {
store.dispatch('accounts/checkout');
};
@@ -76,14 +119,18 @@ const onToggleChatWindow = () => {
}
};
onMounted(fetchAccountDetails);
onMounted(handleBillingPageLogic);
</script>
<template>
<SettingsLayout
:is-loading="uiFlags.isFetchingItem"
:loading-message="$t('ATTRIBUTES_MGMT.LOADING')"
:no-records-found="!hasABillingPlan"
:is-loading="uiFlags.isFetchingItem || isWaitingForBilling"
:loading-message="
isWaitingForBilling
? $t('BILLING_SETTINGS.NO_BILLING_USER')
: $t('ATTRIBUTES_MGMT.LOADING')
"
:no-records-found="!hasABillingPlan && !isWaitingForBilling"
:no-records-message="$t('BILLING_SETTINGS.NO_BILLING_USER')"
>
<template #header>