Skip to content

Commit 0750216

Browse files
committed
Rrport & Location history upload
1 parent ada020b commit 0750216

File tree

15 files changed

+3362
-1133
lines changed

15 files changed

+3362
-1133
lines changed

UIcode/client/.env.example

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
REACT_APP_API_URL=
2-
REACT_APP_GOOGLE_CLIENT_ID=
2+
REACT_APP_GOOGLE_CLIENT_ID=
3+
REACT_APP_ENCLAVE_URL=https://safetrace.enigma.co

UIcode/client/package-lock.json

+3,009-1,023
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

UIcode/client/package.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6-
"axios": "^0.18.1",
6+
"enigma-js": "^0.3.0",
7+
"axios": "^0.19.2",
78
"bootstrap": "^4.4.1",
89
"date-fns": "^2.11.1",
10+
"eth-crypto": "^1.5.2",
11+
"jayson": "^3.2.0",
912
"js-cookie": "^2.2.1",
13+
"node-forge": "^0.9.1",
1014
"react": "^16.8.6",
1115
"react-bootstrap": "^1.0.0",
1216
"react-day-picker": "^7.4.0",

UIcode/client/src/App/index.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Home from "Pages/Home";
66
import API from "Pages/API";
77
import Contribute from "Pages/Contribute";
88
import AuthProvider from "Providers/AuthProvider";
9+
import Results from "Pages/Results";
910

