mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 20:18:08 +00:00
feat: Add the ability to block/unblock contact via contact details page (#10899)
This commit is contained in:
@@ -8,17 +8,17 @@ import Breadcrumb from 'dashboard/components-next/breadcrumb/Breadcrumb.vue';
|
|||||||
import ComposeConversation from 'dashboard/components-next/NewConversation/ComposeConversation.vue';
|
import ComposeConversation from 'dashboard/components-next/NewConversation/ComposeConversation.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
buttonLabel: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
selectedContact: {
|
selectedContact: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
|
isUpdating: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['goToContactsList']);
|
const emit = defineEmits(['goToContactsList', 'toggleBlock']);
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const slots = useSlots();
|
const slots = useSlots();
|
||||||
@@ -45,9 +45,17 @@ const breadcrumbItems = computed(() => {
|
|||||||
return items;
|
return items;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isContactBlocked = computed(() => {
|
||||||
|
return props.selectedContact?.blocked;
|
||||||
|
});
|
||||||
|
|
||||||
const handleBreadcrumbClick = () => {
|
const handleBreadcrumbClick = () => {
|
||||||
emit('goToContactsList');
|
emit('goToContactsList');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleBlock = () => {
|
||||||
|
emit('toggleBlock', isContactBlocked.value);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -64,11 +72,29 @@ const handleBreadcrumbClick = () => {
|
|||||||
:items="breadcrumbItems"
|
:items="breadcrumbItems"
|
||||||
@click="handleBreadcrumbClick"
|
@click="handleBreadcrumbClick"
|
||||||
/>
|
/>
|
||||||
<ComposeConversation :contact-id="contactId">
|
<div class="flex items-center gap-2">
|
||||||
<template #trigger="{ toggle }">
|
<Button
|
||||||
<Button :label="buttonLabel" size="sm" @click="toggle" />
|
:label="
|
||||||
</template>
|
!isContactBlocked
|
||||||
</ComposeConversation>
|
? $t('CONTACTS_LAYOUT.HEADER.BLOCK_CONTACT')
|
||||||
|
: $t('CONTACTS_LAYOUT.HEADER.UNBLOCK_CONTACT')
|
||||||
|
"
|
||||||
|
size="sm"
|
||||||
|
slate
|
||||||
|
:is-loading="isUpdating"
|
||||||
|
:disabled="isUpdating"
|
||||||
|
@click="toggleBlock"
|
||||||
|
/>
|
||||||
|
<ComposeConversation :contact-id="contactId">
|
||||||
|
<template #trigger="{ toggle }">
|
||||||
|
<Button
|
||||||
|
:label="$t('CONTACTS_LAYOUT.HEADER.SEND_MESSAGE')"
|
||||||
|
size="sm"
|
||||||
|
@click="toggle"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</ComposeConversation>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -289,6 +289,8 @@
|
|||||||
"SEARCH_PLACEHOLDER": "Search...",
|
"SEARCH_PLACEHOLDER": "Search...",
|
||||||
"MESSAGE_BUTTON": "Message",
|
"MESSAGE_BUTTON": "Message",
|
||||||
"SEND_MESSAGE": "Send message",
|
"SEND_MESSAGE": "Send message",
|
||||||
|
"BLOCK_CONTACT": "Block contact",
|
||||||
|
"UNBLOCK_CONTACT": "Unblock contact",
|
||||||
"BREADCRUMB": {
|
"BREADCRUMB": {
|
||||||
"CONTACTS": "Contacts"
|
"CONTACTS": "Contacts"
|
||||||
},
|
},
|
||||||
@@ -303,6 +305,10 @@
|
|||||||
"SUCCESS_MESSAGE": "Contact saved successfully",
|
"SUCCESS_MESSAGE": "Contact saved successfully",
|
||||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||||
},
|
},
|
||||||
|
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||||
|
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||||
|
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||||
|
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||||
"IMPORT_CONTACT": {
|
"IMPORT_CONTACT": {
|
||||||
"TITLE": "Import contacts",
|
"TITLE": "Import contacts",
|
||||||
"DESCRIPTION": "Import contacts through a CSV file.",
|
"DESCRIPTION": "Import contacts through a CSV file.",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, computed, ref } from 'vue';
|
import { onMounted, computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useAlert } from 'dashboard/composables';
|
||||||
import { useStore, useMapGetter } from 'dashboard/composables/store';
|
import { useStore, useMapGetter } from 'dashboard/composables/store';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ const contactMergeRef = ref(null);
|
|||||||
|
|
||||||
const isFetchingItem = computed(() => uiFlags.value.isFetchingItem);
|
const isFetchingItem = computed(() => uiFlags.value.isFetchingItem);
|
||||||
const isMergingContact = computed(() => uiFlags.value.isMerging);
|
const isMergingContact = computed(() => uiFlags.value.isMerging);
|
||||||
|
const isUpdatingContact = computed(() => uiFlags.value.isUpdating);
|
||||||
|
|
||||||
const selectedContact = computed(() => contact.value(route.params.contactId));
|
const selectedContact = computed(() => contact.value(route.params.contactId));
|
||||||
|
|
||||||
@@ -88,6 +90,33 @@ const fetchAttributes = () => {
|
|||||||
store.dispatch('attributes/get');
|
store.dispatch('attributes/get');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleContactBlock = async isBlocked => {
|
||||||
|
const ALERT_MESSAGES = {
|
||||||
|
success: {
|
||||||
|
block: t('CONTACTS_LAYOUT.HEADER.ACTIONS.BLOCK_SUCCESS_MESSAGE'),
|
||||||
|
unblock: t('CONTACTS_LAYOUT.HEADER.ACTIONS.UNBLOCK_SUCCESS_MESSAGE'),
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
block: t('CONTACTS_LAYOUT.HEADER.ACTIONS.BLOCK_ERROR_MESSAGE'),
|
||||||
|
unblock: t('CONTACTS_LAYOUT.HEADER.ACTIONS.UNBLOCK_ERROR_MESSAGE'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await store.dispatch(`contacts/update`, {
|
||||||
|
...selectedContact.value,
|
||||||
|
blocked: !isBlocked,
|
||||||
|
});
|
||||||
|
useAlert(
|
||||||
|
isBlocked ? ALERT_MESSAGES.success.unblock : ALERT_MESSAGES.success.block
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
useAlert(
|
||||||
|
isBlocked ? ALERT_MESSAGES.error.unblock : ALERT_MESSAGES.error.block
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchActiveContact();
|
fetchActiveContact();
|
||||||
fetchContactNotes();
|
fetchContactNotes();
|
||||||
@@ -105,7 +134,9 @@ onMounted(() => {
|
|||||||
:selected-contact="selectedContact"
|
:selected-contact="selectedContact"
|
||||||
is-detail-view
|
is-detail-view
|
||||||
:show-pagination-footer="false"
|
:show-pagination-footer="false"
|
||||||
|
:is-updating="isUpdatingContact"
|
||||||
@go-to-contacts-list="goToContactsList"
|
@go-to-contacts-list="goToContactsList"
|
||||||
|
@toggle-block="toggleContactBlock"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="showSpinner"
|
v-if="showSpinner"
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ class Contact < ApplicationRecord
|
|||||||
name: name,
|
name: name,
|
||||||
phone_number: phone_number,
|
phone_number: phone_number,
|
||||||
thumbnail: avatar_url,
|
thumbnail: avatar_url,
|
||||||
|
blocked: blocked,
|
||||||
type: 'contact'
|
type: 'contact'
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -157,7 +158,8 @@ class Contact < ApplicationRecord
|
|||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
name: name,
|
name: name,
|
||||||
phone_number: phone_number,
|
phone_number: phone_number,
|
||||||
thumbnail: avatar_url
|
thumbnail: avatar_url,
|
||||||
|
blocked: blocked
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ json.email resource.email
|
|||||||
json.id resource.id
|
json.id resource.id
|
||||||
json.name resource.name
|
json.name resource.name
|
||||||
json.phone_number resource.phone_number
|
json.phone_number resource.phone_number
|
||||||
|
json.blocked resource.blocked
|
||||||
json.identifier resource.identifier
|
json.identifier resource.identifier
|
||||||
json.thumbnail resource.avatar_url
|
json.thumbnail resource.avatar_url
|
||||||
json.custom_attributes resource.custom_attributes
|
json.custom_attributes resource.custom_attributes
|
||||||
|
|||||||
Reference in New Issue
Block a user