diff --git a/src/api/ror/GetRORsByName.ts b/src/api/ror/GetRORsByName.ts new file mode 100644 index 0000000..639fb0e --- /dev/null +++ b/src/api/ror/GetRORsByName.ts @@ -0,0 +1,42 @@ +/* Import Dependencies */ +import axios from 'axios'; + +/* Import Types */ +import { Dict } from 'app/Types'; + + +/** + * Function that searches for and fetches ROR data from the ROR API by providing a query + * @param query The provided query to search by + * @returns + */ +const GetRORsByName = async ({ query }: { query?: string }) => { + let rors: Dict[] = []; + + if (query) { + try { + const result = await axios({ + baseURL: 'https://api.ror.org/v2', + method: 'get', + url: '/organizations', + params: { + query + }, + responseType: 'json' + }); + + /* Get result data from JSON */ + const data: any = result.data; + + rors = data.items; + } catch (error) { + console.error(error); + + throw (error); + } + }; + + return rors; +} + +export default GetRORsByName; \ No newline at end of file diff --git a/src/app/Types.ts b/src/app/Types.ts index a1d4f73..ce5d93c 100644 --- a/src/app/Types.ts +++ b/src/app/Types.ts @@ -37,13 +37,21 @@ export type TaxonomicService = { /* Type for an Agent */ export type Maintainer = { - "@type": string, - "schema:identifier"?: string | Dict[]; + "@type": string; + "schema:identifier": string | [{ + type: "string"; + description: "A unique identifier to identify the maintainer; GitHub identifiers are valid"; + examples: ["https://api.github.com/users/username"]; + }, { + type: "string"; + description: "A unique identifier to identify the maintainer; ORCID identifiers are valid"; + examples: ["https://orcid.org/0000-0001-9790-9277"]; + }]; "schema:name"?: string; "schema:Affiliation"?: { - "@type": string, - "schema:identifier"?: string; - "schema:legalName"?: string; + "@type": "schema:Organization"; + "schema:identifier": string; + "schema:name"?: string; }; } diff --git a/src/components/taxonomicService/taxonomicServiceFormComponents/FormBuilder.tsx b/src/components/taxonomicService/taxonomicServiceFormComponents/FormBuilder.tsx index 1241aff..316d5dc 100644 --- a/src/components/taxonomicService/taxonomicServiceFormComponents/FormBuilder.tsx +++ b/src/components/taxonomicService/taxonomicServiceFormComponents/FormBuilder.tsx @@ -11,6 +11,7 @@ import BooleanField from "./BooleanField"; import DateField from "./DateField"; import FormBuilderFieldArray from "./FormBuilderFieldArray"; import MultiSelectField from "./MultiSelectField"; +import RORField from "./RORField"; import SelectField from "./SelectField"; import StringField from "./StringField"; import StringArrayField from "./StringArrayField"; @@ -142,6 +143,13 @@ const FormBuilder = (props: Props) => { return SetFieldValue?.(fieldName, value)} />; + } case 'ror': { + return { + SetFieldValue?.(fieldName, value) + }} + />; } case 'text': { return ; } default: { diff --git a/src/components/taxonomicService/taxonomicServiceFormComponents/RORField.tsx b/src/components/taxonomicService/taxonomicServiceFormComponents/RORField.tsx new file mode 100644 index 0000000..29f6e23 --- /dev/null +++ b/src/components/taxonomicService/taxonomicServiceFormComponents/RORField.tsx @@ -0,0 +1,134 @@ +/* Import Dependencies */ +import { Field } from "formik"; +import { useState } from 'react'; +import { Row, Col } from 'react-bootstrap'; +import Select from "react-select"; + +/* Import Types */ +import { FormField, Dict, DropdownItem } from "app/Types"; + +/* Import API */ +import GetRORsByName from 'api/ror/GetRORsByName'; + +/* Import Components */ +import { Button, Spinner } from 'components/general/CustomComponents'; + + +/* Props Type */ +type Props = { + field: FormField, + fieldValue: Dict, + SetFieldValue: Function +}; + + +/** + * Component that renders a dynamic ROR field for defining the organisation (affiliation) identifier and name + * @param field The provided form field + * @param fieldValue The current value of the field + * @param SetFieldValue Function to set the value of a field in the form + * @returns JSX Component + */ +const RORField = (props: Props) => { + const { field, fieldValue, SetFieldValue } = props; + + /* Base variables */ + const [query, setQuery] = useState(''); + const [loading, setLoading] = useState(false); + const [dropdownOptions, setDropdownOptions] = useState(); + + /** + * Function to search for RORs and fill the dropdown with options + */ + const SearchForROR = async () => { + setLoading(true); + + const rors = await GetRORsByName({ query }); + + /* Reset field name */ + SetFieldValue(field.jsonPath.replace('$', ''), { + "schema:identifier": '', + "schema:name": '' + }); + + /* Construct dropdown items from ROR */ + const dropdownOptions: DropdownItem[] = []; + + rors.forEach(ror => { + dropdownOptions.push({ + label: ror.names[0].value, + value: ror.id + }); + }) + + setDropdownOptions(dropdownOptions); + setLoading(false); + }; + + return ( +
+

+ {field.title}{field.required ? * : ''} +

+ + + setQuery(field.target.value as string)} + /> + + {loading && + + + + } + + + + + {/* Display ROR selection dropdown if dropdown options is not undefiend */} + {dropdownOptions && + + +