1011
const App = () => {
1112
return (
@@ -15,6 +16,7 @@ const App = () => {
1516
<DefaultLayout exact path="/" component={Home} />
1617
<DefaultLayout exact path="/API" component={API} />
1718
<DefaultLayout exact path="/contribute" component={Contribute} />
19+
<DefaultLayout exact path="/results" component={Results} />
1820
</Switch>
1921
</Router>
2022
</AuthProvider>

UIcode/client/src/Components/FileUpload/index.jsx.js

+34-75
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,49 @@
1-
import React, { Fragment, useState } from "react";
2-
import Message from "../Message";
3-
import Progress from "../Progress";
4-
import axios from "axios";
1+
import React, { useState } from "react";
52

6-
const FileUpload = ({ onChange }) => {
3+
const FileUpload = ({ placeholder = "Choose file", onChange, onSubmit }) => {
74
const [file, setFile] = useState("");
8-
const [filename, setFilename] = useState("Choose File");
9-
const [uploadedFile, setUploadedFile] = useState({});
10-
const [message, setMessage] = useState("");
11-
const [uploadPercentage, setUploadPercentage] = useState(0);
5+
const [filename, setFilename] = useState("");
126

137
const handleFileChange = (e) => {
14-
setFile(e.target.files[0]);
15-
setFilename(e.target.files[0].name);
16-
onChange(e.target.files[0]);
8+
if (e.target.files && e.target.files.length) {
9+
if (onChange && onChange instanceof Function) {
10+
const valid = onChange(e.target.files[0]);
11+
if (valid === false) {
12+
setFile("");
13+
setFilename("");
14+
return;
15+
}
16+
}
17+
setFile(e.target.files[0]);
18+
setFilename(e.target.files[0].name);
19+
}
1720
};
1821

19-
const onSubmit = async (e) => {
22+
const handleSubmit = (e) => {
2023
e.preventDefault();
21-
const formData = new FormData();
22-
formData.append("file", file);
23-
24-
try {
25-
const res = await axios.post("/upload", formData, {
26-
headers: {
27-
"Content-Type": "multipart/form-data",
28-
},
29-
onUploadProgress: (progressEvent) => {
30-
setUploadPercentage(
31-
parseInt(
32-
Math.round((progressEvent.loaded * 100) / progressEvent.total)
33-
)
34-
);
35-
36-
// Clear percentage
37-
setTimeout(() => setUploadPercentage(0), 10000);
38-
},
39-
});
40-
41-
const { fileName, filePath } = res.data;
42-
43-
setUploadedFile({ fileName, filePath });
44-
45-
setMessage("File Uploaded");
46-
} catch (err) {
47-
if (err.response.status === 500) {
48-
setMessage("There was a problem with the server");
49-
} else {
50-
setMessage(err.response.data.msg);
51-
}
52-
}
24+
onSubmit(file);
5325
};
5426

5527
return (
56-
<Fragment>
57-
{message ? <Message msg={message} /> : null}
58-
<form onSubmit={onSubmit}>
59-
<div className="custom-file mb-4">
60-
<input
61-
type="file"
62-
className="custom-file-input"
63-
id="customFile"
64-
onChange={handleFileChange}
65-
/>
66-
<label className="custom-file-label" htmlFor="customFile">
67-
{filename}
68-
</label>
69-
</div>
70-
71-
<Progress percentage={uploadPercentage} />
72-
28+
<form onSubmit={handleSubmit}>
29+
<div className="custom-file mb-4">
7330
<input
74-
type="submit"
75-
value="Upload"
76-
className="btn btn-primary btn-block mt-4"
31+
type="file"
32+
className="custom-file-input"
33+
id="customFile"
34+
onChange={handleFileChange}
7735
/>
78-
</form>
79-
{uploadedFile ? (
80-
<div className="row mt-5">
81-
<div className="col-md-6 m-auto">
82-
<h3 className="text-center">{uploadedFile.fileName}</h3>
83-
<img style={{ width: "100%" }} src={uploadedFile.filePath} alt="" />
84-
</div>
85-
</div>
86-
) : null}
87-
</Fragment>
36+
<label className="custom-file-label" htmlFor="customFile">
37+
{filename || placeholder}
38+
</label>
39+
</div>
40+
41+
<input
42+
type="submit"
43+
value="Upload"
44+
className="btn btn-primary btn-block mt-4"
45+
/>
46+
</form>
8847
);
8948
};
9049

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const FlashMessage = ({ location }) => {
2+
const message = location && location.state ? location.state : null;
3+
4+
return message;
5+
};
6+
7+
export default FlashMessage;

UIcode/client/src/Pages/Contribute/Step2.jsx

+5
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ import React from "react";
22
import RadioGroup from "Components/RadioGroup";
33
import DatePicker from "Components/DatePicker";
44
import Box from "Styled/Box";
5+
import ErrorMessage from "Styled/ErrorMessage";
56

67
const Step2 = ({
78
selectedTestResult,
89
onTestResultChange,
910
testDate,
1011
onTestDateChange,
12+
errors,
1113
}) => {
14+
const dateError = errors.find((e) => e.param === "testDate");
15+
1216
return (
1317
<>
1418
<h2>Self Report</h2>
@@ -43,6 +47,7 @@ const Step2 = ({
4347
onDayChange={onTestDateChange}
4448
disabled={selectedTestResult === "not_tested"}
4549
/>
50+
{dateError && <ErrorMessage>{dateError.msg}</ErrorMessage>}
4651
</Box>
4752
</>
4853
);

UIcode/client/src/Pages/Contribute/Step3.jsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Box from "Styled/Box";
33
import Row from "Components/Grid/Row";
44
import FileUpload from "Components/FileUpload/index.jsx";
55

6-
const Step3 = ({ onFileChange }) => {
6+
const Step3 = ({ onFileChange, onSubmit }) => {
77
return (
88
<Box>
99
<h2>Self Report</h2>
@@ -44,7 +44,7 @@ const Step3 = ({ onFileChange }) => {
4444
Can’t find the file?
4545
</p>
4646
<Row>
47-
<FileUpload onChange={onFileChange}/>
47+
<FileUpload onChange={onFileChange} onSubmit={onSubmit}/>
4848
</Row>
4949
</Box>
5050
);

UIcode/client/src/Pages/Contribute/index.jsx

+69-31
Original file line numberDiff line numberDiff line change
@@ -9,66 +9,104 @@ import { authContext } from "Providers/AuthProvider";
99
import LoginForm from "Sections/LoginForm";
1010
import Step3 from "./Step3";
1111
import { parseJsonFile, convertLocationData } from "Services/parser";
12+
import { report } from "Services/api";
13+
import { addData } from "Services/enclave";
14+
import Authorized from "Sections/Authorized";
1215

1316
const Wrapper = styled.div`
1417
padding-top: 50px;
1518
`;
1619

17-
const Contribute = () => {
20+
const Contribute = ({ history }) => {
1821
const [step, setStep] = useState(0);
19-
const [selectedTestResult, setSelectedTestResult] = useState("positive");
22+
const [testResult, setTestResult] = useState("positive");
2023
const [testDate, setTestDate] = useState(null);
21-
const { isLoggedIn } = useContext(authContext);
22-
24+
const { jwtToken, me } = useContext(authContext);
25+
const [errors, setErrors] = useState([]);
2326
const showButtons = step === 1;
2427

28+
const nextPage = () => setStep((step) => step + 1);
29+
30+
const sendReport = () =>
31+
report({
32+
token: jwtToken,
33+
data: {
34+
idUser: me.idUser,
35+
testDate,
36+
testResult: testResult === "positive" ? 1 : 0,
37+
},
38+
})
39+
.then(nextPage)
40+
.catch((e) => {
41+
if (e?.response?.data?.errors) {
42+
setErrors(e.response.data.errors);
43+
} else {
44+
alert("error");
45+
}
46+
});
47+
48+
const handleFileSubmit = (file) => {
49+
parseJsonFile(file)
50+
.then((json) => {
51+
const data = convertLocationData(json);
52+
addData(me.encryptedUserId, JSON.stringify(data))
53+
.then(() => {
54+
history.push(
55+
"/results",
56+
"Your data has been successfully shared with SafeTrace API."
57+
);
58+
})
59+
.catch(() => alert("An error occurred. Please try again"));
60+
})
61+
.catch(() => alert("Invalid file"));
62+
};
63+
2564
const handleTestDateChange = (date) => setTestDate(date);
26-
const handleNextClick = () => setStep((step) => step + 1);
65+
const handleNextClick = () => {
66+
if (step === 1) {
67+
sendReport();
68+
} else {
69+
nextPage();
70+
}
71+
};
72+
2773
const handleBackClick = () => setStep((step) => step - 1);
2874
const onFileChange = (f) => {
29-
parseJsonFile(f).then(
30-
(json) => {
31-
console.log(convertLocationData(json));
32-
},
33-
() => alert("Invalid file")
34-
);
75+
parseJsonFile(f).catch(() => alert("Invalid file"));
3576
};
3677

3778
const steps = [
3879
() => <Step1 submitReport={handleNextClick} viewResults={() => {}} />,
3980
() => (
4081
<Step2
41-
selectedTestResult={selectedTestResult}
42-
onTestResultChange={setSelectedTestResult}
82+
selectedTestResult={testResult}
83+
onTestResultChange={setTestResult}
4384
testDate={testDate}
4485
onTestDateChange={handleTestDateChange}
86+
errors={errors}
4587
/>
4688
),
47-
() => <Step3 onFileChange={onFileChange} />,
89+
() => <Step3 onFileChange={onFileChange} onSubmit={handleFileSubmit} />,
4890
];
4991

5092
const CurrentStep = steps[step];
5193

5294
return (
5395
<Wrapper>
54-
{isLoggedIn ? (
55-
<>
56-
<CurrentStep />
57-
{showButtons && (
58-
<Row>
59-
<Button color="secondary" onClick={handleBackClick}>
60-
Back
61-
</Button>
96+
<Authorized alternative={LoginForm}>
97+
<CurrentStep />
98+
{showButtons && (
99+
<Row>
100+
<Button color="secondary" onClick={handleBackClick}>
101+
Back
102+
</Button>
62103

63-
<Button color="primary" onClick={handleNextClick}>
64-
Next
65-
</Button>
66-
</Row>
67-
)}
68-
</>
69-
) : (
70-
<LoginForm />
71-
)}
104+
<Button color="primary" onClick={handleNextClick}>
105+
Next
106+
</Button>
107+
</Row>
108+
)}
109+
</Authorized>
72110
</Wrapper>
73111
);
74112
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import React from "react";
2+
3+
const ResultsTable = () => {
4+
return <div></div>;
5+
};
6+
7+
export default ResultsTable;
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
4+
import LoginForm from "Sections/LoginForm";
5+
6+
import Authorized from "Sections/Authorized";
7+
import Box from "Styled/Box";
8+
import ResultsTable from "./ResultsTable";
9+
import FlashMessage from "FlashMessage";
10+
11+
const Wrapper = styled.div`
12+
padding-top: 50px;
13+
`;
14+
15+
const Results = ({ location }) => {
16+
return (
17+
<Wrapper>
18+
<FlashMessage location={location} />
19+
<Authorized alternative={LoginForm}>
20+
{}
21+
<Box>
22+
<h2>Here are your results:</h2>
23+
<ResultsTable />
24+
</Box>
25+
</Authorized>
26+
</Wrapper>
27+
);
28+
};
29+
30+
export default Results;

0 commit comments

Comments
 (0)