@@ -8,12 +8,11 @@ import {
88 Modal ,
99 List ,
1010 ListItem ,
11- Alert ,
12- ActionIcon ,
1311 ScrollArea ,
1412 Badge ,
13+ ActionIcon ,
1514} from '@mantine/core' ;
16- import { IconTrash , IconCheck , IconX } from '@tabler/icons-react' ;
15+ import { IconTrash , IconUserPlus } from '@tabler/icons-react' ;
1716import { notifications } from '@mantine/notifications' ;
1817import { GroupMemberGetResponse , EntraActionResponse } from '@common/types/iam' ;
1918
@@ -29,17 +28,9 @@ export const GroupMemberManagement: React.FC<GroupMemberManagementProps> = ({
2928 const [ members , setMembers ] = useState < GroupMemberGetResponse > ( [ ] ) ;
3029 const [ toAdd , setToAdd ] = useState < string [ ] > ( [ ] ) ;
3130 const [ toRemove , setToRemove ] = useState < string [ ] > ( [ ] ) ;
32- const [ results , setResults ] = useState <
33- { email : string ; status : 'success' | 'failure' ; message ?: string } [ ]
34- > ( [ ] ) ;
35- const [ email , setEmail ] = useState < string > ( '' ) ;
36- const [ isLoading , setIsLoading ] = useState < boolean > ( false ) ;
37- const [ confirmationModal , setConfirmationModal ] = useState < boolean > ( false ) ;
38- const [ errorModal , setErrorModal ] = useState < { open : boolean ; email : string ; message : string } > ( {
39- open : false ,
40- email : '' ,
41- message : '' ,
42- } ) ;
31+ const [ email , setEmail ] = useState ( '' ) ;
32+ const [ isLoading , setIsLoading ] = useState ( false ) ;
33+ const [ confirmationModal , setConfirmationModal ] = useState ( false ) ;
4334
4435 useEffect ( ( ) => {
4536 const loadMembers = async ( ) => {
@@ -61,9 +52,14 @@ export const GroupMemberManagement: React.FC<GroupMemberManagementProps> = ({
6152 if ( email && ! members . some ( ( member ) => member . email === email ) && ! toAdd . includes ( email ) ) {
6253 setToAdd ( ( prev ) => [ ...prev , email ] ) ;
6354 setEmail ( '' ) ;
55+ } else {
56+ notifications . show ( {
57+ title : 'Invalid Input' ,
58+ message : 'Email is missing or the user already exists.' ,
59+ color : 'orange' ,
60+ } ) ;
6461 }
6562 } ;
66-
6763 const handleRemoveMember = ( email : string ) => {
6864 if ( ! toRemove . includes ( email ) ) {
6965 setToRemove ( ( prev ) => [ ...prev , email ] ) ;
@@ -72,51 +68,60 @@ export const GroupMemberManagement: React.FC<GroupMemberManagementProps> = ({
7268
7369 const handleSaveChanges = async ( ) => {
7470 setIsLoading ( true ) ;
75- const newResults : { email : string ; status : 'success' | 'failure' ; message ?: string } [ ] = [ ] ;
76-
7771 try {
7872 const response = await updateMembers ( toAdd , toRemove ) ;
79- response . success ?. forEach ( ( { email } ) => {
80- newResults . push ( { email, status : 'success' } ) ;
81- } ) ;
82- response . failure ?. forEach ( ( { email, message } ) => {
83- newResults . push ( { email, status : 'failure' , message } ) ;
73+ if ( response . success ) {
74+ setMembers ( ( prev ) =>
75+ prev
76+ . filter ( ( member ) => ! toRemove . includes ( member . email ) )
77+ . concat ( toAdd . map ( ( email ) => ( { name : '' , email } ) ) )
78+ ) ;
79+ setToAdd ( [ ] ) ;
80+ setToRemove ( [ ] ) ;
81+ }
82+
83+ notifications . show ( {
84+ title : 'Success' ,
85+ message : 'Changes saved successfully!' ,
86+ color : 'green' ,
8487 } ) ;
85- setResults ( newResults ) ;
86- setToAdd ( [ ] ) ;
87- setToRemove ( [ ] ) ;
8888 } catch ( error ) {
8989 notifications . show ( {
9090 title : 'Error' ,
91- message : 'An error occurred while saving changes.' ,
91+ message : 'Failed to save changes.' ,
9292 color : 'red' ,
9393 } ) ;
9494 } finally {
9595 setIsLoading ( false ) ;
9696 }
9797 } ;
9898
99- const handleViewErrorDetails = ( email : string , message : string ) => {
100- setErrorModal ( { open : true , email, message } ) ;
101- } ;
102-
10399 return (
104100 < Box p = "md" >
105101 < Text fw = { 500 } mb = { 4 } >
106- Group Member Management
102+ Exec Group Management
107103 </ Text >
108104
109105 { /* Member List */ }
110106 < Box mb = "md" >
111107 < Text size = "sm" fw = { 500 } mb = "xs" >
112108 Current Members
113109 </ Text >
114- < ScrollArea style = { { height : 200 } } >
115- < List >
110+ < ScrollArea style = { { height : 250 } } >
111+ < List spacing = "sm" >
116112 { members . map ( ( member ) => (
117113 < ListItem key = { member . email } >
118114 < Group justify = "space-between" >
119- < Text size = "sm" > { member . email } </ Text >
115+ < Box >
116+ < Text size = "sm" >
117+ { member . name } ({ member . email } )
118+ </ Text >
119+ { toRemove . includes ( member . email ) && (
120+ < Badge color = "green" size = "sm" >
121+ Queued for removal
122+ </ Badge >
123+ ) }
124+ </ Box >
120125 < ActionIcon
121126 color = "red"
122127 variant = "light"
@@ -127,14 +132,45 @@ export const GroupMemberManagement: React.FC<GroupMemberManagementProps> = ({
127132 </ Group >
128133 </ ListItem >
129134 ) ) }
135+ { toAdd . map ( ( member ) => (
136+ < ListItem key = { member } >
137+ < Group justify = "space-between" >
138+ < Box >
139+ < Text size = "sm" > { member } </ Text >
140+ < Badge color = "red" size = "sm" >
141+ Queued for addition
142+ </ Badge >
143+ </ Box >
144+ </ Group >
145+ </ ListItem >
146+ ) ) }
130147 </ List >
131148 </ ScrollArea >
132149 </ Box >
133150
151+ { /* Add Member */ }
152+ < Box mb = "md" >
153+ < TextInput
154+ value = { email }
155+ onChange = { ( e ) => setEmail ( e . currentTarget . value ) }
156+ placeholder = "Enter email"
157+ label = "Add Member"
158+ />
159+ < Button
160+ mt = "sm"
161+ leftSection = { < IconUserPlus size = { 16 } /> }
162+ onClick = { handleAddMember }
163+ disabled = { isLoading }
164+ >
165+ Add Member
166+ </ Button >
167+ </ Box >
168+
134169 { /* Save Changes Button */ }
135170 < Button
136171 fullWidth
137172 color = "blue"
173+ mt = "md"
138174 onClick = { ( ) => setConfirmationModal ( true ) }
139175 disabled = { ! toAdd . length && ! toRemove . length }
140176 loading = { isLoading }
@@ -147,43 +183,41 @@ export const GroupMemberManagement: React.FC<GroupMemberManagementProps> = ({
147183 opened = { confirmationModal }
148184 onClose = { ( ) => setConfirmationModal ( false ) }
149185 title = "Confirm Changes"
150- size = "md"
151186 >
152187 < Box >
153188 { toAdd . length > 0 && (
154189 < Box mb = "md" >
155190 < Text fw = { 500 } size = "sm" >
156191 Members to Add:
157192 </ Text >
158- < ScrollArea style = { { height : 100 } } >
159- < List >
160- { toAdd . map ( ( email ) => (
161- < ListItem key = { email } >
162- < Text size = "sm" > { email } </ Text >
163- </ ListItem >
164- ) ) }
165- </ List >
166- </ ScrollArea >
193+ < List spacing = "sm" >
194+ { toAdd . map ( ( email ) => (
195+ < ListItem key = { email } > { email } </ ListItem >
196+ ) ) }
197+ </ List >
167198 </ Box >
168199 ) }
169200 { toRemove . length > 0 && (
170201 < Box mb = "md" >
171202 < Text fw = { 500 } size = "sm" >
172203 Members to Remove:
173204 </ Text >
174- < ScrollArea style = { { height : 100 } } >
175- < List >
176- { toRemove . map ( ( email ) => (
177- < ListItem key = { email } >
178- < Text size = "sm" > { email } </ Text >
179- </ ListItem >
180- ) ) }
181- </ List >
182- </ ScrollArea >
205+ < List spacing = "sm" >
206+ { toRemove . map ( ( email ) => (
207+ < ListItem key = { email } > { email } </ ListItem >
208+ ) ) }
209+ </ List >
183210 </ Box >
184211 ) }
185212 < Group justify = "center" mt = "lg" >
186- < Button onClick = { handleSaveChanges } loading = { isLoading } color = "blue" >
213+ < Button
214+ onClick = { ( ) => {
215+ handleSaveChanges ( ) ;
216+ setConfirmationModal ( false ) ;
217+ } }
218+ loading = { isLoading }
219+ color = "blue"
220+ >
187221 Confirm and Save
188222 </ Button >
189223 < Button
0 commit comments