Skip to content

Feature: Add support for XEP-0444 Message Reactions#3906

Open
marcellintacite wants to merge 1 commit intoconversejs:masterfrom
marcellintacite:support-xep-0444
Open

Feature: Add support for XEP-0444 Message Reactions#3906
marcellintacite wants to merge 1 commit intoconversejs:masterfrom
marcellintacite:support-xep-0444

Conversation

@marcellintacite
Copy link
Contributor

@marcellintacite marcellintacite commented Nov 23, 2025

Feature: Add support for XEP-0444 Message Reactions

Description

This PR implements XEP-0444: Message Reactions, allowing users to react to messages with emojis. It introduces a new plugin (reactions) that handles the UI for picking reactions, displaying them on messages, and managing the underlying XMPP stanza logic.

Key Changes

1. New Plugin: reactions

  • Created a standalone plugin structure in src/plugins/reactions/.
  • Implemented logic to parse incoming <reaction> elements from message stanzas.
  • Implemented logic to send reaction stanzas with the correct XML namespace (urn:xmpp:reactions:0).
  • Added optimistic UI updates (reactions appear immediately before server confirmation).

2. UI Components

  • Reaction Picker (converse-reaction-picker):
    • Added a "Quick Actions" bar showing popular emojis (👍, ❤️, 😂, 😮).
    • Integrated a full emoji picker dropdown (lazy-loaded for performance).
    • Styled with glassmorphism effects to blend with the chat interface.
    • Uses CSS Anchor Positioning (with fallbacks) for robust dropdown placement.
  • Message Bubbles:
    • Updated message templates to render reaction "pills" below messages.
    • Styled to resemble modern chat apps (Slack-like): rounded pills, hover effects, and active states.
    • Reactions are aggregated (e.g., "👍 3").
    • Clicking an existing reaction toggles it (edit your vote).

3. Technical Details

  • Standard Compliance: Fully compliant with XEP-0444: Message Reactions.
  • Styling: Reused existing emoji picker styles (src/shared/chat/styles/emoji.scss) to ensure consistency between the chat input and the reaction picker.

Screenshots / Video

emoji_converse.mp4

This still a Draft

  • Add a changelog entry for your change in CHANGES.md
  • When adding a configuration variable, please make sure to
    document it in docs/source/configuration.rst
  • Please add a test for your change. Tests can be run in the commandline
    with make check or you can run them in the browser by running make serve

@marcellintacite marcellintacite marked this pull request as draft November 23, 2025 07:51
@JohnXLivingston
Copy link
Contributor

@marcellintacite , did you see that it is possible to add «custom emojis» in the ConverseJS emoji picker? (see bellow for an explanation). I think those emojis should not be selectable as a message reaction.

With this feature, you can link a code name (for example :foo:) to an image. This is not a standard, and this will only work for people using ConverseJS on the same server as you.
You can test it here for example, with the code :pen:: demo.
If you open the emoji picker, you will see these custom emoji at the top of the list, in a section called "stickers" ("autocollants" in french).

@JohnXLivingston
Copy link
Contributor

I thinks there are 2 other missing things in your implementation:

Discovering support

ConverseJS must declare to other client that it handles message reactions, by adding the feature urn:xmpp:reactions:0 to the discovery response. See https://xmpp.org/extensions/xep-0444.html#disco-base

The XEP says it MUST be implemented.

Also, if you are chatting with a user (in a 1 to 1 conversation) that does not support this feature, maybe we should not display the action in the chatbox.
For MUC, maybe we could just display the feature in all cases.

Restricted reactions

The XEP allow some clients or MUC to limit the set of supported emojis. See https://xmpp.org/extensions/xep-0444.html#disco-restricted
The XEP says it SHOULD be implemented.

So, you should check if there is such limitation (for a user in 1 to 1 conversations, and for the MUC in rooms), and filter the emoji picker.

@Neustradamus
Copy link

@marcellintacite: Have you seen @JohnXLivingston comments?

@marcellintacite
Copy link
Contributor Author

