@@ -47,6 +47,67 @@ import SimpleModal from '@/components/SimpleModalV2';
4747import AddEditUser from '@/components/EntityForms/AddEditUser/AddEditUser' ;
4848import { fetchForm } from '@/components/DynamicForm/DynamicFormCallback' ;
4949
50+ const toUpperString = ( value : unknown ) =>
51+ typeof value === 'string' ? value . toUpperCase ( ) : '' ;
52+
53+ const asString = ( value : unknown ) : string | null => {
54+ if ( typeof value === 'string' ) return value ;
55+ if ( value && typeof value === 'object' && 'value' in ( value as any ) ) {
56+ const v = ( value as any ) . value ;
57+ return typeof v === 'string' ? v : null ;
58+ }
59+ return null ;
60+ } ;
61+
62+ const uniqStrings = ( values : Array < string | null | undefined > ) =>
63+ Array . from ( new Set ( values . filter ( ( v ) : v is string => ! ! v ) ) ) ;
64+
65+ const getCustomFieldEntry = ( customField : any [ ] | undefined , label : string ) => {
66+ const target = label . toUpperCase ( ) ;
67+ return ( customField || [ ] ) . find (
68+ ( item ) => toUpperString ( item ?. label ) === target
69+ ) ;
70+ } ;
71+
72+ const getCustomFieldValues = ( customField : any [ ] | undefined , label : string ) => {
73+ const entry = getCustomFieldEntry ( customField , label ) ;
74+ const selectedValues = Array . isArray ( entry ?. selectedValues )
75+ ? entry . selectedValues
76+ : [ ] ;
77+
78+ // Some APIs use `value` (string) instead of `selectedValues`.
79+ if ( selectedValues . length === 0 && entry ?. value ) {
80+ return uniqStrings ( [ asString ( entry . value ) ] ) ;
81+ }
82+
83+ return uniqStrings ( selectedValues . map ( ( v : any ) => asString ( v ) ?? v ) ) ;
84+ } ;
85+
86+ const getCustomFieldSingleValue = (
87+ customField : any [ ] | undefined ,
88+ label : string
89+ ) => {
90+ const values = getCustomFieldValues ( customField , label ) ;
91+ return values ?. [ 0 ] || null ;
92+ } ;
93+
94+ const findCohortById = ( items : any , cohortId : string ) : any | null => {
95+ if ( ! cohortId ) return null ;
96+ const stack : any [ ] = Array . isArray ( items ) ? [ ...items ] : [ ] ;
97+
98+ while ( stack . length ) {
99+ const node = stack . pop ( ) ;
100+ if ( ! node ) continue ;
101+
102+ if ( node ?. cohortId === cohortId ) return node ;
103+
104+ const children = Array . isArray ( node ?. childData ) ? node . childData : [ ] ;
105+ for ( const child of children ) stack . push ( child ) ;
106+ }
107+
108+ return null ;
109+ } ;
110+
50111const CentersPage = ( ) => {
51112 const { t } = useTranslation ( ) ;
52113 const theme = useTheme < any > ( ) ;
@@ -86,9 +147,12 @@ const CentersPage = () => {
86147 const [ centerList , setCenterList ] = useState < any [ ] > ( [ ] ) ;
87148 const userStore = manageUserStore ( ) ;
88149 const [ openBatchModal , setOpenBatchModal ] = useState ( false ) ;
150+ const [ baseBatchSchema , setBaseBatchSchema ] = useState < any > ( null ) ;
151+ const [ baseBatchUiSchema , setBaseBatchUiSchema ] = useState < any > ( null ) ;
89152 const [ addBatchSchema , setAddBatchSchema ] = useState < any > ( null ) ;
90153 const [ addBatchUiSchema , setAddBatchUiSchema ] = useState < any > ( null ) ;
91154 const [ emptyFormData , setEmptyFormData ] = useState < any > ( { } ) ;
155+ const [ batchPrefillFormData , setBatchPrefillFormData ] = useState < any > ( { } ) ;
92156 const [ tempVariable , setTempVariable ] = useState ( [ ] ) ;
93157
94158 const handleChange = ( event : React . SyntheticEvent , newValue : number ) => {
@@ -230,7 +294,9 @@ const CentersPage = () => {
230294 const userData = JSON . parse ( localStorage . getItem ( 'userData' ) || '{}' ) ;
231295 const location = getLocationFromCustomFields ( userData ) ;
232296 // console.log('location', location);
233- setEmptyFormData ( { ...location , name : '' } ) ;
297+ const base = { ...location , name : '' } ;
298+ setEmptyFormData ( base ) ;
299+ setBatchPrefillFormData ( base ) ;
234300 } , [ tempVariable ] ) ;
235301
236302 useEffect ( ( ) => {
@@ -417,6 +483,141 @@ const CentersPage = () => {
417483 }
418484 } ;
419485
486+ const cloneDeep = < T , > ( obj : T ) : T => JSON . parse ( JSON . stringify ( obj ) ) ;
487+
488+ const buildBatchCreateConfigForCenter = ( params : {
489+ baseSchema : any ;
490+ baseUiSchema : any ;
491+ parentId : string ;
492+ parentName ?: string | null ;
493+ centerType : string | null ;
494+ boards : string [ ] ;
495+ mediums : string [ ] ;
496+ grades : string [ ] ;
497+ } ) => {
498+ const schema = cloneDeep ( params . baseSchema ) ;
499+ const uiSchema = cloneDeep ( params . baseUiSchema ) ;
500+
501+ const parentSchema = schema ?. properties ?. parentId ;
502+ const parentIsArray =
503+ parentSchema ?. type === 'array' || typeof parentSchema ?. items === 'object' ;
504+ const prefill : any = {
505+ parentId : parentIsArray ? [ params . parentId ] : params . parentId ,
506+ } ;
507+
508+ // Ensure parentId validates against schema (enum/api often comes from remote lists).
509+ if ( schema ?. properties ?. parentId ) {
510+ const parentLabel = params . parentName || 'Center' ;
511+ if ( schema . properties . parentId ?. api ) delete schema . properties . parentId . api ;
512+ if ( schema . properties . parentId ?. items ?. api )
513+ delete schema . properties . parentId . items . api ;
514+
515+ if ( parentIsArray ) {
516+ schema . properties . parentId . items = {
517+ ...( schema . properties . parentId . items || { } ) ,
518+ type : 'string' ,
519+ enum : [ params . parentId ] ,
520+ enumNames : [ parentLabel ] ,
521+ } ;
522+ } else {
523+ schema . properties . parentId . enum = [ params . parentId ] ;
524+ schema . properties . parentId . enumNames = [ parentLabel ] ;
525+ schema . properties . parentId . default = params . parentId ;
526+ }
527+ }
528+
529+ // Hide parentId since it's derived from selected center dropdown.
530+ uiSchema . parentId = {
531+ ...( uiSchema ?. parentId || { } ) ,
532+ 'ui:widget' : 'hidden' ,
533+ } ;
534+
535+ const ensureEnabled = ( key : string ) => {
536+ if ( uiSchema ?. [ key ] ?. [ 'ui:disabled' ] ) {
537+ const next = { ...( uiSchema [ key ] || { } ) } ;
538+ delete next [ 'ui:disabled' ] ;
539+ uiSchema [ key ] = next ;
540+ }
541+ } ;
542+
543+ const overrideEnum = ( key : 'board' | 'medium' | 'grade' , allowed : any [ ] ) => {
544+ const allowedValues = Array . isArray ( allowed ) ? allowed . filter ( Boolean ) : [ ] ;
545+ if ( ! allowedValues . length ) {
546+ ensureEnabled ( key ) ;
547+ return ;
548+ }
549+
550+ if ( ! schema ?. properties ?. [ key ] ) return ;
551+
552+ // Remove dynamic api source and restrict to center-allowed values.
553+ if ( schema . properties [ key ] ?. api ) delete schema . properties [ key ] . api ;
554+ if ( schema . properties [ key ] ?. items ?. api ) delete schema . properties [ key ] . items . api ;
555+
556+ if ( schema . properties [ key ] ?. type === 'array' || schema . properties [ key ] ?. items ) {
557+ schema . properties [ key ] . items = {
558+ ...( schema . properties [ key ] . items || { } ) ,
559+ type : 'string' ,
560+ enum : allowedValues ,
561+ enumNames : allowedValues ,
562+ } ;
563+ } else {
564+ schema . properties [ key ] . enum = allowedValues ;
565+ schema . properties [ key ] . enumNames = allowedValues ;
566+ }
567+
568+ if ( allowedValues . length === 1 ) {
569+ prefill [ key ] =
570+ schema . properties [ key ] ?. type === 'array' || schema . properties [ key ] ?. items
571+ ? [ allowedValues [ 0 ] ]
572+ : allowedValues [ 0 ] ;
573+ uiSchema [ key ] = {
574+ ...( uiSchema ?. [ key ] || { } ) ,
575+ 'ui:disabled' : true ,
576+ } ;
577+ } else {
578+ ensureEnabled ( key ) ;
579+ }
580+ } ;
581+
582+ overrideEnum ( 'board' , params . boards ) ;
583+ overrideEnum ( 'medium' , params . mediums ) ;
584+ overrideEnum ( 'grade' , params . grades ) ;
585+
586+ // Batch type behavior (if supported by schema), similar to admin app.
587+ const ct = ( params . centerType || '' ) . toLowerCase ( ) ;
588+ if ( schema ?. properties ?. batch_type ) {
589+ if ( ct === 'remote' ) {
590+ schema . properties . batch_type . enum = [ 'remote' ] ;
591+ schema . properties . batch_type . enumNames = [ 'REMOTE' ] ;
592+ schema . properties . batch_type . default = 'remote' ;
593+ prefill . batch_type = 'remote' ;
594+ uiSchema . batch_type = {
595+ ...( uiSchema ?. batch_type || { } ) ,
596+ 'ui:disabled' : true ,
597+ } ;
598+ } else if ( ct === 'regular' ) {
599+ // Only restrict if enum exists; otherwise leave as-is.
600+ const existingEnum = Array . isArray ( schema . properties . batch_type . enum )
601+ ? schema . properties . batch_type . enum
602+ : null ;
603+ if ( existingEnum ) {
604+ const allowed = [ 'regular' , 'contact' ] . filter ( ( v ) =>
605+ existingEnum . includes ( v )
606+ ) ;
607+ if ( allowed . length ) {
608+ schema . properties . batch_type . enum = allowed ;
609+ schema . properties . batch_type . enumNames = allowed . map ( ( v ) =>
610+ v . toUpperCase ( )
611+ ) ;
612+ }
613+ }
614+ ensureEnabled ( 'batch_type' ) ;
615+ }
616+ }
617+
618+ return { schema, uiSchema, prefill } ;
619+ } ;
620+
420621 console . log ( 'filtered batches before render:' , filteredBatches ) ;
421622
422623 useEffect ( ( ) => {
@@ -436,7 +637,7 @@ const CentersPage = () => {
436637
437638 if ( responseForm ?. schema && responseForm ?. uiSchema ) {
438639 // Remove unnecessary fields for batch creation
439- let alterSchema = responseForm ?. schema ;
640+ let alterSchema = cloneDeep ( responseForm ?. schema ) ;
440641 let requiredArray = alterSchema ?. required ?? [ ] ;
441642 const mustRequired = [
442643 'name' ,
@@ -493,17 +694,66 @@ const CentersPage = () => {
493694
494695 return updatedData ;
495696 } ;
496- const fieldsToHide = [ 'state' , 'district' , 'block' ] ;
697+ const fieldsToHide = [ 'state' , 'district' , 'block' , 'village' ] ;
497698 const updatedData = hideFields ( responseForm ?. uiSchema , fieldsToHide ) ;
498- setAddBatchSchema ( alterSchema ) ;
499- setAddBatchUiSchema ( updatedData ) ;
699+ const normalizedUi = cloneDeep ( updatedData ) ;
700+ const normalizedSchema = cloneDeep ( alterSchema ) ;
701+ setBaseBatchSchema ( normalizedSchema ) ;
702+ setBaseBatchUiSchema ( normalizedUi ) ;
703+ setAddBatchSchema ( normalizedSchema ) ;
704+ setAddBatchUiSchema ( normalizedUi ) ;
500705 }
501706 } ;
502707
503708 fetchBatchFormSchema ( ) ;
504709 } , [ ] ) ;
505710
506711 const handleOpenAddBatchModal = ( ) => {
712+ if ( ! selectedCenter ) {
713+ showToastMessage ( t ( 'COMMON.PLEASE_SELECT_THE_CENTER' ) , 'error' ) ;
714+ return ;
715+ }
716+
717+ const effectiveBaseSchema = baseBatchSchema || addBatchSchema ;
718+ const effectiveBaseUiSchema = baseBatchUiSchema || addBatchUiSchema ;
719+ if ( ! effectiveBaseSchema || ! effectiveBaseUiSchema ) {
720+ showToastMessage ( t ( 'COMMON.LOADING' ) , 'info' ) ;
721+ return ;
722+ }
723+
724+ const selectedNode = findCohortById ( centerList , selectedCenter ) ;
725+ const cf = ( selectedNode ?. customField ||
726+ selectedNode ?. customFields ||
727+ [ ] ) as any [ ] ;
728+
729+ const boards = getCustomFieldValues ( cf , 'BOARD' ) ;
730+ const mediums = getCustomFieldValues ( cf , 'MEDIUM' ) ;
731+ const grades = getCustomFieldValues ( cf , 'GRADE' ) ;
732+ const selectedCenterType =
733+ getCustomFieldSingleValue ( cf , 'TYPE_OF_COHORT' ) ||
734+ getCustomFieldSingleValue ( cf , 'TYPE_OF_CENTER' ) ;
735+
736+ const { schema, uiSchema, prefill } = buildBatchCreateConfigForCenter ( {
737+ baseSchema : effectiveBaseSchema ,
738+ baseUiSchema : effectiveBaseUiSchema ,
739+ parentId : selectedCenter ,
740+ parentName :
741+ selectedNode ?. cohortName ||
742+ selectedNode ?. name ||
743+ selectedNode ?. cohortName ,
744+ centerType : selectedCenterType ,
745+ boards,
746+ mediums,
747+ grades,
748+ } ) ;
749+
750+ setAddBatchSchema ( schema ) ;
751+ setAddBatchUiSchema ( uiSchema ) ;
752+ setBatchPrefillFormData ( {
753+ ...( emptyFormData || { } ) ,
754+ ...( prefill || { } ) ,
755+ } ) ;
756+
507757 setOpenBatchModal ( true ) ;
508758 const telemetryInteract = {
509759 context : {
@@ -745,6 +995,7 @@ const CentersPage = () => {
745995 id = "dynamic-form-id"
746996 >
747997 < AddEditUser
998+ key = { `${ selectedCenter || 'no-center' } -batch-create` }
748999 SuccessCallback = { ( ) => {
7491000 if ( selectedCenter ) {
7501001 getBlocksByCenterId ( selectedCenter , centerList ) . then ( ( res ) => {
@@ -756,7 +1007,7 @@ const CentersPage = () => {
7561007 } }
7571008 schema = { addBatchSchema }
7581009 uiSchema = { addBatchUiSchema }
759- editPrefilledFormData = { emptyFormData }
1010+ editPrefilledFormData = { batchPrefillFormData }
7601011 isEdit = { false }
7611012 isReassign = { false }
7621013 editableUserId = { emptyUserId }
@@ -773,7 +1024,16 @@ const CentersPage = () => {
7731024 telemetryUpdateKey = "batch-updated-successfully"
7741025 failureUpdateMessage = "BATCH.BATCH_UPDATE_FAILED"
7751026 isNotificationRequired = { false }
1027+ notificationKey = ""
1028+ notificationMessage = ""
1029+ notificationContext = { { } }
1030+ blockFieldId = ""
1031+ districtFieldId = ""
1032+ villageFieldId = ""
1033+ centerFieldId = ""
7761034 hideSubmit = { true }
1035+ setButtonShow = { ( ) => { } }
1036+ isSteeper = { false }
7771037 type = "batch"
7781038 />
7791039 </ SimpleModal >
0 commit comments