Skip to content

Commit

Permalink
Merge pull request #21 from DiSSCo/MakeDynamicRORField
Browse files Browse the repository at this point in the history
Add ROR field with ROR look up by name
  • Loading branch information
TomDijkema authored Oct 25, 2024
2 parents dfbd738 + ff7b74d commit 7c0f290
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 5 deletions.
42 changes: 42 additions & 0 deletions src/api/ror/GetRORsByName.ts
Original file line number Diff line number Diff line change
@@ -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;
18 changes: 13 additions & 5 deletions src/app/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -142,6 +143,13 @@ const FormBuilder = (props: Props) => {
return <MultiSelectField field={field}
SetFieldValue={(fieldName: string, value: string) => SetFieldValue?.(fieldName, value)}
/>;
} case 'ror': {
return <RORField field={field}
fieldValue={fieldValues as Dict}
SetFieldValue={(fieldName: string, value: Dict) => {
SetFieldValue?.(fieldName, value)
}}
/>;
} case 'text': {
return <TextField field={field} />;
} default: {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<string>('');
const [loading, setLoading] = useState<boolean>(false);
const [dropdownOptions, setDropdownOptions] = useState<DropdownItem[] | undefined>();

/**
* 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 (
<div>
<p>
{field.title}{field.required ? <span className="tc-grey"> *</span> : ''}
</p>
<Row className="mt-1">
<Col>
<Field name="rorSearch"
className="w-100 br-corner px-2 py-1"
onChange={(field: Dict) => setQuery(field.target.value as string)}
/>
</Col>
{loading &&
<Col lg="auto">
<Spinner />
</Col>
}
<Col lg="auto">
<Button type="button"
variant="primary"
OnClick={() => SearchForROR()}
>
<p>
Search for ROR
</p>
</Button>
</Col>
</Row>
{/* Display ROR selection dropdown if dropdown options is not undefiend */}
{dropdownOptions &&
<Row className="mt-2">
<Col>
<Select
options={dropdownOptions}
value={fieldValue['schema:identifier'] ? {
label: fieldValue['schema:name'],
value: fieldValue['schema:identifier']
} : undefined}
placeholder="Select an option"
onChange={(dropdownOption) => {
let jsonPath: string = '';

/* Format JSON path */
field.jsonPath.split('][').forEach(pathSegment => {
const localPathSegment = pathSegment.replace('$', '').replace('[', '').replace(']', '').replaceAll("'", '');

if (!isNaN(Number(localPathSegment))) {
jsonPath = jsonPath.concat(`[${localPathSegment}]`);
} else {
jsonPath = jsonPath.concat(`['${localPathSegment}']`);
}
});

SetFieldValue(jsonPath, {
"schema:identifier": dropdownOption?.value,
"schema:name": dropdownOption?.label
});
}}
/>
</Col>
</Row>
}
</div>
);
};

export default RORField;

0 comments on commit 7c0f290

Please sign in to comment.