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/
106 lines
2.5 KiB
Vue
106 lines
2.5 KiB
Vue
<script setup>
|
|
import { computed } from 'vue';
|
|
import { MESSAGE_STATUS } from '../../constants';
|
|
import { useMessageContext } from '../../provider.js';
|
|
|
|
const { contentAttributes, status, sender } = useMessageContext();
|
|
|
|
const hasError = computed(() => {
|
|
return status.value === MESSAGE_STATUS.FAILED;
|
|
});
|
|
|
|
const fromEmail = computed(() => {
|
|
return contentAttributes.value?.email?.from ?? [];
|
|
});
|
|
|
|
const toEmail = computed(() => {
|
|
const { toEmails, email } = contentAttributes.value;
|
|
return email?.to ?? toEmails ?? [];
|
|
});
|
|
|
|
const ccEmail = computed(() => {
|
|
return (
|
|
contentAttributes.value?.ccEmails ??
|
|
contentAttributes.value?.email?.cc ??
|
|
[]
|
|
);
|
|
});
|
|
|
|
const senderName = computed(() => {
|
|
const fromEmailAddress = fromEmail.value[0] ?? '';
|
|
const senderEmail = sender.value.email ?? '';
|
|
|
|
if (!fromEmailAddress && !senderEmail) return null;
|
|
|
|
// if the sender of the conversation and the sender of this particular
|
|
// email are the same, only then we return the sender name
|
|
if (fromEmailAddress === senderEmail) {
|
|
return sender.value.name;
|
|
}
|
|
|
|
return null;
|
|
});
|
|
|
|
const bccEmail = computed(() => {
|
|
return (
|
|
contentAttributes.value?.bccEmails ??
|
|
contentAttributes.value?.email?.bcc ??
|
|
[]
|
|
);
|
|
});
|
|
|
|
const subject = computed(() => {
|
|
return contentAttributes.value?.email?.subject ?? '';
|
|
});
|
|
|
|
const showMeta = computed(() => {
|
|
return (
|
|
fromEmail.value[0] ||
|
|
toEmail.value.length ||
|
|
ccEmail.value.length ||
|
|
bccEmail.value.length ||
|
|
subject.value
|
|
);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<section
|
|
v-show="showMeta"
|
|
class="space-y-1 rtl:pl-9 ltr:pr-9 text-sm break-words"
|
|
:class="hasError ? 'text-n-ruby-11' : 'text-n-slate-11'"
|
|
>
|
|
<template v-if="showMeta">
|
|
<div
|
|
v-if="fromEmail[0]"
|
|
:class="hasError ? 'text-n-ruby-11' : 'text-n-slate-12'"
|
|
>
|
|
<template v-if="senderName">
|
|
<span>
|
|
{{ senderName }}
|
|
</span>
|
|
<{{ fromEmail[0] }}>
|
|
</template>
|
|
<template v-else>
|
|
{{ fromEmail[0] }}
|
|
</template>
|
|
</div>
|
|
<div v-if="toEmail.length">
|
|
{{ $t('EMAIL_HEADER.TO') }}: {{ toEmail.join(', ') }}
|
|
</div>
|
|
<div v-if="ccEmail.length">
|
|
{{ $t('EMAIL_HEADER.CC') }}:
|
|
{{ ccEmail.join(', ') }}
|
|
</div>
|
|
<div v-if="bccEmail.length">
|
|
{{ $t('EMAIL_HEADER.BCC') }}:
|
|
{{ bccEmail.join(', ') }}
|
|
</div>
|
|
<div v-if="subject">
|
|
{{ $t('EMAIL_HEADER.SUBJECT') }}:
|
|
{{ subject }}
|
|
</div>
|
|
</template>
|
|
</section>
|
|
</template>
|