From 85001a27e9c23c9e4de48ee83f10dbe2ce6a0d54 Mon Sep 17 00:00:00 2001
From: David Battersby <info@davidbattersby.com>
Date: Tue, 13 Feb 2024 12:59:46 +0800
Subject: [PATCH] FIX: sort chat channels by slug (#25656)

Channels can include emojis in front of the channel title which causes problems when sorting.

Using the channel slug is a more reliable way to sort and avoid these kind of issues.
---
 .../services/chat-channels-manager.js         | 12 +++++-----
 .../spec/system/list_channels/mobile_spec.rb  | 22 +++++++++++++++++--
 2 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/plugins/chat/assets/javascripts/discourse/services/chat-channels-manager.js b/plugins/chat/assets/javascripts/discourse/services/chat-channels-manager.js
index 331896b484f..2ce2d4c9db5 100644
--- a/plugins/chat/assets/javascripts/discourse/services/chat-channels-manager.js
+++ b/plugins/chat/assets/javascripts/discourse/services/chat-channels-manager.js
@@ -120,7 +120,7 @@ export default class ChatChannelsManager extends Service {
     if (this.site.mobileView) {
       return this.#sortChannelsByActivity(channels);
     } else {
-      return channels.sort((a, b) => a?.title?.localeCompare?.(b?.title));
+      return channels.sort((a, b) => a?.slug?.localeCompare?.(b?.slug));
     }
   }
 
@@ -161,27 +161,27 @@ export default class ChatChannelsManager extends Service {
 
   #sortChannelsByActivity(channels) {
     return channels.sort((a, b) => {
-      // if both channels have mention count, sort by aplhabetical order
+      // if both channels have mention count, sort by slug
       // otherwise prioritize channel with mention count
       if (a.tracking.mentionCount > 0 && b.tracking.mentionCount > 0) {
-        return a.title?.localeCompare?.(b.title);
+        return a.slug?.localeCompare?.(b.slug);
       }
 
       if (a.tracking.mentionCount > 0 || b.tracking.mentionCount > 0) {
         return a.tracking.mentionCount > b.tracking.mentionCount ? -1 : 1;
       }
 
-      // if both channels have unread count, sort by aplhabetical order
+      // if both channels have unread count, sort by slug
       // otherwise prioritize channel with unread count
       if (a.tracking.unreadCount > 0 && b.tracking.unreadCount > 0) {
-        return a.title?.localeCompare?.(b.title);
+        return a.slug?.localeCompare?.(b.slug);
       }
 
       if (a.tracking.unreadCount > 0 || b.tracking.unreadCount > 0) {
         return a.tracking.unreadCount > b.tracking.unreadCount ? -1 : 1;
       }
 
-      return a.title?.localeCompare?.(b.title);
+      return a.slug?.localeCompare?.(b.slug);
     });
   }
 
diff --git a/plugins/chat/spec/system/list_channels/mobile_spec.rb b/plugins/chat/spec/system/list_channels/mobile_spec.rb
index 793213e2ef8..acee06fcbdb 100644
--- a/plugins/chat/spec/system/list_channels/mobile_spec.rb
+++ b/plugins/chat/spec/system/list_channels/mobile_spec.rb
@@ -62,7 +62,7 @@ RSpec.describe "List channels | mobile", type: :system, mobile: true do
         channel_4.add(current_user)
       end
 
-      it "sorts them by mentions, unread, then alphabetical order" do
+      it "sorts them by mentions, unread, then by slug" do
         Jobs.run_immediately!
 
         Fabricate(
@@ -92,7 +92,7 @@ RSpec.describe "List channels | mobile", type: :system, mobile: true do
         expect(page.find("#public-channels a:nth-child(1)")["data-chat-channel-id"]).to eq(
           channel_4.id.to_s,
         )
-        # channels with unread messages are next, sorted by title
+        # channels with unread messages are next
         expect(page.find("#public-channels a:nth-child(2)")["data-chat-channel-id"]).to eq(
           channel_1.id.to_s,
         )
@@ -100,6 +100,24 @@ RSpec.describe "List channels | mobile", type: :system, mobile: true do
           channel_2.id.to_s,
         )
       end
+
+      context "with emojis in title" do
+        before do
+          channel_1.update!(name: ":pear: a channel")
+          channel_2.update!(name: ":apple: b channel")
+        end
+
+        it "sorts them by slug" do
+          visit("/chat/channels")
+
+          expect(page.find("#public-channels a:nth-child(1)")["data-chat-channel-id"]).to eq(
+            channel_1.id.to_s,
+          )
+          expect(page.find("#public-channels a:nth-child(2)")["data-chat-channel-id"]).to eq(
+            channel_2.id.to_s,
+          )
+        end
+      end
     end
 
     context "when direct message channels" do