@marcellintacite: Have you seen @JohnXLivingston comments?

Yes, i am working on it

@Neustradamus
Copy link

@marcellintacite: Good :)
When it is like this, do not hesitate to comment to confirm that you work on it ^^

@marcellintacite
Copy link
Contributor Author

@marcellintacite: Good :) When it is like this, do not hesitate to comment to confirm that you work on it ^^

Alright , thanks. I am sorry i didn't remember. I'll do

@marcellintacite
Copy link
Contributor Author

@marcellintacite , did you see that it is possible to add «custom emojis» in the ConverseJS emoji picker? (see bellow for an explanation). I think those emojis should not be selectable as a message reaction.

With this feature, you can link a code name (for example :foo:) to an image. This is not a standard, and this will only work for people using ConverseJS on the same server as you. You can test it here for example, with the code :pen:: demo. If you open the emoji picker, you will see these custom emoji at the top of the list, in a section called "stickers" ("autocollants" in french).

I added a support for them

@marcellintacite
Copy link
Contributor Author

I thinks there are 2 other missing things in your implementation:

Discovering support

ConverseJS must declare to other client that it handles message reactions, by adding the feature urn:xmpp:reactions:0 to the discovery response. See https://xmpp.org/extensions/xep-0444.html#disco-base

The XEP says it MUST be implemented.

Also, if you are chatting with a user (in a 1 to 1 conversation) that does not support this feature, maybe we should not display the action in the chatbox. For MUC, maybe we could just display the feature in all cases.

Restricted reactions

The XEP allow some clients or MUC to limit the set of supported emojis. See https://xmpp.org/extensions/xep-0444.html#disco-restricted The XEP says it SHOULD be implemented.

So, you should check if there is such limitation (for a user in 1 to 1 conversations, and for the MUC in rooms), and filter the emoji picker.

can you check my implementation please

@JohnXLivingston
Copy link
Contributor

@marcellintacite , did you see that it is possible to add «custom emojis» in the ConverseJS emoji picker? (see bellow for an explanation). I think those emojis should not be selectable as a message reaction.
With this feature, you can link a code name (for example :foo:) to an image. This is not a standard, and this will only work for people using ConverseJS on the same server as you. You can test it here for example, with the code :pen:: demo. If you open the emoji picker, you will see these custom emoji at the top of the list, in a section called "stickers" ("autocollants" in french).

I added a support for them

What do you mean by "added a support for them"? I can't find the related code.
I'm not sure we understand each other. IMHO, custom emoji must be removed from the picker for message reaction. As there are not real emoji.
I think the shouldBeHidden method should just remove all "emojis" that don't have any associated unicode character. (you can add an option to the picker, like you did with allowed_emojis, to say that we only want unicode emojis).

@JohnXLivingston
Copy link
Contributor

can you check my implementation please

Yeah, the XEP compliance seems OK now :)

@marcellintacite
Copy link
Contributor Author

@marcellintacite , did you see that it is possible to add «custom emojis» in the ConverseJS emoji picker? (see bellow for an explanation). I think those emojis should not be selectable as a message reaction.
With this feature, you can link a code name (for example :foo:) to an image. This is not a standard, and this will only work for people using ConverseJS on the same server as you. You can test it here for example, with the code :pen:: demo. If you open the emoji picker, you will see these custom emoji at the top of the list, in a section called "stickers" ("autocollants" in french).

I added a support for them

What do you mean by "added a support for them"? I can't find the related code. I'm not sure we understand each other. IMHO, custom emoji must be removed from the picker for message reaction. As there are not real emoji. I think the shouldBeHidden method should just remove all "emojis" that don't have any associated unicode character. (you can add an option to the picker, like you did with allowed_emojis, to say that we only want unicode emojis).

Thanks ,
I've updated the PR to address your feedback. Users can now react to their own messages, as I've removed the is_own_message check, and I've ensured custom stickers are properly filtered out of the reaction picker by enforcing a unicode codepoint check. Additionally, i have updated the code comments to accurately reflect the filtering logic.

