@cometchat/skills 4.0.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/README.md +42 -2
  2. package/bin/install.js +448 -57
  3. package/package.json +1 -1
  4. package/skills/cometchat/SKILL.md +337 -80
  5. package/skills/cometchat-a11y/SKILL.md +476 -0
  6. package/skills/cometchat-android-v5/SKILL.md +1 -1
  7. package/skills/cometchat-android-v5-calls/SKILL.md +413 -0
  8. package/skills/cometchat-android-v5-calls/references/README.md +53 -0
  9. package/skills/cometchat-android-v5-calls/references/add-calls-to-existing-chat.md +195 -0
  10. package/skills/cometchat-android-v5-calls/references/audio-controls.md +91 -0
  11. package/skills/cometchat-android-v5-calls/references/background-handling.md +168 -0
  12. package/skills/cometchat-android-v5-calls/references/call-layouts.md +123 -0
  13. package/skills/cometchat-android-v5-calls/references/call-logs.md +113 -0
  14. package/skills/cometchat-android-v5-calls/references/call-session.md +274 -0
  15. package/skills/cometchat-android-v5-calls/references/custom-ui.md +150 -0
  16. package/skills/cometchat-android-v5-calls/references/event-listeners.md +123 -0
  17. package/skills/cometchat-android-v5-calls/references/group-calls.md +205 -0
  18. package/skills/cometchat-android-v5-calls/references/idle-timeout.md +111 -0
  19. package/skills/cometchat-android-v5-calls/references/in-call-chat.md +134 -0
  20. package/skills/cometchat-android-v5-calls/references/join-session.md +120 -0
  21. package/skills/cometchat-android-v5-calls/references/migration-v4-to-v5.md +206 -0
  22. package/skills/cometchat-android-v5-calls/references/participant-management.md +110 -0
  23. package/skills/cometchat-android-v5-calls/references/picture-in-picture.md +106 -0
  24. package/skills/cometchat-android-v5-calls/references/raise-hand.md +242 -0
  25. package/skills/cometchat-android-v5-calls/references/recording.md +101 -0
  26. package/skills/cometchat-android-v5-calls/references/ringing-integration.md +152 -0
  27. package/skills/cometchat-android-v5-calls/references/screen-sharing.md +82 -0
  28. package/skills/cometchat-android-v5-calls/references/server-fcm-voip.md +215 -0
  29. package/skills/cometchat-android-v5-calls/references/session-settings.md +121 -0
  30. package/skills/cometchat-android-v5-calls/references/setup.md +137 -0
  31. package/skills/cometchat-android-v5-calls/references/share-invite.md +151 -0
  32. package/skills/cometchat-android-v5-calls/references/video-controls.md +87 -0
  33. package/skills/cometchat-android-v5-calls/references/voip-calling.md +526 -0
  34. package/skills/cometchat-android-v5-components/SKILL.md +1 -1
  35. package/skills/cometchat-android-v5-core/SKILL.md +1 -1
  36. package/skills/cometchat-android-v5-customization/SKILL.md +1 -1
  37. package/skills/cometchat-android-v5-extensions/SKILL.md +1 -1
  38. package/skills/cometchat-android-v5-features/SKILL.md +1 -1
  39. package/skills/cometchat-android-v5-placement/SKILL.md +1 -1
  40. package/skills/cometchat-android-v5-production/SKILL.md +1 -1
  41. package/skills/cometchat-android-v5-push/SKILL.md +1 -1
  42. package/skills/cometchat-android-v5-testing/SKILL.md +1 -1
  43. package/skills/cometchat-android-v5-theming/SKILL.md +1 -1
  44. package/skills/cometchat-android-v5-troubleshooting/SKILL.md +1 -1
  45. package/skills/cometchat-android-v6/SKILL.md +1 -1
  46. package/skills/cometchat-android-v6-builder-settings/SKILL.md +1 -1
  47. package/skills/cometchat-android-v6-calls/SKILL.md +375 -0
  48. package/skills/cometchat-android-v6-calls/references/add-calls-to-existing-chat.md +97 -0
  49. package/skills/cometchat-android-v6-calls/references/call-layouts.md +91 -0
  50. package/skills/cometchat-android-v6-calls/references/call-session.md +163 -0
  51. package/skills/cometchat-android-v6-calls/references/device-management.md +171 -0
  52. package/skills/cometchat-android-v6-calls/references/group-calls.md +191 -0
  53. package/skills/cometchat-android-v6-calls/references/idle-timeout.md +107 -0
  54. package/skills/cometchat-android-v6-calls/references/in-call-chat.md +136 -0
  55. package/skills/cometchat-android-v6-calls/references/raise-hand.md +186 -0
  56. package/skills/cometchat-android-v6-calls/references/ringing-integration.md +176 -0
  57. package/skills/cometchat-android-v6-calls/references/server-fcm-voip.md +127 -0
  58. package/skills/cometchat-android-v6-calls/references/share-invite.md +105 -0
  59. package/skills/cometchat-android-v6-compose-components/SKILL.md +2 -2
  60. package/skills/cometchat-android-v6-compose-customization/SKILL.md +1 -1
  61. package/skills/cometchat-android-v6-compose-placement/SKILL.md +1 -1
  62. package/skills/cometchat-android-v6-compose-theming/SKILL.md +1 -1
  63. package/skills/cometchat-android-v6-core/SKILL.md +1 -1
  64. package/skills/cometchat-android-v6-events/SKILL.md +1 -1
  65. package/skills/cometchat-android-v6-extensions/SKILL.md +1 -1
  66. package/skills/cometchat-android-v6-features/SKILL.md +1 -1
  67. package/skills/cometchat-android-v6-kotlin-components/SKILL.md +1 -1
  68. package/skills/cometchat-android-v6-kotlin-customization/SKILL.md +1 -1
  69. package/skills/cometchat-android-v6-kotlin-placement/SKILL.md +1 -1
  70. package/skills/cometchat-android-v6-kotlin-theming/SKILL.md +1 -1
  71. package/skills/cometchat-android-v6-migration/SKILL.md +398 -0
  72. package/skills/cometchat-android-v6-production/SKILL.md +1 -1
  73. package/skills/cometchat-android-v6-push/SKILL.md +1 -1
  74. package/skills/cometchat-android-v6-testing/SKILL.md +1 -1
  75. package/skills/cometchat-android-v6-troubleshooting/SKILL.md +1 -1
  76. package/skills/cometchat-angular-calls/SKILL.md +511 -0
  77. package/skills/cometchat-angular-calls/references/add-calls-to-existing-chat.md +95 -0
  78. package/skills/cometchat-angular-calls/references/call-layouts.md +106 -0
  79. package/skills/cometchat-angular-calls/references/call-session.md +167 -0
  80. package/skills/cometchat-angular-calls/references/custom-ui.md +231 -0
  81. package/skills/cometchat-angular-calls/references/device-management.md +135 -0
  82. package/skills/cometchat-angular-calls/references/group-calls.md +412 -0
  83. package/skills/cometchat-angular-calls/references/idle-timeout.md +145 -0
  84. package/skills/cometchat-angular-calls/references/in-call-chat.md +148 -0
  85. package/skills/cometchat-angular-calls/references/lazy-loading-pitfalls.md +205 -0
  86. package/skills/cometchat-angular-calls/references/migration-v4-to-v5.md +53 -0
  87. package/skills/cometchat-angular-calls/references/ngzone-and-async-callbacks.md +183 -0
  88. package/skills/cometchat-angular-calls/references/picture-in-picture.md +285 -0
  89. package/skills/cometchat-angular-calls/references/raise-hand.md +167 -0
  90. package/skills/cometchat-angular-calls/references/recording-screen-share.md +267 -0
  91. package/skills/cometchat-angular-calls/references/ringing-integration.md +131 -0
  92. package/skills/cometchat-angular-calls/references/server-web-push-vapid.md +100 -0
  93. package/skills/cometchat-angular-calls/references/share-invite.md +116 -0
  94. package/skills/cometchat-angular-components/SKILL.md +1 -1
  95. package/skills/cometchat-angular-core/SKILL.md +1 -1
  96. package/skills/cometchat-angular-customization/SKILL.md +1 -1
  97. package/skills/cometchat-angular-features/SKILL.md +1 -1
  98. package/skills/cometchat-angular-patterns/SKILL.md +1 -1
  99. package/skills/cometchat-angular-placement/SKILL.md +1 -1
  100. package/skills/cometchat-angular-production/SKILL.md +1 -1
  101. package/skills/cometchat-angular-push/SKILL.md +403 -0
  102. package/skills/cometchat-angular-testing/SKILL.md +333 -0
  103. package/skills/cometchat-angular-theming/SKILL.md +1 -1
  104. package/skills/cometchat-angular-troubleshooting/SKILL.md +1 -1
  105. package/skills/cometchat-astro-patterns/SKILL.md +1 -1
  106. package/skills/cometchat-calls/SKILL.md +358 -0
  107. package/skills/cometchat-calls/references/use-case-broadcast.md +194 -0
  108. package/skills/cometchat-calls/references/use-case-marketplace.md +158 -0
  109. package/skills/cometchat-calls/references/use-case-support.md +190 -0
  110. package/skills/cometchat-calls/references/use-case-team.md +169 -0
  111. package/skills/cometchat-calls/references/use-case-telehealth.md +154 -0
  112. package/skills/cometchat-components/SKILL.md +1 -1
  113. package/skills/cometchat-core/SKILL.md +1 -1
  114. package/skills/cometchat-customization/SKILL.md +2 -2
  115. package/skills/cometchat-features/SKILL.md +2 -2
  116. package/skills/cometchat-flutter-v5/SKILL.md +1 -1
  117. package/skills/cometchat-flutter-v5-calls/SKILL.md +325 -94
  118. package/skills/cometchat-flutter-v5-calls/references/add-calls-to-existing-chat.md +169 -0
  119. package/skills/cometchat-flutter-v5-calls/references/call-layouts.md +98 -0
  120. package/skills/cometchat-flutter-v5-calls/references/call-session.md +330 -0
  121. package/skills/cometchat-flutter-v5-calls/references/device-management.md +120 -0
  122. package/skills/cometchat-flutter-v5-calls/references/group-calls.md +187 -0
  123. package/skills/cometchat-flutter-v5-calls/references/idle-timeout.md +97 -0
  124. package/skills/cometchat-flutter-v5-calls/references/in-call-chat.md +132 -0
  125. package/skills/cometchat-flutter-v5-calls/references/migration-v4-to-v5.md +160 -0
  126. package/skills/cometchat-flutter-v5-calls/references/raise-hand.md +244 -0
  127. package/skills/cometchat-flutter-v5-calls/references/ringing-integration.md +193 -0
  128. package/skills/cometchat-flutter-v5-calls/references/server-push-bridge.md +101 -0
  129. package/skills/cometchat-flutter-v5-calls/references/share-invite.md +142 -0
  130. package/skills/cometchat-flutter-v5-conversations/SKILL.md +1 -1
  131. package/skills/cometchat-flutter-v5-core/SKILL.md +1 -1
  132. package/skills/cometchat-flutter-v5-customization/SKILL.md +1 -1
  133. package/skills/cometchat-flutter-v5-events/SKILL.md +1 -1
  134. package/skills/cometchat-flutter-v5-messages/SKILL.md +1 -1
  135. package/skills/cometchat-flutter-v5-production/SKILL.md +1 -1
  136. package/skills/cometchat-flutter-v5-push/SKILL.md +1 -1
  137. package/skills/cometchat-flutter-v5-testing/SKILL.md +390 -0
  138. package/skills/cometchat-flutter-v5-theming/SKILL.md +1 -1
  139. package/skills/cometchat-flutter-v5-troubleshooting/SKILL.md +1 -1
  140. package/skills/cometchat-flutter-v5-users-groups/SKILL.md +1 -1
  141. package/skills/cometchat-flutter-v6/SKILL.md +1 -1
  142. package/skills/cometchat-flutter-v6-calls/SKILL.md +308 -243
  143. package/skills/cometchat-flutter-v6-calls/references/add-calls-to-existing-chat.md +134 -0
  144. package/skills/cometchat-flutter-v6-calls/references/call-layouts.md +102 -0
  145. package/skills/cometchat-flutter-v6-calls/references/call-session.md +229 -0
  146. package/skills/cometchat-flutter-v6-calls/references/device-management.md +99 -0
  147. package/skills/cometchat-flutter-v6-calls/references/group-calls.md +190 -0
  148. package/skills/cometchat-flutter-v6-calls/references/idle-timeout.md +80 -0
  149. package/skills/cometchat-flutter-v6-calls/references/in-call-chat.md +122 -0
  150. package/skills/cometchat-flutter-v6-calls/references/raise-hand.md +268 -0
  151. package/skills/cometchat-flutter-v6-calls/references/ringing-integration.md +171 -0
  152. package/skills/cometchat-flutter-v6-calls/references/server-push-bridge.md +93 -0
  153. package/skills/cometchat-flutter-v6-calls/references/share-invite.md +102 -0
  154. package/skills/cometchat-flutter-v6-components/SKILL.md +1 -1
  155. package/skills/cometchat-flutter-v6-conversations/SKILL.md +1 -1
  156. package/skills/cometchat-flutter-v6-core/SKILL.md +1 -1
  157. package/skills/cometchat-flutter-v6-customization/SKILL.md +1 -1
  158. package/skills/cometchat-flutter-v6-events/SKILL.md +1 -1
  159. package/skills/cometchat-flutter-v6-features/SKILL.md +1 -1
  160. package/skills/cometchat-flutter-v6-messages/SKILL.md +1 -1
  161. package/skills/cometchat-flutter-v6-migration/SKILL.md +1 -1
  162. package/skills/cometchat-flutter-v6-placement/SKILL.md +1 -1
  163. package/skills/cometchat-flutter-v6-production/SKILL.md +1 -1
  164. package/skills/cometchat-flutter-v6-push/SKILL.md +452 -0
  165. package/skills/cometchat-flutter-v6-testing/SKILL.md +319 -0
  166. package/skills/cometchat-flutter-v6-theming/SKILL.md +1 -1
  167. package/skills/cometchat-flutter-v6-troubleshooting/SKILL.md +1 -1
  168. package/skills/cometchat-flutter-v6-users-groups/SKILL.md +1 -1
  169. package/skills/cometchat-i18n/SKILL.md +358 -0
  170. package/skills/cometchat-ios/SKILL.md +5 -5
  171. package/skills/cometchat-ios-calls/SKILL.md +409 -0
  172. package/skills/cometchat-ios-calls/references/add-calls-to-existing-chat.md +172 -0
  173. package/skills/cometchat-ios-calls/references/avaudiosession-routing.md +189 -0
  174. package/skills/cometchat-ios-calls/references/call-layouts.md +136 -0
  175. package/skills/cometchat-ios-calls/references/call-session.md +221 -0
  176. package/skills/cometchat-ios-calls/references/callkit-and-pushkit.md +353 -0
  177. package/skills/cometchat-ios-calls/references/custom-ui.md +322 -0
  178. package/skills/cometchat-ios-calls/references/device-management.md +171 -0
  179. package/skills/cometchat-ios-calls/references/group-calls.md +396 -0
  180. package/skills/cometchat-ios-calls/references/idle-timeout.md +185 -0
  181. package/skills/cometchat-ios-calls/references/in-call-chat.md +183 -0
  182. package/skills/cometchat-ios-calls/references/migration-v4-to-v5.md +138 -0
  183. package/skills/cometchat-ios-calls/references/picture-in-picture.md +246 -0
  184. package/skills/cometchat-ios-calls/references/raise-hand.md +239 -0
  185. package/skills/cometchat-ios-calls/references/recording-screen-share.md +339 -0
  186. package/skills/cometchat-ios-calls/references/ringing-integration.md +142 -0
  187. package/skills/cometchat-ios-calls/references/server-apns-pushkit.md +267 -0
  188. package/skills/cometchat-ios-calls/references/share-invite.md +152 -0
  189. package/skills/cometchat-ios-calls/references/swiftui-uikit-hosting.md +246 -0
  190. package/skills/cometchat-ios-calls/references/voip-cert-setup.md +166 -0
  191. package/skills/cometchat-ios-components/SKILL.md +1 -1
  192. package/skills/cometchat-ios-core/SKILL.md +1 -1
  193. package/skills/cometchat-ios-customization/SKILL.md +1 -1
  194. package/skills/cometchat-ios-features/SKILL.md +1 -1
  195. package/skills/cometchat-ios-placement/SKILL.md +1 -1
  196. package/skills/cometchat-ios-production/SKILL.md +1 -1
  197. package/skills/cometchat-ios-push/SKILL.md +1 -1
  198. package/skills/cometchat-ios-testing/SKILL.md +371 -0
  199. package/skills/cometchat-ios-theming/SKILL.md +1 -1
  200. package/skills/cometchat-ios-troubleshooting/SKILL.md +1 -1
  201. package/skills/cometchat-native-bare-patterns/SKILL.md +45 -3
  202. package/skills/cometchat-native-calls/SKILL.md +599 -0
  203. package/skills/cometchat-native-calls/references/add-calls-to-existing-chat.md +203 -0
  204. package/skills/cometchat-native-calls/references/call-layouts.md +124 -0
  205. package/skills/cometchat-native-calls/references/call-session.md +182 -0
  206. package/skills/cometchat-native-calls/references/custom-ui.md +250 -0
  207. package/skills/cometchat-native-calls/references/device-management.md +135 -0
  208. package/skills/cometchat-native-calls/references/expo-vs-bare.md +179 -0
  209. package/skills/cometchat-native-calls/references/group-calls.md +291 -0
  210. package/skills/cometchat-native-calls/references/idle-timeout.md +128 -0
  211. package/skills/cometchat-native-calls/references/in-call-chat.md +143 -0
  212. package/skills/cometchat-native-calls/references/migration-v4-to-v5.md +72 -0
  213. package/skills/cometchat-native-calls/references/picture-in-picture.md +276 -0
  214. package/skills/cometchat-native-calls/references/raise-hand.md +203 -0
  215. package/skills/cometchat-native-calls/references/recording-screen-share.md +290 -0
  216. package/skills/cometchat-native-calls/references/ringing-integration.md +118 -0
  217. package/skills/cometchat-native-calls/references/server-push-bridge.md +135 -0
  218. package/skills/cometchat-native-calls/references/server-push-payloads.md +193 -0
  219. package/skills/cometchat-native-calls/references/share-invite.md +144 -0
  220. package/skills/cometchat-native-calls/references/voip-push-end-to-end.md +317 -0
  221. package/skills/cometchat-native-components/SKILL.md +1 -1
  222. package/skills/cometchat-native-core/SKILL.md +1 -1
  223. package/skills/cometchat-native-customization/SKILL.md +1 -1
  224. package/skills/cometchat-native-expo-patterns/SKILL.md +18 -1
  225. package/skills/cometchat-native-features/SKILL.md +1 -1
  226. package/skills/cometchat-native-placement/SKILL.md +1 -1
  227. package/skills/cometchat-native-production/SKILL.md +1 -1
  228. package/skills/cometchat-native-push/SKILL.md +1 -1
  229. package/skills/cometchat-native-testing/SKILL.md +1 -1
  230. package/skills/cometchat-native-theming/SKILL.md +1 -1
  231. package/skills/cometchat-native-troubleshooting/SKILL.md +1 -1
  232. package/skills/cometchat-nextjs-patterns/SKILL.md +1 -1
  233. package/skills/cometchat-placement/SKILL.md +29 -1
  234. package/skills/cometchat-production/SKILL.md +1 -1
  235. package/skills/cometchat-react-calls/SKILL.md +539 -0
  236. package/skills/cometchat-react-calls/references/add-calls-to-existing-chat.md +145 -0
  237. package/skills/cometchat-react-calls/references/call-layouts.md +161 -0
  238. package/skills/cometchat-react-calls/references/call-session.md +235 -0
  239. package/skills/cometchat-react-calls/references/custom-ui.md +201 -0
  240. package/skills/cometchat-react-calls/references/device-management.md +206 -0
  241. package/skills/cometchat-react-calls/references/group-calls.md +262 -0
  242. package/skills/cometchat-react-calls/references/idle-timeout.md +175 -0
  243. package/skills/cometchat-react-calls/references/in-call-chat.md +212 -0
  244. package/skills/cometchat-react-calls/references/migration-v4-to-v5.md +172 -0
  245. package/skills/cometchat-react-calls/references/picture-in-picture.md +245 -0
  246. package/skills/cometchat-react-calls/references/raise-hand.md +238 -0
  247. package/skills/cometchat-react-calls/references/recording-screen-share.md +143 -0
  248. package/skills/cometchat-react-calls/references/ringing-integration.md +255 -0
  249. package/skills/cometchat-react-calls/references/server-web-push-vapid.md +241 -0
  250. package/skills/cometchat-react-calls/references/share-invite.md +176 -0
  251. package/skills/cometchat-react-calls/references/testing-calls-on-web.md +198 -0
  252. package/skills/cometchat-react-calls/references/voip-and-web-push.md +165 -0
  253. package/skills/cometchat-react-patterns/SKILL.md +56 -8
  254. package/skills/cometchat-react-push/SKILL.md +448 -0
  255. package/skills/cometchat-react-router-patterns/SKILL.md +1 -1
  256. package/skills/cometchat-react-testing/SKILL.md +404 -0
  257. package/skills/cometchat-theming/SKILL.md +3 -3
  258. package/skills/cometchat-troubleshooting/SKILL.md +2 -2
