1- import React , { useState } from 'react'
1+ import React , { useState , Dispatch , SetStateAction } from 'react'
22import { Link , useParams , useNavigate } from "react-router-dom"
33import { Form , Dropdown } from "react-bootstrap"
4- import MultiSelect from "react-bootstrap-multiselect"
5- import 'react-bootstrap-multiselect/css/bootstrap-multiselect.css'
4+ import Select , { MultiValue } from "react-select"
65
7- import { useEngine , useGetDegree , useIndexExam , usePostDegree , usePatchDegree } from '../modules/engine'
6+ import { useEngine , useGetDegree , useIndexExam , usePostDegree , usePatchDegree , ExamGet } from '../modules/engine'
87import Card from '../components/Card'
98import Group from '../components/Group'
109import LoadingMessage from '../components/LoadingMessage'
@@ -163,74 +162,39 @@ export function EditDegreePage() {
163162 const query = useGetDegree ( id || '' )
164163 const updater = usePatchDegree ( id || '' )
165164 const poster = usePostDegree ( )
166- const exams = useIndexExam ( )
165+ const exams_query = useIndexExam ( )
167166 const mutate = isNew ? poster . mutate : updater . mutate
168167 const degree = query . data
169168 const isEdit = degree ?. _id !== undefined
170169
171- if ( query . isLoading || exams . isLoading ) return < LoadingMessage > caricamento...</ LoadingMessage >
170+ if ( query . isLoading || exams_query . isLoading ) return < LoadingMessage > caricamento...</ LoadingMessage >
172171 if ( query . isError ) return < div > Errore: { query . error . message } </ div >
173- if ( exams . isError ) return < div > Errore: { `${ exams } ` } </ div >
172+ if ( exams_query . isError || ! exams_query . data ) return < div > Errore: { `${ exams_query } ` } </ div >
173+
174+ const exams = exams_query . data . items
174175
175176 return < >
176177 < h1 > { isEdit ? "Modifica" : "Nuovo" } corso di Laurea</ h1 >
177178 < DegreeForm mutate = { mutate } degree = { degree } exams = { exams } />
178179 </ >
179180}
180181
181- function DegreeForm ( { mutate, degree, exams } ) {
182- const options = [
183- { label : 'Mela' , value : 'mela' } ,
184- { label : 'Banana' , value : 'banana' } ,
185- { label : 'Arancia' , value : 'arancia' }
186- ] ;
187-
188- const handleChange = ( selectedOptions ) => {
189- console . log ( 'Selezionato:' , selectedOptions ) ;
190- } ;
191-
192- return (
193- < div className = "container mt-5" >
194- < h3 > Frutta preferita</ h3 >
195- < MultiSelect
196- multiple
197- onChange = { handleChange }
198- enableFiltering
199- includeSelectAllOption
200- buttonClass = "btn btn-primary"
201- >
202- { options . map ( option =>
203- < option key = { option . value } value = { option . value } > { option . label } </ option > ) }
204- </ MultiSelect >
205- </ div >
206- ) ;
207- }
182+ type ExamGroup = {
183+ name : string ,
184+ exam_ids : string [ ]
185+ }
208186
209- function DegreeForm_ ( { mutate, degree, exams} ) {
187+ function DegreeForm ( { mutate, degree, exams} ) {
210188 const [ data , setData ] = useState ( degree )
189+ const [ groups , setGroups ] = useState < ExamGroup [ ] > ( Object . entries ( degree . groups as Record < string , string [ ] > )
190+ . map ( ( [ name , exam_ids ] ) => ( { name, exam_ids} ) )
191+ . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
192+ )
211193 const [ validation , setValidation ] = useState < any > ( { } )
212194 const engine = useEngine ( )
213195 const navigate = useNavigate ( )
214196 const current_year = new Date ( ) . getFullYear ( )
215-
216- const [ selectedOptions , setSelectedOptions ] = useState ( [ ] ) ;
217- const options = [
218- { value : 'One' , selected : true } ,
219- { value : 'Two' } ,
220- { value : 'Three' }
221- ] ;
222-
223- const handleChange = ( selected ) => {
224- setSelectedOptions ( selected ) ;
225- } ;
226- return (
227- < MultiSelect
228- onChange = { handleChange }
229- data = { options }
230- multiple
231- />
232- ) ;
233-
197+
234198 return < Card >
235199 < Group
236200 validationError = { validation . name }
@@ -276,37 +240,23 @@ function DegreeForm_({mutate,degree,exams}) {
276240 < option value = "admin" > amministratori</ option >
277241 </ Form . Select >
278242 </ Group >
243+
279244 < h4 > gruppi di esami</ h4 >
280245
281- < Dropdown >
282- < Dropdown . Toggle variant = "success" id = "dropdown-basic" >
283- Select Options
284- </ Dropdown . Toggle >
285- < Dropdown . Menu >
286- { [ "A" , "B" , "C" ] . map ( ( option , index ) => (
287- < Dropdown . Item
288- key = { index }
289- onClick = { ( ) => { } }
290- active = { [ "B" ] . includes ( option ) }
291- >
292- { option }
293- </ Dropdown . Item >
294- ) ) }
295- </ Dropdown . Menu >
296- </ Dropdown >
246+ < EditGroups groups = { groups } setGroups = { setGroups } exams = { exams } />
297247
298248 < Group
299249 validationError = { validation . default_group }
300250 controlId = "default_group"
301251 label = "gruppo esami a scelta libera" >
302252 { } < Form . Select value = { data . default_group } onChange = { onChange ( "default_group" ) } >
303253 < option value = "" > tutti gli esami</ option >
304- { Object . keys ( data . groups ) . map ( name =>
305- < option value = { name } > { name } </ option >
254+ { groups . map ( group =>
255+ < option key = { group . name } value = { group . name } > { group . name } </ option >
306256 ) }
307257 </ Form . Select >
308258 </ Group >
309-
259+
310260 < h4 > notifiche email</ h4 >
311261 < Group
312262 validationError = { validation . submission_confirmation }
@@ -387,3 +337,72 @@ function DegreeForm_({mutate,degree,exams}) {
387337 return e => setData ( data => ( { ...data , [ field ] : e . target . checked } ) )
388338 }
389339}
340+
341+ function EditGroups ( { groups, setGroups, exams} :{
342+ groups : ExamGroup [ ] ,
343+ setGroups : Dispatch < ExamGroup [ ] > ,
344+ exams : ExamGet [ ]
345+ } ) {
346+ const examDict = Object . fromEntries ( exams . map ( exam => [ exam . _id , exam ] ) )
347+ return < >
348+ { groups . map ( ( group , i ) =>
349+ < EditGroup
350+ key = { i }
351+ name = { group . name }
352+ setName = { name => setGroups ( groups . map ( g => ( g . name === group . name
353+ ? { name, exam_ids : g . exam_ids }
354+ : g ) ) ) }
355+ group = { group . exam_ids }
356+ setGroup = { ids => setGroups ( groups . map ( g => ( g . name === group . name
357+ ? { name : g . name , exam_ids : ids }
358+ : g ) ) ) }
359+ examDict = { examDict }
360+ /> ) }
361+ </ >
362+ }
363+
364+ type Option = {
365+ value : string ;
366+ label : string ;
367+ } ;
368+
369+ function EditGroup ( { name, setName, group, setGroup, examDict} :{
370+ name : string ,
371+ setName : Dispatch < string > ,
372+ group : string [ ] ,
373+ setGroup : Dispatch < string [ ] >
374+ examDict : Record < string , { _id : string , name : string , code : string } >
375+ } ) {
376+ const sort_fun = ( a , b ) => a . label . localeCompare ( b . label )
377+ const options : Option [ ] = Object . values ( examDict ) . map ( option_from_exam ) . sort ( sort_fun )
378+ const selected : Option [ ] = group . map ( option_from_exam_id ) . sort ( sort_fun )
379+
380+ // TODO: l'ordinamento non funziona
381+ // sembra che la select ordini sempre in base al codice
382+
383+ return < Group controlId = { `group-${ name } ` } label = "gruppo" >
384+ { } < input value = { name } onChange = { e => setName ( e . target . value ) } />
385+ < Select isMulti isSearchable
386+ options = { options }
387+ value = { selected }
388+ onChange = { onChange }
389+ />
390+ </ Group >
391+
392+ function option_from_exam ( exam ) {
393+ return {
394+ value : exam ?. _id ,
395+ label : `${ exam . code } ${ exam . name } `
396+ }
397+ }
398+
399+ function option_from_exam_id ( exam_id ) {
400+ const exam = examDict [ exam_id ]
401+ if ( ! exam ) return { value : exam_id , label : exam_id }
402+ return option_from_exam ( exam )
403+ }
404+
405+ function onChange ( new_options : readonly Option [ ] ) {
406+ setGroup ( new_options . map ( option => option . value ) )
407+ }
408+ }
0 commit comments