mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 20:18:08 +00:00
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:
@@ -1,9 +1,11 @@
|
|||||||
<script setup>
|
<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 { useMapGetter, useStore } from 'dashboard/composables/store.js';
|
||||||
import { useAccount } from 'dashboard/composables/useAccount';
|
import { useAccount } from 'dashboard/composables/useAccount';
|
||||||
import { useCaptain } from 'dashboard/composables/useCaptain';
|
import { useCaptain } from 'dashboard/composables/useCaptain';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
|
import sessionStorage from 'shared/helpers/sessionStorage';
|
||||||
|
|
||||||
import BillingMeter from './components/BillingMeter.vue';
|
import BillingMeter from './components/BillingMeter.vue';
|
||||||
import BillingCard from './components/BillingCard.vue';
|
import BillingCard from './components/BillingCard.vue';
|
||||||
@@ -13,7 +15,8 @@ import BaseSettingsHeader from '../components/BaseSettingsHeader.vue';
|
|||||||
import SettingsLayout from '../SettingsLayout.vue';
|
import SettingsLayout from '../SettingsLayout.vue';
|
||||||
import ButtonV4 from 'next/button/Button.vue';
|
import ButtonV4 from 'next/button/Button.vue';
|
||||||
|
|
||||||
const { currentAccount } = useAccount();
|
const router = useRouter();
|
||||||
|
const { currentAccount, isOnChatwootCloud } = useAccount();
|
||||||
const {
|
const {
|
||||||
captainEnabled,
|
captainEnabled,
|
||||||
captainLimits,
|
captainLimits,
|
||||||
@@ -24,6 +27,12 @@ const {
|
|||||||
|
|
||||||
const uiFlags = useMapGetter('accounts/getUIFlags');
|
const uiFlags = useMapGetter('accounts/getUIFlags');
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
|
const BILLING_REFRESH_ATTEMPTED = 'billing_refresh_attempted';
|
||||||
|
|
||||||
|
// State for handling refresh attempts and loading
|
||||||
|
const isWaitingForBilling = ref(false);
|
||||||
|
|
||||||
const customAttributes = computed(() => {
|
const customAttributes = computed(() => {
|
||||||
return currentAccount.value.custom_attributes || {};
|
return currentAccount.value.custom_attributes || {};
|
||||||
});
|
});
|
||||||
@@ -61,11 +70,45 @@ const hasABillingPlan = computed(() => {
|
|||||||
|
|
||||||
const fetchAccountDetails = async () => {
|
const fetchAccountDetails = async () => {
|
||||||
if (!hasABillingPlan.value) {
|
if (!hasABillingPlan.value) {
|
||||||
store.dispatch('accounts/subscription');
|
await store.dispatch('accounts/subscription');
|
||||||
fetchLimits();
|
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 = () => {
|
const onClickBillingPortal = () => {
|
||||||
store.dispatch('accounts/checkout');
|
store.dispatch('accounts/checkout');
|
||||||
};
|
};
|
||||||
@@ -76,14 +119,18 @@ const onToggleChatWindow = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(fetchAccountDetails);
|
onMounted(handleBillingPageLogic);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<SettingsLayout
|
<SettingsLayout
|
||||||
:is-loading="uiFlags.isFetchingItem"
|
:is-loading="uiFlags.isFetchingItem || isWaitingForBilling"
|
||||||
:loading-message="$t('ATTRIBUTES_MGMT.LOADING')"
|
:loading-message="
|
||||||
:no-records-found="!hasABillingPlan"
|
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')"
|
:no-records-message="$t('BILLING_SETTINGS.NO_BILLING_USER')"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
|
|||||||
Reference in New Issue
Block a user