diff --git a/api-rework/client/src/activities/activities.scss b/api-rework/client/src/activities/activities.scss index 684eba2ff..dc5c466e8 100644 --- a/api-rework/client/src/activities/activities.scss +++ b/api-rework/client/src/activities/activities.scss @@ -10,7 +10,7 @@ table.activities { } tr:hover { - background-color: #BBDCFF; + background-color: #bbdcff; } } @@ -39,7 +39,6 @@ div.activities-detail { padding: 1em 0; gap: 1.5em; - li { display: inline-block; border: blueviolet; @@ -60,5 +59,5 @@ div.activities-detail { } .warning { - color: red; + color: #b2102f; } diff --git a/api-rework/client/src/activities/form-viewer/FormViewer.tsx b/api-rework/client/src/activities/form-viewer/FormViewer.tsx index 2945152a5..1e1648699 100644 --- a/api-rework/client/src/activities/form-viewer/FormViewer.tsx +++ b/api-rework/client/src/activities/form-viewer/FormViewer.tsx @@ -5,70 +5,93 @@ import './formViewer.css'; import Spacer from 'common-components/inputs/Spacer'; import TerrestrialObservation from 'activities/subtypes/TerrestrialObservation'; import AquaticObservation from 'activities/subtypes/AquaticObservation'; +import ChemicalMonitoring from 'activities/subtypes/ChemicalMonitoring'; +import MechanicalMonitoring from 'activities/subtypes/MechanicalMonitoring'; +import ReleaseMonitoring from 'activities/subtypes/ReleaseMonitoring'; +import AquaticMechTreatment from 'activities/subtypes/AquaticMechTreatment'; +import TerrestrialMechTreatment from 'activities/subtypes/TerrestrialMechTreatment'; +import TerrestrialChemTreatment from 'activities/subtypes/TerrestrialChemTreatment'; +import AquaticChemTreatment from 'activities/subtypes/AquaticChemTreatment'; -const FormViewer = ({ formData }) => { - return ( -
-
-
- - - - - - - - - - - - - - - -
-
- {formData?.projects.map(({ description }) => ( - - ))} -
-
- {formData?.employer.map(({ employer }) => ( - - ))} -
-
- {formData?.funding_agencies.map(({ invasive_species_agency_code }) => ( - - ))} -
-
- {formData?.jurisdictions.map(({ jurisdiction, percent_covered }) => ( -
- - -
- ))} -
-
- {formData?.participants.map(({ name, pac_number }) => ( -
- {pac_number && } - -
- ))} -
+const FormViewer = ({ formData }) => ( +
+
+
+ + + + + - -

Subtype Specific Details

+ + + + + + + + + +
+
+ {formData?.projects.map(({ description }) => ( + + ))} +
+
+ {formData?.employer.map(({ employer }) => ( + + ))} +
+
+ {formData?.funding_agencies.map(({ invasive_species_agency_code }) => ( + + ))} +
+
+ {formData?.jurisdictions.map(({ jurisdiction, percent_covered }) => ( +
+ + +
+ ))} +
+
+ {formData?.participants.map(({ name, pac_number }) => ( +
+ {pac_number && } + +
+ ))} +
+
+ {formData?.linked_activities?.map(({ full, short_id }) => ( +
+ + +
+ ))} +
+ + +

Subtype Specific Details

+ { { - { - Observation_Plant_Terrestrial: , - Observation_Plant_Aquatic: - }[formData?.subtype] - } -
+ Observation_Plant_Terrestrial: , + Observation_Plant_Aquatic: , + Monitoring_Chemical_Plant_Terrestrial_Aquatic: , + Monitoring_Mechanical_Plant_Terrestrial_Aquatic: ( + + ), + Monitoring_Biocontrol_Release_Plant_Terrestrial: , + Treatment_Mechanical_Plant_Terrestrial: , + Treatment_Mechanical_Plant_Aquatic: , + Treatment_Chemical_Plant_Terrestrial: , + Treatment_Chemical_Plant_Aquatic: + }[formData?.subtype] + }
- ); -}; +
+); + export default FormViewer; diff --git a/api-rework/client/src/activities/form-viewer/formViewer.css b/api-rework/client/src/activities/form-viewer/formViewer.css index 66fe20b49..db63a8d6b 100644 --- a/api-rework/client/src/activities/form-viewer/formViewer.css +++ b/api-rework/client/src/activities/form-viewer/formViewer.css @@ -9,7 +9,7 @@ } .contained label { - font-family: 'Comic Sans MS', Arial, sans-serif; + font-family: Calibri, Arial, sans-serif; padding-right: 1rem; text-transform: capitalize; @@ -18,6 +18,16 @@ } } +h2 { + font-family: Calibri, Arial, sans-serif; + text-align: start; + width: 100%; +} + +fieldset input { + width: 95%; +} + .content { display: flex; width: 100%; @@ -32,7 +42,7 @@ align-items: flex-start; flex-flow: row wrap; max-width: 850px; - background-color: #66996650; + background-color: #f2f7f3; } .group-wrap { @@ -57,7 +67,7 @@ .chit { box-sizing: border-box; border-radius: 6pt; - background-color: lightgreen; + background-color: #66996675; border: 1pt solid black; margin-right: 5px; font-size: 12px; @@ -70,13 +80,17 @@ } fieldset { - font-family: 'Comic Sans MS', Arial, sans-serif; + font-family: Calibri, Arial, sans-serif; display: flex; flex-flow: row wrap; text-wrap: wrap; word-break: break-all; width: 100%; justify-content: space-between; + background-color: #e4eee7; + margin-bottom: 1rem; + margin-top: 0.5rem; + font-weight: bold; legend { text-transform: capitalize; @@ -87,3 +101,7 @@ fieldset { overflow: hidden; } } + +fieldset fieldset .group-wrap { + background-color: #9fb6a8; +} diff --git a/api-rework/client/src/activities/subtypes/AquaticChemTreatment.tsx b/api-rework/client/src/activities/subtypes/AquaticChemTreatment.tsx new file mode 100644 index 000000000..5b2d89382 --- /dev/null +++ b/api-rework/client/src/activities/subtypes/AquaticChemTreatment.tsx @@ -0,0 +1,16 @@ +import TextInput from 'common-components/inputs/TextInput'; +import { SubtypeData } from 'constants'; +import Fieldset from 'common-components/inputs/Fieldset'; +import ChemTreatmentInfo from './common/ChemTreatmentInfo'; + +const AquaticChemTreatment = ({ subtypeData }: SubtypeData) => { + return ( + <> + +
+ +
+ + ); +}; +export default AquaticChemTreatment; diff --git a/api-rework/client/src/activities/subtypes/AquaticMechTreatment.tsx b/api-rework/client/src/activities/subtypes/AquaticMechTreatment.tsx new file mode 100644 index 000000000..297aec29a --- /dev/null +++ b/api-rework/client/src/activities/subtypes/AquaticMechTreatment.tsx @@ -0,0 +1,25 @@ +import Fieldset from 'common-components/inputs/Fieldset'; +import { SubtypeData } from 'constants'; +import MechTreatmentInfo from './common/MechTreatmentInfo'; +import TextInput from 'common-components/inputs/TextInput'; +import Spacer from 'common-components/inputs/Spacer'; + +const AquaticMechTreatment = ({ subtypeData }: SubtypeData) => ( + <> +
+ +
+ +
+ {subtypeData?.shoreline_types?.map((st) => ( +
+ + +
+ ))} +
+ + +); + +export default AquaticMechTreatment; diff --git a/api-rework/client/src/activities/subtypes/ChemicalMonitoring.tsx b/api-rework/client/src/activities/subtypes/ChemicalMonitoring.tsx new file mode 100644 index 000000000..d6467200f --- /dev/null +++ b/api-rework/client/src/activities/subtypes/ChemicalMonitoring.tsx @@ -0,0 +1,20 @@ +import Fieldset from 'common-components/inputs/Fieldset'; +import { SubtypeData } from 'constants'; +import MonitoringInfo from './common/MonitoringInfo'; +import NearestWells from './common/NearestWells'; + +const ChemicalMonitoring = ({ subtypeData }: SubtypeData) => { + console.log(subtypeData); + return ( + <> + +
+ {subtypeData?.treatment_monitoring_information?.map((d) => ( + + ))} +
+ + ); +}; + +export default ChemicalMonitoring; diff --git a/api-rework/client/src/activities/subtypes/MechanicalMonitoring.tsx b/api-rework/client/src/activities/subtypes/MechanicalMonitoring.tsx new file mode 100644 index 000000000..48b1234a6 --- /dev/null +++ b/api-rework/client/src/activities/subtypes/MechanicalMonitoring.tsx @@ -0,0 +1,13 @@ +import Fieldset from 'common-components/inputs/Fieldset'; +import { SubtypeData } from 'constants'; +import MonitoringInfo from './common/MonitoringInfo'; + +const MechanicalMonitoring = ({ subtypeData }: SubtypeData) => ( +
+ {subtypeData?.treatment_monitoring_information?.map((d) => ( + + ))} +
+); + +export default MechanicalMonitoring; diff --git a/api-rework/client/src/activities/subtypes/ReleaseMonitoring.tsx b/api-rework/client/src/activities/subtypes/ReleaseMonitoring.tsx new file mode 100644 index 000000000..a070cfaaa --- /dev/null +++ b/api-rework/client/src/activities/subtypes/ReleaseMonitoring.tsx @@ -0,0 +1,28 @@ +import Fieldset from 'common-components/inputs/Fieldset'; +import TextInput from 'common-components/inputs/TextInput'; +import { SubtypeData } from 'constants'; +import BiocontrolMonitoring from './common/BiocontrolMonitoring'; +import TargetPlantPhenology from './common/TargetPlantPhenology'; + +const ReleaseMonitoring = ({ subtypeData }: SubtypeData) => ( + <> +
+ + +
+ + +
+ + + + + +
+ +); + +export default ReleaseMonitoring; diff --git a/api-rework/client/src/activities/subtypes/TerrestrialChemTreatment.tsx b/api-rework/client/src/activities/subtypes/TerrestrialChemTreatment.tsx new file mode 100644 index 000000000..8f5e31987 --- /dev/null +++ b/api-rework/client/src/activities/subtypes/TerrestrialChemTreatment.tsx @@ -0,0 +1,16 @@ +import TextInput from 'common-components/inputs/TextInput'; +import { SubtypeData } from 'constants'; +import Fieldset from 'common-components/inputs/Fieldset'; +import ChemTreatmentInfo from './common/ChemTreatmentInfo'; + +const TerrestrialChemTreatment = ({ subtypeData }: SubtypeData) => { + return ( + <> + +
+ +
+ + ); +}; +export default TerrestrialChemTreatment; diff --git a/api-rework/client/src/activities/subtypes/TerrestrialMechTreatment.tsx b/api-rework/client/src/activities/subtypes/TerrestrialMechTreatment.tsx new file mode 100644 index 000000000..b0bc9e782 --- /dev/null +++ b/api-rework/client/src/activities/subtypes/TerrestrialMechTreatment.tsx @@ -0,0 +1,7 @@ +import { SubtypeData } from 'constants'; +import MechTreatmentInfo from './common/MechTreatmentInfo'; + +const TerrestrialMechTreatment = ({ subtypeData }: SubtypeData) => ( + +); +export default TerrestrialMechTreatment; diff --git a/api-rework/client/src/activities/subtypes/common/BiocontrolMonitoring.tsx b/api-rework/client/src/activities/subtypes/common/BiocontrolMonitoring.tsx new file mode 100644 index 000000000..db4fa86c6 --- /dev/null +++ b/api-rework/client/src/activities/subtypes/common/BiocontrolMonitoring.tsx @@ -0,0 +1,52 @@ +import ChitList from 'common-components/inputs/ChitList'; +import Fieldset from 'common-components/inputs/Fieldset'; +import Spacer from 'common-components/inputs/Spacer'; +import TextInput from 'common-components/inputs/TextInput'; + +const BiocontrolMonitoring = ({ monitoring_information }) => ( +
+ {monitoring_information.map((mi) => ( +
+ + + + + + +
+ +
+
+ +
+ + + + + +
+ {mi.actual_biological_agents?.map((ba) => ( +
+ + + + +
+ ))} +
+
+ {mi.estimated_biological_agents?.map((ba) => ( +
+ + + + +
+ ))} +
+
+ ))} +
+); + +export default BiocontrolMonitoring; diff --git a/api-rework/client/src/activities/subtypes/common/ChemTreatmentInfo.tsx b/api-rework/client/src/activities/subtypes/common/ChemTreatmentInfo.tsx new file mode 100644 index 000000000..237e0dbce --- /dev/null +++ b/api-rework/client/src/activities/subtypes/common/ChemTreatmentInfo.tsx @@ -0,0 +1,36 @@ +import { SubtypeData } from 'constants'; +import NearestWells from './NearestWells'; +import TextInput from 'common-components/inputs/TextInput'; +import Fieldset from 'common-components/inputs/Fieldset'; + +const ChemTreatmentInfo = ({ subtypeData }: SubtypeData) => { + return ( + <> + +
+ + + + + + + + + + + + + + +
+
+ +
+ + ); +}; + +export default ChemTreatmentInfo; diff --git a/api-rework/client/src/activities/subtypes/common/MechTreatmentInfo.tsx b/api-rework/client/src/activities/subtypes/common/MechTreatmentInfo.tsx new file mode 100644 index 000000000..36269815c --- /dev/null +++ b/api-rework/client/src/activities/subtypes/common/MechTreatmentInfo.tsx @@ -0,0 +1,19 @@ +import Fieldset from 'common-components/inputs/Fieldset'; +import TextInput from 'common-components/inputs/TextInput'; + +const MechTreatmentInfo = ({ treatmentInfo }) => ( +
+ {treatmentInfo?.map((ti) => ( +
+ + + + + + +
+ ))} +
+); + +export default MechTreatmentInfo; diff --git a/api-rework/client/src/activities/subtypes/common/MonitoringInfo.tsx b/api-rework/client/src/activities/subtypes/common/MonitoringInfo.tsx new file mode 100644 index 000000000..8e9bf3229 --- /dev/null +++ b/api-rework/client/src/activities/subtypes/common/MonitoringInfo.tsx @@ -0,0 +1,37 @@ +import ChitList from 'common-components/inputs/ChitList'; +import Fieldset from 'common-components/inputs/Fieldset'; +import TextInput from 'common-components/inputs/TextInput'; + +type MonitoringInfo = { + comment: string; + evidence_of_treatment: string; + invasive_plant_aquatic?: string; + invasive_plant?: string; + invasive_plants_on_site: Array; + management_efficacy_rating: string; + treatment_efficacy_rating: string; + treatment_pass: string; +}; + +type PropTypes = { + data: MonitoringInfo; +}; + +const MonitoringInfo = ({ data }: PropTypes) => { + return ( +
+ + + + + +
+ +
+ + +
+ ); +}; + +export default MonitoringInfo; diff --git a/api-rework/client/src/activities/subtypes/common/NearestWells.tsx b/api-rework/client/src/activities/subtypes/common/NearestWells.tsx new file mode 100644 index 000000000..251023404 --- /dev/null +++ b/api-rework/client/src/activities/subtypes/common/NearestWells.tsx @@ -0,0 +1,24 @@ +import Fieldset from 'common-components/inputs/Fieldset'; +import TextInput from 'common-components/inputs/TextInput'; + +interface WellInfo { + well_tag_number: number; + distance: number; +} +type PropTypes = { + data: Array; +}; +const NearestWells = ({ data }: PropTypes) => { + return ( +
+ {!data || (data?.length === 0 && )} + {data?.map((w) => ( +
+ + +
+ ))} +
+ ); +}; +export default NearestWells; diff --git a/api-rework/client/src/activities/subtypes/common/TargetPlantPhenology.tsx b/api-rework/client/src/activities/subtypes/common/TargetPlantPhenology.tsx new file mode 100644 index 000000000..47d265556 --- /dev/null +++ b/api-rework/client/src/activities/subtypes/common/TargetPlantPhenology.tsx @@ -0,0 +1,21 @@ +import Fieldset from 'common-components/inputs/Fieldset'; +import TextInput from 'common-components/inputs/TextInput'; + +const TargetPlantPhenology = ({ targetPlantPhenology }) => ( +
+ + + + + + + +
+ {targetPlantPhenology.target_plant_heights.map((h) => ( + + ))} +
+
+); + +export default TargetPlantPhenology; diff --git a/api-rework/client/src/common-components/inputs/ChitList.tsx b/api-rework/client/src/common-components/inputs/ChitList.tsx index 4f29c0739..ba27bcaae 100644 --- a/api-rework/client/src/common-components/inputs/ChitList.tsx +++ b/api-rework/client/src/common-components/inputs/ChitList.tsx @@ -1,7 +1,6 @@ -interface KeyValue { - code: string; - full: string | number; -} +import { KeyValue } from 'constants'; +import { stringify } from 'utils'; + type PropTypes = { items: Array | Array; }; @@ -9,13 +8,13 @@ type PropTypes = { * Mock MultiSelect Chit input */ const ChitList = ({ items }: PropTypes) => { - const isStr = typeof items?.[0] === 'string'; - + const isEmpty = !items || items.length === 0; return ( -
+
+ {items?.length === 0 && 'NO DATA'} {items?.map((i) => ( - {isStr ? i : `${i.full} (${i.code})`} + {stringify(i)} ))}
diff --git a/api-rework/client/src/common-components/inputs/TextInput.tsx b/api-rework/client/src/common-components/inputs/TextInput.tsx index 2702e2ac5..c1f02e569 100644 --- a/api-rework/client/src/common-components/inputs/TextInput.tsx +++ b/api-rework/client/src/common-components/inputs/TextInput.tsx @@ -1,16 +1,20 @@ +import { KeyValue } from 'constants'; import { useState } from 'react'; +import { stringify } from 'utils'; interface PropTypes { label?: string; - value: string; + value: string | KeyValue; } const TextInput = ({ label, value }: PropTypes) => { + const isEmpty = value == undefined; const [id] = useState(Math.random().toString()); + return (
- {label && } - + {label && } +
); }; diff --git a/api-rework/client/src/constants.ts b/api-rework/client/src/constants.ts index 1fb7f4a13..628a0a087 100644 --- a/api-rework/client/src/constants.ts +++ b/api-rework/client/src/constants.ts @@ -5,5 +5,10 @@ interface SubtypeData { subtypeData: Record; } -export type { SubtypeData }; +interface KeyValue { + code: string; + full: string | number; +} + +export type { SubtypeData, KeyValue }; export { API_URL }; diff --git a/api-rework/client/src/utils.ts b/api-rework/client/src/utils.ts new file mode 100644 index 000000000..94938c288 --- /dev/null +++ b/api-rework/client/src/utils.ts @@ -0,0 +1,12 @@ +import { KeyValue } from 'constants'; + +const stringify = (val: string | KeyValue) => { + if (val == undefined) return 'NO DATA'; + + if (typeof val === 'string' || typeof val === 'number') { + return val; + } + return `${val.full} (${val.code})`; +}; + +export { stringify }; diff --git a/api-rework/client/tsconfig.json b/api-rework/client/tsconfig.json index e6bb5b8e2..dbd81b58d 100644 --- a/api-rework/client/tsconfig.json +++ b/api-rework/client/tsconfig.json @@ -37,6 +37,14 @@ "node_modules", "src/types" ], + "paths": { + "@utils": [ + "src/utils" + ], + "@constants": [ + "src/constants" + ] + }, "noFallthroughCasesInSwitch": true }, "include": [ diff --git a/api-rework/invasives/api/migrations/0003_alter_terrestrialbiocontroldispersalmonitoring_plant_count.py b/api-rework/invasives/api/migrations/0003_alter_terrestrialbiocontroldispersalmonitoring_plant_count.py new file mode 100644 index 000000000..fdf2379f8 --- /dev/null +++ b/api-rework/invasives/api/migrations/0003_alter_terrestrialbiocontroldispersalmonitoring_plant_count.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0 on 2026-01-29 21:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("api", "0002_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="terrestrialbiocontroldispersalmonitoring", + name="plant_count", + field=models.PositiveIntegerField(blank=True, null=True), + ), + ] diff --git a/api-rework/invasives/api/models/activity/biocontrol/terrestrial_biocontrol_dispersal_monitoring.py b/api-rework/invasives/api/models/activity/biocontrol/terrestrial_biocontrol_dispersal_monitoring.py index 9fd5d82f6..4efb5d051 100644 --- a/api-rework/invasives/api/models/activity/biocontrol/terrestrial_biocontrol_dispersal_monitoring.py +++ b/api-rework/invasives/api/models/activity/biocontrol/terrestrial_biocontrol_dispersal_monitoring.py @@ -22,7 +22,7 @@ class TerrestrialBiocontrolDispersalMonitoring(BaseOneToManyActivityTable): biocontrol_agent = models.ForeignKey(BiocontrolAgentCode, on_delete=models.PROTECT) biocontrol_present = models.BooleanField() monitoring_type = models.CharField(choices=CollectionType) - plant_count = models.PositiveIntegerField() + plant_count = models.PositiveIntegerField(null=True, blank=True) monitoring_method = models.ForeignKey( BioAgentCollectionMethodCode, on_delete=models.PROTECT ) @@ -54,7 +54,7 @@ def clean(self): self.sign_of_biocontrol_presence = None if self.collection_method == CollectionType.Count: - if self.plant_count_collection is None: + if self.plant_count is None: errors["plant_count_collection"] = ( "Plant count must be filled if collection type is Count" ) @@ -64,7 +64,7 @@ def clean(self): errors["time_collection_duration_minutes"] = ( "Count duration must be filled if collection type is Timed" ) - self.plant_count_collection = None # Ensure other field is blank + self.plant_count = None # Ensure other field is blank if self.start_time_collecting > timezone.now(): errors["start_time_collecting"] = ( diff --git a/api-rework/invasives/api/serializers/activity.py b/api-rework/invasives/api/serializers/activity.py index 3fa24df31..7c1b37e90 100644 --- a/api-rework/invasives/api/serializers/activity.py +++ b/api-rework/invasives/api/serializers/activity.py @@ -99,6 +99,7 @@ class ActivitySerializer(serializers.ModelSerializer): employer = EmployerSerializer(source="employer_set", many=True) subtype_data = serializers.SerializerMethodField() participants = ParticipantSerializer(source="participant_set", many=True) + linked_activities = serializers.SerializerMethodField() class Meta: model = Activity @@ -108,6 +109,7 @@ class Meta: "id", "created_by", "form_status", + "linked_activities", # Record type details "type", "subtype", @@ -131,6 +133,13 @@ class Meta: "location_description", ) + def get_linked_activities(self, obj): + print(obj) + arr = [] + for linked_id in obj.linked_activities.all(): + arr.append({"short_id": linked_id.short_id, "full": linked_id.id}) + return arr + def get_subtype_data(self, obj: Activity): """Maps the Activity to the proper Subtype Serializer, populating the form specific information""" SUBTYPE_SERIALIZER_MAP = {