mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 19:48:08 +00:00
# Pull Request Template ## Description This PR adds new eslint rules to the code base. **Error rules** | Rule name | Type | Files updated | | ----------------- | --- | - | | `vue/block-order` | error | ✅ | | `vue/component-name-in-template-casing` | error | ✅ | | `vue/component-options-name-casing` | error | ✅ | | `vue/custom-event-name-casing` | error | ✅ | | `vue/define-emits-declaration` | error | ✅ | | `vue/no-unused-properties` | error | ✅ | | `vue/define-macros-order` | error | ✅ | | `vue/define-props-declaration` | error | ✅ | | `vue/match-component-import-name` | error | ✅ | | `vue/next-tick-style` | error | ✅ | | `vue/no-bare-strings-in-template` | error | ✅ | | `vue/no-empty-component-block` | error | ✅ | | `vue/no-multiple-objects-in-class` | error | ✅ | | `vue/no-required-prop-with-default` | error | ✅ | | `vue/no-static-inline-styles` | error | ✅ | | `vue/no-template-target-blank` | error | ✅ | | `vue/no-this-in-before-route-enter` | error | ✅ | | `vue/no-undef-components` | error | ✅ | | `vue/no-unused-emit-declarations` | error | ✅ | | `vue/no-unused-refs` | error | ✅ | | `vue/no-use-v-else-with-v-for` | error | ✅ | | `vue/no-useless-v-bind` | error | ✅ | | `vue/no-v-text` | error | ✅ | | `vue/padding-line-between-blocks` | error | ✅ | | ~`vue/prefer-prop-type-boolean-first`~ | ~error~ | ❌ (removed this rule, cause a bug in displaying custom attributes) | | `vue/prefer-separate-static-class` | error | ✅ | | `vue/prefer-true-attribute-shorthand` | error | ✅ | | `vue/require-explicit-slots` | error | ✅ | | `vue/require-macro-variable-name` | error | ✅ | **Warn rules** | Rule name | Type | Files updated | | ---- | ------------- | ------------- | | `vue/no-root-v-if` | warn | ❎ | Fixes https://linear.app/chatwoot/issue/CW-3492/vue-eslint-rules ## Type of change - [x] New feature (non-breaking change which adds functionality) ## 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 - [x] 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: Fayaz Ahmed <fayazara@gmail.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: Shivam Mishra <scm.mymail@gmail.com> Co-authored-by: Pranav <pranav@chatwoot.com>
178 lines
4.8 KiB
Vue
Executable File
178 lines
4.8 KiB
Vue
Executable File
<script>
|
|
import { mapActions, mapGetters } from 'vuex';
|
|
import { getContrastingTextColor } from '@chatwoot/utils';
|
|
import CustomButton from 'shared/components/Button.vue';
|
|
import FooterReplyTo from 'widget/components/FooterReplyTo.vue';
|
|
import ChatInputWrap from 'widget/components/ChatInputWrap.vue';
|
|
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
|
import { sendEmailTranscript } from 'widget/api/conversation';
|
|
import routerMixin from 'widget/mixins/routerMixin';
|
|
import { IFrameHelper } from '../helpers/utils';
|
|
import { CHATWOOT_ON_START_CONVERSATION } from '../constants/sdkEvents';
|
|
|
|
export default {
|
|
components: {
|
|
ChatInputWrap,
|
|
CustomButton,
|
|
FooterReplyTo,
|
|
},
|
|
mixins: [routerMixin],
|
|
data() {
|
|
return {
|
|
inReplyTo: null,
|
|
};
|
|
},
|
|
computed: {
|
|
...mapGetters({
|
|
conversationAttributes: 'conversationAttributes/getConversationParams',
|
|
widgetColor: 'appConfig/getWidgetColor',
|
|
conversationSize: 'conversation/getConversationSize',
|
|
currentUser: 'contacts/getCurrentUser',
|
|
isWidgetStyleFlat: 'appConfig/isWidgetStyleFlat',
|
|
}),
|
|
textColor() {
|
|
return getContrastingTextColor(this.widgetColor);
|
|
},
|
|
hideReplyBox() {
|
|
const { allowMessagesAfterResolved } = window.chatwootWebChannel;
|
|
const { status } = this.conversationAttributes;
|
|
return !allowMessagesAfterResolved && status === 'resolved';
|
|
},
|
|
showEmailTranscriptButton() {
|
|
return this.hasEmail;
|
|
},
|
|
hasEmail() {
|
|
return this.currentUser && this.currentUser.has_email;
|
|
},
|
|
hasReplyTo() {
|
|
return (
|
|
this.inReplyTo && (this.inReplyTo.content || this.inReplyTo.attachments)
|
|
);
|
|
},
|
|
},
|
|
mounted() {
|
|
this.$emitter.on(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.toggleReplyTo);
|
|
},
|
|
methods: {
|
|
...mapActions('conversation', [
|
|
'sendMessage',
|
|
'sendAttachment',
|
|
'clearConversations',
|
|
]),
|
|
...mapActions('conversationAttributes', [
|
|
'getAttributes',
|
|
'clearConversationAttributes',
|
|
]),
|
|
async handleSendMessage(content) {
|
|
await this.sendMessage({
|
|
content,
|
|
replyTo: this.inReplyTo ? this.inReplyTo.id : null,
|
|
});
|
|
// reset replyTo message after sending
|
|
this.inReplyTo = null;
|
|
// Update conversation attributes on new conversation
|
|
if (this.conversationSize === 0) {
|
|
this.getAttributes();
|
|
}
|
|
},
|
|
async handleSendAttachment(attachment) {
|
|
await this.sendAttachment({
|
|
attachment,
|
|
replyTo: this.inReplyTo ? this.inReplyTo.id : null,
|
|
});
|
|
this.inReplyTo = null;
|
|
},
|
|
startNewConversation() {
|
|
this.clearConversations();
|
|
this.clearConversationAttributes();
|
|
this.replaceRoute('prechat-form');
|
|
IFrameHelper.sendMessage({
|
|
event: 'onEvent',
|
|
eventIdentifier: CHATWOOT_ON_START_CONVERSATION,
|
|
data: { hasConversation: true },
|
|
});
|
|
},
|
|
toggleReplyTo(message) {
|
|
this.inReplyTo = message;
|
|
},
|
|
async sendTranscript() {
|
|
if (this.hasEmail) {
|
|
try {
|
|
await sendEmailTranscript();
|
|
this.$emitter.emit(BUS_EVENTS.SHOW_ALERT, {
|
|
message: this.$t('EMAIL_TRANSCRIPT.SEND_EMAIL_SUCCESS'),
|
|
type: 'success',
|
|
});
|
|
} catch (error) {
|
|
this.$emitter.$emit(BUS_EVENTS.SHOW_ALERT, {
|
|
message: this.$t('EMAIL_TRANSCRIPT.SEND_EMAIL_ERROR'),
|
|
});
|
|
}
|
|
}
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<footer
|
|
v-if="!hideReplyBox"
|
|
class="relative z-50 mb-1"
|
|
:class="{
|
|
'rounded-lg': !isWidgetStyleFlat,
|
|
'pt-2.5 shadow-[0px_-20px_20px_1px_rgba(0,_0,_0,_0.05)] dark:shadow-[0px_-20px_20px_1px_rgba(0,_0,_0,_0.15)] rounded-t-none':
|
|
hasReplyTo,
|
|
}"
|
|
>
|
|
<FooterReplyTo
|
|
v-if="hasReplyTo"
|
|
:in-reply-to="inReplyTo"
|
|
@dismiss="inReplyTo = null"
|
|
/>
|
|
<ChatInputWrap
|
|
class="shadow-sm"
|
|
:on-send-message="handleSendMessage"
|
|
:on-send-attachment="handleSendAttachment"
|
|
/>
|
|
</footer>
|
|
<div v-else>
|
|
<CustomButton
|
|
class="font-medium"
|
|
block
|
|
:bg-color="widgetColor"
|
|
:text-color="textColor"
|
|
@click="startNewConversation"
|
|
>
|
|
{{ $t('START_NEW_CONVERSATION') }}
|
|
</CustomButton>
|
|
<CustomButton
|
|
v-if="showEmailTranscriptButton"
|
|
type="clear"
|
|
class="font-normal"
|
|
@click="sendTranscript"
|
|
>
|
|
{{ $t('EMAIL_TRANSCRIPT.BUTTON_TEXT') }}
|
|
</CustomButton>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
@import '~widget/assets/scss/variables.scss';
|
|
|
|
.branding {
|
|
align-items: center;
|
|
color: $color-body;
|
|
display: flex;
|
|
font-size: $font-size-default;
|
|
justify-content: center;
|
|
padding: $space-one;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
|
|
img {
|
|
margin-right: $space-small;
|
|
max-width: $space-two;
|
|
}
|
|
}
|
|
</style>
|