-
+
+
+
+
-
- {{ $t('CAPTAIN.PAYWALL.UPGRADE_NOW') }}
-
+
+
-
- {{ $t('BILLING_SETTINGS.CHAT_WITH_US.BUTTON_TXT') }}
-
+ sm
+ icon="i-lucide-message-circle"
+ :label="$t('BILLING_SETTINGS.HELP.CHAT')"
+ @click="openChatWidget"
+ />
+
+
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/components/CancelSubscriptionModal.vue b/app/javascript/dashboard/routes/dashboard/settings/billing/components/CancelSubscriptionModal.vue
new file mode 100644
index 000000000..1aa770621
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/billing/components/CancelSubscriptionModal.vue
@@ -0,0 +1,141 @@
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/components/CancellationFeedbackForm.vue b/app/javascript/dashboard/routes/dashboard/settings/billing/components/CancellationFeedbackForm.vue
new file mode 100644
index 000000000..5d1c8645c
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/billing/components/CancellationFeedbackForm.vue
@@ -0,0 +1,117 @@
+
+
+
+
+
+ {{ t('BILLING_SETTINGS.FEEDBACK_MODAL.DESCRIPTION') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/components/ChangePlanModal.vue b/app/javascript/dashboard/routes/dashboard/settings/billing/components/ChangePlanModal.vue
new file mode 100644
index 000000000..a3120a5be
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/billing/components/ChangePlanModal.vue
@@ -0,0 +1,147 @@
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/components/CreditHistoryModal.vue b/app/javascript/dashboard/routes/dashboard/settings/billing/components/CreditHistoryModal.vue
new file mode 100644
index 000000000..3d6fe138b
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/billing/components/CreditHistoryModal.vue
@@ -0,0 +1,146 @@
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/components/CreditPackageCard.vue b/app/javascript/dashboard/routes/dashboard/settings/billing/components/CreditPackageCard.vue
new file mode 100644
index 000000000..f24abcb32
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/billing/components/CreditPackageCard.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
+ {{ t('BILLING_SETTINGS.PURCHASE_MODAL.MOST_POPULAR') }}
+
+
+
+
+
+ {{ formattedCredits }}
+
+
+ {{ t('BILLING_SETTINGS.PURCHASE_MODAL.CREDITS') }}
+
+
+ {{
+ formattedAmount
+ }}
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/components/PlanCard.vue b/app/javascript/dashboard/routes/dashboard/settings/billing/components/PlanCard.vue
new file mode 100644
index 000000000..caca30699
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/billing/components/PlanCard.vue
@@ -0,0 +1,99 @@
+
+
+
+
+
+ {{ t('BILLING_SETTINGS.CHANGE_PLAN_MODAL.CURRENT_PLAN') }}
+
+
+
+
+
+ {{ plan.display_name }}
+
+
+
+ {{ displayPrice }}
+
+
+ {{ t('BILLING_SETTINGS.CHANGE_PLAN_MODAL.PER_USER_MONTH') }}
+
+
+
+ {{ monthlyCredits }}
+ {{ t('BILLING_SETTINGS.CHANGE_PLAN_MODAL.AI_CREDITS_MONTH') }}
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/components/PurchaseCreditsModal.vue b/app/javascript/dashboard/routes/dashboard/settings/billing/components/PurchaseCreditsModal.vue
new file mode 100644
index 000000000..1d65c6750
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/billing/components/PurchaseCreditsModal.vue
@@ -0,0 +1,112 @@
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/components/SeatStepper.vue b/app/javascript/dashboard/routes/dashboard/settings/billing/components/SeatStepper.vue
new file mode 100644
index 000000000..93f54a14c
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/billing/components/SeatStepper.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+ {{ localValue }}
+
+
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/components/SubscriptionRow.vue b/app/javascript/dashboard/routes/dashboard/settings/billing/components/SubscriptionRow.vue
new file mode 100644
index 000000000..43b6b8a31
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/billing/components/SubscriptionRow.vue
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+ {{ label }}
+
+
+
+ {{ value }}
+
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/store/modules/accounts.js b/app/javascript/dashboard/store/modules/accounts.js
index 1eef59cfe..2857783d1 100644
--- a/app/javascript/dashboard/store/modules/accounts.js
+++ b/app/javascript/dashboard/store/modules/accounts.js
@@ -18,7 +18,17 @@ const state = {
isFetchingItem: false,
isUpdating: false,
isCheckoutInProcess: false,
+ isFetchingPricingPlans: false,
+ isFetchingTopupOptions: false,
+ isFetchingCreditGrants: false,
+ isChangingPlan: false,
+ isCancellingSubscription: false,
+ isPurchasingCredits: false,
+ isSubscribing: false,
},
+ pricingPlans: [],
+ topupOptions: [],
+ creditGrants: [],
};
export const getters = {
@@ -28,6 +38,15 @@ export const getters = {
getUIFlags($state) {
return $state.uiFlags;
},
+ getPricingPlans($state) {
+ return $state.pricingPlans;
+ },
+ getTopupOptions($state) {
+ return $state.topupOptions;
+ },
+ getCreditGrants($state) {
+ return $state.creditGrants;
+ },
isRTL: ($state, _getters, rootState, rootGetters) => {
const accountId = Number(rootState.route?.params?.accountId);
const userLocale = rootGetters?.getUISettings?.locale;
@@ -152,6 +171,120 @@ export const actions = {
getCacheKeys: async () => {
return AccountAPI.getCacheKeys();
},
+
+ // V2 Billing Actions
+ fetchPricingPlans: async ({ commit }) => {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, { isFetchingPricingPlans: true });
+ try {
+ const response = await EnterpriseAccountAPI.getPricingPlans();
+ commit(types.default.SET_PRICING_PLANS, response.data.pricing_plans);
+ } catch (error) {
+ // silent error
+ } finally {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, {
+ isFetchingPricingPlans: false,
+ });
+ }
+ },
+
+ fetchTopupOptions: async ({ commit }) => {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, { isFetchingTopupOptions: true });
+ try {
+ const response = await EnterpriseAccountAPI.getTopupOptions();
+ commit(types.default.SET_TOPUP_OPTIONS, response.data.topup_options);
+ } catch (error) {
+ // silent error
+ } finally {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, {
+ isFetchingTopupOptions: false,
+ });
+ }
+ },
+
+ fetchCreditGrants: async ({ commit }) => {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, { isFetchingCreditGrants: true });
+ try {
+ const response = await EnterpriseAccountAPI.getCreditGrants();
+ commit(types.default.SET_CREDIT_GRANTS, response.data.credit_grants);
+ } catch (error) {
+ // silent error
+ } finally {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, {
+ isFetchingCreditGrants: false,
+ });
+ }
+ },
+
+ changePricingPlan: async ({ commit }, { pricingPlanId, quantity }) => {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, { isChangingPlan: true });
+ try {
+ const response = await EnterpriseAccountAPI.changePricingPlan(
+ pricingPlanId,
+ quantity
+ );
+ commit(types.default.EDIT_ACCOUNT, response.data);
+ return response.data;
+ } catch (error) {
+ throwErrorMessage(error);
+ throw error;
+ } finally {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, { isChangingPlan: false });
+ }
+ },
+
+ cancelAccountSubscription: async ({ commit }, { reason, feedback }) => {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, {
+ isCancellingSubscription: true,
+ });
+ try {
+ const response = await EnterpriseAccountAPI.cancelSubscription(
+ reason,
+ feedback
+ );
+ commit(types.default.EDIT_ACCOUNT, response.data);
+ return response.data;
+ } catch (error) {
+ throwErrorMessage(error);
+ throw error;
+ } finally {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, {
+ isCancellingSubscription: false,
+ });
+ }
+ },
+
+ purchaseCredits: async ({ commit }, { credits }) => {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, { isPurchasingCredits: true });
+ try {
+ const response = await EnterpriseAccountAPI.topupCredits(credits);
+ return response.data;
+ } catch (error) {
+ throwErrorMessage(error);
+ throw error;
+ } finally {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, { isPurchasingCredits: false });
+ }
+ },
+
+ subscribeToPlan: async ({ commit }, { pricingPlanId, quantity }) => {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, { isSubscribing: true });
+ try {
+ const response = await EnterpriseAccountAPI.subscribeToPlan(
+ pricingPlanId,
+ quantity
+ );
+ // Redirect to Stripe checkout
+ if (response.data.redirect_url) {
+ window.location = response.data.redirect_url;
+ }
+ return response.data;
+ } catch (error) {
+ throwErrorMessage(error);
+ throw error;
+ } finally {
+ commit(types.default.SET_ACCOUNT_UI_FLAG, { isSubscribing: false });
+ }
+ },
};
export const mutations = {
@@ -164,6 +297,15 @@ export const mutations = {
[types.default.ADD_ACCOUNT]: MutationHelpers.setSingleRecord,
[types.default.EDIT_ACCOUNT]: MutationHelpers.update,
[types.default.SET_ACCOUNT_LIMITS]: MutationHelpers.updateAttributes,
+ [types.default.SET_PRICING_PLANS]($state, data) {
+ $state.pricingPlans = data;
+ },
+ [types.default.SET_TOPUP_OPTIONS]($state, data) {
+ $state.topupOptions = data;
+ },
+ [types.default.SET_CREDIT_GRANTS]($state, data) {
+ $state.creditGrants = data;
+ },
};
export default {
diff --git a/app/javascript/dashboard/store/mutation-types.js b/app/javascript/dashboard/store/mutation-types.js
index 68ff79e66..104155deb 100644
--- a/app/javascript/dashboard/store/mutation-types.js
+++ b/app/javascript/dashboard/store/mutation-types.js
@@ -76,13 +76,16 @@ export default {
EDIT_INBOXES: 'EDIT_INBOXES',
DELETE_INBOXES: 'DELETE_INBOXES',
- // Agent
+ // Account
SET_ACCOUNT_UI_FLAG: 'SET_ACCOUNT_UI_FLAG',
SET_ACCOUNT_LIMITS: 'SET_ACCOUNT_LIMITS',
SET_ACCOUNTS: 'SET_ACCOUNTS',
ADD_ACCOUNT: 'ADD_ACCOUNT',
EDIT_ACCOUNT: 'EDIT_ACCOUNT',
DELETE_ACCOUNT: 'DELETE_AGENT',
+ SET_PRICING_PLANS: 'SET_PRICING_PLANS',
+ SET_TOPUP_OPTIONS: 'SET_TOPUP_OPTIONS',
+ SET_CREDIT_GRANTS: 'SET_CREDIT_GRANTS',
// Agent
SET_AGENT_FETCHING_STATUS: 'SET_AGENT_FETCHING_STATUS',