Merge branch 'develop' into feat/new-auth-screens

This commit is contained in:
Sivin Varghese 2022-11-07 16:37:59 +05:30 committed by GitHub
commit 3276a6d840
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 185 additions and 4 deletions

View file

@ -56,7 +56,7 @@ RAILS_MAX_THREADS=5
# The email from which all outgoing emails are sent # The email from which all outgoing emails are sent
# could user either `email@yourdomain.com` or `BrandName <email@yourdomain.com>` # could user either `email@yourdomain.com` or `BrandName <email@yourdomain.com>`
MAILER_SENDER_EMAIL="Chatwoot <accounts@chatwoot.com>" MAILER_SENDER_EMAIL=Chatwoot <accounts@chatwoot.com>
#SMTP domain key is set up for HELO checking #SMTP domain key is set up for HELO checking
SMTP_DOMAIN=chatwoot.com SMTP_DOMAIN=chatwoot.com

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="user-thumbnail-box" :style="{ height: size, width: size }"> <div :class="thumbnailBoxClass" :style="{ height: size, width: size }">
<img <img
v-if="!imgError && src" v-if="!imgError && src"
:src="src" :src="src"
@ -120,6 +120,10 @@ export default {
this.variant === 'circle' ? 'thumbnail-rounded' : 'thumbnail-square'; this.variant === 'circle' ? 'thumbnail-rounded' : 'thumbnail-square';
return `user-thumbnail ${classname} ${variant}`; return `user-thumbnail ${classname} ${variant}`;
}, },
thumbnailBoxClass() {
const boxClass = this.variant === 'circle' ? 'is-rounded' : '';
return `user-thumbnail-box ${boxClass}`;
},
}, },
watch: { watch: {
src(value, oldValue) { src(value, oldValue) {
@ -142,6 +146,10 @@ export default {
max-width: 100%; max-width: 100%;
position: relative; position: relative;
&.is-rounded {
border-radius: 50%;
}
.user-thumbnail { .user-thumbnail {
border-radius: 50%; border-radius: 50%;
&.thumbnail-square { &.thumbnail-square {

View file

@ -0,0 +1,75 @@
<template>
<div class="overlapping-thumbnails">
<thumbnail
v-for="user in usersList"
:key="user.id"
:src="user.thumbnail"
:username="user.name"
:has-border="true"
:size="size"
class="overlapping-thumbnail"
/>
<span v-if="showMoreThumbnailsCount" class="thumbnail-more-text">
{{ moreThumbnailsText }}
</span>
</div>
</template>
<script>
import Thumbnail from './Thumbnail';
export default {
components: {
Thumbnail,
},
props: {
usersList: {
type: Array,
default: () => [],
},
size: {
type: String,
default: '24px',
},
showMoreThumbnailsCount: {
type: Boolean,
default: false,
},
moreThumbnailsText: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
.overlapping-thumbnails {
display: flex;
}
.overlapping-thumbnail {
position: relative;
box-shadow: var(--shadow-small);
&:not(:first-child) {
margin-left: var(--space-minus-small);
}
}
.thumbnail-more-text {
display: inline-flex;
align-items: center;
position: relative;
margin-left: var(--space-minus-small);
padding: 0 var(--space-small);
box-shadow: var(--shadow-small);
background: var(--color-background);
border-radius: var(--space-giga);
border: 1px solid var(--white);
color: var(--s-600);
font-size: var(--font-size-mini);
font-weight: var(--font-weight-medium);
}
</style>

View file

@ -0,0 +1,69 @@
import ThumbnailGroup from '../ThumbnailGroup.vue';
export default {
title: 'Components/ThumbnailGroup',
component: ThumbnailGroup,
argTypes: {
usersList: {
defaultValue: [
{
name: 'John',
id: 1,
thumbnail: '',
},
{
name: 'John',
id: 2,
thumbnail: '',
},
{
name: 'John',
id: 3,
thumbnail: '',
},
{
name: 'John',
id: 4,
thumbnail: '',
},
{
name: 'John',
id: 5,
thumbnail: '',
},
{
name: 'John',
id: 6,
thumbnail: '',
},
],
control: {
type: 'object',
},
},
size: {
control: {
type: 'text',
},
},
moreThumbnailsText: {
control: {
type: 'text',
default: '2 more',
},
},
showMoreThumbnailsCount: {
control: {
type: 'boolean',
},
},
},
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { ThumbnailGroup },
template: '<ThumbnailGroup v-bind="$props"/>',
});
export const Primary = Template.bind({});

View file

@ -10,6 +10,13 @@ export const MESSAGE_TYPE = {
ACTIVITY: 2, ACTIVITY: 2,
TEMPLATE: 3, TEMPLATE: 3,
}; };
export const CONVERSATION_STATUS = {
OPEN: 'open',
RESOLVED: 'resolved',
PENDING: 'pending',
SNOOZED: 'snoozed',
};
// Size in mega bytes // Size in mega bytes
export const MAXIMUM_FILE_UPLOAD_SIZE = 40; export const MAXIMUM_FILE_UPLOAD_SIZE = 40;
export const MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL = 5; export const MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL = 5;

View file

@ -1,4 +1,5 @@
@import 'shared/assets/stylesheets/animations'; @import 'shared/assets/stylesheets/animations';
@import 'shared/assets/stylesheets/colors';
@import 'reset'; @import 'reset';
@import 'tailwindcss/base'; @import 'tailwindcss/base';

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="conversation--container"> <div class="conversation--container" :class="colorSchemeClass">
<div class="conversation-wrap" :class="{ 'is-typing': isAgentTyping }"> <div class="conversation-wrap" :class="{ 'is-typing': isAgentTyping }">
<div v-if="isFetchingList" class="message--loader"> <div v-if="isFetchingList" class="message--loader">
<spinner /> <spinner />
@ -26,6 +26,8 @@ import ChatMessage from 'widget/components/ChatMessage.vue';
import AgentTypingBubble from 'widget/components/AgentTypingBubble.vue'; import AgentTypingBubble from 'widget/components/AgentTypingBubble.vue';
import DateSeparator from 'shared/components/DateSeparator.vue'; import DateSeparator from 'shared/components/DateSeparator.vue';
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
import darkModeMixin from 'widget/mixins/darkModeMixin';
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
export default { export default {
@ -36,6 +38,7 @@ export default {
DateSeparator, DateSeparator,
Spinner, Spinner,
}, },
mixins: [darkModeMixin],
props: { props: {
groupedMessages: { groupedMessages: {
type: Array, type: Array,
@ -56,6 +59,9 @@ export default {
conversationSize: 'conversation/getConversationSize', conversationSize: 'conversation/getConversationSize',
isAgentTyping: 'conversation/getIsAgentTyping', isAgentTyping: 'conversation/getIsAgentTyping',
}), }),
colorSchemeClass() {
return `${this.darkMode === 'light' ? 'light' : 'dark'}`;
},
}, },
watch: { watch: {
allMessagesLoaded() { allMessagesLoaded() {
@ -110,6 +116,13 @@ export default {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
color-scheme: light dark; color-scheme: light dark;
&.light {
color-scheme: light;
}
&.dark {
color-scheme: dark;
}
} }
.conversation-wrap { .conversation-wrap {

View file

@ -1,7 +1,7 @@
<template> <template>
<div v-if="showHeaderActions" class="actions flex items-center"> <div v-if="showHeaderActions" class="actions flex items-center">
<button <button
v-if="conversationStatus === 'open' && hasEndConversationEnabled" v-if="canLeaveConversation && hasEndConversationEnabled"
class="button transparent compact" class="button transparent compact"
:title="$t('END_CONVERSATION')" :title="$t('END_CONVERSATION')"
@click="resolveConversation" @click="resolveConversation"
@ -45,6 +45,7 @@ import { popoutChatWindow } from '../helpers/popoutHelper';
import FluentIcon from 'shared/components/FluentIcon/Index.vue'; import FluentIcon from 'shared/components/FluentIcon/Index.vue';
import darkModeMixin from 'widget/mixins/darkModeMixin'; import darkModeMixin from 'widget/mixins/darkModeMixin';
import configMixin from 'widget/mixins/configMixin'; import configMixin from 'widget/mixins/configMixin';
import { CONVERSATION_STATUS } from 'shared/constants/messages';
export default { export default {
name: 'HeaderActions', name: 'HeaderActions',
@ -60,6 +61,13 @@ export default {
...mapGetters({ ...mapGetters({
conversationAttributes: 'conversationAttributes/getConversationParams', conversationAttributes: 'conversationAttributes/getConversationParams',
}), }),
canLeaveConversation() {
return [
CONVERSATION_STATUS.OPEN,
CONVERSATION_STATUS.SNOOZED,
CONVERSATION_STATUS.PENDING,
].includes(this.conversationStatus);
},
isIframe() { isIframe() {
return IFrameHelper.isIFrame(); return IFrameHelper.isIFrame();
}, },