1- import { useMemo } from 'react' ;
2-
1+ /* eslint-disable max-lines-per-function */
32import { Form } from '@douglasneuroinformatics/libui/components' ;
43import { useTranslation } from '@douglasneuroinformatics/libui/hooks' ;
4+ import { $RegexString } from '@opendatacapture/schemas/core' ;
55import type { UpdateGroupData } from '@opendatacapture/schemas/group' ;
6- import type { UnilingualInstrumentInfo } from '@opendatacapture/schemas/instrument' ;
7- import { $SubjectIdentificationMethod } from '@opendatacapture/schemas/subject' ;
6+ import { $SubjectIdentificationMethod , type SubjectIdentificationMethod } from '@opendatacapture/schemas/subject' ;
87import type { Promisable } from 'type-fest' ;
98import { z } from 'zod' ;
109
11- import { useSetupState } from '@/hooks/useSetupState' ;
12- import { useAppStore } from '@/store' ;
13-
14- type InstrumentOptions = {
10+ export type AvailableInstrumentOptions = {
1511 form : { [ key : string ] : string } ;
1612 interactive : { [ key : string ] : string } ;
1713 series : { [ key : string ] : string } ;
1814 unknown : { [ key : string ] : string } ;
1915} ;
2016
2117export type ManageGroupFormProps = {
22- availableInstruments : UnilingualInstrumentInfo [ ] ;
18+ availableInstrumentOptions : AvailableInstrumentOptions ;
19+ initialValues : {
20+ accessibleFormInstrumentIds : Set < string > ;
21+ accessibleInteractiveInstrumentIds : Set < string > ;
22+ defaultIdentificationMethod ?: SubjectIdentificationMethod ;
23+ idValidationRegex ?: null | string ;
24+ } ;
2325 onSubmit : ( data : Partial < UpdateGroupData > ) => Promisable < any > ;
26+ readOnly : boolean ;
2427} ;
2528
26- export const ManageGroupForm = ( { availableInstruments, onSubmit } : ManageGroupFormProps ) => {
27- const currentGroup = useAppStore ( ( store ) => store . currentGroup ) ;
28- const { resolvedLanguage } = useTranslation ( ) ;
29+ export const ManageGroupForm = ( {
30+ availableInstrumentOptions,
31+ initialValues,
32+ onSubmit,
33+ readOnly
34+ } : ManageGroupFormProps ) => {
2935 const { t } = useTranslation ( ) ;
30- const setupState = useSetupState ( ) ;
31-
32- const { initialValues, options } = useMemo ( ( ) => {
33- const options : InstrumentOptions = {
34- form : { } ,
35- interactive : { } ,
36- series : { } ,
37- unknown : { }
38- } ;
39- const initialValues = {
40- accessibleFormInstrumentIds : new Set < string > ( ) ,
41- accessibleInteractiveInstrumentIds : new Set < string > ( ) ,
42- defaultIdentificationMethod : currentGroup ?. settings . defaultIdentificationMethod
43- } ;
44- for ( const instrument of availableInstruments ) {
45- if ( instrument . kind === 'FORM' ) {
46- options . form [ instrument . id ] = instrument . details . title ;
47- if ( currentGroup ?. accessibleInstrumentIds . includes ( instrument . id ) ) {
48- initialValues . accessibleFormInstrumentIds . add ( instrument . id ) ;
49- }
50- } else if ( instrument . kind === 'INTERACTIVE' ) {
51- options . interactive [ instrument . id ] = instrument . details . title ;
52- if ( currentGroup ?. accessibleInstrumentIds . includes ( instrument . id ) ) {
53- initialValues . accessibleInteractiveInstrumentIds . add ( instrument . id ) ;
54- }
55- }
56- }
57- return { initialValues, options } ;
58- } , [ availableInstruments , currentGroup , resolvedLanguage ] ) ;
59-
60- const isDisabled = Boolean ( setupState . data ?. isDemo && import . meta. env . PROD ) ;
6136
6237 let description = t ( 'group.manage.accessibleInstrumentsDesc' ) ;
63- if ( isDisabled ) {
38+ if ( readOnly ) {
6439 description += ` ${ t ( 'group.manage.accessibleInstrumentDemoNote' ) } ` ;
6540 }
6641
@@ -74,13 +49,13 @@ export const ManageGroupForm = ({ availableInstruments, onSubmit }: ManageGroupF
7449 accessibleFormInstrumentIds : {
7550 kind : 'set' ,
7651 label : t ( 'group.manage.forms' ) ,
77- options : options . form ,
52+ options : availableInstrumentOptions . form ,
7853 variant : 'listbox'
7954 } ,
8055 accessibleInteractiveInstrumentIds : {
8156 kind : 'set' ,
8257 label : t ( 'group.manage.interactive' ) ,
83- options : options . interactive ,
58+ options : availableInstrumentOptions . interactive ,
8459 variant : 'listbox'
8560 }
8661 } ,
@@ -96,27 +71,81 @@ export const ManageGroupForm = ({ availableInstruments, onSubmit }: ManageGroupF
9671 PERSONAL_INFO : t ( 'common.personalInfo' )
9772 } ,
9873 variant : 'select'
74+ } ,
75+ idValidationRegex : {
76+ description : t ( {
77+ en : 'Define a custom regular expression to validate subject IDs (see https://regexr.com for help designing your regular expression).' ,
78+ fr : "Définir une expression régulière pour valider les identifiants des sujets (voir https://regexr.com pour obtenir de l'aide dans la conception de votre expression régulière)."
79+ } ) ,
80+ kind : 'string' ,
81+ label : t ( {
82+ en : 'ID Validation Pattern' ,
83+ fr : 'TBD'
84+ } ) ,
85+ variant : 'input'
86+ } ,
87+ idValidationRegexErrorMessageEn : {
88+ deps : [ 'idValidationRegex' ] ,
89+ kind : 'dynamic' ,
90+ render : ( data ) => {
91+ if ( ! data . idValidationRegex ) {
92+ return null ;
93+ }
94+ return {
95+ kind : 'string' ,
96+ label : t ( {
97+ en : 'Custom ID Validation Message (English)' ,
98+ fr : 'Message de validation spécifique (en anglais)'
99+ } ) ,
100+ variant : 'input'
101+ } ;
102+ }
103+ } ,
104+ idValidationRegexErrorMessageFr : {
105+ deps : [ 'idValidationRegex' ] ,
106+ kind : 'dynamic' ,
107+ render : ( data ) => {
108+ if ( ! data . idValidationRegex ) {
109+ return null ;
110+ }
111+ return {
112+ kind : 'string' ,
113+ label : t ( {
114+ en : 'Custom ID Validation Message (French)' ,
115+ fr : 'Message de validation spécifique (en français)'
116+ } ) ,
117+ variant : 'input'
118+ } ;
119+ }
99120 }
100121 } ,
101122 title : t ( 'group.manage.groupSettings' )
102123 }
103124 ] }
104125 initialValues = { initialValues }
105126 preventResetValuesOnReset = { true }
106- readOnly = { isDisabled }
127+ readOnly = { readOnly }
107128 validationSchema = { z . object ( {
108129 accessibleFormInstrumentIds : z . set ( z . string ( ) ) ,
109130 accessibleInteractiveInstrumentIds : z . set ( z . string ( ) ) ,
110- defaultIdentificationMethod : $SubjectIdentificationMethod . optional ( )
131+ defaultIdentificationMethod : $SubjectIdentificationMethod . optional ( ) ,
132+ idValidationRegex : $RegexString . optional ( ) ,
133+ idValidationRegexErrorMessageEn : z . string ( ) . optional ( ) ,
134+ idValidationRegexErrorMessageFr : z . string ( ) . optional ( )
111135 } ) }
112- onSubmit = { ( data ) =>
136+ onSubmit = { ( data ) => {
113137 void onSubmit ( {
114138 accessibleInstrumentIds : [ ...data . accessibleFormInstrumentIds , ...data . accessibleInteractiveInstrumentIds ] ,
115139 settings : {
116- defaultIdentificationMethod : data . defaultIdentificationMethod
140+ defaultIdentificationMethod : data . defaultIdentificationMethod ,
141+ idValidationRegex : data . idValidationRegex ,
142+ idValidationRegexErrorMessage : {
143+ en : data . idValidationRegexErrorMessageEn ,
144+ fr : data . idValidationRegexErrorMessageFr
145+ }
117146 }
118- } )
119- }
147+ } ) ;
148+ } }
120149 />
121150 ) ;
122151} ;
0 commit comments