diff --git a/package-lock.json b/package-lock.json
index 879d42f..66aeb5f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,12 +18,13 @@
"axios": "^1.6.7",
"bootstrap": "^5.3.2",
"bootstrap-css": "^4.0.0-alpha.5",
+ "date-fns": "^4.1.0",
+ "date-fns-tz": "^3.2.0",
"formik": "^2.4.5",
"json-schema-to-typescript": "^13.1.2",
"jsonpath": "^1.1.1",
"lodash": "^4.17.21",
"markdown-it": "^14.1.0",
- "moment": "^2.30.1",
"react": "^18.3.1",
"react-bootstrap": "^2.10.1",
"react-countup": "^6.5.3",
@@ -4333,15 +4334,24 @@
}
},
"node_modules/date-fns": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
- "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
+ "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
+ "node_modules/date-fns-tz": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.2.0.tgz",
+ "integrity": "sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "date-fns": "^3.0.0 || ^4.0.0"
+ }
+ },
"node_modules/debug": {
"version": "4.3.7",
"license": "MIT",
@@ -7204,13 +7214,6 @@
"ufo": "^1.5.3"
}
},
- "node_modules/moment": {
- "version": "2.30.1",
- "license": "MIT",
- "engines": {
- "node": "*"
- }
- },
"node_modules/ms": {
"version": "2.1.3",
"license": "MIT"
@@ -7946,6 +7949,16 @@
"react-dom": "^16.9.0 || ^17 || ^18"
}
},
+ "node_modules/react-datepicker/node_modules/date-fns": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
+ "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/kossnocorp"
+ }
+ },
"node_modules/react-devtools-inline": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/react-devtools-inline/-/react-devtools-inline-4.4.0.tgz",
diff --git a/package.json b/package.json
index 7eb5bfa..9541868 100644
--- a/package.json
+++ b/package.json
@@ -22,12 +22,13 @@
"axios": "^1.6.7",
"bootstrap": "^5.3.2",
"bootstrap-css": "^4.0.0-alpha.5",
+ "date-fns": "^4.1.0",
+ "date-fns-tz": "^3.2.0",
"formik": "^2.4.5",
"json-schema-to-typescript": "^13.1.2",
"jsonpath": "^1.1.1",
"lodash": "^4.17.21",
"markdown-it": "^14.1.0",
- "moment": "^2.30.1",
"react": "^18.3.1",
"react-bootstrap": "^2.10.1",
"react-countup": "^6.5.3",
diff --git a/src/api/taxonomicService/GetTaxonomicService.ts b/src/api/taxonomicService/GetTaxonomicService.ts
index c61d793..d48acd2 100644
--- a/src/api/taxonomicService/GetTaxonomicService.ts
+++ b/src/api/taxonomicService/GetTaxonomicService.ts
@@ -1,6 +1,6 @@
/* Import Dependencies */
import axios from 'axios';
-import moment from 'moment';
+import { format } from 'date-fns';
/* Import Types */
import { TaxonomicService, CordraResult } from 'app/Types';
@@ -39,8 +39,8 @@ const GetTaxonomicService = async ({ handle }: { handle?: string }) => {
};
/* Set created and modified */
- taxonomicService.taxonomicService['schema:dateCreated'] = moment(new Date(data.attributes.metadata.createdOn)).format('YYYY-MM-DDTHH:mm:ss.sssZ');
- taxonomicService.taxonomicService['schema:dateModified'] = moment(new Date(data.attributes.metadata.modifiedOn)).format('YYYY-MM-DDTHH:mm:ss.sssZ');
+ taxonomicService.taxonomicService['schema:dateCreated'] = format(new Date(data.attributes.metadata.createdOn), "yyyy-MM-dd'T'HH:mm:ss.SSSxxx");
+ taxonomicService.taxonomicService['schema:dateModified'] = format(new Date(data.attributes.metadata.modifiedOn), "yyyy-MM-dd'T'HH:mm:ss.SSSxxx");
} catch (error) {
console.error(error);
diff --git a/src/api/taxonomicService/GetTaxonomicServices.ts b/src/api/taxonomicService/GetTaxonomicServices.ts
index f5a9bd0..846ffb4 100644
--- a/src/api/taxonomicService/GetTaxonomicServices.ts
+++ b/src/api/taxonomicService/GetTaxonomicServices.ts
@@ -1,6 +1,6 @@
/* Import Dependencies */
import axios from 'axios';
-import moment from 'moment';
+import { format } from 'date-fns';
import { isEmpty } from 'lodash';
/* Import Types */
@@ -86,8 +86,8 @@ const GetTaxonomicServices = async ({ pageNumber, pageSize, searchFilters }: { p
const taxonomicService = dataFragment.attributes.content as TaxonomicService;
/* Set created and modified */
- taxonomicService.taxonomicService['schema:dateCreated'] = moment(new Date(dataFragment.attributes.metadata.createdOn)).format('YYYY-MM-DDTHH:mm:ss.sssZ');
- taxonomicService.taxonomicService['schema:dateModified'] = moment(new Date(dataFragment.attributes.metadata.modifiedOn)).format('YYYY-MM-DDTHH:mm:ss.sssZ');
+ taxonomicService.taxonomicService['schema:dateCreated'] = format(new Date(dataFragment.attributes.metadata.createdOn), "yyyy-MM-dd'T'HH:mm:ss.SSSxxx");
+ taxonomicService.taxonomicService['schema:dateModified'] = format(new Date(dataFragment.attributes.metadata.modifiedOn), "yyyy-MM-dd'T'HH:mm:ss.SSSxxx");
/* Push to taxonomic services array */
taxonomicServices.push(taxonomicService);
diff --git a/src/api/taxonomicService/InsertTaxonomicService.ts b/src/api/taxonomicService/InsertTaxonomicService.ts
index 2cfd0b8..747cfd7 100644
--- a/src/api/taxonomicService/InsertTaxonomicService.ts
+++ b/src/api/taxonomicService/InsertTaxonomicService.ts
@@ -1,6 +1,6 @@
/* Import Dependencies */
import axios from 'axios';
-import moment from 'moment';
+import { format } from 'date-fns';
/* Import Types */
import { TaxonomicService, CordraResult, Dict } from 'app/Types';
@@ -55,8 +55,8 @@ const InsertTaxonomicService = async ({ taxonomicServiceRecord }: { taxonomicSer
taxonomicService = data.attributes.content as TaxonomicService;
/* Set created and modified */
- taxonomicService.taxonomicService['schema:dateCreated'] = moment(new Date(data.attributes.metadata.createdOn)).format('YYYY-MM-DDTHH:mm:ss.sssZ');
- taxonomicService.taxonomicService['schema:dateModified'] = moment(new Date(data.attributes.metadata.modifiedOn)).format('YYYY-MM-DDTHH:mm:ss.sssZ');
+ taxonomicService.taxonomicService['schema:dateCreated'] = format(new Date(data.attributes.metadata.createdOn), "yyyy-MM-dd'T'HH:mm:ss.SSSxxx");
+ taxonomicService.taxonomicService['schema:dateModified'] = format(new Date(data.attributes.metadata.modifiedOn), "yyyy-MM-dd'T'HH:mm:ss.SSSxxx");
} catch (error) {
console.error(error);
diff --git a/src/components/search/components/SearchResult.tsx b/src/components/search/components/SearchResult.tsx
index 6e01730..189457a 100644
--- a/src/components/search/components/SearchResult.tsx
+++ b/src/components/search/components/SearchResult.tsx
@@ -1,7 +1,7 @@
/* Import Dependencies */
import { useNavigate } from 'react-router-dom';
import classNames from 'classnames';
-import moment from 'moment';
+import { format } from 'date-fns';
import { Row, Col } from 'react-bootstrap';
/* Import Hooks */
@@ -72,7 +72,7 @@ const SearchResult = (props: Props) => {
{(!previewImage || window.innerWidth < 768) &&
{taxonomicService.taxonomicService['schema:availableLanguage']?.join(' / ').toUpperCase()}
@@ -97,7 +97,9 @@ const SearchResult = (props: Props) => {
{(!previewImage || window.innerWidth < 768) &&
- {moment(taxonomicService.taxonomicService['schema:dateCreated']).format('MMM DD - YYYY')}
+ {taxonomicService.taxonomicService['schema:dateCreated'] &&
+ format(taxonomicService.taxonomicService['schema:dateCreated'], 'MMMM dd - yyyy')}
+
}
@@ -123,7 +125,9 @@ const SearchResult = (props: Props) => {
{/* Publishing Date */}
- {moment(taxonomicService.taxonomicService['schema:dateCreated']).format('MMM DD - YYYY')}
+ {taxonomicService.taxonomicService['schema:dateCreated'] &&
+ format(taxonomicService.taxonomicService['schema:dateCreated'], 'MMMM dd - yyyy')
+ }
diff --git a/src/components/taxonomicService/TaxonomicService.tsx b/src/components/taxonomicService/TaxonomicService.tsx
index e51ed33..3f63560 100644
--- a/src/components/taxonomicService/TaxonomicService.tsx
+++ b/src/components/taxonomicService/TaxonomicService.tsx
@@ -1,6 +1,6 @@
/* Import Dependencies */
import classNames from 'classnames';
-import moment from 'moment';
+import { format } from 'date-fns';
import { useState } from 'react';
import { Link, useParams } from 'react-router-dom';
import { Container, Row, Col } from 'react-bootstrap';
@@ -129,7 +129,7 @@ const TaxonomicService = () => {
licence: taxonomicService.taxonomicService['schema:license'],
sourceURL: taxonomicService.taxonomicService['schema:url'],
changeLog: taxonomicService.taxonomicService['schema:about'],
- datePublished: moment(taxonomicService.taxonomicService['schema:datePublished']).format('MMM DD - YYYY'),
+ datePublished: taxonomicService.taxonomicService['schema:datePublished'] && format(taxonomicService.taxonomicService['schema:datePublished'], 'MMMM dd - yyyy'),
availableOnAppStore: taxonomicService.taxonomicService['schema:additionalProperty']?.[1] as string[] | undefined,
documentationURL: taxonomicService.taxonomicService['schema:documentation'],
paymentModel: taxonomicService.taxonomicService['schema:additionalProperty']?.[2] as string | undefined,
diff --git a/src/components/taxonomicService/components/DescriptionBlock.tsx b/src/components/taxonomicService/components/DescriptionBlock.tsx
index 5e334c0..d109d03 100644
--- a/src/components/taxonomicService/components/DescriptionBlock.tsx
+++ b/src/components/taxonomicService/components/DescriptionBlock.tsx
@@ -1,7 +1,7 @@
/* Import Dependencies */
import classNames from 'classnames';
+import { format } from 'date-fns';
import MarkdownIt from 'markdown-it';
-import moment from 'moment';
import { Row, Col } from 'react-bootstrap';
/* Import Types */
@@ -82,7 +82,9 @@ const DescriptionBlock = (props: Props) => {
className="mt-2 mt-lg-0"
>
Publishing date
- {moment(taxonomicService.taxonomicService['schema:dateCreated']).format('MMM DD - YYYY')}
+ {taxonomicService.taxonomicService['schema:dateCreated'] &&
+ format(taxonomicService.taxonomicService['schema:dateCreated'], 'MMMM dd - yyyy')}
+
{/* Quality score */}
{
applicableToServiceTypes?: string[]
}
} = {};
+ const inactiveFormSections: {
+ [section: string]: {
+ type: string,
+ jsonPath: string,
+ fields: FormField[],
+ applicableToServiceTypes?: string[]
+ }
+ } = {};
const initialFormValues: Dict = {};
/**
@@ -105,14 +113,8 @@ const FormBuilder = (props: Props) => {
};
/* Construct initial form values */
- Object.entries(formTemplate).forEach(([_key, formSection]) => {
- if ((serviceType && formSection.applicableToServiceTypes?.includes(serviceType)) || !formSection.applicableToServiceTypes) {
- formSections[formSection.title] = {
- type: formSection.type,
- jsonPath: formSection.jsonPath ?? '',
- fields: []
- };
-
+ if (isEmpty(initialFormValues)) {
+ Object.entries(formTemplate).forEach(([_key, formSection]) => {
/* If is array, push to initial form values */
if (formSection.type === 'array') {
jp.value(initialFormValues, formSection.jsonPath ?? '', []);
@@ -132,10 +134,36 @@ const FormBuilder = (props: Props) => {
/* Add to initial form values */
jp.value(initialFormValues, field.jsonPath, DetermineInitialFormValue(field.type, field.const));
}
+ });
+ });
+ }
+
+ /* Construct form sections */
+ Object.entries(formTemplate).forEach(([_key, formSection]) => {
+ if ((serviceType && formSection.applicableToServiceTypes?.includes(serviceType)) || !formSection.applicableToServiceTypes || !serviceType) {
+ formSections[formSection.title] = {
+ type: formSection.type,
+ jsonPath: formSection.jsonPath ?? '',
+ fields: [],
+ applicableToServiceTypes: formSection.applicableToServiceTypes
+ };
+ formSection.fields.forEach(field => {
/* Push to form fields */
formSections[formSection.title].fields.push(field);
});
+ } else {
+ inactiveFormSections[formSection.title] = {
+ type: formSection.type,
+ jsonPath: formSection.jsonPath ?? '',
+ fields: [],
+ applicableToServiceTypes: formSection.applicableToServiceTypes
+ };
+
+ formSection.fields.forEach(field => {
+ /* Push to form fields */
+ inactiveFormSections[formSection.title].fields.push(field);
+ });
}
});
@@ -207,10 +235,21 @@ const FormBuilder = (props: Props) => {
};
};
+ /**
+ * Function to remove irrelevant classes from the form values object
+ * @param obj The form values object
+ */
+ const CheckForIrrelevantClasses = (obj: Dict) => {
+ Object.keys(obj).forEach(key => {
+ if (Object.values(inactiveFormSections).find(values => values.jsonPath === `$['${key}']`)) {
+ delete obj[key];
+ }
+ });
+ };
+
return (
{
await new Promise((resolve) => setTimeout(resolve, 100));
@@ -246,21 +285,27 @@ const FormBuilder = (props: Props) => {
};
Object.values(formSections).forEach(formSection => {
- formSection.fields.filter(field => field.required).forEach(field => {
- if (field.jsonPath.includes('index')) {
- const array = jp.value(values, field.jsonPath.split("['index']").at(0) as string);
-
- ValidateArray(array);
- } else if (isEmpty(jp.value(values, field.jsonPath))) {
- validationFlag = false;
- }
- });
+ if ((formSection?.applicableToServiceTypes?.includes(values['schema:service']['schema:serviceType'])) || !formSection.applicableToServiceTypes) {
+ formSection.fields.filter(field => field.required).forEach(field => {
+ if (field.jsonPath.includes('index')) {
+ const array = jp.value(values, field.jsonPath.split("['index']").at(0) as string);
+
+ ValidateArray(array);
+ } else if (isEmpty(jp.value(values, field.jsonPath))) {
+ validationFlag = false;
+ }
+ });
+ }
});
if (validationFlag && captchaHook.captchaStatus.solution !== null) {
/* Start loading indication */
setLoading(true);
+ /**
+ * Function to search for and remove empty properties in the given form values object
+ * @param obj The form values object
+ */
const RemoveEmptyProperties = (obj: Dict) => {
for (const key in obj) {
if (isEmpty(obj[key]) || (Array.isArray(obj[key]) && !obj[key].find((value: string) => !!value))) {
@@ -274,6 +319,7 @@ const FormBuilder = (props: Props) => {
let taxonomicServiceRecord = cloneDeep(values);
RemoveEmptyProperties(taxonomicServiceRecord);
+ CheckForIrrelevantClasses(taxonomicServiceRecord);
try {
await InsertTaxonomicService({
diff --git a/src/sources/forms/TaxonomicServiceForm.json b/src/sources/forms/TaxonomicServiceForm.json
index de38473..7a4a41b 100644
--- a/src/sources/forms/TaxonomicServiceForm.json
+++ b/src/sources/forms/TaxonomicServiceForm.json
@@ -347,6 +347,16 @@
"type": "ror",
"required": true
}
+ ],
+ "applicableToServiceTypes": [
+ "AI training dataset",
+ "e-Learning service",
+ "Factsheet",
+ "Identification tool",
+ "Knowledge website",
+ "Mobile app",
+ "Reference collection",
+ "Specimen dataset not in GBIF"
]
},
"maintainer": {
@@ -382,33 +392,38 @@
"type": "ror",
"required": true
}
+ ],
+ "applicableToServiceTypes": [
+ "Data tool",
+ "Identification tool"
]
},
"funding": {
"title": "Funding",
+ "jsonPath": "$['schema:fundingScheme']",
"type": "object",
"fields": [
{
- "jsonPath": "$['schema:fundingscheme']['schema:award']",
+ "jsonPath": "$['schema:fundingScheme']['schema:award']",
"title": "Award",
"description": "An award won by or for this service",
"type": "string"
},
{
- "jsonPath": "$['schema:fundingscheme']['schema:funding']['schema:identifier']",
+ "jsonPath": "$['schema:fundingScheme']['schema:funding']['schema:identifier']",
"title": "Grant Identifier",
"description": "A unique identifier to identify the funder organisation; ROR identifiers are valid",
"type": "string",
"required": true
},
{
- "jsonPath": "$['schema:fundingscheme']['schema:funding']['schema:description']",
+ "jsonPath": "$['schema:fundingScheme']['schema:funding']['schema:description']",
"title": "Grant Description",
"description": "A description of the service's grant",
"type": "string"
},
{
- "jsonPath": "$['schema:fundingscheme']['schema:funding']['schema:funder']",
+ "jsonPath": "$['schema:fundingScheme']['schema:funding']['schema:funder']",
"title": "Funding Organisation",
"description": "An organization that supports (sponsors) something through some kind of financial contribution",
"type": "ror",
@@ -416,11 +431,22 @@
}
],
"applicableToServiceTypes": [
- "AI training dataset"
+ "AI training dataset",
+ "CrowdSourcing",
+ "Data tool",
+ "e-Learning service",
+ "Factsheet",
+ "Identification tool",
+ "Knowledge website",
+ "Mobile app",
+ "Service inventory",
+ "Reference collection",
+ "Specimen dataset not in GBIF"
]
},
"softwareSourceCode": {
"title": "Software Source Code",
+ "jsonPath": "$['schema:softwareSourceCode']",
"type": "object",
"fields": [
{
@@ -462,7 +488,8 @@
}
],
"applicableToServiceTypes": [
- "AI training dataset"
+ "Data tool",
+ "Identification tool"
]
},
"associatedMedia": {