diff --git a/app/javascript/dashboard/components-next/inline-input/InlineInput.vue b/app/javascript/dashboard/components-next/inline-input/InlineInput.vue index 81d7719cf..d65bb4257 100644 --- a/app/javascript/dashboard/components-next/inline-input/InlineInput.vue +++ b/app/javascript/dashboard/components-next/inline-input/InlineInput.vue @@ -36,7 +36,13 @@ const props = defineProps({ }, }); -const emit = defineEmits(['enterPress', 'input', 'blur', 'focus']); +const emit = defineEmits([ + 'enterPress', + 'escapePress', + 'input', + 'blur', + 'focus', +]); const modelValue = defineModel({ type: [String, Number], @@ -49,6 +55,10 @@ const onEnterPress = () => { emit('enterPress'); }; +const onEscapePress = () => { + emit('escapePress'); +}; + const handleInput = event => { emit('input', event.target.value); modelValue.value = event.target.value; @@ -102,6 +112,7 @@ defineExpose({ @focus="handleFocus" @blur="handleBlur" @keydown.enter.prevent="onEnterPress" + @keydown.escape.prevent="onEscapePress" /> diff --git a/app/javascript/dashboard/i18n/locale/en/contact.json b/app/javascript/dashboard/i18n/locale/en/contact.json index 803cd66cb..9234071d1 100644 --- a/app/javascript/dashboard/i18n/locale/en/contact.json +++ b/app/javascript/dashboard/i18n/locale/en/contact.json @@ -20,6 +20,7 @@ "CALL": "Call", "CALL_INITIATED": "Calling the contact…", "CALL_FAILED": "Unable to start the call. Please try again.", + "CLICK_TO_EDIT": "Click to edit", "VOICE_INBOX_PICKER": { "TITLE": "Choose a voice inbox" }, diff --git a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue index 3899d1ddf..2b6001729 100644 --- a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue +++ b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue @@ -1,6 +1,10 @@ @@ -194,10 +254,26 @@ export default {
+

{{ contact.name }} +

{ + this.$refs.editInput?.focus(); + }); + }, + saveEdit() { + if (!this.isEditing) return; + this.isEditing = false; + const trimmed = this.editValue.trim(); + if (trimmed !== (this.value || '')) { + this.$emit('update', trimmed); + } + }, + cancelEdit() { + this.isEditing = false; + }, }, }; diff --git a/app/javascript/dashboard/store/modules/contacts/actions.js b/app/javascript/dashboard/store/modules/contacts/actions.js index d7f87b776..d0029207e 100644 --- a/app/javascript/dashboard/store/modules/contacts/actions.js +++ b/app/javascript/dashboard/store/modules/contacts/actions.js @@ -36,7 +36,11 @@ const buildContactFormData = contactParams => { export const handleContactOperationErrors = error => { if (error.response?.status === 422) { - throw new DuplicateContactException(error.response.data.attributes); + const exception = new DuplicateContactException( + error.response.data.attributes + ); + exception.message = error.response.data.message || exception.message; + throw exception; } else if (error.response?.data?.message) { throw new ExceptionWithMessage(error.response.data.message); } else { diff --git a/app/javascript/shared/helpers/CustomErrors.js b/app/javascript/shared/helpers/CustomErrors.js index 4f31eb291..ef5947189 100644 --- a/app/javascript/shared/helpers/CustomErrors.js +++ b/app/javascript/shared/helpers/CustomErrors.js @@ -1,10 +1,19 @@ /* eslint-disable max-classes-per-file */ export class DuplicateContactException extends Error { + static DEFAULT_MESSAGE = 'DUPLICATE_CONTACT'; + constructor(data) { - super('DUPLICATE_CONTACT'); + super(DuplicateContactException.DEFAULT_MESSAGE); this.data = data; this.name = 'DuplicateContactException'; } + + /** Server or client may assign `message` after construction; otherwise still DEFAULT_MESSAGE. */ + get contactErrorDetail() { + return this.message === DuplicateContactException.DEFAULT_MESSAGE + ? null + : this.message; + } } export class ExceptionWithMessage extends Error { constructor(data) {