Files
gochat/frontend/app/javascript/dashboard/components/app/PaymentPendingBanner.vue
T
rogee 321c61aaae Vendor Chatwoot Vue 3 frontend into frontend/
Copy the Chatwoot (v4.14.0) frontend runnable subset into frontend/ for
customization:
- app/javascript/ (Vue SPA: dashboard, widget, sdk, portal, superadmin)
- app/views/ (ERB templates for vite-plugin-ruby entrypoint resolution)
- app/helpers/, app/assets/ (Rails view helpers, static assets)
- enterprise/ (Enterprise edition frontend overlay)
- config/vite.json, vite.config.ts, bin/vite (Vite-Rails toolchain)
- package.json, pnpm-lock.yaml, tailwind/postcss/eslint configs
- Gemfile, Gemfile.lock (vite_rails gem for bin/vite binstub)

Excluded Rails backend: controllers, models, services, jobs, mailers,
policies, db, lib, spec, public, node_modules.

Update references to the new frontend location:
- .gitignore: exclude frontend build artifacts (node_modules, tmp, packs),
  keep frontend/bin/ and frontend/vendor/ via negation
- backend/scripts/parity_frontend_smoke.sh: CHATWOOT_DIR default
  reference/chatwoot -> ../frontend
- backend/scripts/parity_frontend_browser_smoke.mjs: same default update
- AGENTS.md: add frontend section with Rails/Vite coupling notes
- README: architecture tree includes frontend/
2026-07-07 14:56:01 +08:00

93 lines
2.1 KiB
Vue

<script>
import { mapGetters } from 'vuex';
import { useAdmin } from 'dashboard/composables/useAdmin';
import { useAccount } from 'dashboard/composables/useAccount';
import Banner from 'dashboard/components/ui/Banner.vue';
const EMPTY_SUBSCRIPTION_INFO = {
status: null,
endsOn: null,
};
export default {
components: { Banner },
setup() {
const { isAdmin } = useAdmin();
const { accountId } = useAccount();
return {
accountId,
isAdmin,
};
},
computed: {
...mapGetters({
isOnChatwootCloud: 'globalConfig/isOnChatwootCloud',
getAccount: 'accounts/getAccount',
}),
bannerMessage() {
return this.$t('GENERAL_SETTINGS.PAYMENT_PENDING');
},
actionButtonMessage() {
return this.$t('GENERAL_SETTINGS.OPEN_BILLING');
},
shouldShowBanner() {
if (!this.isOnChatwootCloud) {
return false;
}
if (!this.isAdmin) {
return false;
}
return this.isPaymentPending();
},
},
methods: {
routeToBilling() {
this.$router.push({
name: 'billing_settings_index',
params: { accountId: this.accountId },
});
},
isPaymentPending() {
const { status, endsOn } = this.getSubscriptionInfo();
if (status && endsOn) {
const now = new Date();
if (status === 'past_due' && endsOn < now) {
return true;
}
}
return false;
},
getSubscriptionInfo() {
const account = this.getAccount(this.accountId);
if (!account) return EMPTY_SUBSCRIPTION_INFO;
const { custom_attributes: subscription } = account;
if (!subscription) return EMPTY_SUBSCRIPTION_INFO;
const { subscription_status: status, subscription_ends_on: endsOn } =
subscription;
return { status, endsOn: new Date(endsOn) };
},
},
};
</script>
<!-- eslint-disable-next-line vue/no-root-v-if -->
<template>
<Banner
v-if="shouldShowBanner"
color-scheme="alert"
:banner-message="bannerMessage"
:action-button-label="actionButtonMessage"
has-action-button
@primary-action="routeToBilling"
/>
</template>