Files
chatwoot/app/javascript/widget/components/ChatFooter.vue
Sivin Varghese b4b308336f feat: Eslint rules (#9839)
# 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>
2024-08-05 14:02:16 +05:30

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>