Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

265 adding ipt required fields to metadata form #284

Closed
wants to merge 13 commits into from
Closed
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ __pycache__

firebase-debug.log
.Rproj.user
package-lock.json

.env
145 changes: 145 additions & 0 deletions src/components/FormComponents/MethodSteps.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import React from "react";
import {
Add,
Delete,
ArrowUpwardSharp,
ArrowDownwardSharp,
} from "@material-ui/icons";
import { Button, Grid, Paper } from "@material-ui/core";
// import validator from "validator";
import { En, Fr, I18n } from "../I18n";

import BilingualTextInput from "./BilingualTextInput";
import RequiredMark from "./RequiredMark";
import { deepCopy } from "../../utils/misc";
import { QuestionText, paperClass } from "./QuestionStyles";

// const validateURL = (url) => !url || validator.isURL(url);

const MethodSteps = ({ updateMethods, methods, disabled }) => {
const emptyMethod = {
title: { en: "", fr: "" },
description: { en: "", fr: "" },
};

const nameLabel = <I18n en="Title" fr="Titre" />;
const descriptionLabel = <I18n en="Description" fr="Description" />;

// Extract Method as array of objects, methods are not seen as an array when
// returning from firebase, possibly due to nesting?
const methodList = Object.entries(methods).map(([key, method]) => ({
...method,
}));

function addMethodStep() {
updateMethods(methodList.concat(deepCopy(emptyMethod)));
}

// removes the method step section from the list at index i
function removeMethodStep(i) {
updateMethods(methodList.filter((e, index) => index !== i));
}

// move the method step section
function moveMethodStep(i, newIndex) {
if (newIndex < 0 || newIndex >= methodList.length) return;
const element = methodList.splice(i, 1)[0];
methodList.splice(newIndex, 0, element);
updateMethods(methodList);
}

return (
<div>
{methodList.map((method = deepCopy(emptyMethod), i) => {
function handleMethodStepChange(key) {
return (e) => {
const newValue = [...methodList];
newValue[i][key] = e.target.value;

updateMethods(newValue);
};
}
return (
<Paper key={i} style={paperClass}>
<Grid container direction="column" spacing={3}>
<Grid item xs>
<QuestionText>
<I18n>
<En>{i + 1}. Enter a title for this method step</En>
<Fr>{i + 1}. Entrez un titre pour cette étape de méthode</Fr>
</I18n>
<RequiredMark passes={method.title?.en || method.title?.fr} />
</QuestionText>
<BilingualTextInput
label={nameLabel}
value={method.title}
onChange={handleMethodStepChange("title")}
fullWidth
disabled={disabled}
/>
</Grid>
<Grid item xs>
<QuestionText>
<I18n>
<En>Enter a description of this method step</En>
<Fr>Entrez une description de cette étape de méthode</Fr>
</I18n>
</QuestionText>{" "}
<BilingualTextInput
name="description"
label={descriptionLabel}
value={method.description}
onChange={handleMethodStepChange("description")}
disabled={disabled}
/>
</Grid>
<Grid item xs>
<Button
startIcon={<Delete />}
disabled={disabled}
onClick={() => removeMethodStep(i)}
>
<I18n>
<En>Remove step</En>
<Fr>Étape de suppression</Fr>
</I18n>
</Button>
<Button
startIcon={<ArrowUpwardSharp />}
disabled={disabled || i - 1 < 0}
onClick={() => moveMethodStep(i, i - 1)}
>
<I18n>
<En>Move up</En>
<Fr>Déplacer vers le haut</Fr>
</I18n>
</Button>
<Button
startIcon={<ArrowDownwardSharp />}
disabled={disabled || i + 1 === methodList.length}
onClick={() => moveMethodStep(i, i + 1)}
>
<I18n>
<En>Move down</En>
<Fr>Déplacer vers le bas</Fr>
</I18n>
</Button>
</Grid>
</Grid>
</Paper>
);
})}

<Paper style={paperClass}>
<Button startIcon={<Add />} disabled={disabled} onClick={addMethodStep}>
<I18n>
<En>Add Method Step</En>
<Fr>Étape d'ajout de méthode</Fr>
</I18n>
</Button>
</Paper>
</div>
);
};

export default MethodSteps;
10 changes: 10 additions & 0 deletions src/components/Pages/MetadataForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import IdentificationTab from "../Tabs/IdentificationTab";
import PlatformTab from "../Tabs/PlatformTab";
import SpatialTab from "../Tabs/SpatialTab";
import SubmitTab from "../Tabs/SubmitTab";
import BiologicalTab from "../Tabs/BiologicalTab";