@marcellintacite
Copy link
Contributor Author

Hi @JohnXLivingston , could you please take a look at the MR? I need to finalize it for review now that it's in draft form.

@JohnXLivingston
Copy link
Contributor

Hi @JohnXLivingston , could you please take a look at the MR? I need to finalize it for review now that it's in draft form.

I took a quick look. Seems good now. I think you can mark it as ready for a review.

@marcellintacite marcellintacite marked this pull request as ready for review January 2, 2026 16:57
@jcbrand
Copy link
Member

jcbrand commented Jan 5, 2026

@marcellintacite there are 10 failing tests.

Looks like a bunch of them are because the CAPS version string is different, since you're now advertising support for a new additional XMPP feature.

You'll have to update the tests to check for the new version string.

See here for example:

Stanzas don't match:
	Actual:
	<presence xmlns="jabber:client" id="8ff86976-eed3-4dd8-ba12-82979e5efb50" from="romeo@montague.lit/orchard" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="IVrSARVJ+weVvRNIXt5E3K0e1NE="/></presence>
	Expected:
	<presence xmlns="jabber:client" from="romeo@montague.lit/orchard" id="8ff86976-eed3-4dd8-ba12-82979e5efb50" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="qgxN8hmrdSa2/4/7PUoM9bPFN2s="/></presence>
	    at <Jasmine>
	    at src/plugins/bookmark-views/tests/bookmarks.js:268:29
	    at async UserContext.<anonymous> (src/headless/tests/mock.js:648:13)

The old version string is qgxN8hmrdSa2/4/7PUoM9bPFN2s= and it needs to be replaced with the new one which is IVrSARVJ+weVvRNIXt5E3K0e1NE=

@marcellintacite
Copy link
Contributor Author

@marcellintacite there are 10 failing tests.

Looks like a bunch of them are because the CAPS version string is different, since you're now advertising support for a new additional XMPP feature.

You'll have to update the tests to check for the new version string.

See here for example:

Stanzas don't match:
	Actual:
	<presence xmlns="jabber:client" id="8ff86976-eed3-4dd8-ba12-82979e5efb50" from="romeo@montague.lit/orchard" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="IVrSARVJ+weVvRNIXt5E3K0e1NE="/></presence>
	Expected:
	<presence xmlns="jabber:client" from="romeo@montague.lit/orchard" id="8ff86976-eed3-4dd8-ba12-82979e5efb50" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="qgxN8hmrdSa2/4/7PUoM9bPFN2s="/></presence>
	    at <Jasmine>
	    at src/plugins/bookmark-views/tests/bookmarks.js:268:29
	    at async UserContext.<anonymous> (src/headless/tests/mock.js:648:13)

The old version string is qgxN8hmrdSa2/4/7PUoM9bPFN2s= and it needs to be replaced with the new one which is IVrSARVJ+weVvRNIXt5E3K0e1NE=

Thanks, i am working on it

@marcellintacite
Copy link
Contributor Author

Hello @jcbrand ,

I've updated all the test files to use the new CAPS version string and rebased with the latest changes.

I also added the dependencies array to the reactions plugin to ensure converse-disco is loaded first

@jcbrand
Copy link
Member

jcbrand commented Jan 13, 2026

Thanks @marcellintacite, can you please do a rebase onto the master branch?

Currently there are a bunch of unrelated commits in this PR.

@marcellintacite
Copy link
Contributor Author

Thanks @marcellintacite, can you please do a rebase onto the master branch?

Currently there are a bunch of unrelated commits in this PR.

Done

Copy link
Member

@jcbrand jcbrand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @marcellintacite. I did a first review from my side and left some review comments.