@@ -0,0 +1,412 @@
1
+ # Group calls (meetings) on Angular
2
+
3
+ Angular wraps the same JS Calls SDK as React/Vue/Svelte; the SDK semantics are identical. The wiring differences are Angular-specific: NgZone for active-speaker updates, `@Input` / `@Output` patterns for participant components, OnPush + `markForCheck` for roster changes.
4
+
5
+ For SDK-level semantics — capacity limits, bandwidth scaling, moderator actions — see `cometchat-native-calls/references/group-calls.md`. This reference covers the Angular-specific patterns.
6
+
7
+ ---
8
+
9
+ ## Signaling architecture — meeting-message broadcast, NOT call ringing
10
+
11
+ **Critical to read first.** Group calls do NOT use the Ringing channel (`CometChat.initiateCall` → `onIncomingCallReceived`). That channel is **1:1 user calls only**. The kit broadcasts a **custom message of type `"meeting"`** to the group; receivers see a "Join meeting" card in their `<cometchat-message-list />` (kit Angular components) or need an explicit `MessageListener.onCustomMessageReceived` (custom UI — the common Angular path since many Angular apps build custom call surfaces).
12
+
13
+ Confirmed 2026-05-15 by direct test: Pixel 3 (kit-based RN, group call initiated) → Angular custom-UI app at `localhost:4200` (uid-5 in same group) → Angular received NOTHING because it only registered `CometChat.addCallListener`. Adding `CometChat.addMessageListener` filtering for `category === CATEGORY_CUSTOM && type === 'meeting'` fixed it.
14
+
15
+ ```
16
+ Caller (uid-A, member of group-X) CometChat Receivers (members of group-X)
17
+ │ │ │
18
+ │ kit: <cometchat-call-buttons │ │
19
+ │ [group]="g"> │ │
20
+ │ — OR — custom Angular code: │ │
21
+ │ CometChat.sendCustomMessage( │ │
22
+ │ new CometChat.CustomMessage( │ │
23
+ │ guid, GROUP, "meeting", │ │
24
+ │ { callType, sessionId })) │ │
25
+ ├─────────────────────────────────────────>│ │
26
+ │ │ onCustomMessageReceived │
27
+ │ ├─────────────────────────────>│ (each receiver's
28
+ │ │ │ MessageListener,
29
+ │ │ │ wrapped in NgZone.run)
30
+ │ ───── WebRTC session active (sessionId = group GUID) ───── │
31
+ ```
32
+
33
+ | Channel | 1:1 user calls | Group calls |
34
+ |---|---|---|
35
+ | Signaling API (caller) | `CometChat.initiateCall(call)` | `CometChat.sendCustomMessage(meetingMessage)` with type="meeting" |
36
+ | Receiver event | `CallListener.onIncomingCallReceived` | `MessageListener.onCustomMessageReceived` (category=CATEGORY_CUSTOM + type="meeting") |
37
+ | Session ID | server-generated unique per call | the group's GUID (persistent) |
38
+ | Ring/decline semantics | yes — `CometChat.acceptCall` / `rejectCall` | no — receivers join or ignore |
39
+ | Auto-cancel timeout | yes (45s default) | no — meeting persists in chat history |
40
+
41
+ ### Receiver — custom Angular UI: `CallStateService` extension
42
+
43
+ The canonical pattern in `cometchat-angular-calls/SKILL.md` puts call state in a `CallStateService`. Extend it with a `MessageListener` for group meetings:
44
+
45
+ ```ts
46
+ // services/call-state.service.ts (extension)
47
+ import { Injectable, NgZone, inject, signal } from '@angular/core';
48
+ import { CometChat } from '@cometchat/chat-sdk-javascript';
49
+
50
+ const GROUP_MEETING_LISTENER_ID = 'app-root-group-meeting-listener';
51
+
52
+ @Injectable({ providedIn: 'root' })
53
+ export class CallStateService {
54
+ private readonly zone = inject(NgZone);
55
+
56
+ // existing signals: phase, statusMessage, errorMessage, incoming, ...
57
+ readonly incomingMeeting = signal<{
58
+ sessionId: string;
59
+ callType: 'audio' | 'video';
60
+ fromUid: string;
61
+ groupGuid: string;
62
+ } | null>(null);
63
+
64
+ start(): void {
65
+ // existing CometChat.addCallListener (1:1 user calls)
66
+ // ...
67
+
68
+ // NEW — addMessageListener for group meetings:
69
+ CometChat.addMessageListener(
70
+ GROUP_MEETING_LISTENER_ID,
71
+ new CometChat.MessageListener({
72
+ onCustomMessageReceived: (msg: any) => {
73
+ if (msg.getCategory?.() !== CometChat.CATEGORY_CUSTOM) return;
74
+ if (msg.getType?.() !== 'meeting') return;
75
+ const customData = msg.getCustomData?.() ?? {};
76
+ this.zone.run(() => {
77
+ this.incomingMeeting.set({
78
+ sessionId: customData.sessionId ?? msg.getReceiverId(),
79
+ callType: customData.callType ?? 'video',
80
+ fromUid: msg.getSender().getUid(),
81
+ groupGuid: msg.getReceiverId(),
82
+ });
83
+ });
84
+ },
85
+ }),
86
+ );
87
+ }
88
+ }
89
+ ```
90
+
91
+ Then in your root template (next to where the 1:1 incoming-call overlay lives):
92
+
93
+ ```html
94
+ @if (state.incomingMeeting(); as meeting) {
95
+ <app-incoming-meeting-overlay
96
+ [meeting]="meeting"
97
+ (joined)="state.acceptMeeting(meeting.sessionId, meeting.callType)"
98
+ (dismissed)="state.incomingMeeting.set(null)"
99
+ />
100
+ }
101
+ ```
102
+
103
+ ### Why this matters specifically for Angular
104
+
105
+ Angular apps disproportionately build custom call UI (raw SDK + their own component templates) rather than dropping in `<cometchat-call-buttons>` / `<cometchat-incoming-call>` selectors. The Angular UI Kit is less prevalent than React's UI Kit. So **most Angular customers hit this gap** if they only follow the 1:1 ringing-integration guidance.
106
+
107
+ The two listeners (`addCallListener` for user channel + `addMessageListener` for meeting channel) MUST coexist in any Angular app that supports both 1:1 and group calling. Wire both in `CallStateService.start()` and tear both down in `ngOnDestroy` / hangup.
108
+
109
+ ---
110
+
111
+ ## Initiating a group call
112
+
113
+ ```ts
114
+ // services/group-call.service.ts
115
+ import { Injectable } from "@angular/core";
116
+ import { CometChat } from "@cometchat/chat-sdk-javascript";
117
+
118
+ @Injectable({ providedIn: "root" })
119
+ export class GroupCallService {
120
+ async initiate(guid: string, callType: "voice" | "video"): Promise<unknown> {
121
+ const group = await CometChat.getGroup(guid);
122
+ const cometchatType = callType === "video"
123
+ ? CometChat.CALL_TYPE.VIDEO
124
+ : CometChat.CALL_TYPE.AUDIO;
125
+ const call = new CometChat.Call(group.getGuid(), cometchatType, CometChat.RECEIVER_TYPE.GROUP);
126
+ return CometChat.initiateCall(call);
127
+ }
128
+ }
129
+ ```
130
+
131
+ The receiver is the GROUP (`RECEIVER_TYPE.GROUP`) — anyone in the group can `acceptCall` until the call ends.
132
+
133
+ ---
134
+
135
+ ## Roster + active-speaker — NgZone-aware
136
+
137
+ The SDK's `OngoingCallListener` callbacks fire outside Angular's zone. Wrap with `NgZone.run` (general rule from `references/ngzone-and-async-callbacks.md`):
138
+
139
+ ```ts
140
+ @Component({
141
+ selector: "app-group-call",
142
+ template: `
143
+ <div class="spotlight">
144
+ <app-participant-tile *ngIf="activeSpeaker" [participant]="activeSpeaker" [size]="'large'"></app-participant-tile>
145
+ </div>
146
+ <div class="strip">
147
+ <app-participant-tile
148
+ *ngFor="let p of others; trackBy: trackByUid"
149
+ [participant]="p"
150
+ [size]="'small'">
151
+ </app-participant-tile>
152
+ </div>
153
+ `,
154
+ changeDetection: ChangeDetectionStrategy.OnPush,
155
+ })
156
+ export class GroupCallComponent implements OnInit, OnDestroy {
157
+ participants: Participant[] = [];
158
+ activeSpeaker: Participant | null = null;
159
+ others: Participant[] = [];
160
+
161
+ constructor(private zone: NgZone, private cd: ChangeDetectorRef) {}
162
+
163
+ ngOnInit() {
164
+ const listener = new CometChatCalls.OngoingCallListener({
165
+ onUserListUpdated: (users: Participant[]) => {
166
+ this.zone.run(() => {
167
+ this.participants = users;
168
+ this.recomputeLayout();
169
+ this.cd.markForCheck(); // OnPush — must mark
170
+ });
171
+ },
172
+ onActiveSpeakerUpdated: (uid: string) => {
173
+ this.zone.run(() => {
174
+ // Debounce — see "Debouncing active-speaker" below
175
+ this.scheduleSpeakerSwap(uid);
176
+ });
177
+ },
178
+ });
179
+ // ... build CallSettings, startSession ...
180
+ }
181
+
182
+ trackByUid(_: number, p: Participant) {
183
+ return p.uid;
184
+ }
185
+
186
+ private recomputeLayout() {
187
+ const localUid = this.getLocalUid();
188
+ const remote = this.participants.filter(p => p.uid !== localUid);
189
+ this.activeSpeaker = remote.find(p => p.uid === this.activeSpeakerUid) ?? remote[0] ?? null;
190
+ this.others = remote.filter(p => p.uid !== this.activeSpeaker?.uid);
191
+ }
192
+
193
+ private speakerSwapTimeout: ReturnType<typeof setTimeout> | null = null;
194
+ private activeSpeakerUid: string | null = null;
195
+ private scheduleSpeakerSwap(uid: string) {
196
+ if (this.speakerSwapTimeout) clearTimeout(this.speakerSwapTimeout);
197
+ this.speakerSwapTimeout = setTimeout(() => {
198
+ this.zone.run(() => {
199
+ this.activeSpeakerUid = uid;
200
+ this.recomputeLayout();
201
+ this.cd.markForCheck();
202
+ });
203
+ }, 500);
204
+ }
205
+ }
206
+ ```
207
+
208
+ `trackByUid` is critical — without it, every roster update re-creates every tile, which destroys the WebRTC video track each time. The roster jitters and call quality degrades.
209
+
210
+ ---
211
+
212
+ ## Debouncing active-speaker
213
+
214
+ Same rule as RN — `onActiveSpeakerUpdated` can fire many times per second in a noisy call. Debounce to 500ms minimum:
215
+
216
+ ```ts
217
+ private speakerSwapTimeout: ReturnType<typeof setTimeout> | null = null;
218
+
219
+ scheduleSpeakerSwap(uid: string) {
220
+ if (this.speakerSwapTimeout) clearTimeout(this.speakerSwapTimeout);
221
+ this.speakerSwapTimeout = setTimeout(() => {
222
+ this.zone.run(() => {
223
+ this.activeSpeakerUid = uid;
224
+ this.recomputeLayout();
225
+ this.cd.markForCheck();
226
+ });
227
+ }, 500);
228
+ }
229
+ ```
230
+
231
+ Or use RxJS:
232
+
233
+ ```ts
234
+ import { Subject } from "rxjs";
235
+ import { debounceTime } from "rxjs/operators";
236
+
237
+ private speakerSubject = new Subject<string>();
238
+
239
+ ngOnInit() {
240
+ this.speakerSubject.pipe(debounceTime(500)).subscribe((uid) => {
241
+ this.zone.run(() => { this.activeSpeakerUid = uid; this.recomputeLayout(); this.cd.markForCheck(); });
242
+ });
243
+
244
+ const listener = new CometChatCalls.OngoingCallListener({
245
+ onActiveSpeakerUpdated: (uid: string) => this.speakerSubject.next(uid),
246
+ });
247
+ }
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Moderator actions — guarded by group scope
253
+
254
+ ```ts
255
+ // In your component or a CallControlsService
256
+ async muteParticipant(uid: string) {
257
+ if (!this.canModerate()) return;
258
+ await CometChatCalls.muteUser(uid);
259
+ }
260
+
261
+ async kickParticipant(uid: string) {
262
+ if (!this.canModerate()) return;
263
+ await CometChatCalls.removeUser(uid);
264
+ }
265
+
266
+ async muteAll() {
267
+ if (!this.canModerate()) return;
268
+ for (const p of this.others) {
269
+ await CometChatCalls.muteUser(p.uid);
270
+ }
271
+ }
272
+
273
+ private canModerate(): boolean {
274
+ const scope = this.group?.getScope();
275
+ return scope === "admin" || scope === "moderator";
276
+ }
277
+ ```
278
+
279
+ Hide the moderator-only buttons in the template:
280
+
281
+ ```html
282
+ <div *ngIf="canModerate()" class="moderator-controls">
283
+ <button (click)="muteAll()">Mute all</button>
284
+ <button (click)="kickParticipant(p.uid)" *ngFor="let p of others">Kick</button>
285
+ </div>
286
+ ```
287
+
288
+ ---
289
+
290
+ ## Capacity-error handling
291
+
292
+ ```ts
293
+ const listener = new CometChatCalls.OngoingCallListener({
294
+ onError: (error: { code: string; message: string }) => {
295
+ this.zone.run(() => {
296
+ if (error.code === "ERR_CALL_FULL") {
297
+ this.snackBar.open("This meeting is full.", "Dismiss", { duration: 5000 });
298
+ } else if (error.code === "ERR_NOT_GROUP_MEMBER") {
299
+ this.snackBar.open("You're not a member of this group.", "Dismiss", { duration: 5000 });
300
+ } else {
301
+ this.snackBar.open(`Call error: ${error.message}`, "Dismiss", { duration: 5000 });
302
+ }
303
+ });
304
+ },
305
+ });
306
+ ```
307
+
308
+ Material's `MatSnackBar` is the canonical Angular surface for transient errors — pick whatever the project uses.
309
+
310
+ ---
311
+
312
+ ## Bandwidth + battery — auto-downgrade to audio-only
313
+
314
+ Angular doesn't have a first-party battery API, but `BatteryManager` works in browsers (deprecated but functional in Chrome/Edge):
315
+
316
+ ```ts
317
+ async observeBattery() {
318
+ if ("getBattery" in navigator) {
319
+ const battery = await (navigator as unknown as { getBattery: () => Promise<{ level: number; addEventListener: (e: string, h: () => void) => void }> }).getBattery();
320
+
321
+ const check = () => {
322
+ if (battery.level < 0.2 && this.callActive) {
323
+ this.zone.run(() => {
324
+ CometChatCalls.pauseVideo(true);
325
+ this.snackBar.open("Video paused — low battery", "Dismiss", { duration: 5000 });
326
+ });
327
+ }
328
+ };
329
+ battery.addEventListener("levelchange", check);
330
+ check();
331
+ }
332
+ }
333
+ ```
334
+
335
+ Firefox + Safari don't have `getBattery()` — gracefully skip. For mobile-web users, network-quality detection (Network Information API) is more reliable.
336
+
337
+ ---
338
+
339
+ ## Joining a group call already in progress
340
+
341
+ Angular `Resolver` for the group-detail route can pre-check active call state:
342
+
343
+ ```ts
344
+ @Injectable({ providedIn: "root" })
345
+ export class GroupCallStateResolver implements Resolve<{ activeCall: unknown | null }> {
346
+ async resolve(route: ActivatedRouteSnapshot): Promise<{ activeCall: unknown | null }> {
347
+ const activeCall = await CometChat.getActiveCall();
348
+ return {
349
+ activeCall: activeCall && activeCall.getReceiverType() === "group"
350
+ ? activeCall
351
+ : null,
352
+ };
353
+ }
354
+ }
355
+ ```
356
+
357
+ Wire on the route:
358
+
359
+ ```ts
360
+ {
361
+ path: "groups/:guid",
362
+ component: GroupDetailComponent,
363
+ resolve: { callState: GroupCallStateResolver },
364
+ }
365
+ ```
366
+
367
+ In the component:
368
+
369
+ ```ts
370
+ ngOnInit() {
371
+ const callState = this.route.snapshot.data["callState"];
372
+ if (callState.activeCall) {
373
+ // Show "Join meeting" button
374
+ this.activeCall = callState.activeCall;
375
+ }
376
+ }
377
+ ```
378
+
379
+ ---
380
+
381
+ ## Anti-patterns
382
+
383
+ 1. **Roster updates without `trackByUid`** in `*ngFor`. Tiles re-create; video tracks die.
384
+ 2. **Skipping `markForCheck`** with OnPush. Roster updates don't render.
385
+ 3. **No debounce on active-speaker.** Tiles jitter at 5+ Hz.
386
+ 4. **Moderator buttons rendered for non-moderators.** SDK rejects but UI is misleading.
387
+ 5. **`getBattery()` without feature detect.** Firefox/Safari throws.
388
+ 6. **Leaving the call doesn't unsubscribe RxJS subjects.** Memory leak across multiple call sessions.
389
+ 7. **Group call from a lazy-loaded module.** CallInitService must be eager (cf. `references/lazy-loading-pitfalls.md`).
390
+
391
+ ---
392
+
393
+ ## Verification checklist
394
+
395
+ - [ ] `*ngFor` over participants uses `trackBy: trackByUid`
396
+ - [ ] OnPush components call `cd.markForCheck()` on roster updates
397
+ - [ ] Active-speaker updates debounced ≥500ms
398
+ - [ ] All SDK callbacks wrapped in `zone.run`
399
+ - [ ] Moderator controls hidden for non-moderator scopes
400
+ - [ ] Capacity error handled (`ERR_CALL_FULL`) with user-facing snackbar
401
+ - [ ] Battery API feature-detected before use
402
+ - [ ] `Resolver` checks `getActiveCall()` on group route entry
403
+ - [ ] RxJS subscriptions cleaned up in `ngOnDestroy`
404
+
405
+ ---
406
+
407
+ ## Pointers
408
+
409
+ - `references/ngzone-and-async-callbacks.md` — NgZone primer
410
+ - `references/lazy-loading-pitfalls.md` — eager-load CallInitService rule
411
+ - `references/custom-ui.md` — multi-tile custom layouts
412
+ - `cometchat-native-calls/references/group-calls.md` — sister reference (same SDK, RN-flavored patterns; capacity/bandwidth/moderator actions covered there)
@@ -0,0 +1,145 @@
1
+ # Idle timeout on Angular
2
+
3
+ Same SDK API as web. Angular-specific delta: NgZone wrap on the timeout event + Angular Material dialog or custom modal for the prompt.
4
+
5
+ **Canonical docs:** https://www.cometchat.com/docs/calls/javascript/idle-timeout
6
+ **Read first:** `cometchat-react-calls/references/idle-timeout.md` — settings + archetype timeouts + custom prompt pattern.
7
+
8
+ ---
9
+
10
+ ## SDK API
11
+
12
+ ```ts
13
+ const settings = new CometChatCalls.CallSettingsBuilder()
14
+ .setSessionID(sessionId)
15
+ .setIdleTimeoutPeriodBeforePrompt(60_000)
16
+ .setIdleTimeoutPeriodAfterPrompt(120_000)
17
+ .build();
18
+
19
+ CometChatCalls.addEventListener("onSessionTimedOut", () => {
20
+ this.zone.run(() => {
21
+ this.router.navigate(["/"]);
22
+ this.snackBar.open("Call ended due to inactivity", "Dismiss", { duration: 5000 });
23
+ });
24
+ });
25
+ ```
26
+
27
+ `NgZone.run` wrap is mandatory — without it, the navigation + snackbar don't fire because the SDK callback is outside Angular's zone.
28
+
29
+ ---
30
+
31
+ ## Service-level wiring
32
+
33
+ ```ts
34
+ // services/idle-timeout.service.ts
35
+ import { Injectable, NgZone } from "@angular/core";
36
+ import { Router } from "@angular/router";
37
+ import { MatSnackBar } from "@angular/material/snack-bar";
38
+ import { CometChatCalls } from "@cometchat/calls-sdk-javascript";
39
+
40
+ @Injectable({ providedIn: "root" })
41
+ export class IdleTimeoutService {
42
+ private listener?: () => void;
43
+
44
+ constructor(
45
+ private zone: NgZone,
46
+ private router: Router,
47
+ private snackBar: MatSnackBar,
48
+ ) {}
49
+
50
+ attachToCallSession() {
51
+ this.listener = () => {
52
+ this.zone.run(() => {
53
+ this.router.navigate(["/"]);
54
+ this.snackBar.open("Call ended due to inactivity", "Dismiss", { duration: 5000 });
55
+ });
56
+ };
57
+ CometChatCalls.addEventListener("onSessionTimedOut", this.listener);
58
+ }
59
+
60
+ detach() {
61
+ if (this.listener) {
62
+ CometChatCalls.removeEventListener("onSessionTimedOut", this.listener);
63
+ this.listener = undefined;
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ Call `attachToCallSession()` from the OngoingCallComponent's `ngOnInit`, `detach()` from `ngOnDestroy`.
70
+
71
+ ---
72
+
73
+ ## Custom prompt — Angular Material Dialog
74
+
75
+ ```ts
76
+ import { MatDialog } from "@angular/material/dialog";
77
+ import { Component } from "@angular/core";
78
+
79
+ @Component({
80
+ template: `
81
+ <h2 mat-dialog-title>Still there?</h2>
82
+ <mat-dialog-content>
83
+ You're alone in this call. It'll end in 60 seconds.
84
+ </mat-dialog-content>
85
+ <mat-dialog-actions>
86
+ <button mat-button [mat-dialog-close]="'stay'">Stay</button>
87
+ <button mat-button color="warn" [mat-dialog-close]="'end'">End now</button>
88
+ </mat-dialog-actions>
89
+ `,
90
+ })
91
+ export class IdleTimeoutDialogComponent {}
92
+
93
+ // Use:
94
+ @Component({ /* ... */ })
95
+ export class OngoingCallComponent {
96
+ constructor(private dialog: MatDialog) {}
97
+
98
+ showIdlePrompt() {
99
+ const ref = this.dialog.open(IdleTimeoutDialogComponent, {
100
+ disableClose: true,
101
+ ariaLabel: "Idle timeout warning",
102
+ });
103
+ ref.afterClosed().subscribe(result => {
104
+ if (result === "end") {
105
+ CometChatCalls.leaveSession(); // v5 canonical (endSession is deprecated)
106
+ }
107
+ // 'stay' → reset your custom timer (see Pattern A in web ref)
108
+ });
109
+ }
110
+ }
111
+ ```
112
+
113
+ `disableClose: true` prevents the user from dismissing via Esc/backdrop — they must explicitly choose. `ariaLabel` for screen readers.
114
+
115
+ ---
116
+
117
+ ## Anti-patterns
118
+
119
+ Web sister reference rules apply, plus Angular-specific:
120
+
121
+ 1. **No `NgZone.run` wrap on the listener.** Navigation + snackbar fire silently because change detection doesn't trigger.
122
+ 2. **`MatDialog` opened from `setTimeout` callback** without zone wrap. Dialog opens but template doesn't render.
123
+ 3. **Subscription leaks** — `dialog.afterClosed()` returns an Observable; if you don't unsubscribe (or use `take(1)` / `first()`), it leaks across calls.
124
+ 4. **Service NOT provided in `root`.** Lazy-loaded → listener attaches late.
125
+
126
+ ---
127
+
128
+ ## Verification checklist
129
+
130
+ - [ ] `IdleTimeoutService` provided in root
131
+ - [ ] Listener wraps in `NgZone.run`
132
+ - [ ] Service `attachToCallSession()` called from OngoingCall `ngOnInit`
133
+ - [ ] Service `detach()` called from `ngOnDestroy`
134
+ - [ ] Dialog uses `disableClose: true` + `ariaLabel`
135
+ - [ ] `dialog.afterClosed()` subscription doesn't leak (use `first()` or unsubscribe)
136
+ - [ ] Browser smoke: 2 tabs in call, hangup one → other shows snackbar after configured delay
137
+
138
+ ---
139
+
140
+ ## Pointers
141
+
142
+ - `cometchat-react-calls/references/idle-timeout.md` — sister reference
143
+ - `cometchat-angular-calls` SKILL.md
144
+ - `references/ngzone-and-async-callbacks.md` — NgZone primer
145
+ - Canonical docs: https://www.cometchat.com/docs/calls/javascript/idle-timeout
@@ -0,0 +1,148 @@
1
+ # In-call chat on Angular
2
+
3
+ Same SDK API as web. Angular wraps panel state in a service + uses Angular Material's `MatSidenav` for the side-drawer chat panel pattern.
4
+
5
+ **Canonical docs:** https://www.cometchat.com/docs/calls/javascript/in-call-chat
6
+ **Read first:** `cometchat-react-calls/references/in-call-chat.md` — group-as-session architecture, anti-patterns.
7
+
8
+ ---
9
+
10
+ ## SDK + service
11
+
12
+ ```ts
13
+ import { Injectable, NgZone } from "@angular/core";
14
+ import { BehaviorSubject } from "rxjs";
15
+ import { CometChatCalls } from "@cometchat/calls-sdk-javascript";
16
+ import { CometChat } from "@cometchat/chat-sdk-javascript";
17
+
18
+ @Injectable({ providedIn: "root" })
19
+ export class InCallChatService {
20
+ readonly open$ = new BehaviorSubject<boolean>(false);
21
+ readonly unread$ = new BehaviorSubject<number>(0);
22
+
23
+ constructor(private zone: NgZone) {
24
+ CometChatCalls.addEventListener("onChatButtonClicked", () => {
25
+ this.zone.run(() => this.open$.next(true));
26
+ });
27
+ }
28
+
29
+ async ensureGroup(sessionId: string): Promise<CometChat.Group> {
30
+ try {
31
+ return await CometChat.getGroup(sessionId);
32
+ } catch {
33
+ const group = new CometChat.Group(sessionId, `Call ${sessionId}`, CometChat.GROUP_TYPE.PUBLIC);
34
+ return await CometChat.createGroup(group);
35
+ }
36
+ }
37
+
38
+ async joinGroup(sessionId: string): Promise<void> {
39
+ await CometChat.joinGroup(sessionId, CometChat.GROUP_TYPE.PUBLIC, "");
40
+ }
41
+
42
+ trackUnread(sessionId: string): void {
43
+ const listenerId = `in-call-chat-${sessionId}`;
44
+ const listener = new CometChat.MessageListener({
45
+ onTextMessageReceived: (msg: CometChat.TextMessage) => {
46
+ if (
47
+ msg.getReceiverType() === CometChat.RECEIVER_TYPE.GROUP &&
48
+ msg.getReceiverId() === sessionId &&
49
+ !this.open$.value
50
+ ) {
51
+ this.zone.run(() => {
52
+ const next = this.unread$.value + 1;
53
+ this.unread$.next(next);
54
+ CometChatCalls.setChatButtonUnreadCount(next);
55
+ });
56
+ }
57
+ },
58
+ });
59
+ CometChat.addMessageListener(listenerId, listener);
60
+ }
61
+
62
+ open(): void {
63
+ this.open$.next(true);
64
+ this.unread$.next(0);
65
+ CometChatCalls.setChatButtonUnreadCount(0);
66
+ }
67
+
68
+ close(): void {
69
+ this.open$.next(false);
70
+ }
71
+ }
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Panel component (MatSidenav)
77
+
78
+ ```ts
79
+ @Component({
80
+ selector: "app-in-call-chat",
81
+ template: `
82
+ <mat-sidenav-container [hasBackdrop]="false">
83
+ <mat-sidenav
84
+ #drawer
85
+ position="end"
86
+ mode="side"
87
+ [opened]="open$ | async"
88
+ (closed)="svc.close()"
89
+ role="dialog"
90
+ aria-label="In-call chat"
91
+ >
92
+ <ng-container *ngIf="group">
93
+ <cometchat-message-list [group]="group" [hideReplyInThreadOption]="true"></cometchat-message-list>
94
+ <cometchat-message-composer [group]="group"></cometchat-message-composer>
95
+ </ng-container>
96
+ </mat-sidenav>
97
+ <mat-sidenav-content>
98
+ <!-- call surface goes here -->
99
+ <ng-content></ng-content>
100
+ </mat-sidenav-content>
101
+ </mat-sidenav-container>
102
+ `,
103
+ })
104
+ export class InCallChatComponent implements OnInit {
105
+ @Input() sessionId!: string;
106
+ open$ = this.svc.open$;
107
+ group?: CometChat.Group;
108
+
109
+ constructor(public svc: InCallChatService) {}
110
+
111
+ async ngOnInit() {
112
+ this.group = await this.svc.ensureGroup(this.sessionId);
113
+ this.svc.trackUnread(this.sessionId);
114
+ }
115
+ }
116
+ ```
117
+
118
+ `mode="side"` makes the drawer slide out without an overlay backdrop — call view stays visible. `[hasBackdrop]="false"` doubles down.
119
+
120
+ ---
121
+
122
+ ## Anti-patterns
123
+
124
+ Web sister rules apply, plus Angular-specific:
125
+
126
+ 1. **No `NgZone.run` wrap on `onChatButtonClicked`.** Drawer doesn't open in OnPush components.
127
+ 2. **`MatSidenav` `mode="over"`.** Backdrop blocks the call. Use `mode="side"`.
128
+ 3. **Service NOT in `root`.** Lazy module → button events miss.
129
+
130
+ ---
131
+
132
+ ## Verification checklist
133
+
134
+ - [ ] `InCallChatService` provided in root
135
+ - [ ] `NgZone.run` wraps the chat-button event
136
+ - [ ] `MatSidenav` uses `mode="side"` + `hasBackdrop="false"`
137
+ - [ ] Group resolved on `ngOnInit`
138
+ - [ ] Unread badge updates via service, clears on open
139
+ - [ ] Browser smoke: 2 tabs, chat works, unread badge increments
140
+
141
+ ---
142
+
143
+ ## Pointers
144
+
145
+ - `cometchat-react-calls/references/in-call-chat.md` — sister web reference
146
+ - `cometchat-angular-calls` SKILL.md
147
+ - `references/ngzone-and-async-callbacks.md`
148
+ - Canonical docs: https://www.cometchat.com/docs/calls/javascript/in-call-chat