2828import java .util .EnumSet ;
2929import java .util .HashMap ;
3030import java .util .HashSet ;
31+ import java .util .LinkedHashSet ;
3132import java .util .List ;
3233import java .util .Map ;
3334import java .util .Set ;
6667import de .symeda .sormas .api .exposure .ExposureProtectiveMeasure ;
6768import de .symeda .sormas .api .exposure .ExposureSetting ;
6869import de .symeda .sormas .api .exposure .ExposureSubSetting ;
70+ import de .symeda .sormas .api .exposure .ExposureType ;
6971import de .symeda .sormas .api .exposure .FomiteTransmissionLocation ;
7072import de .symeda .sormas .api .exposure .ProphylaxisAdherence ;
7173import de .symeda .sormas .api .exposure .TravelPurpose ;
@@ -103,9 +105,13 @@ public class ExposureForm extends AbstractEditForm<ExposureDto> {
103105 private static final String UUID_REPORTING_USER = fluidRowLocs (ExposureDto .UUID , ExposureDto .REPORTING_USER );
104106
105107 //@formatter:off
106- private static final String EXPOSURE_DETAILS_LAYOUT =
108+ private static final String GENERAL_DETAILS_LAYOUT =
107109 fluidRowLocs (ExposureDto .START_DATE , ExposureDto .END_DATE ) +
108- loc (LOC_CUSTOMIZABLE_FIELDS_EXPOSURE_DETAILS ) +
110+ fluidRowLocs (ExposureDto .EXPOSURE_TYPE , ExposureDto .EXPOSURE_TYPE_DETAILS ) +
111+ loc (ExposureDto .DESCRIPTION );
112+
113+ private static final String EXPOSURE_DETAILS_LAYOUT =
114+ loc (LOC_CUSTOMIZABLE_FIELDS_EXPOSURE_DETAILS ) +
109115 loc (LOC_EXPOSURES_HEADING ) +
110116 fluidRowLocs (ExposureDto .EXPOSURE_CATEGORY , ExposureDto .EXPOSURE_SETTING , ExposureDto .EXPOSURE_SETTING_DETAILS ) +
111117 fluidRow (
@@ -142,8 +148,7 @@ public class ExposureForm extends AbstractEditForm<ExposureDto> {
142148 ExposureDto .PROTECTIVE_MEASURE_DETAILS
143149 ))
144150 ) +
145- loc (LOC_CUSTOMIZABLE_FIELDS_EXPOSURES_GENERAL ) +
146- loc (ExposureDto .DESCRIPTION );
151+ loc (LOC_CUSTOMIZABLE_FIELDS_EXPOSURES_GENERAL );
147152
148153 private static final String LOCATION_DETAILS_LAYOUT =
149154 loc (LOC_LOCATION_HEADING ) +
@@ -164,6 +169,7 @@ public class ExposureForm extends AbstractEditForm<ExposureDto> {
164169 private final Class <? extends EntityDto > epiDataParentClass ;
165170 private final List <ContactReferenceDto > sourceContacts ;
166171
172+ private CustomLayout generalDetailsLayout ;
167173 private CustomLayout exposureDetailsLayout ;
168174 private CustomLayout locationDetailsLayout ;
169175
@@ -174,6 +180,8 @@ public class ExposureForm extends AbstractEditForm<ExposureDto> {
174180 private LocationEditForm locationForm ;
175181 private Disease disease ;
176182
183+ private ComboBox exposureTypeField ;
184+
177185 private ComboBox categoryField ;
178186 private ComboBox settingField ;
179187 private TextField settingDetailsField ;
@@ -230,6 +238,9 @@ protected void addFields() {
230238
231239 FormSectionAccordion accordion = new FormSectionAccordion ();
232240
241+ generalDetailsLayout = new CustomLayout ();
242+ generalDetailsLayout .setTemplateContents (GENERAL_DETAILS_LAYOUT );
243+
233244 exposureDetailsLayout = new CustomLayout ();
234245 exposureDetailsLayout .setTemplateContents (EXPOSURE_DETAILS_LAYOUT );
235246
@@ -254,8 +265,6 @@ protected void addFields() {
254265 exposuresGeneralPanel .updateFieldsDisplay ();
255266 exposureDetailsLayout .addComponent (exposuresGeneralPanel , LOC_CUSTOMIZABLE_FIELDS_EXPOSURES_GENERAL );
256267
257- addField (exposureDetailsLayout , ExposureDto .DESCRIPTION , TextArea .class ).setRows (5 );
258-
259268 locationForm = addField (locationDetailsLayout , ExposureDto .LOCATION , LocationEditForm .class );
260269 locationForm .setCaption (null );
261270 addField (locationDetailsLayout , ExposureDto .CONNECTION_NUMBER , TextField .class );
@@ -275,7 +284,8 @@ protected void addFields() {
275284 }
276285 });
277286
278- accordion .addFormSectionPanel (Captions .titleExposuresSection , true , exposureDetailsLayout );
287+ accordion .addFormSectionPanel (Captions .titleExposuresGeneralSection , true , generalDetailsLayout );
288+ accordion .addFormSectionPanel (Captions .titleExposuresSection , false , exposureDetailsLayout );
279289 accordion .addFormSectionPanel (Captions .titleExposureLocationSection , false , locationDetailsLayout );
280290
281291 getContent ().addComponent (accordion , MAIN_ACCORDION_LOC );
@@ -285,6 +295,8 @@ protected void addFields() {
285295 initializeVisibilitiesAndAllowedVisibilities ();
286296 initializeAccessAndAllowedAccesses ();
287297
298+ setUpRequirements ();
299+
288300 setReadOnly (true , ExposureDto .UUID , ExposureDto .REPORTING_USER );
289301 }
290302
@@ -303,14 +315,19 @@ private void addHeadingsAndInfoTexts() {
303315 private void addBasicFields () {
304316 addFields (ExposureDto .UUID , ExposureDto .REPORTING_USER , ExposureDto .PROBABLE_INFECTION_ENVIRONMENT );
305317
306- DateTimeField startDate = addField (exposureDetailsLayout , ExposureDto .START_DATE , DateTimeField .class );
307- DateTimeField endDate = addField (exposureDetailsLayout , ExposureDto .END_DATE , DateTimeField .class );
318+ DateTimeField startDate = addField (generalDetailsLayout , ExposureDto .START_DATE , DateTimeField .class );
319+ DateTimeField endDate = addField (generalDetailsLayout , ExposureDto .END_DATE , DateTimeField .class );
308320
309321 DateComparisonValidator .addStartEndValidators (startDate , endDate , false );
310322
323+ exposureTypeField = addField (generalDetailsLayout , ExposureDto .EXPOSURE_TYPE , ComboBox .class );
324+ exposureTypeField .setItemCaptionMode (ItemCaptionMode .ID_TOSTRING );
325+
326+ addField (generalDetailsLayout , ExposureDto .EXPOSURE_TYPE_DETAILS , TextField .class );
327+ addField (generalDetailsLayout , ExposureDto .DESCRIPTION , TextArea .class ).setRows (5 );
328+
311329 categoryField = addField (exposureDetailsLayout , ExposureDto .EXPOSURE_CATEGORY , ComboBox .class );
312330 categoryField .setItemCaptionMode (ItemCaptionMode .ID_TOSTRING );
313- categoryField .setRequired (true );
314331
315332 settingField = addField (exposureDetailsLayout , ExposureDto .EXPOSURE_SETTING , ComboBox .class );
316333 settingField .setItemCaptionMode (ItemCaptionMode .ID_TOSTRING );
@@ -500,6 +517,7 @@ private void addBasicFields() {
500517 }
501518
502519 private void setUpVisibilityDependencies () {
520+ FieldHelper .setVisibleWhen (getFieldGroup (), ExposureDto .EXPOSURE_TYPE_DETAILS , ExposureDto .EXPOSURE_TYPE , ExposureType .OTHER , true );
503521 FieldHelper .setVisibleWhen (getFieldGroup (), ExposureDto .TYPE_OF_PLACE_DETAILS , ExposureDto .TYPE_OF_PLACE , TypeOfPlace .OTHER , true );
504522 FieldHelper .setVisibleWhen (
505523 getFieldGroup (),
@@ -536,6 +554,15 @@ private void setUpVisibilityDependencies() {
536554 locationForm .setContinentFieldsVisibility ();
537555 }
538556
557+ private void setUpRequirements () {
558+ setRequired (true , ExposureDto .EXPOSURE_TYPE );
559+ FieldHelper .setRequiredWhen (
560+ getFieldGroup (),
561+ ExposureDto .EXPOSURE_TYPE ,
562+ Collections .singletonList (ExposureDto .EXPOSURE_TYPE_DETAILS ),
563+ Collections .singletonList (ExposureType .OTHER ));
564+ }
565+
539566 private void updateSettingFieldItems (ExposureCategory category ) {
540567 List <ExposureSetting > settings = ExposureSetting .getValues (category );
541568 FieldHelper .updateItems (settingField , settings );
@@ -550,14 +577,12 @@ private void updateSettingFieldItems(ExposureCategory category) {
550577 settingDetailsField .setValue (null );
551578 settingDetailsField .setVisible (false );
552579
553- if (category != null ) {
554- if (category .hasNoSetting ()) {
555- settingField .setVisible (false );
556- settingField .setRequired (false );
557- } else {
558- settingField .setVisible (true );
559- settingField .setRequired (true );
560- }
580+ if (category == null || category .hasNoSetting ()) {
581+ settingField .setVisible (false );
582+ settingField .setRequired (false );
583+ } else {
584+ settingField .setVisible (true );
585+ settingField .setRequired (true );
561586 }
562587 }
563588
@@ -647,6 +672,7 @@ private void updateFomiteTransmissionField(ExposureCategory category) {
647672 public void setValue (ExposureDto newFieldValue ) throws ReadOnlyException , Converter .ConversionException {
648673 super .setValue (newFieldValue );
649674
675+ populateExposureTypes (newFieldValue );
650676 populateExposureCategories (newFieldValue );
651677
652678 if (newFieldValue != null ) {
@@ -783,6 +809,29 @@ public void setValue(ExposureDto newFieldValue) throws ReadOnlyException, Conver
783809 locationForm .discard ();
784810 }
785811
812+ private void populateExposureTypes (ExposureDto exposure ) {
813+ // Get disease configuration
814+ DiseaseConfigurationDto diseaseConfig = null ;
815+ if (disease != null ) {
816+ diseaseConfig = FacadeProvider .getDiseaseConfigurationFacade ().getDiseaseConfiguration (disease );
817+ }
818+
819+ Set <ExposureCategory > diseaseCategories = diseaseConfig != null && diseaseConfig .getExposureCategories () != null
820+ ? new HashSet <>(diseaseConfig .getExposureCategories ())
821+ : Collections .emptySet ();
822+
823+ // defaults (+ types matching the disease's configured categories, if any)
824+ List <ExposureType > filteredTypes = ExposureType .getValues (diseaseCategories );
825+
826+ // Preserve existing record's value even if it is no longer in the filtered set (legacy data)
827+ Set <ExposureType > finalTypes = new LinkedHashSet <>(filteredTypes );
828+ if (exposure != null && exposure .getExposureType () != null ) {
829+ finalTypes .add (exposure .getExposureType ());
830+ }
831+
832+ FieldHelper .updateItems (exposureTypeField , new ArrayList <>(finalTypes ));
833+ }
834+
786835 private void populateExposureCategories (ExposureDto exposure ) {
787836 Set <ExposureCategory > categories ;
788837
0 commit comments