registerEvents() {
this.onKeyDown = (ev) => this.#onKeyDown(ev);
this.dropdown.addEventListener("hide.bs.dropdown", () => this.onDropdownHide());
this.dropdown?.addEventListener("hide.bs.dropdown", () => this.onDropdownHide());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would this.dropdown sometimes be undefined?

This seems like a code smell (red flag) that masks a potential underlying problem.

@marcellintacite
Copy link
Contributor Author

Hello @jcbrand , I've completed the rebase, but the tests are still failing. It appears some of the failing tests aren't connected to this pull request. Could you please take a look?

@marcellintacite
Copy link
Contributor Author

when running locally , i am getting 10 failures and most of them are related to : XEP-0461 Message Replies
Screenshot 2026-01-27 at 22 02 12

@jcbrand
Copy link
Member

jcbrand commented Jan 29, 2026

@marcellintacite The latest commit in the master branch is green in CI, so the issue has to be in your commits/changes.
https://github.com/conversejs/converse.js/actions/runs/21430359222/job/61708056174

The failing Message Replies tests might be because you didn't compile a new dist/converse.js file before running the tests again.


Looking at the CI run of your last commit in this PR, I still see a failing test due to a changed CAPS version.

Stanzas don't match:
	Actual:
	<presence xmlns="jabber:client" id="f747bd22-49df-4610-a9d2-004a795124ac" from="romeo@montague.lit/orchard" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="Hbd4V8rlZualGDSkxW/4bVlnudc="/></presence>
	Expected:
	<presence xmlns="jabber:client" from="romeo@montague.lit/orchard" id="f747bd22-49df-4610-a9d2-004a795124ac" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="IVrSARVJ+weVvRNIXt5E3K0e1NE="/></presence>
	    at <Jasmine>
	    at src/plugins/bookmark-views/tests/bookmarks.js:268:29
	    at async UserContext.<anonymous> (src/headless/tests/mock.js:648:13)
Chrome 144.0.0.0 (Linux 0.0.0): Executed 22 of 556 (1 FAILED) (0 secs / 1.011 secs)
Chrome 144.0.0.0 (Linux 0.0.0) Bookmarks can have a password which will be used to enter FAILED
	Stanzas don't match:
	Actual:
	<presence xmlns="jabber:client" id="f747bd22-49df-4610-a9d2-004a795124ac" from="romeo@montague.lit/orchard" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="Hbd4V8rlZualGDSkxW/4bVlnudc="/></presence>
	Expected:
	<presence xmlns="jabber:client" from="romeo@montague.lit/orchard" id="f747bd22-49df-4610-a9d2-004a795124ac" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="IVrSARVJ+weVvRNIXt5E3K0e1NE="/></presence>
	    at <Jasmine>
	    at src/plugins/bookmark-views/tests/bookmarks.js:268:29
	    at async UserContext.<anonymous> (src/headless/tests/mock.js:648:13)

@marcellintacite
Copy link
Contributor Author

@marcellintacite The latest commit in the master branch is green in CI, so the issue has to be in your commits/changes. https://github.com/conversejs/converse.js/actions/runs/21430359222/job/61708056174

The failing Message Replies tests might be because you didn't compile a new dist/converse.js file before running the tests again.

Looking at the CI run of your last commit in this PR, I still see a failing test due to a changed CAPS version.

Stanzas don't match:
	Actual:
	<presence xmlns="jabber:client" id="f747bd22-49df-4610-a9d2-004a795124ac" from="romeo@montague.lit/orchard" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="Hbd4V8rlZualGDSkxW/4bVlnudc="/></presence>
	Expected:
	<presence xmlns="jabber:client" from="romeo@montague.lit/orchard" id="f747bd22-49df-4610-a9d2-004a795124ac" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="IVrSARVJ+weVvRNIXt5E3K0e1NE="/></presence>
	    at <Jasmine>
	    at src/plugins/bookmark-views/tests/bookmarks.js:268:29
	    at async UserContext.<anonymous> (src/headless/tests/mock.js:648:13)
Chrome 144.0.0.0 (Linux 0.0.0): Executed 22 of 556 (1 FAILED) (0 secs / 1.011 secs)
Chrome 144.0.0.0 (Linux 0.0.0) Bookmarks can have a password which will be used to enter FAILED
	Stanzas don't match:
	Actual:
	<presence xmlns="jabber:client" id="f747bd22-49df-4610-a9d2-004a795124ac" from="romeo@montague.lit/orchard" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="Hbd4V8rlZualGDSkxW/4bVlnudc="/></presence>
	Expected:
	<presence xmlns="jabber:client" from="romeo@montague.lit/orchard" id="f747bd22-49df-4610-a9d2-004a795124ac" to="theplay@conference.shakespeare.lit/JC"><x xmlns="http://jabber.org/protocol/muc"><history maxstanzas="0"/><password>secret</password></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="https://conversejs.org/" ver="IVrSARVJ+weVvRNIXt5E3K0e1NE="/></presence>
	    at <Jasmine>
	    at src/plugins/bookmark-views/tests/bookmarks.js:268:29
	    at async UserContext.<anonymous> (src/headless/tests/mock.js:648:13)

Thanks , i have fixed the issue

@marcellintacite
Copy link
Contributor Author

marcellintacite commented Jan 31, 2026

Hi @jcbrand , can you check the PR please ?

Copy link
Member

@jcbrand jcbrand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a quick look and left some comments.

I'll do a more thorough check a bit later when I have more time.

@jcbrand
Copy link
Member

jcbrand commented Feb 5, 2026

@marcellintacite Can you please rebase your branch onto master again.

It's also a good idea to squash all your commits into a single one. Doing so makes rebasing onto master easier and also reduces the risk of conflicts.

Thanks!

image

@marcellintacite marcellintacite force-pushed the support-xep-0444 branch 2 times, most recently from 772a8ba to d38b48b Compare February 7, 2026 19:42
@marcellintacite
Copy link
Contributor Author

Hi @jcbrand , I've completed the rebase to master and merged all commit changes.

Copy link
Member

@jcbrand jcbrand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your effort and patience so far @marcellintacite.

I think we're close to being able to merge this PR, but I still found some issues that should be fixed and improvements to be made.


Also, when clicking on an already made reaction, it should be removed:
Image

Comment on lines 14 to 15
const current_reactions = message.get('reactions') || {};
const reactions = JSON.parse(JSON.stringify(current_reactions));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also work and doesn't require two function JSON function calls:

Suggested change
const current_reactions = message.get('reactions') || {};
const reactions = JSON.parse(JSON.stringify(current_reactions));
const reactions = { ...(message.get('reactions') || {}) };

// Strategy 1: Try to find chatbox by sender's bare JID
const { Strophe } = converse.env;
const bare_jid = Strophe.getBareJidFromJid(from_jid);
const chatbox = api.chatboxes.get(bare_jid);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const chatbox = api.chatboxes.get(bare_jid);
const chatbox = await api.chatboxes.get(bare_jid);

@marcellintacite
Copy link
Contributor Author

Thanks for your effort and patience so far @marcellintacite.

I think we're close to being able to merge this PR, but I still found some issues that should be fixed and improvements to be made.

Also, when clicking on an already made reaction, it should be removed: Image

i am working on it

* Popular emojis shown in the quick picker
* These are the most commonly used reactions across messaging platforms
*/
const POPULAR_EMOJIS = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcellintacite Please don't forget this ☝️

@marcellintacite
Copy link
Contributor Author

Hello @jcbrand , I've completed the plugin's headless implementation as you requested. Would you mind reviewing it?

Comment on lines +35 to +60
if (emojis.length === 0) {
return attrs;
}

const reactions = { ...(/** @type {any} */(attrs).reactions || {}) };
const reacting_jid = attrs.from;

emojis.forEach(emoji => {
if (!reactions[emoji]) {
reactions[emoji] = [];
}
if (!reactions[emoji].includes(reacting_jid)) {
reactions[emoji].push(reacting_jid);
}
});

// Remove user's reactions that aren't in the new emoji list
for (const emoji in reactions) {
if (!emojis.includes(emoji)) {
reactions[emoji] = reactions[emoji].filter(jid => jid !== reacting_jid);
if (reactions[emoji].length === 0) {
delete reactions[emoji];
}
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When parsing an incoming reaction message, you only have the reactions from a single JID. You don't have any of the other reactions from other JIDs that might have already been applied to the message.

For now the task is only to parse this message and then later you can properly update the reactions on the original message.

Also, given that when parsing you only know the emojis of a single JID, you need make the keys of your reactions object the JIDs of the reactors, not the emojis themselves.

Then, in getUpdatedMessageAttributes in you need to trigger a hook which you can listen to in your reactions headless plugin.

Then in inside the handler for the hook, you need to update the reactions object to also add all the other JIDs and their emojis.

Otherwise if you don't do that, you'll delete all the emojis from the other JIDs when the new attributes are saved.

Suggested change
if (emojis.length === 0) {
return attrs;
}
const reactions = { ...(/** @type {any} */(attrs).reactions || {}) };
const reacting_jid = attrs.from;
emojis.forEach(emoji => {
if (!reactions[emoji]) {
reactions[emoji] = [];
}
if (!reactions[emoji].includes(reacting_jid)) {
reactions[emoji].push(reacting_jid);
}
});
// Remove user's reactions that aren't in the new emoji list
for (const emoji in reactions) {
if (!emojis.includes(emoji)) {
reactions[emoji] = reactions[emoji].filter(jid => jid !== reacting_jid);
if (reactions[emoji].length === 0) {
delete reactions[emoji];
}
}
}
const reacting_jid = attrs.from;
const reactions = { [reacting_jid]: emojis };

@aliraza556
Copy link
Contributor

aliraza556 commented Feb 24, 2026

Hi @marcellintacite I noticed that some changes were requested on this PR. It has been about 5 days, so I just wanted to kindly check in and see if you’re still working on it.

@marcellintacite
Copy link
Contributor Author

Hi @marcellintacite I noticed that some changes were requested on this PR. It has been about 5 days, so I just wanted to kindly check in and see if you’re still working on it.

Hi, I am still working on it. I experienced a busy week last week, but I am now addressing the requested changes. Thanks for the follow up

Implement support for XEP-0444 message reactions with the following features:

- Add emoji reaction picker to message actions
- Support for discovering reaction support via service disco
- Restrict reactions based on server capabilities
- Reactive UI updates using Lit components
- Proper handling of multiple reactions per message
- CAPS version string updates for test suite

Fixing the reaction auto-open behavior
@marcellintacite
Copy link
Contributor Author

Hello @jcbrand, I've resolved the test issue and cleaned up some comments. Please review the changes. All tests are now successfully passing.

msg_model.save({ 'reactions': { '👍': [contact_jid], '❤️': [contact_jid] } });
expect(msg_model.get('reactions')['👍']).toContain(contact_jid);

msg_model.save({ 'reactions': {} });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to test with incoming message stanzas, first with one that contains reactions and then one that doesn't contain reactions, instead of calling msg_model.save which is too low-level.

If you did that then this test would have caught this bug:
https://github.com/conversejs/converse.js/pull/3906/changes#r2851508030

.filter(e => e);

if (emojis.length === 0) {
return attrs;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're exiting too quickly here and thereby preventing previously added emojis from being removed again.

await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
const msg_model = view.model.messages.at(0);
const reactions = { '👍': [contact1_jid, contact2_jid] };
msg_model.save({ 'reactions': reactions });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, you need to test by mocking incoming message stanzas containing reactions, not by calling .save on the model.


emojis.forEach(emoji => {
if (!reactions[emoji]) {
reactions[emoji] = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like you implemented the recommendations in this comment?
#3906 (comment)

The reactions object needs to be changed so that the JID is the key instead of the emoji.
Otherwise you'll lose all reaction emojis added by other users.

I even gave a code suggestion which you ignored. You can choose to not accept a code suggestion and do something else, but then please explain to me what you did and why.

Looks like you also didn't create a listener for getUpdatedMessageAttributes.

The fact that the tests don't highlight this issue also shows that they're not written properly. The tests should mock incoming message stanzas with reactions instead of manually calling .save() on the message model which is not representative of actual usage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants