diff --git a/src/components/explorer/IndividualBiosamples.js b/src/components/explorer/IndividualBiosamples.js index 0ca23c750..5f11baff0 100644 --- a/src/components/explorer/IndividualBiosamples.js +++ b/src/components/explorer/IndividualBiosamples.js @@ -17,6 +17,7 @@ import JsonView from "./JsonView"; import OntologyTerm from "./OntologyTerm"; import "./explorer.css"; +import TimeElement from "./TimeElement"; // TODO: Only show biosamples from the relevant dataset, if specified; // highlight those found in search results, if specified @@ -30,6 +31,12 @@ const BiosampleProcedure = ({ resourcesTuple, procedure }) => ( ) : null} + {procedure.performed ? ( +
+ Time Performed:{" "} + +
+ ): null} ); BiosampleProcedure.propTypes = { @@ -62,6 +69,7 @@ ExperimentsClickList.propTypes = { const BiosampleDetail = ({ individual, biosample, handleExperimentClick }) => { const resourcesTuple = useIndividualResources(individual); + console.log(biosample.procedure); return ( @@ -85,12 +93,8 @@ const BiosampleDetail = ({ individual, biosample, handleExperimentClick }) => { - - {biosample.individual_age_at_collection - ? biosample.individual_age_at_collection.age ?? - `Between ${biosample.individual_age_at_collection.start.age}` + - `and ${biosample.individual_age_at_collection.end.age}` - : EM_DASH} + + {biosample.hasOwnProperty("measurements") && diff --git a/src/components/explorer/TimeElement.js b/src/components/explorer/TimeElement.js new file mode 100644 index 000000000..b8a0463c4 --- /dev/null +++ b/src/components/explorer/TimeElement.js @@ -0,0 +1,82 @@ +import React, { memo, useEffect } from "react"; +import PropTypes from "prop-types"; + +import { EM_DASH } from "../../constants"; +import OntologyTerm from "./OntologyTerm"; + +const TIME_ELEMENT_TYPES_LABELS = { + "age": "Age", + "gestational_age": "Gestational Age", + "age_range": "Age Range", + "ontology_class": "Ontology Class", + "timestamp": "Timestamp", + "interval": "Interval", +} + +const getTimeElementTypeLabel = (timeElement) => { + const keys = Object.keys(timeElement); + if (keys ?? keys.length === 1) { + // A Phenopacket TimeElement should only have 1 property + const type = keys[0]; + if (type in TIME_ELEMENT_TYPES_LABELS) { + const label = TIME_ELEMENT_TYPES_LABELS[type]; + return [type, label]; + } + } + return [null, "NOT_SUPPORTED"]; +} + +const renderTimeElement = (type, timeElement) => { + switch (type) { + case "age": + return <>{timeElement.age.iso8601duration}; + case "gestational_age": + return <> + Weeks:{" "}{timeElement.gestationalAge.weeks} + Days:{" "}{timeElement.gestationalAge.days} + ; + case "age_range": + return <> + Start:{" "}<>{timeElement.age_range.start.iso8601duration} + End:{" "}<>{timeElement.age_range.end.iso8601duration} + ; + case "ontology_class": + return <> + ID:{" "}{timeElement.ontology_class.id} + Label:{" "}{timeElement.ontology_class.label} + ; + case "timestamp": + return <> + Timestamp:{" "}{timeElement.timestamp} + ; + case "interval": + return <> + Start:{" "}<>{timeElement.interval.start} + End:{" "}<>{timeElement.interval.end} + ; + default: + return EM_DASH; + } +} + +const TimeElement = ({timeElement}) => { + const [timeType, label] = getTimeElementTypeLabel(timeElement); + + if (!timeType) { + // Unexpected TimeElement type + return EM_DASH; + } + + return ( +
+ {label}: + {renderTimeElement(timeType, timeElement)} +
+ ); +} + +TimeElement.propTypes = { + timeElement: PropTypes.object, +}; + +export default TimeElement;