- {!!reportFromEventStore && !!eventSchema
- ?
+ {!!reportFromEventStore
+ ?
:
}
diff --git a/src/DetailViewComponents/ActivitySection/ContainedReportListItem/index.test.js b/src/DetailViewComponents/ActivitySection/ContainedReportListItem/index.test.js
index b07f88d94..1c6c52cc7 100644
--- a/src/DetailViewComponents/ActivitySection/ContainedReportListItem/index.test.js
+++ b/src/DetailViewComponents/ActivitySection/ContainedReportListItem/index.test.js
@@ -16,7 +16,7 @@ import ContainedReportListItem from '.';
const server = setupServer(
http.get(`${EVENT_API_URL}:eventId`, () => HttpResponse.json( { data: { ...report } })),
- http.get(`${EVENT_TYPE_SCHEMA_API_URL}:name`, () => HttpResponse.json( { data: { results: {} } }))
+ http.get(`${EVENT_TYPE_SCHEMA_API_URL}/:name`, () => HttpResponse.json( { data: { results: {} } }))
);
beforeAll(() => server.listen());
diff --git a/src/ReportFormSummary/V1SchemaFormSummary/index.js b/src/ReportFormSummary/V1SchemaFormSummary/index.js
new file mode 100644
index 000000000..2aa07a45a
--- /dev/null
+++ b/src/ReportFormSummary/V1SchemaFormSummary/index.js
@@ -0,0 +1,56 @@
+import React, { useMemo } from 'react';
+import Form from '@rjsf/bootstrap-4';
+
+import { formValidator } from '../../utils/events';
+
+import {
+ AddButton,
+ ArrayFieldItemTemplate,
+ ArrayFieldTemplate,
+ BaseInputTemplate,
+ ExternalLinkField,
+ MoveDownButton,
+ MoveUpButton,
+ ObjectFieldTemplate,
+ RemoveButton,
+} from '../../SchemaFields';
+
+import * as styles from './styles.module.scss';
+
+// For V1 schemas, we basically hack a rjsf Form so they render all the fields for us and we styled them so they don't
+// look like fields.
+const V1SchemaFormSummary = ({ eventSchema, report }) => {
+ const { schema, uiSchema } = eventSchema;
+
+ const filteredSchema = useMemo(() => {
+ const { properties = {} } = schema ?? {};
+ const eventDetailsKeys = Object.keys(report?.event_details ?? {});
+
+ return {
+ ...schema,
+ properties: Object.entries(properties).reduce((acc, [key, value]) => {
+ return eventDetailsKeys.includes(key) ? { ...acc, [key]: value } : acc;
+ }, {})
+ };
+ }, [report, schema]);
+
+ return
;
+};
+
+export default V1SchemaFormSummary;
diff --git a/src/ReportFormSummary/V1SchemaFormSummary/styles.module.scss b/src/ReportFormSummary/V1SchemaFormSummary/styles.module.scss
new file mode 100644
index 000000000..4524b4b4a
--- /dev/null
+++ b/src/ReportFormSummary/V1SchemaFormSummary/styles.module.scss
@@ -0,0 +1,113 @@
+@use '../../common/styles/vars/colors';
+
+.form {
+ [class*=react-datepicker-wrapper] {
+ div {
+ border: none;
+ padding: 0;
+ height: auto;
+ background: transparent;
+ }
+ }
+
+ [class*=row] {
+ padding: 0;
+
+ > * {
+ padding: 0;
+ }
+ }
+
+ [class*=col-] {
+ padding: 0;
+ }
+
+ label {
+ color: colors.$secondary-medium-gray;
+ font-size: 0.875rem;
+ margin: 0.75rem 0 0;
+ }
+
+ button,
+ input,
+ [class*=control] {
+ background-color: transparent !important;
+ border: transparent;
+ font-size: 1rem;
+ height: 1.5rem !important;
+ margin: 0;
+ padding: 0;
+ }
+
+ [class*=control] {
+ min-height: 1.5rem;
+ }
+
+ [class*=selectWidget] {
+ div {
+ height: 1.5rem;
+ display: block;
+ padding: 0;
+ }
+
+ [class*=singleValue] {
+ color: black;
+ margin: 0;
+ }
+ }
+
+ legend {
+ border-bottom: 1px solid colors.$light-gray-border;
+ font-size: 1rem;
+ font-weight: 500;
+ margin: 1.5rem 0 0.5rem;
+ }
+
+ h5 {
+ font-size: 1rem;
+ }
+
+ hr {
+ margin-bottom: 0;
+ }
+
+ button[class*=moveButton],
+ button[type=submit],
+ svg,
+ [class*=addButton],
+ [class*=triangle],
+ [class*=IndicatorsContainer] {
+ display: none !important;
+ }
+
+ [class*=checkboxesWidget] {
+ border: none;
+ max-height: none;
+ overflow-y: hidden;
+
+ [class*=checkbox] {
+ margin-bottom: 0;
+ padding-left: 0;
+
+ label {
+ color: black;
+ font-size: 1rem;
+ margin: 0;
+ opacity: 1;
+
+ &:before {
+ content: "\002D";
+ margin-right: 0.25rem;
+ }
+ }
+
+ input {
+ display: none;
+ }
+
+ &:has(input:not(:checked)) {
+ display: none;
+ }
+ }
+ }
+}
diff --git a/src/ReportFormSummary/V2SchemaFormSummary/index.js b/src/ReportFormSummary/V2SchemaFormSummary/index.js
new file mode 100644
index 000000000..8a10c67c7
--- /dev/null
+++ b/src/ReportFormSummary/V2SchemaFormSummary/index.js
@@ -0,0 +1,75 @@
+import React, { useMemo } from 'react';
+import { useSelector } from 'react-redux';
+import { useTranslation } from 'react-i18next';
+
+import getHumanizedFieldValue from '../../utils/v2-event-schemas/getHumanizedFieldValue';
+import makeFieldsFromSchema from '../../utils/v2-event-schemas/makeFieldsFromSchema';
+import { FORM_ELEMENT_TYPES, ROOT_CANVAS_ID } from '../../utils/v2-event-schemas/constants';
+
+import * as styles from './styles.module.scss';
+
+const FieldSummary = ({ field, formData, id }) => {
+ const { i18n, t } = useTranslation('details-view', { keyPrefix: 'reportFormSummary.v2SchemaFormSummary' });
+
+ const gpsFormat = useSelector((state) => state.view.userPreferences.gpsFormat);
+
+ return <>
+
{field.details.label}
+
+
{getHumanizedFieldValue(
+ field,
+ formData[id],
+ '-',
+ i18n.language,
+ gpsFormat,
+ t
+ )}
+ >;
+};
+
+const SectionSummary = ({ details, fields, formData }) =>
+
+
+ {details.label &&
{details.label}
}
+
+
+
+ {details.leftColumn.map((fieldId) => fields[fieldId].type === FORM_ELEMENT_TYPES.HEADER
+ ?
+ {fields[fieldId].details.label}
+
+ :
)}
+
+
+ {details.columns === 2 &&
+ {details.rightColumn.map((fieldId) => )}
+
}
+
+
;
+
+// For V2 schemas, we have a customized rendering of the details using utility functions like makeFieldsFromSchema and
+// getHumanizedFieldValue following the schema definition.
+const V2SchemaFormSummary = ({ eventSchema, formData }) => {
+ const fields = useMemo(() => makeFieldsFromSchema(eventSchema), [eventSchema]);
+
+ return fields[ROOT_CANVAS_ID]?.details.fields.map((sectionId) =>
);
+};
+
+export default V2SchemaFormSummary;
diff --git a/src/ReportFormSummary/V2SchemaFormSummary/styles.module.scss b/src/ReportFormSummary/V2SchemaFormSummary/styles.module.scss
new file mode 100644
index 000000000..c2b2de8c3
--- /dev/null
+++ b/src/ReportFormSummary/V2SchemaFormSummary/styles.module.scss
@@ -0,0 +1,62 @@
+@use '../../common/styles/vars/colors';
+
+.section {
+ .separator {
+ margin: 0.75rem -1rem;
+ }
+
+ .sectionLabel {
+ font-size: 1.125rem;
+ font-weight: 500;
+ margin: 0;
+ }
+
+ .columns {
+ display: flex;
+
+ .column {
+ &.fullWidth {
+ width: 100%;
+ }
+
+ &.halfWidthLeft {
+ padding-right: 0.5rem;
+ width: 50%;
+ }
+
+ &.halfWidthRight {
+ padding-left: 0.5rem;
+ width: 50%;
+ }
+
+ .header-large,
+ .header-medium,
+ .header-small {
+ font-weight: 500;
+ margin: 1rem 0 0.25rem;
+ }
+
+ .header-large {
+ font-size: 1.125rem;
+ }
+
+ .header-medium {
+ font-size: 1rem;
+ }
+
+ .header-small {
+ font-size: 0.875rem;
+ }
+
+ .fieldLabel {
+ color: colors.$secondary-medium-gray;
+ font-size: 0.875rem;
+ margin: 0.75rem 0 0;
+ }
+
+ .fieldValue {
+ margin: 0;
+ }
+ }
+ }
+}
diff --git a/src/ReportFormSummary/index.js b/src/ReportFormSummary/index.js
index 70de21336..fc13e8007 100644
--- a/src/ReportFormSummary/index.js
+++ b/src/ReportFormSummary/index.js
@@ -1,39 +1,45 @@
-import React, { memo, useMemo } from 'react';
-import Form from '@rjsf/bootstrap-4';
+import React, { memo, useEffect } from 'react';
+import MoonLoader from 'react-spinners/MoonLoader';
+import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
+import { fetchEventTypeSchema } from '../ducks/event-schemas';
+import { selectEventSchema } from '../selectors/event-schemas';
+import { selectEventTypeByValue } from '../selectors/event-types';
import useReport from '../hooks/useReport';
-import {
- AddButton,
- ArrayFieldItemTemplate,
- ArrayFieldTemplate,
- BaseInputTemplate,
- ExternalLinkField,
- MoveDownButton,
- MoveUpButton,
- ObjectFieldTemplate,
- RemoveButton,
-} from '../SchemaFields';
-import { formValidator } from '../utils/events';
+import V1SchemaFormSummary from './V1SchemaFormSummary';
+import V2SchemaFormSummary from './V2SchemaFormSummary';
import * as styles from './styles.module.scss';
-const ReportFormSummary = ({ className, report, schema, uiSchema }) => {
+const LOADER_COLOR = '#006cd9'; // Bright blue
+const LOADER_SIZE = 30;
+
+const EventFormSummary = ({ report }) => {
+ const dispatch = useDispatch();
const { t } = useTranslation('details-view', { keyPrefix: 'reportFormSummary' });
+
+ const eventSchema = useSelector((state) => report
+ ? selectEventSchema(state, report.event_type, report.id)
+ : null);
+ const eventType = useSelector((state) => selectEventTypeByValue(state, report.event_type));
+
const { eventTypeTitle } = useReport(report);
- const filteredSchema = useMemo(() => {
- const { properties = {} } = schema ?? {};
- const eventDetailsKeys = Object.keys(report?.event_details ?? {});
- return {
- ...schema,
- properties: Object.entries(properties).reduce((acc, [key, value]) => {
- return eventDetailsKeys.includes(key) ? { ...acc, [key]: value } : acc;
- }, {})
- };
- }, [report, schema]);
- return
+ useEffect(() => {
+ if (!!eventType && !eventSchema) {
+ dispatch(fetchEventTypeSchema(report.event_type, report.id));
+ }
+ }, [dispatch, eventSchema, eventType, report.event_type, report.id]);
+
+ if (!eventSchema) {
+ return
+
+
;
+ }
+
+ return
- {
- report.reported_by?.name &&
-
-
- {report.reported_by?.name}
-
- }
+ {report.reported_by?.name &&
+
+ {report.reported_by?.name}
+
}
- {schema &&
}
+
+ {eventType.version === 2 &&
}
;
};
-export default memo(ReportFormSummary);
+export default memo(EventFormSummary);
diff --git a/src/ReportFormSummary/index.test.js b/src/ReportFormSummary/index.test.js
index 8499df1d9..3691182af 100644
--- a/src/ReportFormSummary/index.test.js
+++ b/src/ReportFormSummary/index.test.js
@@ -1,79 +1,132 @@
import React from 'react';
+import { http, HttpResponse } from 'msw';
+import { setupServer } from 'msw/node';
+import { EVENT_TYPE_SCHEMA_API_URL } from '../ducks/event-schemas';
+import { GPS_FORMATS } from '../utils/location';
import ReportFormSummary from './index';
import { report as mockedReport } from '../__test-helpers/fixtures/reports';
-import { eventSchemas } from '../__test-helpers/fixtures/event-schemas';
+import { eventSchemas, snareSchemaV2 } from '../__test-helpers/fixtures/event-schemas';
import { Provider } from 'react-redux';
import { mockStore } from '../__test-helpers/MockStore';
import { eventTypes } from '../__test-helpers/fixtures/event-types';
-import { eventTypeTitleForEvent } from '../utils/events';
import { render, screen } from '../test-utils';
+const server = setupServer(
+ http.get(
+ `${EVENT_TYPE_SCHEMA_API_URL}/:name`,
+ () => HttpResponse.json( { data: eventSchemas.wildlife_sighting_rep['a78576a5-3c5b-40df-b374-12db53fbfdd6'] })
+ )
+);
-describe('ReportFormSummary', () => {
+beforeAll(() => server.listen());
+afterEach(() => server.resetHandlers());
+afterAll(() => server.close());
- const { schema, uiSchema } = eventSchemas.wildlife_sighting_rep['a78576a5-3c5b-40df-b374-12db53fbfdd6'];
- const event_details = {
- wildlifesightingrep_species: 'cheetah',
- wildlifesightingrep_numberanimals: 2,
- wildlifesightingrep_collared: 'yes',
- };
- const reported_by = { name: 'Ranger' };
- const report = { ...mockedReport, event_details, reported_by };
- const initialProps = { report, schema, uiSchema };
- const store = mockStore({
- data: { eventTypes }
+describe('ReportFormSummary', () => {
+ let store;
+ beforeEach(() => {
+ store = {
+ data: {
+ eventSchemas: {
+ light_rep: {
+ 'd45cb504-4612-41fe-9ea5-f1b423ac3ba4': eventSchemas.wildlife_sighting_rep['a78576a5-3c5b-40df-b374-12db53fbfdd6']
+ },
+ },
+ eventTypes,
+ },
+ view: {
+ userPreferences: {
+ gpsFormat: GPS_FORMATS.DEG,
+ },
+ },
+ };
});
- const renderReportFormSummary = (props = initialProps) => render(
-
-
+ const renderReportFormSummary = (props) => render(
+
+
);
- test('render given summary form', async () => {
+ test('renders a loader while the schema is being loaded', () => {
+ store.data.eventSchemas = {};
+ renderReportFormSummary();
+
+ expect(screen.getByTestId('reportFormSummary-loader')).toBeVisible();
+ });
+
+ test('render a form summary for a v1 schema', async () => {
renderReportFormSummary();
- const reportTitle = eventTypeTitleForEvent(report, eventTypes);
- expect( screen.getByText(reportTitle) ).toBeInTheDocument();
- expect( screen.getByText(reported_by.name) ).toBeInTheDocument();
+ expect(screen.getByText('Light')).toBeInTheDocument();
+ expect(screen.getByText('Ranger')).toBeInTheDocument();
const numberAnimalsInput = screen.getByRole('spinbutton');
- expect( numberAnimalsInput ).toHaveValue(event_details.wildlifesightingrep_numberanimals);
- expect( numberAnimalsInput ).toHaveAttribute('disabled');
+ expect(numberAnimalsInput).toHaveValue(2);
+ expect(numberAnimalsInput).toHaveAttribute('disabled');
const species = screen.getByRole('combobox', { name: 'Species' } );
- expect( species ).toHaveValue('2');// cheetah
- expect( species ).toHaveAttribute('disabled');
+ expect(species).toHaveValue('2');
+ expect(species).toHaveAttribute('disabled');
const animals = screen.getByRole('combobox', { name: 'Are Animals Collared' } );
- expect( animals ).toHaveValue('0'); // yes
- expect( animals ).toHaveAttribute('disabled');
+ expect(animals).toHaveValue('0');
+ expect(animals).toHaveAttribute('disabled');
});
- test('Hide blank fields of a report summary', async () => {
+ test('hides the blank fields of a form summary for a v1 schema', async () => {
const roleOptions = { name: 'Species' };
const { rerender } = renderReportFormSummary();
- expect( screen.queryByRole('combobox', roleOptions ) ).toBeInTheDocument();
-
- const eventDetails = { ...event_details };
- delete eventDetails.wildlifesightingrep_species;
- const props = {
- ...initialProps,
- report: {
- ...report,
- event_details: eventDetails
- }
- };
-
- rerender(
-
+ expect(screen.queryByRole('combobox', roleOptions )).toBeInTheDocument();
+
+ rerender(
+
);
- expect( screen.queryByRole('combobox', roleOptions ) ).not.toBeInTheDocument();
+ expect(screen.queryByRole('combobox', roleOptions)).not.toBeInTheDocument();
});
+ test('render a form summary for a v2 schema', async () => {
+ store.data.eventTypes = [{ value: 'snare_v2_rep', version: 2 }];
+ store.data.eventSchemas.snare_v2_rep = {
+ 'd45cb504-4612-41fe-9ea5-f1b423ac3ba4': snareSchemaV2,
+ };
+ renderReportFormSummary({
+ report: {
+ ...mockedReport,
+ event_details: {
+ number_of_snares_found: 3,
+ },
+ event_type: 'snare_v2_rep',
+ reported_by: { name: 'Ranger' },
+ }
+ });
+ expect(screen.getByText('Ranger')).toBeVisible();
+ expect(screen.getByText('Number of Snares Found')).toBeVisible();
+ expect(screen.getByText('3')).toBeVisible();
+ });
});
diff --git a/src/ReportFormSummary/styles.module.scss b/src/ReportFormSummary/styles.module.scss
index 40219a3d2..843606d34 100644
--- a/src/ReportFormSummary/styles.module.scss
+++ b/src/ReportFormSummary/styles.module.scss
@@ -1,17 +1,13 @@
-@import '../common/styles/vars/colors';
-@import '../common/styles/layout';
+@use '../common/styles/vars/colors';
+@use '../common/styles/layout';
-.reportFormSummary {
-
- [class*=react-datepicker-wrapper] {
- div {
- border: none;
- padding: 0;
- height: auto;
- background: transparent;
- }
- }
+.loaderWrapper {
+ display: flex;
+ justify-content: center;
+ width: 100%;
+}
+.reportFormSummary {
.nonSchemaFields {
display: flex;
flex-direction: column;
@@ -23,119 +19,18 @@
width: 100%;
label {
- margin: 0;
+ color: colors.$secondary-medium-gray;
+ font-size: 0.875rem;
+ margin: 0.75rem 0 0;
}
- @media (min-width: $md-layout-width-min) {
+ @media (min-width: layout.$md-layout-width-min) {
width: 50%;
}
}
- @media (min-width: $md-layout-width-min) {
+ @media (min-width: layout.$md-layout-width-min) {
flex-direction: row;
}
}
-
- label {
- color: $secondary-medium-gray;
- font-size: 0.875rem;
- margin: 0.75rem 0 0;
- }
-
- .form {
- [class*=row] {
- padding: 0;
-
- > * {
- padding: 0;
- }
- }
-
- [class*=col-] {
- padding: 0;
- }
-
- button,
- input,
- [class*=control] {
- background-color: transparent !important;
- border: transparent;
- font-size: 1rem;
- height: 1.5rem !important;
- margin: 0;
- padding: 0;
- }
-
- [class*=control] {
- min-height: 1.5rem;
- }
-
- [class*=selectWidget] {
- div {
- height: 1.5rem;
- display: block;
- padding: 0;
- }
-
- [class*=singleValue] {
- color: black;
- margin: 0;
- }
- }
-
- legend {
- border-bottom: 1px solid $light-gray-border;
- font-size: 1rem;
- font-weight: 500;
- margin: 1.5rem 0 0.5rem;
- }
-
- h5 {
- font-size: 1rem;
- }
-
- hr {
- margin-bottom: 0;
- }
-
- button[class*=moveButton],
- button[type=submit],
- svg,
- [class*=addButton],
- [class*=triangle],
- [class*=IndicatorsContainer] {
- display: none !important;
- }
-
- [class*=checkboxesWidget] {
- border: none;
- max-height: none;
- overflow-y: hidden;
-
- [class*=checkbox] {
- margin-bottom: 0;
- padding-left: 0;
-
- label {
- color: black;
- font-size: 1rem;
- margin: 0;
- opacity: 1;
-
- &:before {
- content: "\002D";
- margin-right: 0.25rem;
- }
- }
-
- input {
- display: none;
- }
-
- &:has(input:not(:checked)) {
- display: none;
- }
- }
- }
- }
}
diff --git a/src/ReportManager/DetailsSection/SchemaForm/constants.js b/src/ReportManager/DetailsSection/SchemaForm/constants.js
index 03eb6c1c6..441a32389 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/constants.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/constants.js
@@ -1,42 +1 @@
-export const CHOICE_LIST_ELEMENT_CHOICE_TYPES = {
- EXISTING_CHOICE_LIST: 'EXISTING_CHOICE_LIST',
- MY_DATA: 'MY_DATA',
-};
-
-export const CHOICE_LIST_ELEMENT_INPUT_TYPES = {
- DROPDOWN: 'DROPDOWN',
- LIST: 'LIST',
-};
-
-export const DATE_TIME_ELEMENT_INPUT_TYPES = {
- DATE_TIME: 'DATE_TIME',
- DATE: 'DATE',
- TIME: 'TIME',
-};
-
-export const FORM_ELEMENT_TYPES = {
- ATTACHMENT: 'ATTACHMENT',
- CHOICE_LIST: 'CHOICE_LIST',
- COLLECTION: 'COLLECTION',
- DATE_TIME: 'DATE_TIME',
- HEADER: 'HEADER',
- LOCATION: 'LOCATION',
- NUMERIC: 'NUMERIC',
- SECTION: 'SECTION',
- TEXT: 'TEXT',
-};
-
-export const HEADER_ELEMENT_SIZES = {
- LARGE: 'LARGE',
- MEDIUM: 'MEDIUM',
- SMALL: 'SMALL',
-};
-
export const JUMP_TO_LOCATION_BUTTON_ZOOM = 20;
-
-export const ROOT_CANVAS_ID = 'root';
-
-export const TEXT_ELEMENT_INPUT_TYPES = {
- SHORT: 'SHORT_TEXT',
- LONG: 'LONG_TEXT',
-};
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/ChoiceList/index.js b/src/ReportManager/DetailsSection/SchemaForm/fields/ChoiceList/index.js
index 7484343cc..9d824f695 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/ChoiceList/index.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/ChoiceList/index.js
@@ -1,6 +1,6 @@
import React, { memo } from 'react';
-import { CHOICE_LIST_ELEMENT_INPUT_TYPES } from '../../constants';
+import { CHOICE_LIST_ELEMENT_INPUT_TYPES } from '../../../../../utils/v2-event-schemas/constants';
import Dropdown from './Dropdown';
import List from './List';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/ChoiceList/index.test.js b/src/ReportManager/DetailsSection/SchemaForm/fields/ChoiceList/index.test.js
index b4b3eae6b..21934adb3 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/ChoiceList/index.test.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/ChoiceList/index.test.js
@@ -1,9 +1,8 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
-import { CHOICE_LIST_ELEMENT_INPUT_TYPES } from '../../constants';
-
import { render, screen } from '../../../../../test-utils';
+import { CHOICE_LIST_ELEMENT_INPUT_TYPES } from '../../../../../utils/v2-event-schemas/constants';
import ChoiceList from './';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/FormPreview/index.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/FormPreview/index.js
index be97a4d8d..016f5d623 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/FormPreview/index.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/FormPreview/index.js
@@ -4,8 +4,9 @@ import { useTranslation } from 'react-i18next';
import { ReactComponent as MarkerFeedIcon } from '../../../../../../../../common/images/icons/marker-feed.svg';
-import { FORM_ELEMENT_TYPES, JUMP_TO_LOCATION_BUTTON_ZOOM } from '../../../../../constants';
-import { getHumanizedValue } from '../utils';
+import { FORM_ELEMENT_TYPES } from '../../../../../../../../utils/v2-event-schemas/constants';
+import { JUMP_TO_LOCATION_BUTTON_ZOOM } from '../../../../../constants';
+import getHumanizedFieldValue from '../../../../../../../../utils/v2-event-schemas/getHumanizedFieldValue';
import useJumpToLocation from '../../../../../../../../hooks/useJumpToLocation';
import * as styles from './styles.module.scss';
@@ -39,7 +40,7 @@ const FormPreview = ({
- {getHumanizedValue(fields[fieldId], formData[fieldId], '-', i18n.language, gpsFormat, t)}
+ {getHumanizedFieldValue(fields[fieldId], formData[fieldId], '-', i18n.language, gpsFormat, t)}
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/FormPreview/index.test.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/FormPreview/index.test.js
index 6a91642ec..7da9cf0fc 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/FormPreview/index.test.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/FormPreview/index.test.js
@@ -3,7 +3,7 @@ import { Provider } from 'react-redux';
import userEvent from '@testing-library/user-event';
import { fireEvent, render, screen } from '../../../../../../../../test-utils';
-import { FORM_ELEMENT_TYPES } from '../../../../../constants';
+import { FORM_ELEMENT_TYPES } from '../../../../../../../../utils/v2-event-schemas/constants';
import { GPS_FORMATS } from '../../../../../../../../utils/location';
import { mockStore } from '../../../../../../../../__test-helpers/MockStore';
import useJumpToLocation from '../../../../../../../../hooks/useJumpToLocation';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/index.test.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/index.test.js
index 1c84f1281..4b3c44948 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/index.test.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/index.test.js
@@ -3,7 +3,7 @@ import { Provider } from 'react-redux';
import userEvent from '@testing-library/user-event';
import { render, screen, within } from '../../../../../../../test-utils';
-import { FORM_ELEMENT_TYPES } from '../../../../constants';
+import { FORM_ELEMENT_TYPES } from '../../../../../../../utils/v2-event-schemas/constants';
import { GPS_FORMATS } from '../../../../../../../utils/location';
import { mockStore } from '../../../../../../../__test-helpers/MockStore';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/utils/index.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/utils/index.js
index 576a1e051..0c8b4e7d9 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/utils/index.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/utils/index.js
@@ -1,67 +1,6 @@
-import { format, isValid, parseISO } from 'date-fns';
-
-import { calcGpsDisplayString } from '../../../../../../../../utils/location';
-import { DATE_TIME_ELEMENT_INPUT_TYPES, FORM_ELEMENT_TYPES } from '../../../../../constants';
-import { shouldUse12HourFormat } from '../../../../../../../../utils/datetime';
-
-const getChoiceListOptionLabel = (value, field) => field.details.options
- .find((option) => option.const === value)?.title;
-
-// Utility to calculate a human readable version of the field values. For example, render a date-time like
-// 2020/01/01 12:00 PM instead of 2020-01-01T12:00:00Z.
-export const getHumanizedValue = (field, value, defaultHumanizedValue, language, gpsFormat, t) => {
- if (!value) {
- return defaultHumanizedValue;
- }
-
- const use12HourFormat = shouldUse12HourFormat(language);
-
- switch (field.type) {
- case FORM_ELEMENT_TYPES.COLLECTION:
- return t('collectionHumanizedValue', { collectionLength: value.length });
-
- case FORM_ELEMENT_TYPES.CHOICE_LIST:
- if (field.details.multiple) {
- const humanizedValues = value.map((val) => {
- return getChoiceListOptionLabel(val, field);
- });
- return humanizedValues.join(', ');
- }
- return getChoiceListOptionLabel(value, field);
-
- case FORM_ELEMENT_TYPES.DATE_TIME:
- let parsedDate;
- let formatStr;
- switch (field.details.inputType) {
- case DATE_TIME_ELEMENT_INPUT_TYPES.DATE:
- parsedDate = parseISO(value);
- formatStr = 'yyyy/MM/dd';
- break;
-
- case DATE_TIME_ELEMENT_INPUT_TYPES.DATE_TIME:
- parsedDate = parseISO(value);
- formatStr = use12HourFormat ? 'yyyy/MM/dd hh:mm a' : 'yyyy/MM/dd HH:mm';
- break;
-
- case DATE_TIME_ELEMENT_INPUT_TYPES.TIME:
- parsedDate = parseISO(`2000-01-01T${value}`);
- formatStr = use12HourFormat ? 'hh:mm a' : 'HH:mm';
- break;
-
- default:
- return defaultHumanizedValue;
- }
- return isValid(parsedDate) ? format(parsedDate, formatStr) : defaultHumanizedValue;
-
- case FORM_ELEMENT_TYPES.LOCATION:
- return calcGpsDisplayString(value.latitude, value.longitude, gpsFormat);
-
- default:
- return value;
- };
-};
+import getHumanizedFieldValue from '../../../../../../../../utils/v2-event-schemas/getHumanizedFieldValue';
export const getItemTitle = (formData, identifier, defaultTitle, identifierField, language, gpsFormat, t) =>
!identifier || !formData[identifier]
? defaultTitle
- : getHumanizedValue(identifierField, formData[identifier], defaultTitle, language, gpsFormat, t);
+ : getHumanizedFieldValue(identifierField, formData[identifier], defaultTitle, language, gpsFormat, t);
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/utils/index.test.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/utils/index.test.js
index f802ba8e4..0b94ea0b2 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/utils/index.test.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/Item/utils/index.test.js
@@ -1,133 +1,9 @@
-import { format, parseISO } from 'date-fns';
-
-import { choicesListOptions } from '../../../../../fixtures';
-import { DATE_TIME_ELEMENT_INPUT_TYPES, FORM_ELEMENT_TYPES } from '../../../../../constants';
+import { FORM_ELEMENT_TYPES } from '../../../../../../../../utils/v2-event-schemas/constants';
import { GPS_FORMATS } from '../../../../../../../../utils/location';
-import { getHumanizedValue, getItemTitle } from './';
+import { getItemTitle } from './';
describe('ReportManager - DetailsSection - SchemaForm - fields - Collection - SortableList - Item - utils', () => {
- describe('getHumanizedValue', () => {
- const t = (_, { collectionLength }) => `${collectionLength} items`;
-
- test('returns the default value if no value is provided', () => {
- expect(getHumanizedValue({ type: FORM_ELEMENT_TYPES.TEXT }, undefined, 'default', 'en-US', GPS_FORMATS.DEG, t)).toBe('default');
- });
-
- test('returns the length of a collection', () => {
- expect(getHumanizedValue(
- { type: FORM_ELEMENT_TYPES.COLLECTION },
- [{}, {}],
- 'default',
- 'en-US',
- GPS_FORMATS.DEG,
- t
- )).toBe('2 items');
- });
-
- test('returns the choice list values separated by a comma if it supports multiple values', () => {
- expect(getHumanizedValue(
- {
- details: {
- multiple: true,
- options: choicesListOptions
- },
- type: FORM_ELEMENT_TYPES.CHOICE_LIST
- },
- ['17e67b22-0e4a-4fcb-aeee-903b51a7a2e0', '223ab492-0ea7-4ff2-b8b8-cb6504c943b6'],
- 'default',
- 'en-US',
- GPS_FORMATS.DEG,
- t
- )).toBe('Desert Bighorn Sheep, Ranger Cruz');
- });
-
- test('returns the choice list value it supports a single value', () => {
- expect(getHumanizedValue(
- {
- details: {
- multiple: false,
- options: choicesListOptions
- },
- type: FORM_ELEMENT_TYPES.CHOICE_LIST
- },
- '0d553bb7-5c4f-43d7-9b82-a561a668ae64',
- 'default',
- 'en-US',
- GPS_FORMATS.DEG,
- t
- )).toBe('EarthRanger System');
- });
-
- test('returns a readable date value', () => {
- expect(getHumanizedValue(
- { details: { inputType: DATE_TIME_ELEMENT_INPUT_TYPES.DATE }, type: FORM_ELEMENT_TYPES.DATE_TIME },
- '2020-01-01',
- 'default',
- 'en-US',
- GPS_FORMATS.DEG,
- t
- )).toBe('2020/01/01');
- });
-
- test('returns a readable date time value', () => {
- const utcValue = '2020-01-01T06:30:00Z';
- expect(getHumanizedValue(
- { details: { inputType: DATE_TIME_ELEMENT_INPUT_TYPES.DATE_TIME }, type: FORM_ELEMENT_TYPES.DATE_TIME },
- utcValue,
- 'default',
- 'en-US',
- GPS_FORMATS.DEG,
- t
- )).toBe(format(parseISO(utcValue), 'yyyy/MM/dd hh:mm a'));
- });
-
- test('returns a readable time value', () => {
- const utcValue = '06:30:00Z';
- expect(getHumanizedValue(
- { details: { inputType: DATE_TIME_ELEMENT_INPUT_TYPES.TIME }, type: FORM_ELEMENT_TYPES.DATE_TIME },
- utcValue,
- 'default',
- 'en-US',
- GPS_FORMATS.DEG,
- t
- )).toBe(format(parseISO(`2000-01-01T${utcValue}`), 'hh:mm a'));
- });
-
- test('returns the default value if a date-time element is invalid', () => {
- expect(getHumanizedValue(
- { details: { inputType: DATE_TIME_ELEMENT_INPUT_TYPES.DATE }, type: FORM_ELEMENT_TYPES.DATE_TIME },
- 'invalid',
- 'default',
- 'en-US',
- GPS_FORMATS.DEG,
- t
- )).toBe('default');
- });
-
- test('returns the coordinates from a location in the provided GPS format', () => {
- expect(getHumanizedValue(
- { type: FORM_ELEMENT_TYPES.LOCATION },
- { latitude: 10.1234, longitude: 30.987 },
- 'default',
- 'en-US',
- GPS_FORMATS.DEG,
- t
- )).toBe('10.123400°, 30.987000°');
- });
-
- test('returns the plain value for other element types', () => {
- expect(getHumanizedValue(
- { type: FORM_ELEMENT_TYPES.TEXT },
- 'Value',
- 'default',
- 'en-US',
- GPS_FORMATS.DEG,
- t
- )).toBe('Value');
- });
- });
-
describe('getItemTitle', () => {
const t = (_, { collectionLength }) => `${collectionLength} items`;
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/SortableItem/index.test.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/SortableItem/index.test.js
index f5e8278c2..37e733447 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/SortableItem/index.test.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/SortableList/SortableItem/index.test.js
@@ -6,7 +6,7 @@ import { useSortable } from '@dnd-kit/sortable';
import { render, screen } from '../../../../../../../test-utils';
import { GPS_FORMATS } from '../../../../../../../utils/location';
import { mockStore } from '../../../../../../../__test-helpers/MockStore';
-import { FORM_ELEMENT_TYPES } from '../../../../constants';
+import { FORM_ELEMENT_TYPES } from '../../../../../../../utils/v2-event-schemas/constants';
import SortableItem from './';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/index.test.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/index.test.js
index 0ef9b48ae..ea99f22a5 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/index.test.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Collection/index.test.js
@@ -3,7 +3,7 @@ import { Provider } from 'react-redux';
import userEvent from '@testing-library/user-event';
import { render, screen, within } from '../../../../../test-utils';
-import { FORM_ELEMENT_TYPES } from '../../constants';
+import { FORM_ELEMENT_TYPES } from '../../../../../utils/v2-event-schemas/constants';
import { GPS_FORMATS } from '../../../../../utils/location';
import { mockStore } from '../../../../../__test-helpers/MockStore';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/DateTime/index.js b/src/ReportManager/DetailsSection/SchemaForm/fields/DateTime/index.js
index af757a1b0..603e01acd 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/DateTime/index.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/DateTime/index.js
@@ -1,7 +1,7 @@
import React, { memo, useEffect, useState } from 'react';
import { format, isValid, parseISO } from 'date-fns';
-import { DATE_TIME_ELEMENT_INPUT_TYPES } from '../../constants';
+import { DATE_TIME_ELEMENT_INPUT_TYPES } from '../../../../../utils/v2-event-schemas/constants';
import DatePicker, { isValidDate, EMPTY_DATE_VALUE } from '../../../../../DatePicker';
import DateTimePicker, { EMPTY_DATE_TIME_VALUE } from '../../../../../DateTimePicker';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/DateTime/index.test.js b/src/ReportManager/DetailsSection/SchemaForm/fields/DateTime/index.test.js
index da627a503..05af9db95 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/DateTime/index.test.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/DateTime/index.test.js
@@ -3,7 +3,7 @@ import { format, parseISO } from 'date-fns';
import userEvent from '@testing-library/user-event';
import { render, screen } from '../../../../../test-utils';
-import { DATE_TIME_ELEMENT_INPUT_TYPES } from '../../constants';
+import { DATE_TIME_ELEMENT_INPUT_TYPES } from '../../../../../utils/v2-event-schemas/constants';
import DateTime from './';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Header/index.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Header/index.js
index 243a578b8..936cbcd98 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Header/index.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Header/index.js
@@ -1,6 +1,6 @@
import React, { memo } from 'react';
-import { HEADER_ELEMENT_SIZES } from '../../constants';
+import { HEADER_ELEMENT_SIZES } from '../../../../../utils/v2-event-schemas/constants';
import * as styles from './styles.module.scss';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Header/index.test.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Header/index.test.js
index 8f15fefa2..c38f09b11 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Header/index.test.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Header/index.test.js
@@ -1,7 +1,7 @@
import React from 'react';
import { render, screen } from '../../../../../test-utils';
-import { HEADER_ELEMENT_SIZES } from '../../constants';
+import { HEADER_ELEMENT_SIZES } from '../../../../../utils/v2-event-schemas/constants';
import Header from './';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Text/index.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Text/index.js
index ce8584047..cad18e303 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Text/index.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Text/index.js
@@ -1,6 +1,6 @@
import React, { memo, useEffect, useRef } from 'react';
-import { TEXT_ELEMENT_INPUT_TYPES } from '../../constants';
+import { TEXT_ELEMENT_INPUT_TYPES } from '../../../../../utils/v2-event-schemas/constants';
import * as styles from './styles.module.scss';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fields/Text/index.test.js b/src/ReportManager/DetailsSection/SchemaForm/fields/Text/index.test.js
index 9e3edc388..eb39f7c6c 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fields/Text/index.test.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/fields/Text/index.test.js
@@ -2,7 +2,7 @@ import React from 'react';
import userEvent from '@testing-library/user-event';
import { render, screen } from '../../../../../test-utils';
-import { TEXT_ELEMENT_INPUT_TYPES } from '../../constants';
+import { TEXT_ELEMENT_INPUT_TYPES } from '../../../../../utils/v2-event-schemas/constants';
import Text from './';
diff --git a/src/ReportManager/DetailsSection/SchemaForm/index.js b/src/ReportManager/DetailsSection/SchemaForm/index.js
index 0b4472ca7..1a5467092 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/index.js
+++ b/src/ReportManager/DetailsSection/SchemaForm/index.js
@@ -1,7 +1,7 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
-import { FORM_ELEMENT_TYPES, ROOT_CANVAS_ID } from './constants';
-import makeFieldsFromSchema from './utils/makeFieldsFromSchema';
+import { FORM_ELEMENT_TYPES, ROOT_CANVAS_ID } from '../../../utils/v2-event-schemas/constants';
+import makeFieldsFromSchema from '../../../utils/v2-event-schemas/makeFieldsFromSchema';
import useMapLocationMarkers from './utils/useMapLocationMarkers';
import useSchemaValidations from './utils/useSchemaValidations';
diff --git a/src/i18n.js b/src/i18n.js
index 85a6f99d6..58a96b37d 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -50,12 +50,12 @@ i18n
backendOptions: [{
expirationTime: 24 * 60 * 60 * 1000 * 7,
versions: {
- es: 'v1.11',
- 'en-US': 'v1.11',
- fr: 'v1.11',
- 'ne-NP': 'v1.11',
- pt: 'v1.11',
- sw: 'v1.11'
+ es: 'v1.12',
+ 'en-US': 'v1.12',
+ fr: 'v1.12',
+ 'ne-NP': 'v1.12',
+ pt: 'v1.12',
+ sw: 'v1.12'
}
}]
}
diff --git a/src/utils/v2-event-schemas/constants.js b/src/utils/v2-event-schemas/constants.js
new file mode 100644
index 000000000..58885bf63
--- /dev/null
+++ b/src/utils/v2-event-schemas/constants.js
@@ -0,0 +1,40 @@
+export const CHOICE_LIST_ELEMENT_CHOICE_TYPES = {
+ EXISTING_CHOICE_LIST: 'EXISTING_CHOICE_LIST',
+ MY_DATA: 'MY_DATA',
+};
+
+export const CHOICE_LIST_ELEMENT_INPUT_TYPES = {
+ DROPDOWN: 'DROPDOWN',
+ LIST: 'LIST',
+};
+
+export const DATE_TIME_ELEMENT_INPUT_TYPES = {
+ DATE_TIME: 'DATE_TIME',
+ DATE: 'DATE',
+ TIME: 'TIME',
+};
+
+export const FORM_ELEMENT_TYPES = {
+ ATTACHMENT: 'ATTACHMENT',
+ CHOICE_LIST: 'CHOICE_LIST',
+ COLLECTION: 'COLLECTION',
+ DATE_TIME: 'DATE_TIME',
+ HEADER: 'HEADER',
+ LOCATION: 'LOCATION',
+ NUMERIC: 'NUMERIC',
+ SECTION: 'SECTION',
+ TEXT: 'TEXT',
+};
+
+export const HEADER_ELEMENT_SIZES = {
+ LARGE: 'LARGE',
+ MEDIUM: 'MEDIUM',
+ SMALL: 'SMALL',
+};
+
+export const ROOT_CANVAS_ID = 'root';
+
+export const TEXT_ELEMENT_INPUT_TYPES = {
+ SHORT: 'SHORT_TEXT',
+ LONG: 'LONG_TEXT',
+};
diff --git a/src/ReportManager/DetailsSection/SchemaForm/fixtures.js b/src/utils/v2-event-schemas/fixtures.js
similarity index 99%
rename from src/ReportManager/DetailsSection/SchemaForm/fixtures.js
rename to src/utils/v2-event-schemas/fixtures.js
index 1b0fc59a4..c713e88a5 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/fixtures.js
+++ b/src/utils/v2-event-schemas/fixtures.js
@@ -63,4 +63,4 @@ export const choicesListOptions = [
const: '3bc7c8df-3461-47f2-8196-7b0a45405a13',
title: 'Subject X'
}
-];
\ No newline at end of file
+];
diff --git a/src/utils/v2-event-schemas/getHumanizedFieldValue/index.js b/src/utils/v2-event-schemas/getHumanizedFieldValue/index.js
new file mode 100644
index 000000000..d54493977
--- /dev/null
+++ b/src/utils/v2-event-schemas/getHumanizedFieldValue/index.js
@@ -0,0 +1,64 @@
+import { format, isValid, parseISO } from 'date-fns';
+
+import { calcGpsDisplayString } from '../../location';
+import { DATE_TIME_ELEMENT_INPUT_TYPES, FORM_ELEMENT_TYPES } from '../constants';
+import { shouldUse12HourFormat } from '../../datetime';
+
+const getChoiceListOptionLabel = (value, field) => field.details.options
+ .find((option) => option.const === value)?.title;
+
+// Utility to calculate a human readable version of the field values. For example, render a date-time like
+// 2020/01/01 12:00 PM instead of 2020-01-01T12:00:00Z.
+const getHumanizedFieldValue = (field, value, defaultHumanizedValue, language, gpsFormat, t) => {
+ if (!value) {
+ return defaultHumanizedValue;
+ }
+
+ const use12HourFormat = shouldUse12HourFormat(language);
+
+ switch (field.type) {
+ case FORM_ELEMENT_TYPES.COLLECTION:
+ return t('collectionHumanizedValue', { collectionLength: value.length });
+
+ case FORM_ELEMENT_TYPES.CHOICE_LIST:
+ if (field.details.multiple) {
+ const humanizedValues = value.map((val) => {
+ return getChoiceListOptionLabel(val, field);
+ });
+ return humanizedValues.join(', ');
+ }
+ return getChoiceListOptionLabel(value, field);
+
+ case FORM_ELEMENT_TYPES.DATE_TIME:
+ let parsedDate;
+ let formatStr;
+ switch (field.details.inputType) {
+ case DATE_TIME_ELEMENT_INPUT_TYPES.DATE:
+ parsedDate = parseISO(value);
+ formatStr = 'yyyy/MM/dd';
+ break;
+
+ case DATE_TIME_ELEMENT_INPUT_TYPES.DATE_TIME:
+ parsedDate = parseISO(value);
+ formatStr = use12HourFormat ? 'yyyy/MM/dd hh:mm a' : 'yyyy/MM/dd HH:mm';
+ break;
+
+ case DATE_TIME_ELEMENT_INPUT_TYPES.TIME:
+ parsedDate = parseISO(`2000-01-01T${value}`);
+ formatStr = use12HourFormat ? 'hh:mm a' : 'HH:mm';
+ break;
+
+ default:
+ return defaultHumanizedValue;
+ }
+ return isValid(parsedDate) ? format(parsedDate, formatStr) : defaultHumanizedValue;
+
+ case FORM_ELEMENT_TYPES.LOCATION:
+ return calcGpsDisplayString(value.latitude, value.longitude, gpsFormat);
+
+ default:
+ return value;
+ };
+};
+
+export default getHumanizedFieldValue;
diff --git a/src/utils/v2-event-schemas/getHumanizedFieldValue/index.test.js b/src/utils/v2-event-schemas/getHumanizedFieldValue/index.test.js
new file mode 100644
index 000000000..7f3063cb7
--- /dev/null
+++ b/src/utils/v2-event-schemas/getHumanizedFieldValue/index.test.js
@@ -0,0 +1,127 @@
+import { format, parseISO } from 'date-fns';
+
+import { choicesListOptions } from '../fixtures';
+import { DATE_TIME_ELEMENT_INPUT_TYPES, FORM_ELEMENT_TYPES } from '../constants';
+import getHumanizedFieldValue from '.';
+import { GPS_FORMATS } from '../../location';
+
+describe('getHumanizedFieldValue', () => {
+ const t = (_, { collectionLength }) => `${collectionLength} items`;
+
+ test('returns the default value if no value is provided', () => {
+ expect(getHumanizedFieldValue({ type: FORM_ELEMENT_TYPES.TEXT }, undefined, 'default', 'en-US', GPS_FORMATS.DEG, t)).toBe('default');
+ });
+
+ test('returns the length of a collection', () => {
+ expect(getHumanizedFieldValue(
+ { type: FORM_ELEMENT_TYPES.COLLECTION },
+ [{}, {}],
+ 'default',
+ 'en-US',
+ GPS_FORMATS.DEG,
+ t
+ )).toBe('2 items');
+ });
+
+ test('returns the choice list values separated by a comma if it supports multiple values', () => {
+ expect(getHumanizedFieldValue(
+ {
+ details: {
+ multiple: true,
+ options: choicesListOptions
+ },
+ type: FORM_ELEMENT_TYPES.CHOICE_LIST
+ },
+ ['17e67b22-0e4a-4fcb-aeee-903b51a7a2e0', '223ab492-0ea7-4ff2-b8b8-cb6504c943b6'],
+ 'default',
+ 'en-US',
+ GPS_FORMATS.DEG,
+ t
+ )).toBe('Desert Bighorn Sheep, Ranger Cruz');
+ });
+
+ test('returns the choice list value it supports a single value', () => {
+ expect(getHumanizedFieldValue(
+ {
+ details: {
+ multiple: false,
+ options: choicesListOptions
+ },
+ type: FORM_ELEMENT_TYPES.CHOICE_LIST
+ },
+ '0d553bb7-5c4f-43d7-9b82-a561a668ae64',
+ 'default',
+ 'en-US',
+ GPS_FORMATS.DEG,
+ t
+ )).toBe('EarthRanger System');
+ });
+
+ test('returns a readable date value', () => {
+ expect(getHumanizedFieldValue(
+ { details: { inputType: DATE_TIME_ELEMENT_INPUT_TYPES.DATE }, type: FORM_ELEMENT_TYPES.DATE_TIME },
+ '2020-01-01',
+ 'default',
+ 'en-US',
+ GPS_FORMATS.DEG,
+ t
+ )).toBe('2020/01/01');
+ });
+
+ test('returns a readable date time value', () => {
+ const utcValue = '2020-01-01T06:30:00Z';
+ expect(getHumanizedFieldValue(
+ { details: { inputType: DATE_TIME_ELEMENT_INPUT_TYPES.DATE_TIME }, type: FORM_ELEMENT_TYPES.DATE_TIME },
+ utcValue,
+ 'default',
+ 'en-US',
+ GPS_FORMATS.DEG,
+ t
+ )).toBe(format(parseISO(utcValue), 'yyyy/MM/dd hh:mm a'));
+ });
+
+ test('returns a readable time value', () => {
+ const utcValue = '06:30:00Z';
+ expect(getHumanizedFieldValue(
+ { details: { inputType: DATE_TIME_ELEMENT_INPUT_TYPES.TIME }, type: FORM_ELEMENT_TYPES.DATE_TIME },
+ utcValue,
+ 'default',
+ 'en-US',
+ GPS_FORMATS.DEG,
+ t
+ )).toBe(format(parseISO(`2000-01-01T${utcValue}`), 'hh:mm a'));
+ });
+
+ test('returns the default value if a date-time element is invalid', () => {
+ expect(getHumanizedFieldValue(
+ { details: { inputType: DATE_TIME_ELEMENT_INPUT_TYPES.DATE }, type: FORM_ELEMENT_TYPES.DATE_TIME },
+ 'invalid',
+ 'default',
+ 'en-US',
+ GPS_FORMATS.DEG,
+ t
+ )).toBe('default');
+ });
+
+ test('returns the coordinates from a location in the provided GPS format', () => {
+ expect(getHumanizedFieldValue(
+ { type: FORM_ELEMENT_TYPES.LOCATION },
+ { latitude: 10.1234, longitude: 30.987 },
+ 'default',
+ 'en-US',
+ GPS_FORMATS.DEG,
+ t
+ )).toBe('10.123400°, 30.987000°');
+ });
+
+ test('returns the plain value for other element types', () => {
+ expect(getHumanizedFieldValue(
+ { type: FORM_ELEMENT_TYPES.TEXT },
+ 'Value',
+ 'default',
+ 'en-US',
+ GPS_FORMATS.DEG,
+ t
+ )).toBe('Value');
+ });
+});
\ No newline at end of file
diff --git a/src/ReportManager/DetailsSection/SchemaForm/utils/makeFieldsFromSchema/index.js b/src/utils/v2-event-schemas/makeFieldsFromSchema/index.js
similarity index 99%
rename from src/ReportManager/DetailsSection/SchemaForm/utils/makeFieldsFromSchema/index.js
rename to src/utils/v2-event-schemas/makeFieldsFromSchema/index.js
index 3689a4230..224d9d4ce 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/utils/makeFieldsFromSchema/index.js
+++ b/src/utils/v2-event-schemas/makeFieldsFromSchema/index.js
@@ -1,4 +1,4 @@
-import { DATE_TIME_ELEMENT_INPUT_TYPES, FORM_ELEMENT_TYPES, ROOT_CANVAS_ID } from '../../constants';
+import { DATE_TIME_ELEMENT_INPUT_TYPES, FORM_ELEMENT_TYPES, ROOT_CANVAS_ID } from '../constants';
const SECTION_CHILD_TYPES = { FIELD: 'field', HEADER: 'header' };
diff --git a/src/ReportManager/DetailsSection/SchemaForm/utils/makeFieldsFromSchema/index.test.js b/src/utils/v2-event-schemas/makeFieldsFromSchema/index.test.js
similarity index 99%
rename from src/ReportManager/DetailsSection/SchemaForm/utils/makeFieldsFromSchema/index.test.js
rename to src/utils/v2-event-schemas/makeFieldsFromSchema/index.test.js
index 807bef944..5d1729a35 100644
--- a/src/ReportManager/DetailsSection/SchemaForm/utils/makeFieldsFromSchema/index.test.js
+++ b/src/utils/v2-event-schemas/makeFieldsFromSchema/index.test.js
@@ -6,9 +6,8 @@ import {
HEADER_ELEMENT_SIZES,
ROOT_CANVAS_ID,
TEXT_ELEMENT_INPUT_TYPES,
-} from '../../constants';
-
-import { choicesListOptions } from '../../fixtures';
+} from '../constants';
+import { choicesListOptions } from '../fixtures';
describe('ReportManager - DetailsSection - SchemaForm - Utils - makeFieldsFromSchema', () => {
it('creates section fields from the schema', () => {