import { auth } from "../../auth";
import firebase from "../../firebase";
Expand Down Expand Up @@ -474,6 +475,12 @@ class MetadataForm extends FormClassTemplate {
label={tabs.platform[language]}
value="platform"
/>
<Tab
fullWidth
classes={{ root: classes.tabRoot }}
label={tabs.biological[language]}
value="biological"
/>
{loggedInUserCanEditRecord && (
<Tab
fullWidth
Expand Down Expand Up @@ -528,6 +535,9 @@ class MetadataForm extends FormClassTemplate {
<TabPanel value={tabIndex} index="distribution">
<ResourcesTab {...tabProps} />
</TabPanel>
<TabPanel value={tabIndex} index="biological">
<BiologicalTab {...tabProps} />
</TabPanel>

<TabPanel value={tabIndex} index="submit">
<SubmitTab
Expand Down
183 changes: 183 additions & 0 deletions src/components/Tabs/BiologicalTab.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import React from "react";
import { Paper } from "@material-ui/core";
import { En, Fr, I18n } from "../I18n";

import BilingualTextInput from "../FormComponents/BilingualTextInput";
import MethodSteps from "../FormComponents/MethodSteps";

import {
QuestionText,
SupplementalText,
paperClass,
} from "../FormComponents/QuestionStyles";


const BiologicalTab = ({ disabled, record, updateRecord }) => {
const updateBiological = updateRecord("biological");

function handleBiologicalChange(key) {
return (e) => {
const newData = { ...record.biological, [key]: e.target.value };
updateBiological(newData);
};
}

function updateMethods(methodCollection) {
const newData = { ...record.biological, methods: methodCollection };

updateBiological(newData);
}

return (
<div>
<Paper style={paperClass}>
<QuestionText>
<I18n>
<En>
What is the geographic description of the area?
</En>
<Fr>
Quelle est la description géographique de la région?
</Fr>
</I18n>
<SupplementalText>
<I18n>
<En>
A free text description of the geographic area
in which the data was collected.
</En>
<Fr>
Une description textuelle libre de la région
géographique dans laquelle les données ont été
recueillies.
</Fr>
</I18n>
</SupplementalText>
</QuestionText>

<BilingualTextInput
value={record.biological.geographicDescription}
onChange={handleBiologicalChange("geographicDescription")}
disabled={disabled}
multiline
/>
</Paper>

<Paper style={paperClass}>
<QuestionText>
<I18n>
<En>
What is the sampling procedure for this dataset?
</En>
<Fr>
Quelle est la procédure d'échantillonnage pour cet
ensemble de données?
</Fr>
</I18n>
<SupplementalText>
<I18n>
<En>
This field allows for a text-based / human
readable description of the sampling procedures
used in the research project. The content of
this element would be similar to a description
of sampling procedures found in the methods
section of a journal article.
</En>
<Fr>
Une description textuelle libre de la région
géographique dans laquelle les données ont
été recueillies.
</Fr>
</I18n>
</SupplementalText>
</QuestionText>

<BilingualTextInput
value={record.biological.samplingDescription}
onChange={handleBiologicalChange("samplingDescription")}
disabled={disabled}
multiline
/>
</Paper>

<Paper style={paperClass}>
<QuestionText>
<I18n>
<En>
What is the study extent for this dataset?
</En>
<Fr>
Quelle est l'étendue de l'étude pour cet ensemble de données?
</Fr>
</I18n>
<SupplementalText>
<I18n>
<En>
This field represents both a specific sampling area and the
sampling frequency (temporal boundaries, frequency of
occurrence).
</En>
<Fr>
Ce champ représente à la fois une zone d'échantillonnage
spécifique et la fréquence d'échantillonnage (limites
temporelles, fréquence d'occurrence).
</Fr>
</I18n>
</SupplementalText>
</QuestionText>

<BilingualTextInput
value={record.biological.studyExtent}
onChange={handleBiologicalChange("studyExtent")}
disabled={disabled}
multiline
/>
</Paper>

<Paper style={paperClass}>
<QuestionText>
<I18n>
<En>
What are the methods and procedures used in this dataset?
</En>
<Fr>
Quelles sont les méthodes et procédures utilisées dans cet
ensemble de données?
</Fr>
</I18n>
<SupplementalText>
<I18n>
<En>
This field allows for repeated sets of elements that document
a series of methods and procedures used in the study, and the
processing steps leading to the production of the data files.
These include e.g. text descriptions of the procedures,
relevant literature, software, instrumentation and any quality
control measurements taken.
</En>
<Fr>
Ce champ permet des ensembles répétés d'éléments qui documentent
une série de méthodes et de procédures utilisées dans l'étude ;
les étapes de traitement menant à la production des fichiers de
données. Ceux-ci comprennent par exemple des descriptions
textuelles des procédures, la documentation, les logiciels,
les instruments et toute qualité pertinents ; mesures de
contrôle prises.
</Fr>
</I18n>
</SupplementalText>
</QuestionText>

<MethodSteps
paperClass={paperClass}
methods={record.biological.methods || []}
updateMethods={updateMethods}
disabled={disabled}
/>
</Paper>
</div>
);
};

export default BiologicalTab;
6 changes: 6 additions & 0 deletions src/utils/blankRecord.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ const blankRecord = {
filename: "",
organization: "",
timeFirstPublished: "",
biological: {
geographicDescription: { en: "", fr: "" },
methods: [],
samplingDescription: { en: "", fr: "" },
studyExtent: { en: "", fr: "" },
},
};

function getBlankRecord() {
Expand Down
Loading
Loading