@@ -219,15 +219,17 @@ export function CometChatAddMembers(props: IAddMembersProps) {
219219 const membersToAddRef = useRef < CometChat . GroupMember [ ] > ( [ ] ) ;
220220 const selectionModeRef = useRef ( selectionMode ) ;
221221 const loggedInUserRef = useRef < CometChat . User | null > ( null ) ;
222- const onSelectPropRef = useRefSync ( onSelect ) ;
223222 const groupPropRef = useRefSync ( group ) ;
224223 const onBackPropRef = useRefSync ( onBack ) ;
225224 const onAddMembersButtonClickPropRef = useRefSync ( onAddMembersButtonClick ) ;
226225 const errorHandler = useCometChatErrorHandler ( onError ! ) ;
227226 const [ isLoading , setIsLoading ] = useState ( false ) ;
228227 const [ isDisabled , setIsDisabled ] = useState ( true ) ;
229228 const [ isError , setIsError ] = useState ( false ) ;
230- /**
229+ const [ membersCount , setMembersCount ] = useState ( 0 ) ;
230+ // Track selected users internally
231+ const selectedUsersMapRef = useRef < Map < string , CometChat . User > > ( new Map ( ) ) ;
232+
231233 /**
232234 * Creates a `CometChat.GroupMember` instance from the provided `user`
233235 */
@@ -241,48 +243,28 @@ export function CometChatAddMembers(props: IAddMembersProps) {
241243 } , [ groupPropRef ] ) ;
242244
243245 /**
244- * Updates `membersToAddRef`
245- *
246- * @remarks
247- * This function makes sure `membersToAddRef` is in sync with the UI
246+ * Handles individual user selection changes from CometChatUsers
247+ * Tracks selected users internally and updates state accordingly
248248 */
249- const onSelectWrapper = useCallback ( ( user : CometChat . User , selected : boolean ) : void => {
250-
251- if ( onSelectPropRef . current ) {
252- return onSelectPropRef . current ( user , selected ) ;
253- }
254- if ( selectionModeRef . current === SelectionMode . single ) {
255- membersToAddRef . current = [ createGroupMemberFromUser ( user ) ] ;
256- }
257- else if ( selectionModeRef . current === SelectionMode . multiple ) {
258- updateAddMembersList ( user ) ;
259- }
260- if ( membersToAddRef . current . length == 0 ) {
261- setIsDisabled ( true )
262- }
263- else {
264- setIsDisabled ( false ) ;
249+ const handleSelect = useCallback ( ( user : CometChat . User , selected : boolean ) : void => {
250+ if ( selected ) {
251+ selectedUsersMapRef . current . set ( user . getUid ( ) , user ) ;
252+ } else {
253+ selectedUsersMapRef . current . delete ( user . getUid ( ) ) ;
265254 }
266- } , [ createGroupMemberFromUser , onSelectPropRef ] ) ;
267-
268- const updateAddMembersList = ( user : CometChat . User ) => {
269- const targetUid = user . getUid ( ) ;
270- const tmpMembersToAddList : CometChat . GroupMember [ ] = [ ] ;
271- let updated = false ;
272- for ( let i = 0 ; i < membersToAddRef . current . length ; i ++ ) {
273- const curMember = membersToAddRef . current [ i ] ;
274- if ( targetUid === curMember . getUid ( ) ) {
275- updated = true ;
276- }
277- else {
278- tmpMembersToAddList . push ( curMember ) ;
279- }
280- }
281- if ( ! updated ) {
282- tmpMembersToAddList . push ( createGroupMemberFromUser ( user ) ) ;
283- }
284- membersToAddRef . current = tmpMembersToAddList ;
285- }
255+
256+ // Convert selected users to group members
257+ const selectedUsersList = Array . from ( selectedUsersMapRef . current . values ( ) ) ;
258+ membersToAddRef . current = selectedUsersList . map ( u => createGroupMemberFromUser ( u ) ) ;
259+
260+ // Update button disabled state and count based on selection
261+ const count = selectedUsersList . length ;
262+ setMembersCount ( count ) ;
263+ setIsDisabled ( count === 0 ) ;
264+
265+ // Call the original onSelect prop if provided
266+ onSelect ?.( user , selected ) ;
267+ } , [ createGroupMemberFromUser , onSelect ] ) ;
286268
287269 /**
288270 * Creates a `CometChat.Action` instance
@@ -322,6 +304,7 @@ export function CometChatAddMembers(props: IAddMembersProps) {
322304 if ( onAddBtnClick ) {
323305 onAddBtnClick ( group . getGuid ( ) , membersToAddRef . current ) ;
324306 membersToAddRef . current = [ ] ;
307+ setMembersCount ( 0 ) ;
325308 return ;
326309 }
327310 const UIDsToRemove : Set < string > = new Set ( ) ;
@@ -353,6 +336,7 @@ export function CometChatAddMembers(props: IAddMembersProps) {
353336 } ) ;
354337 }
355338 membersToAddRef . current = [ ] ;
339+ setMembersCount ( 0 ) ;
356340 onBackPropRef . current ?.( ) ;
357341 }
358342 catch ( error ) {
@@ -379,31 +363,59 @@ export function CometChatAddMembers(props: IAddMembersProps) {
379363 ) ;
380364 }
381365
366+ /**
367+ * Gets the localized button text based on member count
368+ */
369+ function getButtonText ( ) : string {
370+ if ( buttonText && buttonText !== getLocalizedString ( "add_members" ) ) {
371+ return buttonText ;
372+ }
373+ if ( membersCount === 0 ) {
374+ return getLocalizedString ( "add_members" ) ;
375+ }
376+ if ( membersCount === 1 ) {
377+ // Prefer dedicated singular key for better localization
378+ const singular = getLocalizedString ( "add_member" ) ;
379+ if ( singular && singular !== "" ) {
380+ return singular ;
381+ }
382+ // Fallback to plural template with n = 1, if available
383+ const nSingular = getLocalizedString ( "add_n_members" ) ;
384+ if ( nSingular && nSingular !== "" ) {
385+ return nSingular . replace ( "{n}" , "1" ) ;
386+ }
387+ // Final English fallback
388+ const generic = getLocalizedString ( "add_members" ) ;
389+ return generic && generic !== "" ? generic : "" ;
390+ }
391+ const n = getLocalizedString ( "add_n_members" ) ;
392+ // Fallback if localization key is missing
393+ if ( ! n || n === "" ) {
394+ // Use localized fallback instead of hardcoded English string
395+ const generic = getLocalizedString ( "add_members" ) ;
396+ return generic && generic !== "" ? generic : "" ;
397+ }
398+ const text = n . replace ( "{n}" , membersCount . toString ( ) ) ;
399+ return text ;
400+ }
401+
382402 /**
383403 * Creates add members button view
384404 */
385405 function getAddMembersBtnView ( ) {
406+ const buttonTextValue = getButtonText ( ) ;
386407 return (
387408 < div className = { `cometchat-add-members__add-btn-wrapper ${ isDisabled ? "cometchat-add-members__add-btn-wrapper-disabled" : "" } ` } >
388409 < CometChatButton
410+ key = { `add-btn-${ membersCount } ` }
389411 isLoading = { isLoading }
390- text = { buttonText }
412+ text = { buttonTextValue }
391413 onClick = { onAddBtnClickWrapper }
392414 />
393415 </ div >
394416 ) ;
395417 }
396418
397- const onUsersSelected = ( user : CometChat . User ) => {
398- updateAddMembersList ( user ) ;
399- if ( membersToAddRef . current . length == 0 ) {
400- setIsDisabled ( true )
401- }
402- else {
403- setIsDisabled ( false ) ;
404- }
405- }
406-
407419 useCometChatAddMembers ( {
408420 loggedInUserRef,
409421 errorHandler,
@@ -427,14 +439,13 @@ export function CometChatAddMembers(props: IAddMembersProps) {
427439 onError = { onError }
428440 options = { options }
429441 selectionMode = { selectionMode }
430- onSelect = { onSelectWrapper }
442+ onSelect = { handleSelect }
431443 usersRequestBuilder = { usersRequestBuilder }
432444 searchRequestBuilder = { searchRequestBuilder }
433445 itemView = { listItemView }
434446 subtitleView = { subtitleView }
435- onItemClick = { onUsersSelected }
436447 activeUser = { undefined }
437-
448+ showSelectedUsersPreview = { true }
438449 />
439450 { isError ? < div className = "cometchat-add-members_error-view" >
440451 { getLocalizedString ( "member_error_subtitle" ) }
0 commit comments