From 6bf9ff24021c6183ff1632d323d365a197d500a8 Mon Sep 17 00:00:00 2001 From: Kjartan Date: Fri, 27 Oct 2023 16:51:32 -0700 Subject: [PATCH 1/8] Initial setup for sample period start/end time --- .../survey/{surveyId}/sample-site/index.ts | 6 + .../repositories/sample-period-repository.ts | 21 ++- api/src/services/sample-method-service.ts | 8 +- .../components/fields/StartEndTimeFields.tsx | 141 ++++++++++++++++++ .../surveys/components/MethodForm.tsx | 39 +++-- .../observations-table/ObservationsTable.tsx | 14 +- .../edit/components/SampleMethodEditForm.tsx | 6 +- app/src/interfaces/useSurveyApi.interface.ts | 2 + ...31027000000_update_survey_sample_period.ts | 36 +++++ 9 files changed, 252 insertions(+), 21 deletions(-) create mode 100644 app/src/components/fields/StartEndTimeFields.tsx create mode 100644 database/src/migrations/20231027000000_update_survey_sample_period.ts diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/index.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/index.ts index ea64e3ebca..5ca2c0dc08 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/index.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/index.ts @@ -260,6 +260,12 @@ POST.apiDoc = { }, end_date: { type: 'string' + }, + start_time: { + type: 'string' + }, + end_time: { + type: 'string' } } } diff --git a/api/src/repositories/sample-period-repository.ts b/api/src/repositories/sample-period-repository.ts index 31674ac624..f0bec9eaf5 100644 --- a/api/src/repositories/sample-period-repository.ts +++ b/api/src/repositories/sample-period-repository.ts @@ -4,11 +4,14 @@ import { getKnex } from '../database/db'; import { ApiExecuteSQLError } from '../errors/api-error'; import { BaseRepository } from './base-repository'; -export type InsertSamplePeriodRecord = Pick; +export type InsertSamplePeriodRecord = Pick< + SamplePeriodRecord, + 'survey_sample_method_id' | 'start_date' | 'end_date' | 'start_time' | 'end_time' +>; export type UpdateSamplePeriodRecord = Pick< SamplePeriodRecord, - 'survey_sample_period_id' | 'survey_sample_method_id' | 'start_date' | 'end_date' + 'survey_sample_period_id' | 'survey_sample_method_id' | 'start_date' | 'end_date' | 'start_time' | 'end_time' >; // This describes a row in the database for Survey Sample Period @@ -17,6 +20,8 @@ export const SamplePeriodRecord = z.object({ survey_sample_method_id: z.number(), start_date: z.string(), end_date: z.string(), + start_time: z.string().nullable(), + end_time: z.string().nullable(), create_date: z.string(), create_user: z.number(), update_date: z.string().nullable(), @@ -64,7 +69,9 @@ export class SamplePeriodRepository extends BaseRepository { SET survey_sample_method_id=${sample.survey_sample_method_id}, start_date=${sample.start_date}, - end_date=${sample.end_date} + end_date=${sample.end_date}, + start_time=${sample.start_time}, + end_time=${sample.end_time} WHERE survey_sample_period_id = ${sample.survey_sample_period_id} RETURNING @@ -94,11 +101,15 @@ export class SamplePeriodRepository extends BaseRepository { INSERT INTO survey_sample_period ( survey_sample_method_id, start_date, - end_date + end_date, + start_time, + end_time ) VALUES ( ${sample.survey_sample_method_id}, ${sample.start_date}, - ${sample.end_date} + ${sample.end_date}, + ${sample.start_time}, + ${sample.end_time} ) RETURNING *;`; diff --git a/api/src/services/sample-method-service.ts b/api/src/services/sample-method-service.ts index d1a0b79ef9..6ec3658cb2 100644 --- a/api/src/services/sample-method-service.ts +++ b/api/src/services/sample-method-service.ts @@ -70,7 +70,9 @@ export class SampleMethodService extends DBService { const samplePeriod = { survey_sample_method_id: record.survey_sample_method_id, start_date: item.start_date, - end_date: item.end_date + end_date: item.end_date, + start_time: item.start_time, + end_time: item.end_time }; return samplePeriodService.insertSamplePeriod(samplePeriod); }); @@ -134,7 +136,9 @@ export class SampleMethodService extends DBService { const samplePeriod = { survey_sample_method_id: sampleMethod.survey_sample_method_id, start_date: item.start_date, - end_date: item.end_date + end_date: item.end_date, + start_time: item.start_time, + end_time: item.end_time }; await samplePeriodService.insertSamplePeriod(samplePeriod); } diff --git a/app/src/components/fields/StartEndTimeFields.tsx b/app/src/components/fields/StartEndTimeFields.tsx new file mode 100644 index 0000000000..827b342460 --- /dev/null +++ b/app/src/components/fields/StartEndTimeFields.tsx @@ -0,0 +1,141 @@ +import { mdiClockOutline, mdiClockPlusOutline } from '@mdi/js'; +import Icon from '@mdi/react'; +import Grid from '@mui/material/Grid'; +import { LocalizationProvider, TimePicker } from '@mui/x-date-pickers'; +import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment'; +import { TIME_FORMAT } from 'constants/dateTimeFormats'; +import get from 'lodash-es/get'; +import moment from 'moment'; +import React from 'react'; + +interface IStartEndTimeFieldsProps { + formikProps: any; + startName: string; + endName: string; + startRequired: boolean; + endRequired: boolean; + startTimeHelperText?: string; + endTimeHelperText?: string; +} + +const TimeStartIcon = () => { + return ; +}; + +const TimeEndIcon = () => { + return ; +}; + +/** + * Start/end Time fields - commonly used throughout forms + * + */ +const StartEndTimeFields: React.FC = (props) => { + const { + formikProps: { values, errors, touched, setFieldValue }, + startName, + endName, + startRequired, + endRequired, + startTimeHelperText, + endTimeHelperText + } = props; + + const rawStartTimeValue = get(values, startName); + const rawEndTimeValue = get(values, endName); + + const formattedStartTimeValue = + (rawStartTimeValue && + moment(rawStartTimeValue, TIME_FORMAT.ShortTimeFormatAmPm).isValid() && + moment(rawStartTimeValue, TIME_FORMAT.ShortTimeFormatAmPm)) || + null; + + const formattedEndTimeValue = + (rawEndTimeValue && + moment(rawEndTimeValue, TIME_FORMAT.ShortTimeFormatAmPm).isValid() && + moment(rawEndTimeValue, TIME_FORMAT.ShortTimeFormatAmPm)) || + null; + + return ( + + + + { + if (!value || String(value.creationData().input) === 'Invalid Time') { + // The creation input value will be 'Invalid Time' when the Time field is cleared (empty), and will + // contain an actual Time string value if the field is not empty but is invalid. + setFieldValue(startName, null); + return; + } + + setFieldValue(startName, moment(value).format(TIME_FORMAT.ShortTimeFormatAmPm)); + }} + /> + + + { + if (!value || String(value.creationData().input) === 'Invalid Time') { + // The creation input value will be 'Invalid Time' when the Time field is cleared (empty), and will + // contain an actual Time string value if the field is not empty but is invalid. + setFieldValue(endName, null); + return; + } + + setFieldValue(endName, moment(value).format(TIME_FORMAT.ShortTimeFormatAmPm)); + }} + /> + + + + ); +}; + +export default StartEndTimeFields; diff --git a/app/src/features/surveys/components/MethodForm.tsx b/app/src/features/surveys/components/MethodForm.tsx index cd8849e301..36a4be6b02 100644 --- a/app/src/features/surveys/components/MethodForm.tsx +++ b/app/src/features/surveys/components/MethodForm.tsx @@ -15,6 +15,7 @@ import Select from '@mui/material/Select'; import Typography from '@mui/material/Typography'; import CustomTextField from 'components/fields/CustomTextField'; import StartEndDateFields from 'components/fields/StartEndDateFields'; +import StartEndTimeFields from 'components/fields/StartEndTimeFields'; import { CodesContext } from 'contexts/codesContext'; import { FieldArray, FieldArrayRenderProps, useFormikContext } from 'formik'; import get from 'lodash-es/get'; @@ -26,6 +27,8 @@ interface ISurveySampleMethodPeriodData { survey_sample_method_id: number | null; start_date: string; end_date: string; + start_time: string | null; + end_time: string | null; } export interface ISurveySampleMethodData { @@ -45,7 +48,9 @@ export const SurveySampleMethodPeriodArrayItemInitialValues = { survey_sample_period_id: '' as unknown as null, survey_sample_method_id: '' as unknown as null, start_date: '', - end_date: '' + end_date: '', + start_time: '', + end_time: '' }; export const SurveySampleMethodDataInitialValues = { @@ -72,7 +77,9 @@ export const SamplingSiteMethodYupSchema = yup.object({ .typeError('End Date is required') .isValidDateString() .required('End Date is required') - .isEndDateSameOrAfterStartDate('start_date') + .isEndDateSameOrAfterStartDate('start_date'), + start_time: yup.string().nullable(), + end_time: yup.string().nullable() }) ) .hasUniqueDateRanges('Periods cannot overlap', 'start_date', 'end_date') @@ -156,17 +163,29 @@ const MethodForm = () => { } }}> - + + + + + + + { .map((samplePeriod: IGetSamplePeriodRecord) => ({ survey_sample_period_id: samplePeriod.survey_sample_period_id, survey_sample_method_id: samplePeriod.survey_sample_method_id, - sample_period_name: `${samplePeriod.start_date} - ${samplePeriod.end_date}` + sample_period_name: `${samplePeriod.start_date} - ${samplePeriod.end_date}`, + sample_period_time: `${samplePeriod.start_time} - ${samplePeriod.end_time}` })); const observationColumns: GridColDef[] = [ @@ -226,7 +228,10 @@ const ObservationsTable = (props: ISpeciesObservationTableProps) => { optionsGetter={(row, allOptions) => { return allOptions .filter((item) => item.survey_sample_method_id === row.survey_sample_method_id) - .map((item) => ({ label: item.sample_period_name, value: item.survey_sample_period_id })); + .map((item) => ({ + label: `${item.sample_period_name} | ${item.sample_period_time}`, + value: item.survey_sample_period_id + })); }} allOptions={samplePeriodOptions} /> @@ -239,7 +244,10 @@ const ObservationsTable = (props: ISpeciesObservationTableProps) => { optionsGetter={(row, allOptions) => { return allOptions .filter((item) => item.survey_sample_method_id === row.survey_sample_method_id) - .map((item) => ({ label: item.sample_period_name, value: item.survey_sample_period_id })); + .map((item) => ({ + label: `${item.sample_period_name} | ${item.sample_period_time}`, + value: item.survey_sample_period_id + })); }} allOptions={samplePeriodOptions} /> diff --git a/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx b/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx index deb08059c9..73964625a1 100644 --- a/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx +++ b/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx @@ -1,4 +1,4 @@ -import { mdiCalendarRangeOutline, mdiPencilOutline, mdiPlus, mdiTrashCanOutline } from '@mdi/js'; +import { mdiCalendarRangeOutline, mdiClockOutline, mdiPencilOutline, mdiPlus, mdiTrashCanOutline } from '@mdi/js'; import Icon from '@mdi/react'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import Alert from '@mui/material/Alert'; @@ -196,6 +196,10 @@ const SampleMethodEditForm = (props: SampleMethodEditFormProps) => { + + + + ))} diff --git a/app/src/interfaces/useSurveyApi.interface.ts b/app/src/interfaces/useSurveyApi.interface.ts index 907db5c545..c877d89e48 100644 --- a/app/src/interfaces/useSurveyApi.interface.ts +++ b/app/src/interfaces/useSurveyApi.interface.ts @@ -397,6 +397,8 @@ export interface IGetSamplePeriodRecord { survey_sample_method_id: number; start_date: string; end_date: string; + start_time: string | null; + end_time: string | null; create_date: string; create_user: number; update_date: string | null; diff --git a/database/src/migrations/20231027000000_update_survey_sample_period.ts b/database/src/migrations/20231027000000_update_survey_sample_period.ts new file mode 100644 index 0000000000..105fc1ba9c --- /dev/null +++ b/database/src/migrations/20231027000000_update_survey_sample_period.ts @@ -0,0 +1,36 @@ +import { Knex } from 'knex'; + +/** + * Add new columns to survey_sample_period table + * + * @export + * @param {Knex} knex + * @return {*} {Promise} + */ +export async function up(knex: Knex): Promise { + await knex.raw(`--sql + ---------------------------------------------------------------------------------------- +-- Add new columns + ---------------------------------------------------------------------------------------- + +SET search_path=biohub; + +ALTER TABLE survey_sample_period ADD start_time time; +ALTER TABLE survey_sample_period ADD end_time time; + +COMMENT ON COLUMN survey_sample_period.start_time IS 'start time of the survey observation'; +COMMENT ON COLUMN survey_sample_period.end_time IS 'end time of the survey observation'; + +---------------------------------------------------------------------------------------- +-- Create new views + ---------------------------------------------------------------------------------------- + +set search_path=biohub_dapi_v1; + +create or replace view survey_sample_period as select * from biohub.survey_sample_period; +`); +} + +export async function down(knex: Knex): Promise { + await knex.raw(``); +} From 8ea066ee615e58ec5e84231fbac25e5c7674ed94 Mon Sep 17 00:00:00 2001 From: Kjartan Date: Wed, 1 Nov 2023 14:00:55 -0700 Subject: [PATCH 2/8] fix null values, clean up --- .../survey/{surveyId}/sample-site/index.ts | 6 ++++-- .../sample-site/{surveySampleSiteId}/index.ts | 8 ++++++++ api/src/repositories/sample-period-repository.ts | 8 ++++---- app/src/features/surveys/components/MethodForm.tsx | 4 ++-- .../sampling-sites/SamplingSiteList.tsx | 14 ++++++++++++++ .../edit/components/SampleMethodEditForm.tsx | 13 +++++++++---- 6 files changed, 41 insertions(+), 12 deletions(-) diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/index.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/index.ts index 5ca2c0dc08..434df86b98 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/index.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/index.ts @@ -262,10 +262,12 @@ POST.apiDoc = { type: 'string' }, start_time: { - type: 'string' + type: 'string', + nullable: true }, end_time: { - type: 'string' + type: 'string', + nullable: true } } } diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/{surveySampleSiteId}/index.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/{surveySampleSiteId}/index.ts index 043ebf2a37..2d1c321a1c 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/{surveySampleSiteId}/index.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/sample-site/{surveySampleSiteId}/index.ts @@ -113,6 +113,14 @@ PUT.apiDoc = { }, end_date: { type: 'string' + }, + start_time: { + type: 'string', + nullable: true + }, + end_time: { + type: 'string', + nullable: true } } } diff --git a/api/src/repositories/sample-period-repository.ts b/api/src/repositories/sample-period-repository.ts index f0bec9eaf5..13825666c8 100644 --- a/api/src/repositories/sample-period-repository.ts +++ b/api/src/repositories/sample-period-repository.ts @@ -70,8 +70,8 @@ export class SamplePeriodRepository extends BaseRepository { survey_sample_method_id=${sample.survey_sample_method_id}, start_date=${sample.start_date}, end_date=${sample.end_date}, - start_time=${sample.start_time}, - end_time=${sample.end_time} + start_time=${sample.start_time || null}, + end_time=${sample.end_time || null} WHERE survey_sample_period_id = ${sample.survey_sample_period_id} RETURNING @@ -108,8 +108,8 @@ export class SamplePeriodRepository extends BaseRepository { ${sample.survey_sample_method_id}, ${sample.start_date}, ${sample.end_date}, - ${sample.start_time}, - ${sample.end_time} + ${sample.start_time || null}, + ${sample.end_time || null} ) RETURNING *;`; diff --git a/app/src/features/surveys/components/MethodForm.tsx b/app/src/features/surveys/components/MethodForm.tsx index 36a4be6b02..7ffbc3d891 100644 --- a/app/src/features/surveys/components/MethodForm.tsx +++ b/app/src/features/surveys/components/MethodForm.tsx @@ -178,8 +178,8 @@ const MethodForm = () => { formikProps={formikProps} startName={`periods[${index}].start_time`} endName={`periods[${index}].end_time`} - startRequired={true} - endRequired={true} + startRequired={false} + endRequired={false} /> diff --git a/app/src/features/surveys/observations/sampling-sites/SamplingSiteList.tsx b/app/src/features/surveys/observations/sampling-sites/SamplingSiteList.tsx index 232fb92ca9..a3927902f5 100644 --- a/app/src/features/surveys/observations/sampling-sites/SamplingSiteList.tsx +++ b/app/src/features/surveys/observations/sampling-sites/SamplingSiteList.tsx @@ -1,6 +1,7 @@ import { mdiCalendarRange, mdiChevronDown, + mdiClockOutline, mdiDotsVertical, mdiPencilOutline, mdiPlus, @@ -331,6 +332,19 @@ const SamplingSiteList = () => { + + {samplePeriod.start_time && ( + <> + + + + + + )} ); })} diff --git a/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx b/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx index 73964625a1..b93dcda8a1 100644 --- a/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx +++ b/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx @@ -195,11 +195,16 @@ const SampleMethodEditForm = (props: SampleMethodEditFormProps) => { + - - - - + {period.start_time && ( + <> + + + + + + )} ))} From 0035d1b225a7b8953bc3c609a13a5ada8586367f Mon Sep 17 00:00:00 2001 From: Kjartan Date: Mon, 6 Nov 2023 15:43:23 -0800 Subject: [PATCH 3/8] Fix tests, add clock picker --- api/package-lock.json | 4 +- .../sample-method-repository.test.ts | 68 +++++- .../sample-period-repository.test.ts | 16 +- .../services/sample-location-service.test.ts | 4 +- .../services/sample-method-service.test.ts | 43 +++- .../services/sample-period-service.test.ts | 18 +- app/package-lock.json | 224 +++++++++--------- .../components/fields/StartEndTimeFields.tsx | 12 +- .../surveys/components/SamplingMethodForm.tsx | 12 +- .../sampling-sites/SamplingSiteList.tsx | 4 +- .../edit/components/SampleMethodEditForm.tsx | 4 +- 11 files changed, 269 insertions(+), 140 deletions(-) diff --git a/api/package-lock.json b/api/package-lock.json index 0cab9949f9..fe1fcdacf4 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -4838,7 +4838,7 @@ "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, "import-fresh": { @@ -6497,7 +6497,7 @@ "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", "dev": true, "requires": { "abbrev": "1" diff --git a/api/src/repositories/sample-method-repository.test.ts b/api/src/repositories/sample-method-repository.test.ts index e298f1f7a9..6859a6ce41 100644 --- a/api/src/repositories/sample-method-repository.test.ts +++ b/api/src/repositories/sample-method-repository.test.ts @@ -54,8 +54,22 @@ describe('SampleMethodRepository', () => { method_lookup_id: 3, description: 'description', periods: [ - { end_date: '2023-01-02', start_date: '2023-10-02', survey_sample_method_id: 1, survey_sample_period_id: 4 }, - { end_date: '2023-10-03', start_date: '2023-11-05', survey_sample_method_id: 1, survey_sample_period_id: 5 } + { + end_date: '2023-01-02', + start_date: '2023-10-02', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1, + survey_sample_period_id: 4 + }, + { + end_date: '2023-10-03', + start_date: '2023-11-05', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1, + survey_sample_period_id: 5 + } ] }; const repo = new SampleMethodRepository(dbConnectionObj); @@ -75,8 +89,22 @@ describe('SampleMethodRepository', () => { method_lookup_id: 3, description: 'description', periods: [ - { end_date: '2023-01-02', start_date: '2023-10-02', survey_sample_method_id: 1, survey_sample_period_id: 4 }, - { end_date: '2023-10-03', start_date: '2023-11-05', survey_sample_method_id: 1, survey_sample_period_id: 5 } + { + end_date: '2023-01-02', + start_date: '2023-10-02', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1, + survey_sample_period_id: 4 + }, + { + end_date: '2023-10-03', + start_date: '2023-11-05', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1, + survey_sample_period_id: 5 + } ] }; const repo = new SampleMethodRepository(dbConnectionObj); @@ -101,8 +129,20 @@ describe('SampleMethodRepository', () => { method_lookup_id: 3, description: 'description', periods: [ - { end_date: '2023-01-02', start_date: '2023-10-02', survey_sample_method_id: 1 }, - { end_date: '2023-10-03', start_date: '2023-11-05', survey_sample_method_id: 1 } + { + end_date: '2023-01-02', + start_date: '2023-10-02', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1 + }, + { + end_date: '2023-10-03', + start_date: '2023-11-05', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1 + } ] }; const repo = new SampleMethodRepository(dbConnectionObj); @@ -121,8 +161,20 @@ describe('SampleMethodRepository', () => { method_lookup_id: 3, description: 'description', periods: [ - { end_date: '2023-01-02', start_date: '2023-10-02', survey_sample_method_id: 1 }, - { end_date: '2023-10-03', start_date: '2023-11-05', survey_sample_method_id: 1 } + { + end_date: '2023-01-02', + start_date: '2023-10-02', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1 + }, + { + end_date: '2023-10-03', + start_date: '2023-11-05', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1 + } ] }; const repo = new SampleMethodRepository(dbConnectionObj); diff --git a/api/src/repositories/sample-period-repository.test.ts b/api/src/repositories/sample-period-repository.test.ts index 40590eb301..287ebeda1e 100644 --- a/api/src/repositories/sample-period-repository.test.ts +++ b/api/src/repositories/sample-period-repository.test.ts @@ -52,7 +52,9 @@ describe('SamplePeriodRepository', () => { survey_sample_method_id: 1, survey_sample_period_id: 2, start_date: '2023-10-02', - end_date: '2023-01-02' + end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00' }; const repo = new SamplePeriodRepository(dbConnectionObj); const response = await repo.updateSamplePeriod(samplePeriod); @@ -69,7 +71,9 @@ describe('SamplePeriodRepository', () => { survey_sample_method_id: 1, survey_sample_period_id: 2, start_date: '2023-10-02', - end_date: '2023-01-02' + end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00' }; const repo = new SamplePeriodRepository(dbConnectionObj); @@ -91,7 +95,9 @@ describe('SamplePeriodRepository', () => { const samplePeriod: InsertSamplePeriodRecord = { survey_sample_method_id: 1, start_date: '2023-10-02', - end_date: '2023-01-02' + end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00' }; const repo = new SamplePeriodRepository(dbConnectionObj); const response = await repo.insertSamplePeriod(samplePeriod); @@ -107,7 +113,9 @@ describe('SamplePeriodRepository', () => { const samplePeriod: InsertSamplePeriodRecord = { survey_sample_method_id: 1, start_date: '2023-10-02', - end_date: '2023-01-02' + end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00' }; const repo = new SamplePeriodRepository(dbConnectionObj); diff --git a/api/src/services/sample-location-service.test.ts b/api/src/services/sample-location-service.test.ts index 1a4b01293a..4328b8aac0 100644 --- a/api/src/services/sample-location-service.test.ts +++ b/api/src/services/sample-location-service.test.ts @@ -52,7 +52,9 @@ describe('SampleLocationService', () => { { survey_sample_method_id: 1, start_date: '2023-01-01', - end_date: '2023-01-03' + end_date: '2023-01-03', + start_time: '12:00:00', + end_time: '13:00:00' } ] } diff --git a/api/src/services/sample-method-service.test.ts b/api/src/services/sample-method-service.test.ts index 8095ec3d89..0b6d0783a0 100644 --- a/api/src/services/sample-method-service.test.ts +++ b/api/src/services/sample-method-service.test.ts @@ -130,6 +130,8 @@ describe('SampleMethodService', () => { survey_sample_period_id: 2, start_date: '2023-10-04', end_date: '2023-11-05', + start_time: '12:00:00', + end_time: '13:00:00', create_date: '2023-01-02', create_user: 1, update_date: null, @@ -145,8 +147,20 @@ describe('SampleMethodService', () => { method_lookup_id: 3, description: 'description', periods: [ - { end_date: '2023-01-02', start_date: '2023-10-02', survey_sample_method_id: 1 }, - { end_date: '2023-10-03', start_date: '2023-11-05', survey_sample_method_id: 1 } + { + end_date: '2023-01-02', + start_date: '2023-10-02', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1 + }, + { + end_date: '2023-10-03', + start_date: '2023-11-05', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1 + } ] }; const sampleMethodService = new SampleMethodService(mockDBConnection); @@ -156,12 +170,16 @@ describe('SampleMethodService', () => { expect(insertSamplePeriodStub).to.be.calledWith({ survey_sample_method_id: mockSampleMethodRecord.survey_sample_method_id, start_date: sampleMethod.periods[0].start_date, - end_date: sampleMethod.periods[0].end_date + end_date: sampleMethod.periods[0].end_date, + start_time: sampleMethod.periods[0].start_time, + end_time: sampleMethod.periods[0].end_time }); expect(insertSamplePeriodStub).to.be.calledWith({ survey_sample_method_id: mockSampleMethodRecord.survey_sample_method_id, start_date: sampleMethod.periods[1].start_date, - end_date: sampleMethod.periods[1].end_date + end_date: sampleMethod.periods[1].end_date, + start_time: sampleMethod.periods[1].start_time, + end_time: sampleMethod.periods[1].end_time }); expect(response).to.eql(mockSampleMethodRecord); }); @@ -201,8 +219,21 @@ describe('SampleMethodService', () => { method_lookup_id: 3, description: 'description', periods: [ - { end_date: '2023-01-02', start_date: '2023-10-02', survey_sample_method_id: 1, survey_sample_period_id: 4 }, - { end_date: '2023-10-03', start_date: '2023-11-05', survey_sample_method_id: 1 } as SamplePeriodRecord + { + end_date: '2023-01-02', + start_date: '2023-10-02', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1, + survey_sample_period_id: 4 + }, + { + end_date: '2023-10-03', + start_date: '2023-11-05', + start_time: '12:00:00', + end_time: '13:00:00', + survey_sample_method_id: 1 + } as SamplePeriodRecord ] }; const sampleMethodService = new SampleMethodService(mockDBConnection); diff --git a/api/src/services/sample-period-service.test.ts b/api/src/services/sample-period-service.test.ts index e2e668f9c2..da9cf4570b 100644 --- a/api/src/services/sample-period-service.test.ts +++ b/api/src/services/sample-period-service.test.ts @@ -35,6 +35,8 @@ describe('SamplePeriodService', () => { survey_sample_method_id: 2, start_date: '2023-10-02', end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00', create_date: '2023-05-06', create_user: 1, update_date: null, @@ -68,6 +70,8 @@ describe('SamplePeriodService', () => { survey_sample_method_id: 2, start_date: '2023-10-02', end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00', create_date: '2023-05-06', create_user: 1, update_date: null, @@ -100,6 +104,8 @@ describe('SamplePeriodService', () => { survey_sample_method_id: 2, start_date: '2023-10-02', end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00', create_date: '2023-05-06', create_user: 1, update_date: null, @@ -113,7 +119,9 @@ describe('SamplePeriodService', () => { const samplePeriod: InsertSamplePeriodRecord = { survey_sample_method_id: 1, start_date: '2023-10-02', - end_date: '2023-01-02' + end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00' }; const samplePeriodService = new SamplePeriodService(mockDBConnection); const response = await samplePeriodService.insertSamplePeriod(samplePeriod); @@ -136,6 +144,8 @@ describe('SamplePeriodService', () => { survey_sample_method_id: 2, start_date: '2023-10-02', end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00', create_date: '2023-05-06', create_user: 1, update_date: null, @@ -150,7 +160,9 @@ describe('SamplePeriodService', () => { survey_sample_method_id: 1, survey_sample_period_id: 2, start_date: '2023-10-02', - end_date: '2023-01-02' + end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00' }; const samplePeriodService = new SamplePeriodService(mockDBConnection); const response = await samplePeriodService.updateSamplePeriod(samplePeriod); @@ -170,6 +182,8 @@ describe('SamplePeriodService', () => { survey_sample_method_id: 2, start_date: '2023-10-02', end_date: '2023-01-02', + start_time: '12:00:00', + end_time: '13:00:00', create_date: '2023-05-06', create_user: 1, update_date: null, diff --git a/app/package-lock.json b/app/package-lock.json index 0de756377d..88485c7cc4 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -5973,7 +5973,7 @@ "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==" }, "ansi-escapes": { "version": "4.3.2", @@ -6074,12 +6074,12 @@ "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==" }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "array-includes": { "version": "3.1.6", @@ -6193,7 +6193,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" }, "ast-types-flow": { "version": "0.0.7", @@ -6210,12 +6210,12 @@ "async-foreach": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", - "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=" + "integrity": "sha512-VUeSMD8nEGBWaZK4lizI1sf3yEC7pnAQ/mrI7pC2fBz2s/tq5jWWEngTwaf0Gruu/OoXRGLGg1XFqpYBiGTYJA==" }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "at-least-node": { "version": "1.0.0", @@ -6250,7 +6250,7 @@ "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" }, "aws4": { "version": "1.12.0", @@ -6555,7 +6555,7 @@ "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "requires": { "tweetnacl": "^0.14.3" } @@ -6587,7 +6587,7 @@ "block-stream": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "integrity": "sha512-OorbnJVPII4DuUKbjARAe8u8EfqOmkEEaSFIyoQ7OjTHn6kafxWl0wLgoZ2rXaYd7MyLcDaU4TmhfxtwgcccMQ==", "requires": { "inherits": "~2.0.0" } @@ -6754,7 +6754,7 @@ "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + "integrity": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==" }, "camelcase-css": { "version": "2.0.1", @@ -6765,7 +6765,7 @@ "camelcase-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "integrity": "sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==", "requires": { "camelcase": "^2.0.0", "map-obj": "^1.0.0" @@ -6797,7 +6797,7 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, "chalk": { "version": "2.4.2", @@ -6937,7 +6937,7 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==" }, "collect-v8-coverage": { "version": "1.0.2", @@ -6956,7 +6956,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "colord": { "version": "2.9.3", @@ -7058,7 +7058,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concaveman": { "version": "1.2.1", @@ -7086,7 +7086,7 @@ "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" }, "content-disposition": { "version": "0.5.4", @@ -7114,7 +7114,7 @@ "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "core-js": { "version": "3.31.1", @@ -7536,7 +7536,7 @@ "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", "requires": { "array-find-index": "^1.0.1" } @@ -7568,7 +7568,7 @@ "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "requires": { "assert-plus": "^1.0.0" } @@ -7595,7 +7595,7 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" }, "decimal.js": { "version": "10.4.3", @@ -7660,12 +7660,12 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, "density-clustering": { "version": "1.3.0", @@ -7675,7 +7675,7 @@ "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" }, "dequal": { "version": "2.0.3", @@ -7686,7 +7686,7 @@ "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" }, "detect-newline": { "version": "3.1.0", @@ -7906,7 +7906,7 @@ "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -7915,7 +7915,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "ejs": { "version": "3.1.9", @@ -7951,7 +7951,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "enhanced-resolve": { "version": "5.15.0", @@ -8106,12 +8106,12 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "escodegen": { "version": "2.1.0", @@ -8797,7 +8797,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "eventemitter3": { "version": "4.0.7", @@ -8930,7 +8930,7 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" }, "fast-deep-equal": { "version": "3.1.3", @@ -9113,7 +9113,7 @@ "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "requires": { "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" @@ -9162,7 +9162,7 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" }, "fork-ts-checker-webpack-plugin": { "version": "6.5.3", @@ -9353,7 +9353,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "fs-constants": { "version": "1.0.0", @@ -9381,7 +9381,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "2.3.2", @@ -9425,7 +9425,7 @@ "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -9453,7 +9453,7 @@ "geojson-equality": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/geojson-equality/-/geojson-equality-0.1.6.tgz", - "integrity": "sha1-oXE3TvBD5dR5eZWEC65GSOB1LXI=", + "integrity": "sha512-TqG8YbqizP3EfwP5Uw4aLu6pKkg6JQK9uq/XZ1lXQntvTHD1BBKJWhNpJ2M0ax6TuWMP3oyx6Oq7FCIfznrgpQ==", "requires": { "deep-equal": "^1.0.0" } @@ -9508,7 +9508,7 @@ "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==" }, "get-stream": { "version": "6.0.1", @@ -9528,7 +9528,7 @@ "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "requires": { "assert-plus": "^1.0.0" } @@ -9680,7 +9680,7 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" }, "har-validator": { "version": "5.1.5", @@ -9708,7 +9708,7 @@ "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "requires": { "ansi-regex": "^2.0.0" } @@ -9721,7 +9721,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "has-property-descriptors": { "version": "1.0.0", @@ -9752,7 +9752,7 @@ "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, "he": { "version": "1.2.0", @@ -9965,7 +9965,7 @@ "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -10037,7 +10037,7 @@ "immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "immer": { "version": "9.0.21", @@ -10086,7 +10086,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -10140,7 +10140,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "is-bigint": { "version": "1.0.4", @@ -10215,7 +10215,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "requires": { "number-is-nan": "^1.0.0" } @@ -10247,7 +10247,7 @@ "is-in-browser": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", - "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" }, "is-map": { "version": "2.0.2", @@ -10386,12 +10386,12 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==" }, "is-weakmap": { "version": "2.0.1", @@ -10429,17 +10429,17 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, "istanbul-lib-coverage": { "version": "3.2.0", @@ -12973,7 +12973,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" }, "jsdom": { "version": "16.7.0", @@ -13075,7 +13075,7 @@ "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, "json5": { "version": "2.2.3", @@ -13268,7 +13268,7 @@ "leaflet-fullscreen": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/leaflet-fullscreen/-/leaflet-fullscreen-1.0.2.tgz", - "integrity": "sha1-CcYcS6xF9jsu4Sav2H5c2XZQ/Bs=" + "integrity": "sha512-1Yxm8RZg6KlKX25+hbP2H/wnOAphH7hFcvuADJFb4QZTN7uOSN9Hsci5EZpow8vtNej9OGzu59Jxmn+0qKOO9Q==" }, "leaflet.locatecontrol": { "version": "0.79.0", @@ -13366,7 +13366,7 @@ "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" } } }, @@ -13421,7 +13421,7 @@ "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "integrity": "sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==", "requires": { "currently-unhandled": "^0.4.1", "signal-exit": "^3.0.0" @@ -13480,7 +13480,7 @@ "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==" }, "mdn-data": { "version": "2.0.4", @@ -13491,7 +13491,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "memfs": { "version": "3.5.3", @@ -13515,7 +13515,7 @@ "meow": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", "requires": { "camelcase-keys": "^2.0.0", "decamelize": "^1.1.2", @@ -13532,7 +13532,7 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "merge-stream": { "version": "2.0.0", @@ -13549,7 +13549,7 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "mgrs": { "version": "1.0.0", @@ -13828,12 +13828,12 @@ "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==" }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -13845,14 +13845,14 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==" } } }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", "requires": { "abbrev": "1" } @@ -14026,7 +14026,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==" }, "nwsapi": { "version": "2.2.7", @@ -14042,7 +14042,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-hash": { "version": "3.0.0", @@ -14143,18 +14143,18 @@ "dev": true }, "oidc-client-ts": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-2.3.0.tgz", - "integrity": "sha512-7RUKU+TJFQo+4X9R50IGJAIDF18uRBaFXyZn4VVCfwmwbSUhKcdDnw4zgeut3uEXkiD3NqURq+d88sDPxjf1FA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-2.4.0.tgz", + "integrity": "sha512-WijhkTrlXK2VvgGoakWJiBdfIsVGz6CFzgjNNqZU1hPKV2kyeEaJgLs7RwuiSp2WhLfWBQuLvr2SxVlZnk3N1w==", "requires": { - "crypto-js": "^4.1.1", + "crypto-js": "^4.2.0", "jwt-decode": "^3.1.2" } }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "requires": { "ee-first": "1.1.1" } @@ -14168,7 +14168,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } @@ -14210,12 +14210,12 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==" }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" }, "osenv": { "version": "0.1.5", @@ -14330,7 +14330,7 @@ "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "requires": { "pinkie-promise": "^2.0.0" } @@ -14338,7 +14338,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "3.1.1", @@ -14354,7 +14354,7 @@ "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "path-type": { "version": "4.0.0", @@ -14364,7 +14364,7 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "picocolors": { "version": "1.0.0", @@ -14385,17 +14385,17 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==" }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "requires": { "pinkie": "^2.0.0" } @@ -15410,7 +15410,7 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" }, "psl": { "version": "1.9.0", @@ -16896,7 +16896,7 @@ "read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" @@ -17121,7 +17121,7 @@ "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==", "requires": { "is-finite": "^1.0.0" } @@ -17168,7 +17168,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, "require-from-string": { "version": "2.0.2", @@ -17467,7 +17467,7 @@ "scss-tokenizer": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", - "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "integrity": "sha512-dYE8LhncfBUar6POCxMTm0Ln+erjeczqEvCJib5/7XNkdw1FkUGgwMPY360FY0FgPWQxHWCx29Jl3oejyGLM9Q==", "requires": { "js-base64": "^2.1.8", "source-map": "^0.4.2" @@ -17476,7 +17476,7 @@ "source-map": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "integrity": "sha512-Y8nIfcb1s/7DcobUz1yOO1GSp7gyL+D9zLHDehT7iRESqGSxjJ448Sg7rvfgsRJCnKLdSl11uGf0s9X80cH0/A==", "requires": { "amdefine": ">=0.0.4" } @@ -17624,7 +17624,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "setprototypeof": { "version": "1.2.0", @@ -17666,7 +17666,7 @@ "lru-cache": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" + "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==" } } }, @@ -17722,7 +17722,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" }, "source-map-js": { "version": "1.0.2", @@ -17903,7 +17903,7 @@ "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" }, "stdout-stream": { "version": "1.4.1", @@ -17981,7 +17981,7 @@ "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -18073,7 +18073,7 @@ "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "requires": { "ansi-regex": "^2.0.0" } @@ -18081,7 +18081,7 @@ "strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", "requires": { "is-utf8": "^0.2.0" } @@ -18510,7 +18510,7 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, "to-regex-range": { "version": "5.0.1", @@ -18559,7 +18559,7 @@ "toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=" + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" }, "tough-cookie": { "version": "2.5.0", @@ -18582,7 +18582,7 @@ "trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==" }, "true-case-path": { "version": "1.0.3", @@ -18658,7 +18658,7 @@ "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "requires": { "safe-buffer": "^5.0.1" } @@ -18671,7 +18671,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" }, "type-check": { "version": "0.4.0", @@ -18817,7 +18817,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, "unquote": { "version": "1.1.1", @@ -18874,7 +18874,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "util.promisify": { "version": "1.0.1", @@ -18897,7 +18897,7 @@ "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "uuid": { "version": "8.3.2", @@ -18932,12 +18932,12 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -19639,7 +19639,7 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" }, "string-width": { "version": "3.1.0", @@ -19664,7 +19664,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "write-file-atomic": { "version": "4.0.2", @@ -19685,7 +19685,7 @@ "xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", "dev": true }, "xml-name-validator": { @@ -19748,7 +19748,7 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" }, "string-width": { "version": "3.1.0", diff --git a/app/src/components/fields/StartEndTimeFields.tsx b/app/src/components/fields/StartEndTimeFields.tsx index 827b342460..61c17b265d 100644 --- a/app/src/components/fields/StartEndTimeFields.tsx +++ b/app/src/components/fields/StartEndTimeFields.tsx @@ -1,7 +1,7 @@ import { mdiClockOutline, mdiClockPlusOutline } from '@mdi/js'; import Icon from '@mdi/react'; import Grid from '@mui/material/Grid'; -import { LocalizationProvider, TimePicker } from '@mui/x-date-pickers'; +import { LocalizationProvider, renderTimeViewClock, TimePicker } from '@mui/x-date-pickers'; import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment'; import { TIME_FORMAT } from 'constants/dateTimeFormats'; import get from 'lodash-es/get'; @@ -94,6 +94,11 @@ const StartEndTimeFields: React.FC = (props) => { setFieldValue(startName, moment(value).format(TIME_FORMAT.ShortTimeFormatAmPm)); }} + viewRenderers={{ + hours: renderTimeViewClock, + minutes: renderTimeViewClock, + seconds: renderTimeViewClock + }} /> @@ -131,6 +136,11 @@ const StartEndTimeFields: React.FC = (props) => { setFieldValue(endName, moment(value).format(TIME_FORMAT.ShortTimeFormatAmPm)); }} + viewRenderers={{ + hours: renderTimeViewClock, + minutes: renderTimeViewClock, + seconds: renderTimeViewClock + }} /> diff --git a/app/src/features/surveys/components/SamplingMethodForm.tsx b/app/src/features/surveys/components/SamplingMethodForm.tsx index a76447c285..601cb72626 100644 --- a/app/src/features/surveys/components/SamplingMethodForm.tsx +++ b/app/src/features/surveys/components/SamplingMethodForm.tsx @@ -1,4 +1,4 @@ -import { mdiCalendarRangeOutline, mdiPencilOutline, mdiPlus, mdiTrashCanOutline } from '@mdi/js'; +import { mdiCalendarRangeOutline, mdiClockOutline, mdiPencilOutline, mdiPlus, mdiTrashCanOutline } from '@mdi/js'; import Icon from '@mdi/react'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import Alert from '@mui/material/Alert'; @@ -190,6 +190,16 @@ const SamplingMethodForm = () => { + {period.start_time && ( + <> + + + + + + )} ))} diff --git a/app/src/features/surveys/observations/sampling-sites/SamplingSiteList.tsx b/app/src/features/surveys/observations/sampling-sites/SamplingSiteList.tsx index a3927902f5..cad954ac99 100644 --- a/app/src/features/surveys/observations/sampling-sites/SamplingSiteList.tsx +++ b/app/src/features/surveys/observations/sampling-sites/SamplingSiteList.tsx @@ -339,8 +339,8 @@ const SamplingSiteList = () => { diff --git a/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx b/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx index b93dcda8a1..c43aa8e2ed 100644 --- a/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx +++ b/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx @@ -202,7 +202,9 @@ const SampleMethodEditForm = (props: SampleMethodEditFormProps) => { - + )} From 80c78483f1ac955b32b76bf76009008e95d7446c Mon Sep 17 00:00:00 2001 From: Alfred Rosenthal Date: Tue, 7 Nov 2023 09:29:43 -0800 Subject: [PATCH 4/8] added new date time fields component --- app/src/components/fields/DateTimeFields.tsx | 142 ++++++++++++++++++ .../surveys/components/MethodForm.tsx | 42 ++++-- .../sampling-sites/SamplingSiteList.tsx | 19 +-- 3 files changed, 173 insertions(+), 30 deletions(-) create mode 100644 app/src/components/fields/DateTimeFields.tsx diff --git a/app/src/components/fields/DateTimeFields.tsx b/app/src/components/fields/DateTimeFields.tsx new file mode 100644 index 0000000000..075a8c269a --- /dev/null +++ b/app/src/components/fields/DateTimeFields.tsx @@ -0,0 +1,142 @@ +import { mdiCalendarStart } from '@mdi/js'; +import Icon from '@mdi/react'; +import Grid from '@mui/material/Grid'; +import { DatePicker, renderTimeViewClock, TimePicker } from '@mui/x-date-pickers'; +import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { DATE_FORMAT, DATE_LIMIT, TIME_FORMAT } from 'constants/dateTimeFormats'; +import get from 'lodash-es/get'; +import moment from 'moment'; +import React from 'react'; + +interface IDateTimeFieldsProps { + date: { + dateLabel: string; + dateName: string; + dateId: string; + dateRequired: boolean; + dateHelperText?: string; + }; + time: { + timeLabel: string; + timeName: string; + timeId: string; + timeRequired: boolean; + timeHelperText?: string; + }; + formikProps: any; +} + +const CalendarStartIcon = () => { + return ; +}; + +export const DateTimeFields: React.FC = (props) => { + const { + formikProps: { values, errors, touched, setFieldValue }, + date: { dateName, dateId, dateRequired, dateHelperText, dateLabel }, + time: { timeLabel, timeName, timeId, timeRequired, timeHelperText } + } = props; + + const rawDateValue = get(values, dateName); + const formattedDateValue = + (rawDateValue && + moment(rawDateValue, DATE_FORMAT.ShortDateFormat).isValid() && + moment(rawDateValue, DATE_FORMAT.ShortDateFormat)) || + null; + + const rawTimeValue = get(values, timeName); + const formattedTimeValue = + (rawTimeValue && + moment(rawTimeValue, TIME_FORMAT.ShortTimeFormatAmPm).isValid() && + moment(rawTimeValue, TIME_FORMAT.ShortTimeFormatAmPm)) || + null; + + return ( + + + + { + if (!value || String(value.creationData().input) === 'Invalid Date') { + // The creation input value will be 'Invalid Date' when the date field is cleared (empty), and will + // contain an actual date string value if the field is not empty but is invalid. + setFieldValue(dateName, null); + return; + } + + setFieldValue(dateName, moment(value).format(DATE_FORMAT.ShortDateFormat)); + }} + /> + + + { + if (!value || String(value.creationData().input) === 'Invalid Time') { + // The creation input value will be 'Invalid Time' when the Time field is cleared (empty), and will + // contain an actual Time string value if the field is not empty but is invalid. + setFieldValue(timeName, null); + return; + } + + setFieldValue(timeName, moment(value).format(TIME_FORMAT.ShortTimeFormatAmPm)); + }} + viewRenderers={{ + hours: renderTimeViewClock, + minutes: renderTimeViewClock, + seconds: renderTimeViewClock + }} + /> + + + + ); +}; diff --git a/app/src/features/surveys/components/MethodForm.tsx b/app/src/features/surveys/components/MethodForm.tsx index 7ffbc3d891..6f0e5b34e4 100644 --- a/app/src/features/surveys/components/MethodForm.tsx +++ b/app/src/features/surveys/components/MethodForm.tsx @@ -1,5 +1,6 @@ -import { mdiPlus, mdiTrashCanOutline } from '@mdi/js'; +import { mdiCalendarStart, mdiPlus, mdiTrashCanOutline } from '@mdi/js'; import Icon from '@mdi/react'; +import { Grid } from '@mui/material'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import CircularProgress from '@mui/material/CircularProgress'; @@ -13,9 +14,11 @@ import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction'; import MenuItem from '@mui/material/MenuItem'; import Select from '@mui/material/Select'; import Typography from '@mui/material/Typography'; +import { DatePicker, TimePicker } from '@mui/x-date-pickers'; +import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import CustomTextField from 'components/fields/CustomTextField'; -import StartEndDateFields from 'components/fields/StartEndDateFields'; -import StartEndTimeFields from 'components/fields/StartEndTimeFields'; +import { DateTimeFields } from 'components/fields/DateTimeFields'; import { CodesContext } from 'contexts/codesContext'; import { FieldArray, FieldArrayRenderProps, useFormikContext } from 'formik'; import get from 'lodash-es/get'; @@ -163,24 +166,31 @@ const MethodForm = () => { } }}> - - + + }} formikProps={formikProps} - startName={`periods[${index}].start_date`} - endName={`periods[${index}].end_date`} - startRequired={true} - endRequired={true} /> - + + + + + + + + + + { + primary={samplePeriod.start_date} + secondary={samplePeriod.start_time || '\u00A0'}> - {samplePeriod.start_time && ( - <> - - - - - - )} + ); })} From 1182a3ba837ab0dde4546501daaf25cf617486b2 Mon Sep 17 00:00:00 2001 From: Kjartan Date: Tue, 7 Nov 2023 10:16:43 -0800 Subject: [PATCH 5/8] Implement new dateTimeFields --- app/src/components/fields/DateTimeFields.tsx | 27 +++++---- app/src/constants/dateTimeFormats.ts | 3 +- .../surveys/components/MethodForm.tsx | 58 +++++++++++++------ 3 files changed, 57 insertions(+), 31 deletions(-) diff --git a/app/src/components/fields/DateTimeFields.tsx b/app/src/components/fields/DateTimeFields.tsx index 075a8c269a..af31d80fcc 100644 --- a/app/src/components/fields/DateTimeFields.tsx +++ b/app/src/components/fields/DateTimeFields.tsx @@ -1,4 +1,3 @@ -import { mdiCalendarStart } from '@mdi/js'; import Icon from '@mdi/react'; import Grid from '@mui/material/Grid'; import { DatePicker, renderTimeViewClock, TimePicker } from '@mui/x-date-pickers'; @@ -16,6 +15,7 @@ interface IDateTimeFieldsProps { dateId: string; dateRequired: boolean; dateHelperText?: string; + dateIcon: string; }; time: { timeLabel: string; @@ -23,21 +23,26 @@ interface IDateTimeFieldsProps { timeId: string; timeRequired: boolean; timeHelperText?: string; + timeIcon: string; }; formikProps: any; } -const CalendarStartIcon = () => { - return ; -}; - export const DateTimeFields: React.FC = (props) => { const { formikProps: { values, errors, touched, setFieldValue }, - date: { dateName, dateId, dateRequired, dateHelperText, dateLabel }, - time: { timeLabel, timeName, timeId, timeRequired, timeHelperText } + date: { dateLabel, dateName, dateId, dateRequired, dateHelperText, dateIcon }, + time: { timeLabel, timeName, timeId, timeRequired, timeHelperText, timeIcon } } = props; + const DateIcon = () => { + return ; + }; + + const TimeIcon = () => { + return ; + }; + const rawDateValue = get(values, dateName); const formattedDateValue = (rawDateValue && @@ -58,7 +63,7 @@ export const DateTimeFields: React.FC = (props) => { = (props) => { = (props) => { } }} label={timeLabel} - format={TIME_FORMAT.ShortTimeFormatAmPm} + format={TIME_FORMAT.LongTimeFormat24Hour} value={formattedTimeValue} onChange={(value: moment.Moment | null) => { if (!value || String(value.creationData().input) === 'Invalid Time') { @@ -127,7 +132,7 @@ export const DateTimeFields: React.FC = (props) => { return; } - setFieldValue(timeName, moment(value).format(TIME_FORMAT.ShortTimeFormatAmPm)); + setFieldValue(timeName, moment(value).format(TIME_FORMAT.LongTimeFormat24Hour)); }} viewRenderers={{ hours: renderTimeViewClock, diff --git a/app/src/constants/dateTimeFormats.ts b/app/src/constants/dateTimeFormats.ts index 99b4c384bb..c7530d922f 100644 --- a/app/src/constants/dateTimeFormats.ts +++ b/app/src/constants/dateTimeFormats.ts @@ -30,5 +30,6 @@ export enum DATE_LIMIT { * */ export enum TIME_FORMAT { - ShortTimeFormatAmPm = 'hh:mm A' //11:00 AM + ShortTimeFormatAmPm = 'hh:mm A', //11:00 AM + LongTimeFormat24Hour = 'HH:mm:ss' //23:00 } diff --git a/app/src/features/surveys/components/MethodForm.tsx b/app/src/features/surveys/components/MethodForm.tsx index 6f0e5b34e4..e14b2cac7b 100644 --- a/app/src/features/surveys/components/MethodForm.tsx +++ b/app/src/features/surveys/components/MethodForm.tsx @@ -1,6 +1,12 @@ -import { mdiCalendarStart, mdiPlus, mdiTrashCanOutline } from '@mdi/js'; +import { + mdiCalendarEnd, + mdiCalendarStart, + mdiClockOutline, + mdiClockTimeOneOutline, + mdiPlus, + mdiTrashCanOutline +} from '@mdi/js'; import Icon from '@mdi/react'; -import { Grid } from '@mui/material'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import CircularProgress from '@mui/material/CircularProgress'; @@ -14,9 +20,6 @@ import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction'; import MenuItem from '@mui/material/MenuItem'; import Select from '@mui/material/Select'; import Typography from '@mui/material/Typography'; -import { DatePicker, TimePicker } from '@mui/x-date-pickers'; -import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment'; -import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import CustomTextField from 'components/fields/CustomTextField'; import { DateTimeFields } from 'components/fields/DateTimeFields'; import { CodesContext } from 'contexts/codesContext'; @@ -169,28 +172,45 @@ const MethodForm = () => { + dateIcon: mdiCalendarStart + }} + time={{ + timeLabel: 'Start Time', + timeName: `periods[${index}].start_time`, + timeId: String(index), + timeRequired: false, + timeHelperText: '', + timeIcon: mdiClockTimeOneOutline }} formikProps={formikProps} /> - - - - - - - - - - + Date: Tue, 7 Nov 2023 10:36:51 -0800 Subject: [PATCH 6/8] remove unused file --- .../components/fields/StartEndTimeFields.tsx | 151 ------------------ app/src/constants/dateTimeFormats.ts | 2 +- 2 files changed, 1 insertion(+), 152 deletions(-) delete mode 100644 app/src/components/fields/StartEndTimeFields.tsx diff --git a/app/src/components/fields/StartEndTimeFields.tsx b/app/src/components/fields/StartEndTimeFields.tsx deleted file mode 100644 index 61c17b265d..0000000000 --- a/app/src/components/fields/StartEndTimeFields.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { mdiClockOutline, mdiClockPlusOutline } from '@mdi/js'; -import Icon from '@mdi/react'; -import Grid from '@mui/material/Grid'; -import { LocalizationProvider, renderTimeViewClock, TimePicker } from '@mui/x-date-pickers'; -import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment'; -import { TIME_FORMAT } from 'constants/dateTimeFormats'; -import get from 'lodash-es/get'; -import moment from 'moment'; -import React from 'react'; - -interface IStartEndTimeFieldsProps { - formikProps: any; - startName: string; - endName: string; - startRequired: boolean; - endRequired: boolean; - startTimeHelperText?: string; - endTimeHelperText?: string; -} - -const TimeStartIcon = () => { - return ; -}; - -const TimeEndIcon = () => { - return ; -}; - -/** - * Start/end Time fields - commonly used throughout forms - * - */ -const StartEndTimeFields: React.FC = (props) => { - const { - formikProps: { values, errors, touched, setFieldValue }, - startName, - endName, - startRequired, - endRequired, - startTimeHelperText, - endTimeHelperText - } = props; - - const rawStartTimeValue = get(values, startName); - const rawEndTimeValue = get(values, endName); - - const formattedStartTimeValue = - (rawStartTimeValue && - moment(rawStartTimeValue, TIME_FORMAT.ShortTimeFormatAmPm).isValid() && - moment(rawStartTimeValue, TIME_FORMAT.ShortTimeFormatAmPm)) || - null; - - const formattedEndTimeValue = - (rawEndTimeValue && - moment(rawEndTimeValue, TIME_FORMAT.ShortTimeFormatAmPm).isValid() && - moment(rawEndTimeValue, TIME_FORMAT.ShortTimeFormatAmPm)) || - null; - - return ( - - - - { - if (!value || String(value.creationData().input) === 'Invalid Time') { - // The creation input value will be 'Invalid Time' when the Time field is cleared (empty), and will - // contain an actual Time string value if the field is not empty but is invalid. - setFieldValue(startName, null); - return; - } - - setFieldValue(startName, moment(value).format(TIME_FORMAT.ShortTimeFormatAmPm)); - }} - viewRenderers={{ - hours: renderTimeViewClock, - minutes: renderTimeViewClock, - seconds: renderTimeViewClock - }} - /> - - - { - if (!value || String(value.creationData().input) === 'Invalid Time') { - // The creation input value will be 'Invalid Time' when the Time field is cleared (empty), and will - // contain an actual Time string value if the field is not empty but is invalid. - setFieldValue(endName, null); - return; - } - - setFieldValue(endName, moment(value).format(TIME_FORMAT.ShortTimeFormatAmPm)); - }} - viewRenderers={{ - hours: renderTimeViewClock, - minutes: renderTimeViewClock, - seconds: renderTimeViewClock - }} - /> - - - - ); -}; - -export default StartEndTimeFields; diff --git a/app/src/constants/dateTimeFormats.ts b/app/src/constants/dateTimeFormats.ts index c7530d922f..5373bfe342 100644 --- a/app/src/constants/dateTimeFormats.ts +++ b/app/src/constants/dateTimeFormats.ts @@ -31,5 +31,5 @@ export enum DATE_LIMIT { */ export enum TIME_FORMAT { ShortTimeFormatAmPm = 'hh:mm A', //11:00 AM - LongTimeFormat24Hour = 'HH:mm:ss' //23:00 + LongTimeFormat24Hour = 'HH:mm:ss' //23:00:00 } From 8b390ad687cfb5020751672cb926562b24d15235 Mon Sep 17 00:00:00 2001 From: Kjartan Date: Tue, 7 Nov 2023 14:17:40 -0800 Subject: [PATCH 7/8] PR review edits --- app/src/components/fields/DateTimeFields.tsx | 18 ++++++++--------- .../surveys/components/EditSamplingMethod.tsx | 20 +------------------ .../surveys/components/MethodForm.tsx | 19 +++++++++++++++++- .../surveys/components/SamplingMethodForm.tsx | 4 ++++ .../edit/components/SampleMethodEditForm.tsx | 10 +++++++++- 5 files changed, 40 insertions(+), 31 deletions(-) diff --git a/app/src/components/fields/DateTimeFields.tsx b/app/src/components/fields/DateTimeFields.tsx index af31d80fcc..6a903577c4 100644 --- a/app/src/components/fields/DateTimeFields.tsx +++ b/app/src/components/fields/DateTimeFields.tsx @@ -1,9 +1,11 @@ import Icon from '@mdi/react'; import Grid from '@mui/material/Grid'; -import { DatePicker, renderTimeViewClock, TimePicker } from '@mui/x-date-pickers'; +import { DatePicker, TimePicker } from '@mui/x-date-pickers'; import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { DATE_FORMAT, DATE_LIMIT, TIME_FORMAT } from 'constants/dateTimeFormats'; +import { ISurveySampleMethodData } from 'features/surveys/components/MethodForm'; +import { FormikContextType } from 'formik'; import get from 'lodash-es/get'; import moment from 'moment'; import React from 'react'; @@ -25,7 +27,7 @@ interface IDateTimeFieldsProps { timeHelperText?: string; timeIcon: string; }; - formikProps: any; + formikProps: FormikContextType; } export const DateTimeFields: React.FC = (props) => { @@ -125,20 +127,16 @@ export const DateTimeFields: React.FC = (props) => { format={TIME_FORMAT.LongTimeFormat24Hour} value={formattedTimeValue} onChange={(value: moment.Moment | null) => { - if (!value || String(value.creationData().input) === 'Invalid Time') { - // The creation input value will be 'Invalid Time' when the Time field is cleared (empty), and will - // contain an actual Time string value if the field is not empty but is invalid. + if (!value || !moment(value).isValid()) { + // Check if the value is null or invalid, and if so, clear the field. setFieldValue(timeName, null); return; } setFieldValue(timeName, moment(value).format(TIME_FORMAT.LongTimeFormat24Hour)); }} - viewRenderers={{ - hours: renderTimeViewClock, - minutes: renderTimeViewClock, - seconds: renderTimeViewClock - }} + views={['hours', 'minutes', 'seconds']} + timeSteps={{ hours: 1, minutes: 1, seconds: 1 }} /> diff --git a/app/src/features/surveys/components/EditSamplingMethod.tsx b/app/src/features/surveys/components/EditSamplingMethod.tsx index 84577589f7..7cd4797498 100644 --- a/app/src/features/surveys/components/EditSamplingMethod.tsx +++ b/app/src/features/surveys/components/EditSamplingMethod.tsx @@ -1,8 +1,8 @@ import EditDialog from 'components/dialog/EditDialog'; -import yup from 'utils/YupSchema'; import MethodForm, { IEditSurveySampleMethodData, ISurveySampleMethodData, + SamplingSiteMethodYupSchema, SurveySampleMethodDataInitialValues } from './MethodForm'; @@ -13,24 +13,6 @@ interface IEditSamplingMethodProps { onClose: () => void; } -export const SamplingSiteMethodYupSchema = yup.object({ - method_lookup_id: yup.number().required(), - description: yup.string(), - periods: yup - .array( - yup.object({ - start_date: yup.string().isValidDateString().required('Start date is required'), - end_date: yup - .string() - .isValidDateString() - .isEndDateSameOrAfterStartDate('start_date') - .required('End date is required') - }) - ) - .hasUniqueDateRanges('Periods cannot overlap', 'start_date', 'end_date') - .min(1, 'At least one time period is required') -}); - const EditSamplingMethod: React.FC = (props) => { const { open, initialData, onSubmit, onClose } = props; return ( diff --git a/app/src/features/surveys/components/MethodForm.tsx b/app/src/features/surveys/components/MethodForm.tsx index e14b2cac7b..1e42e53738 100644 --- a/app/src/features/surveys/components/MethodForm.tsx +++ b/app/src/features/surveys/components/MethodForm.tsx @@ -25,6 +25,7 @@ import { DateTimeFields } from 'components/fields/DateTimeFields'; import { CodesContext } from 'contexts/codesContext'; import { FieldArray, FieldArrayRenderProps, useFormikContext } from 'formik'; import get from 'lodash-es/get'; +import moment from 'moment'; import { useContext, useEffect } from 'react'; import yup from 'utils/YupSchema'; @@ -85,7 +86,23 @@ export const SamplingSiteMethodYupSchema = yup.object({ .required('End Date is required') .isEndDateSameOrAfterStartDate('start_date'), start_time: yup.string().nullable(), - end_time: yup.string().nullable() + end_time: yup + .string() + .nullable() + .test( + 'checkDatesAreSameAndEndTimeIsAfterStart', + 'End Date and Time must be after Start Date and Time', + function (value) { + const { start_date, end_date, start_time } = this.parent; + if (start_date === end_date && start_time && value) { + const val = moment(`${start_date} ${start_time}`, 'YYYY-MM-DD HH:mm:ss').isBefore( + moment(`${end_date} ${value}`, 'YYYY-MM-DD HH:mm:ss') + ); + return val; + } + return true; + } + ) }) ) .hasUniqueDateRanges('Periods cannot overlap', 'start_date', 'end_date') diff --git a/app/src/features/surveys/components/SamplingMethodForm.tsx b/app/src/features/surveys/components/SamplingMethodForm.tsx index 601cb72626..3ed6dd5f8a 100644 --- a/app/src/features/surveys/components/SamplingMethodForm.tsx +++ b/app/src/features/surveys/components/SamplingMethodForm.tsx @@ -62,9 +62,11 @@ const SamplingMethodForm = () => { onSubmit={(data) => { setFieldValue(`methods[${values.methods.length}]`, data); validateField('methods'); + setAnchorEl(null); setIsCreateModalOpen(false); }} onClose={() => { + setAnchorEl(null); setIsCreateModalOpen(false); }} /> @@ -75,9 +77,11 @@ const SamplingMethodForm = () => { open={isEditModalOpen} onSubmit={(data, index) => { setFieldValue(`methods[${index}]`, data); + setAnchorEl(null); setIsEditModalOpen(false); }} onClose={() => { + setAnchorEl(null); setIsEditModalOpen(false); }} /> diff --git a/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx b/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx index c43aa8e2ed..94e71a3b76 100644 --- a/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx +++ b/app/src/features/surveys/observations/sampling-sites/edit/components/SampleMethodEditForm.tsx @@ -68,9 +68,11 @@ const SampleMethodEditForm = (props: SampleMethodEditFormProps) => { onSubmit={(data) => { setFieldValue(`${name}[${values.sampleSite.methods.length}]`, data); validateField(`${name}`); + setAnchorEl(null); setIsCreateModalOpen(false); }} onClose={() => { + setAnchorEl(null); setIsCreateModalOpen(false); }} /> @@ -81,9 +83,11 @@ const SampleMethodEditForm = (props: SampleMethodEditFormProps) => { open={isEditModalOpen} onSubmit={(data, index) => { setFieldValue(`${name}[${index}]`, data); + setAnchorEl(null); setIsEditModalOpen(false); }} onClose={() => { + setAnchorEl(null); setIsEditModalOpen(false); }} /> @@ -100,7 +104,11 @@ const SampleMethodEditForm = (props: SampleMethodEditFormProps) => { vertical: 'top', horizontal: 'right' }}> - setIsEditModalOpen(true)}> + { + setIsEditModalOpen(true); + }}> From f91231dcba48471c5cb019412785a83ebbe873cc Mon Sep 17 00:00:00 2001 From: Alfred Rosenthal Date: Tue, 7 Nov 2023 15:20:44 -0800 Subject: [PATCH 8/8] updated edit process and reworded error message --- app/src/components/fields/DateTimeFields.tsx | 4 ++-- .../surveys/components/MethodForm.tsx | 22 ++++++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/app/src/components/fields/DateTimeFields.tsx b/app/src/components/fields/DateTimeFields.tsx index 6a903577c4..372c613570 100644 --- a/app/src/components/fields/DateTimeFields.tsx +++ b/app/src/components/fields/DateTimeFields.tsx @@ -55,8 +55,8 @@ export const DateTimeFields: React.FC = (props) => { const rawTimeValue = get(values, timeName); const formattedTimeValue = (rawTimeValue && - moment(rawTimeValue, TIME_FORMAT.ShortTimeFormatAmPm).isValid() && - moment(rawTimeValue, TIME_FORMAT.ShortTimeFormatAmPm)) || + moment(rawTimeValue, TIME_FORMAT.LongTimeFormat24Hour).isValid() && + moment(rawTimeValue, TIME_FORMAT.LongTimeFormat24Hour)) || null; return ( diff --git a/app/src/features/surveys/components/MethodForm.tsx b/app/src/features/surveys/components/MethodForm.tsx index 1e42e53738..ebd9c3d235 100644 --- a/app/src/features/surveys/components/MethodForm.tsx +++ b/app/src/features/surveys/components/MethodForm.tsx @@ -89,20 +89,16 @@ export const SamplingSiteMethodYupSchema = yup.object({ end_time: yup .string() .nullable() - .test( - 'checkDatesAreSameAndEndTimeIsAfterStart', - 'End Date and Time must be after Start Date and Time', - function (value) { - const { start_date, end_date, start_time } = this.parent; - if (start_date === end_date && start_time && value) { - const val = moment(`${start_date} ${start_time}`, 'YYYY-MM-DD HH:mm:ss').isBefore( - moment(`${end_date} ${value}`, 'YYYY-MM-DD HH:mm:ss') - ); - return val; - } - return true; + .test('checkDatesAreSameAndEndTimeIsAfterStart', 'End time must be after Start time', function (value) { + const { start_date, end_date, start_time } = this.parent; + if (start_date === end_date && start_time && value) { + const val = moment(`${start_date} ${start_time}`, 'YYYY-MM-DD HH:mm:ss').isBefore( + moment(`${end_date} ${value}`, 'YYYY-MM-DD HH:mm:ss') + ); + return val; } - ) + return true; + }) }) ) .hasUniqueDateRanges('Periods cannot overlap', 'start_date', 'end_date')