fix: Issues with custom attributes in conversation sidebar (#11476)

# Pull Request Template

## Description

This PR fixes,

1. Fix display issue where the attribute value `0` was not shown for
attributes of type "number" and instead displayed as `"---"`
2. Fix issue where the copy and delete buttons were not visible when the
attribute value was `0`
3. Fix an issue with updating contact custom attributes in the
conversation sidebar (caused by the camelCase param key mismatch in
`contacts/update`; only reproducible for attributes type "date")
4. Ensure the delete button is shown for checkbox-type attributes, even
when the value is `true` or `false` (previously hidden when the value
was `false`, despite the key being present)

Fixes
[CW-4326](https://linear.app/chatwoot/issue/CW-4326/custom-attribute-with-value-0-not-displayed-correctly-in-chatwoot)
https://github.com/chatwoot/chatwoot/issues/11459

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

### Loom video

https://www.loom.com/share/77257dc09a37452bab7876d1554b8a03?sid=dc5635eb-4fe0-4f39-8da2-036d71649ffc

## 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
- [ ] 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: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
Sivin Varghese
2025-05-16 15:22:18 +05:30
committed by GitHub
parent d0611cb7f2
commit 42548dc24c
2 changed files with 11 additions and 12 deletions

View File

@@ -49,12 +49,12 @@ export default {
if (this.isAttributeTypeDate) { if (this.isAttributeTypeDate) {
return this.value return this.value
? new Date(this.value || new Date()).toLocaleDateString() ? new Date(this.value || new Date()).toLocaleDateString()
: ''; : '---';
} }
if (this.isAttributeTypeCheckbox) { if (this.isAttributeTypeCheckbox) {
return this.value === 'false' ? false : this.value; return this.value === 'false' ? false : this.value;
} }
return this.value; return this.hasValue ? this.value : '---';
}, },
formattedValue() { formattedValue() {
return this.isAttributeTypeDate return this.isAttributeTypeDate
@@ -83,6 +83,9 @@ export default {
isAttributeTypeDate() { isAttributeTypeDate() {
return this.attributeType === 'date'; return this.attributeType === 'date';
}, },
hasValue() {
return this.value !== null && this.value !== '';
},
urlValue() { urlValue() {
return isValidURL(this.value) ? this.value : '---'; return isValidURL(this.value) ? this.value : '---';
}, },
@@ -223,7 +226,7 @@ export default {
/> />
</span> </span>
<NextButton <NextButton
v-if="showActions && value" v-if="showActions && hasValue"
v-tooltip.left="$t('CUSTOM_ATTRIBUTES.ACTIONS.DELETE')" v-tooltip.left="$t('CUSTOM_ATTRIBUTES.ACTIONS.DELETE')"
slate slate
sm sm
@@ -281,13 +284,13 @@ export default {
v-else v-else
class="group-hover:bg-n-slate-3 group-hover:dark:bg-n-solid-3 inline-block rounded-sm mb-0 break-all py-0.5 px-1" class="group-hover:bg-n-slate-3 group-hover:dark:bg-n-solid-3 inline-block rounded-sm mb-0 break-all py-0.5 px-1"
> >
{{ displayValue || '---' }} {{ displayValue }}
</p> </p>
<div <div
class="flex items-center max-w-[2rem] gap-1 ml-1 rtl:mr-1 rtl:ml-0" class="flex items-center max-w-[2rem] gap-1 ml-1 rtl:mr-1 rtl:ml-0"
> >
<NextButton <NextButton
v-if="showActions && value" v-if="showActions && hasValue"
v-tooltip="$t('CUSTOM_ATTRIBUTES.ACTIONS.COPY')" v-tooltip="$t('CUSTOM_ATTRIBUTES.ACTIONS.COPY')"
xs xs
slate slate

View File

@@ -80,17 +80,13 @@ const filteredCustomAttributes = computed(() =>
customAttributes.value, customAttributes.value,
attribute.attribute_key attribute.attribute_key
); );
const isCheckbox = attribute.attribute_display_type === 'checkbox';
const defaultValue = isCheckbox ? false : '';
return { return {
...attribute, ...attribute,
type: 'custom_attribute', type: 'custom_attribute',
key: attribute.attribute_key, key: attribute.attribute_key,
// Set value from customAttributes if it exists, otherwise use default value // Set value from customAttributes if it exists, otherwise use ''
value: hasValue value: hasValue ? customAttributes.value[attribute.attribute_key] : '',
? customAttributes.value[attribute.attribute_key]
: defaultValue,
}; };
}) })
); );
@@ -215,7 +211,7 @@ const onUpdate = async (key, value) => {
} else { } else {
store.dispatch('contacts/update', { store.dispatch('contacts/update', {
id: props.contactId, id: props.contactId,
custom_attributes: updatedAttributes, customAttributes: updatedAttributes,
}); });
} }
useAlert(t('CUSTOM_ATTRIBUTES.FORM.UPDATE.SUCCESS')); useAlert(t('CUSTOM_ATTRIBUTES.FORM.UPDATE.SUCCESS'));