Files
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

66 lines
1.8 KiB
Vue

<script setup>
import { computed } from 'vue';
import BaseBubble from './Base.vue';
import { useI18n } from 'vue-i18n';
import { CONTENT_TYPES } from '../constants.js';
import { useMessageContext } from '../provider.js';
import { useInbox } from 'dashboard/composables/useInbox';
const { content, contentAttributes, contentType } = useMessageContext();
const { t } = useI18n();
const { isAWebWidgetInbox } = useInbox();
const formValues = computed(() => {
if (contentType.value === CONTENT_TYPES.FORM) {
const { items, submittedValues = [] } = contentAttributes.value;
if (submittedValues.length) {
return submittedValues.map(submittedValue => {
const item = items.find(
formItem => formItem.name === submittedValue.name
);
return {
title: submittedValue.value,
value: submittedValue.value,
label: item?.label,
};
});
}
return [];
}
if (contentType.value === CONTENT_TYPES.INPUT_SELECT) {
const [item] = contentAttributes.value?.submittedValues ?? [];
if (!item) return [];
return [
{
title: item.title,
value: item.value,
label: '',
},
];
}
return [];
});
</script>
<template>
<BaseBubble class="px-4 py-3" data-bubble-name="csat">
<span v-dompurify-html="content" :title="content" />
<dl v-if="formValues.length" class="mt-4">
<template v-for="item in formValues" :key="item.title">
<dt class="text-n-slate-11 italic mt-2">
{{ item.label || t('CONVERSATION.RESPONSE') }}
</dt>
<dd>{{ item.title }}</dd>
</template>
</dl>
<div v-else-if="isAWebWidgetInbox" class="my-2 font-medium">
{{ t('CONVERSATION.NO_RESPONSE') }}
</div>
</BaseBubble>
</template>