11import {
2- useState , useCallback , useEffect , useMemo ,
2+ useState , useCallback , useMemo , useRef , useEffect ,
33} from 'react' ;
44import { useIntl } from '@edx/frontend-platform/i18n' ;
55import {
@@ -8,11 +8,10 @@ import {
88import { SpinnerSimple } from '@openedx/paragon/icons' ;
99import SelectUsersAndRoleStep from './SelectUsersAndRoleStep' ;
1010import DefineApplicationScopeStep from './DefineApplicationScopeStep' ;
11- import { useValidateUsers , useAssignTeamMembersRole } from '../data/hooks' ;
11+ import { useValidateUsers } from '../data/hooks' ;
1212import {
1313 CONTENT_LIBRARY_PERMISSIONS , COURSE_PERMISSIONS , courseRolesMetadata , libraryRolesMetadata ,
1414} from '../constants' ;
15- import { useToastManager } from '../libraries-manager/ToastManagerContext' ;
1615import { useValidateUserPermissions } from '../../data/hooks' ;
1716import messages from './messages' ;
1817
@@ -47,9 +46,9 @@ const AssignRoleWizard = ({ onClose, scope, initialUsers = '' }: AssignRoleWizar
4746 const [ invalidUsers , setInvalidUsers ] = useState < string [ ] > ( [ ] ) ;
4847 const [ validatedUsers , setValidatedUsers ] = useState < string [ ] > ( [ ] ) ;
4948
49+ const usersInputRef = useRef < HTMLTextAreaElement > ( null ) ;
50+
5051 const validateUsersMutation = useValidateUsers ( ) ;
51- const assignRoleMutation = useAssignTeamMembersRole ( ) ;
52- const { showToast, showErrorToast } = useToastManager ( ) ;
5352
5453 // Filter role groups based on what the current user is allowed to manage
5554 const permissionChecks = useMemo ( ( ) => [
@@ -59,12 +58,10 @@ const AssignRoleWizard = ({ onClose, scope, initialUsers = '' }: AssignRoleWizar
5958
6059 const { data : permissionsData } = useValidateUserPermissions ( permissionChecks ) ;
6160
62- // Clear highlights as soon as the user edits the input
63- useEffect ( ( ) => {
64- if ( invalidUsers . length > 0 ) {
65- setInvalidUsers ( [ ] ) ;
66- }
67- } , [ users ] ) ; // eslint-disable-line react-hooks/exhaustive-deps
61+ const handleUsersChange = useCallback ( ( value : string ) => {
62+ setInvalidUsers ( ( prev ) => ( prev . length > 0 ? [ ] : prev ) ) ;
63+ setUsers ( value ) ;
64+ } , [ ] ) ;
6865
6966 const filteredRoles = useMemo ( ( ) => {
7067 const allowedContextTypes = new Set (
@@ -76,12 +73,6 @@ const AssignRoleWizard = ({ onClose, scope, initialUsers = '' }: AssignRoleWizar
7673 return allRolesMetadata . filter ( ( r ) => allowedContextTypes . has ( r . contextType || '' ) ) ;
7774 } , [ permissionsData ] ) ;
7875
79- useEffect ( ( ) => {
80- if ( filteredRoles . length === 0 ) {
81- onClose ( ) ;
82- }
83- } , [ filteredRoles . length , onClose ] ) ;
84-
8576 const handleClose = ( ) => {
8677 setActiveStep ( STEPS . SELECT_USERS_AND_ROLE ) ;
8778 setUsers ( '' ) ;
@@ -126,43 +117,44 @@ const AssignRoleWizard = ({ onClose, scope, initialUsers = '' }: AssignRoleWizar
126117 } ) ;
127118 } , [ ] ) ;
128119
129- const handleSave = async ( ) => {
120+ // TODO: replace with real assignment API call
121+ const handleSave = ( ) => {
130122 if ( ! selectedRole || selectedScopes . size === 0 || validatedUsers . length === 0 ) { return ; }
131123
132- try {
133- await Promise . all (
134- Array . from ( selectedScopes ) . map ( ( selectedScope ) => assignRoleMutation . mutateAsync ( {
135- data : { users : validatedUsers , role : selectedRole , scope : selectedScope } ,
136- } ) ) ,
137- ) ;
138- showToast ( { message : intl . formatMessage ( messages [ 'wizard.save.success' ] ) , type : 'success' , delay : 5000 } ) ;
139- handleClose ( ) ;
140- } catch ( error : unknown ) {
141- showErrorToast ( error , handleSave ) ;
142- }
124+ // eslint-disable-next-line no-console
125+ console . log ( '[AssignRoleWizard] handleSave' , { users : validatedUsers , role : selectedRole , scopes : Array . from ( selectedScopes ) } ) ;
126+ handleClose ( ) ;
143127 } ;
144128
145- const canProceed = users . trim ( ) && selectedRole && ! validateUsersMutation . isPending ;
146- const canSave = selectedScopes . size > 0 && ! assignRoleMutation . isPending ;
129+ const isError = invalidUsers . length > 0 || ! ! validationError ;
130+
131+ useEffect ( ( ) => {
132+ if ( isError && usersInputRef . current ) {
133+ usersInputRef . current . scrollIntoView ( { behavior : 'smooth' , block : 'center' } ) ;
134+ }
135+ } , [ isError ] ) ;
136+
137+ const canProceed = ! ! users . trim ( ) && ! ! selectedRole ;
138+ const canSave = selectedScopes . size > 0 ;
147139
148140 return (
149141 < Stepper activeKey = { activeStep } >
150142 < Stepper . Header className = "bg-info-100" />
151143
152144 < Container className = "p-5" >
153145 < Stepper . Step
154- onClick = { ( ) => setActiveStep ( STEPS . SELECT_USERS_AND_ROLE ) }
155146 eventKey = { STEPS . SELECT_USERS_AND_ROLE }
156147 title = { intl . formatMessage ( messages [ 'wizard.step.selectUsersAndRole.title' ] ) }
157148 >
158149 < SelectUsersAndRoleStep
159150 users = { users }
160- setUsers = { setUsers }
151+ setUsers = { handleUsersChange }
161152 selectedRole = { selectedRole }
162153 setSelectedRole = { setSelectedRole }
163154 roles = { filteredRoles }
164155 validationError = { validationError }
165156 invalidUsers = { invalidUsers }
157+ inputRef = { usersInputRef }
166158 />
167159 </ Stepper . Step >
168160
@@ -191,6 +183,7 @@ const AssignRoleWizard = ({ onClose, scope, initialUsers = '' }: AssignRoleWizar
191183 pending : intl . formatMessage ( messages [ 'wizard.button.next.pending' ] ) ,
192184 } }
193185 icons = { { pending : < Icon src = { SpinnerSimple } /> } }
186+ variant = { isError ? 'danger' : 'primary' }
194187 state = { validateUsersMutation . isPending ? 'pending' : 'default' }
195188 onClick = { validateUsersAndProceed }
196189 disabled = { ! canProceed || validateUsersMutation . isPending }
@@ -211,7 +204,7 @@ const AssignRoleWizard = ({ onClose, scope, initialUsers = '' }: AssignRoleWizar
211204 pending : intl . formatMessage ( messages [ 'wizard.button.save.pending' ] ) ,
212205 } }
213206 icons = { { pending : < Icon src = { SpinnerSimple } /> } }
214- state = { assignRoleMutation . isPending ? 'pending' : ' default' }
207+ state = " default"
215208 onClick = { handleSave }
216209 disabled = { ! canSave }
217210 />
0 commit comments