feat: Create a new conversation from the contact panel (#2019)
* Chore: Improve button component styles
This commit is contained in:
committed by
GitHub
parent
c287ad08fb
commit
864471a21e
@@ -3,7 +3,7 @@
|
||||
<span class="close-button" @click="onClose">
|
||||
<i class="ion-android-close close-icon" />
|
||||
</span>
|
||||
<contact-info :contact="contact" />
|
||||
<contact-info show-new-message :contact="contact" />
|
||||
<contact-custom-attributes
|
||||
v-if="hasContactAttributes"
|
||||
:custom-attributes="contact.custom_attributes"
|
||||
|
||||
@@ -50,19 +50,41 @@
|
||||
</div>
|
||||
</div>
|
||||
<woot-button
|
||||
v-if="!showNewMessage"
|
||||
class="edit-contact"
|
||||
variant="clear"
|
||||
variant="clear link"
|
||||
size="small"
|
||||
@click="toggleEditModal"
|
||||
>
|
||||
{{ $t('EDIT_CONTACT.BUTTON_LABEL') }}
|
||||
</woot-button>
|
||||
<div v-else class="contact-actions">
|
||||
<woot-button
|
||||
class="new-message"
|
||||
size="small expanded"
|
||||
@click="toggleConversationModal"
|
||||
>
|
||||
{{ $t('CONTACT_PANEL.NEW_MESSAGE') }}
|
||||
</woot-button>
|
||||
<woot-button
|
||||
variant="hollow"
|
||||
size="small expanded"
|
||||
@click="toggleEditModal"
|
||||
>
|
||||
{{ $t('EDIT_CONTACT.BUTTON_LABEL') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
<edit-contact
|
||||
v-if="showEditModal"
|
||||
:show="showEditModal"
|
||||
:contact="contact"
|
||||
@cancel="toggleEditModal"
|
||||
/>
|
||||
<new-conversation
|
||||
:show="showConversationModal"
|
||||
:contact="contact"
|
||||
@cancel="toggleConversationModal"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -71,6 +93,7 @@ import ContactInfoRow from './ContactInfoRow';
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||
import SocialIcons from './SocialIcons';
|
||||
import EditContact from './EditContact';
|
||||
import NewConversation from './NewConversation';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -78,6 +101,7 @@ export default {
|
||||
EditContact,
|
||||
Thumbnail,
|
||||
SocialIcons,
|
||||
NewConversation,
|
||||
},
|
||||
props: {
|
||||
contact: {
|
||||
@@ -88,10 +112,15 @@ export default {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
showNewMessage: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showEditModal: false,
|
||||
showConversationModal: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -111,6 +140,9 @@ export default {
|
||||
toggleEditModal() {
|
||||
this.showEditModal = !this.showEditModal;
|
||||
},
|
||||
toggleConversationModal() {
|
||||
this.showConversationModal = !this.showConversationModal;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -120,7 +152,7 @@ export default {
|
||||
@import '~dashboard/assets/scss/mixins';
|
||||
.contact--profile {
|
||||
align-items: flex-start;
|
||||
padding: var(--space-normal) var(--space-normal) var(--space-large);
|
||||
padding: var(--space-normal) var(--space-normal);
|
||||
|
||||
.user-thumbnail-box {
|
||||
margin-right: $space-normal;
|
||||
@@ -164,8 +196,21 @@ export default {
|
||||
font-size: $font-weight-normal;
|
||||
}
|
||||
}
|
||||
.contact-actions {
|
||||
margin: var(--space-small) 0;
|
||||
}
|
||||
.button.edit-contact {
|
||||
margin-left: var(--space-two);
|
||||
padding-left: var(--space-micro);
|
||||
}
|
||||
|
||||
.edit-contact {
|
||||
margin-left: var(--space-slab);
|
||||
.button.new-message {
|
||||
margin-right: var(--space-small);
|
||||
}
|
||||
|
||||
.contact-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<form class="conversation--form" @submit.prevent="handleSubmit">
|
||||
<div v-if="showNoInboxAlert" class="callout warning">
|
||||
<p>
|
||||
{{ $t('NEW_CONVERSATION.NO_INBOX') }}
|
||||
</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="row">
|
||||
<div class="columns">
|
||||
<label :class="{ error: $v.targetInbox.$error }">
|
||||
{{ $t('NEW_CONVERSATION.FORM.INBOX.LABEL') }}
|
||||
<select v-model="targetInbox">
|
||||
<option
|
||||
v-for="contactableInbox in inboxes"
|
||||
:key="contactableInbox.inbox.id"
|
||||
:value="contactableInbox"
|
||||
>
|
||||
{{ contactableInbox.inbox.name }}
|
||||
</option>
|
||||
</select>
|
||||
<span v-if="$v.targetInbox.$error" class="message">
|
||||
{{ $t('NEW_CONVERSATION.FORM.INBOX.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<label>
|
||||
{{ $t('NEW_CONVERSATION.FORM.TO.LABEL') }}
|
||||
<div class="contact-input">
|
||||
<thumbnail
|
||||
:src="contact.thumbnail"
|
||||
size="24px"
|
||||
:username="contact.name"
|
||||
:status="contact.availability_status"
|
||||
/>
|
||||
<h4 class="text-block-title contact-name">
|
||||
{{ contact.name }}
|
||||
</h4>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="columns">
|
||||
<label :class="{ error: $v.message.$error }">
|
||||
{{ $t('NEW_CONVERSATION.FORM.MESSAGE.LABEL') }}
|
||||
<textarea
|
||||
v-model="message"
|
||||
class="message-input"
|
||||
type="text"
|
||||
:placeholder="$t('NEW_CONVERSATION.FORM.MESSAGE.PLACEHOLDER')"
|
||||
@input="$v.message.$touch"
|
||||
/>
|
||||
<span v-if="$v.message.$error" class="message">
|
||||
{{ $t('NEW_CONVERSATION.FORM.MESSAGE.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="button clear" @click.prevent="onCancel">
|
||||
{{ $t('NEW_CONVERSATION.FORM.CANCEL') }}
|
||||
</button>
|
||||
<woot-button type="submit" :is-loading="conversationsUiFlags.isCreating">
|
||||
{{ $t('NEW_CONVERSATION.FORM.SUBMIT') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail';
|
||||
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import { ExceptionWithMessage } from 'shared/helpers/CustomErrors';
|
||||
import { required } from 'vuelidate/lib/validators';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Thumbnail,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
contact: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
onSubmit: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
message: '',
|
||||
selectedInbox: '',
|
||||
};
|
||||
},
|
||||
validations: {
|
||||
message: {
|
||||
required,
|
||||
},
|
||||
targetInbox: {
|
||||
required,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
uiFlags: 'contacts/getUIFlags',
|
||||
conversationsUiFlags: 'contactConversations/getUIFlags',
|
||||
}),
|
||||
getNewConversation() {
|
||||
return {
|
||||
inboxId: this.targetInbox.inbox.id,
|
||||
sourceId: this.targetInbox.source_id,
|
||||
contactId: this.contact.id,
|
||||
message: { content: this.message },
|
||||
};
|
||||
},
|
||||
targetInbox: {
|
||||
get() {
|
||||
return this.selectedInbox || '';
|
||||
},
|
||||
set(value) {
|
||||
this.selectedInbox = value;
|
||||
},
|
||||
},
|
||||
showNoInboxAlert() {
|
||||
if (!this.contact.contactableInboxes) {
|
||||
return false;
|
||||
}
|
||||
return this.inboxes.length === 0 && !this.uiFlags.isFetchingInboxes;
|
||||
},
|
||||
inboxes() {
|
||||
return this.contact.contactableInboxes || [];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onCancel() {
|
||||
this.$emit('cancel');
|
||||
},
|
||||
onSuccess() {
|
||||
this.$emit('success');
|
||||
},
|
||||
|
||||
async handleSubmit() {
|
||||
this.$v.$touch();
|
||||
if (this.$v.$invalid) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const payload = this.getNewConversation;
|
||||
|
||||
await this.onSubmit(payload);
|
||||
this.onSuccess();
|
||||
this.showAlert(this.$t('NEW_CONVERSATION.FORM.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
if (error instanceof ExceptionWithMessage) {
|
||||
this.showAlert(error.data);
|
||||
} else {
|
||||
this.showAlert(this.$t('NEW_CONVERSATION.FORM.ERROR_MESSAGE'));
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.conversation--form {
|
||||
padding: var(--space-normal) var(--space-large) var(--space-large);
|
||||
|
||||
.columns {
|
||||
padding: 0 var(--space-smaller);
|
||||
}
|
||||
}
|
||||
|
||||
.input-group-label {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.contact-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 3.9rem;
|
||||
background: var(--color-background-light);
|
||||
|
||||
border: 1px solid var(--color-border);
|
||||
padding: var(--space-smaller) var(--space-small);
|
||||
border-radius: var(--border-radius-small);
|
||||
|
||||
.contact-name {
|
||||
margin: 0;
|
||||
margin-left: var(--space-small);
|
||||
}
|
||||
}
|
||||
|
||||
.message-input {
|
||||
min-height: 8rem;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<woot-modal :show.sync="show" :on-close="onCancel">
|
||||
<div class="column content-box">
|
||||
<woot-modal-header
|
||||
:header-title="$t('NEW_CONVERSATION.TITLE')"
|
||||
:header-content="$t('NEW_CONVERSATION.DESC')"
|
||||
/>
|
||||
<conversation-form
|
||||
:contact="contact"
|
||||
:on-submit="onSubmit"
|
||||
@success="onSuccess"
|
||||
@cancel="onCancel"
|
||||
/>
|
||||
</div>
|
||||
</woot-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ConversationForm from './ConversationForm';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ConversationForm,
|
||||
},
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
contact: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const { id } = this.contact;
|
||||
this.$store.dispatch('contacts/fetchContactableInbox', id);
|
||||
},
|
||||
methods: {
|
||||
onCancel() {
|
||||
this.$emit('cancel');
|
||||
},
|
||||
onSuccess() {
|
||||
this.$emit('cancel');
|
||||
},
|
||||
async onSubmit(contactItem) {
|
||||
await this.$store.dispatch('contactConversations/create', contactItem);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user