Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .prettierrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ trailingComma: "all"
tabWidth: 2
semi: true
singleQuote: true
printWidth: 80
printWidth: 120
33 changes: 31 additions & 2 deletions backend/app.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
from flask import Flask
from flask import Flask, request
from flask_cors import CORS
from waitress import serve
from http import HTTPStatus


app = Flask(__name__)
cors = CORS(app)


def allowed_file(filename):
ALLOWED_EXTENSIONS = {'txt', 'csv'}
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


@app.route("/")
def hello():
return "Hello, World!"


@app.route('/analyze_sleep', methods=['POST'])
def analyze_sleep():
if 'file' not in request.files:
return 'Missing file', HTTPStatus.BAD_REQUEST
file = request.files['file']

if file.filename == '':
return 'No selected file', HTTPStatus.BAD_REQUEST

if not allowed_file(file.filename):
return 'File format not allowed', HTTPStatus.BAD_REQUEST

file_content = file.read()
form_data = request.form.to_dict()

return ''


CORS(app,
resources={r'/*': {"origins": '*'}},
allow_headers='Content-Type')
app.config['CORS_HEADERS'] = 'Content-Type'

serve(app, host='0.0.0.0', port=8080)
4 changes: 3 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"format": "yarn prettier --config ../.vscode/.prettierrc.yaml --write \"./**/*.{js,jsx,css,scss,json}\""
"format": "yarn prettier --config ../.prettierrc.yaml --write \"./**/*.{js,jsx,css,scss,json}\""
},
"eslintConfig": {
"extends": "react-app"
Expand All @@ -25,6 +25,7 @@
"dependencies": {
"argon-design-system-react": "^1.1.0",
"axios": "^0.20.0",
"axios-observable": "^1.1.3",
"bootstrap": "^4.5.0",
"classnames": "2.2.6",
"d3": "^5.16.0",
Expand All @@ -41,6 +42,7 @@
"react-scripts": "3.4.0",
"react-waypoint": "^9.0.2",
"reactstrap": "8.4.1",
"rxjs": "^6.6.3",
"yarn": "^1.22.4"
},
"devDependencies": {
Expand Down
4 changes: 0 additions & 4 deletions web/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ import Performance from 'views/performance';
import AnalyzeSleep from 'views/analyze-sleep';
import ScrollToTop from 'components/scroll_to_top';
import Emoji from 'components/emoji';
import * as axios from 'axios';

// Communication with server (test)
axios.get('http://localhost:8080').then(console.log);

const underConstruction = () => {
const text = {
Expand Down
8 changes: 8 additions & 0 deletions web/src/requests/analayze-sleep.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { SERVER_URL } from './constants';
import Axios from 'axios-observable';
import { objectToFormData } from './object-to-formdata';

export const analyzeSleep = (formData) =>
Axios.post(`${SERVER_URL}/analyze_sleep`, objectToFormData(formData), {
headers: { 'Content-Type': 'multipart/form-data' },
});
1 change: 1 addition & 0 deletions web/src/requests/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const SERVER_URL = 'http://localhost:8080';
7 changes: 7 additions & 0 deletions web/src/requests/object-to-formdata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const objectToFormData = (obj) => {
const formData = new FormData();
for (const key in obj) {
formData.append(key, obj[key]);
}
return formData;
};
12 changes: 12 additions & 0 deletions web/src/requests/ping-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { SERVER_URL } from './constants';
import Axios from 'axios-observable';
import { catchError, exhaustMap, map } from 'rxjs/operators';
import { timer, of } from 'rxjs';

const pingServer = () =>
Axios.get(SERVER_URL).pipe(
map(() => true),
catchError(() => of(false)),
);

export const periodicPingServer = (period) => timer(0, period).pipe(exhaustMap(pingServer));
26 changes: 20 additions & 6 deletions web/src/views/analyze-sleep/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { Container } from 'reactstrap';

import Header from 'components/header';
import WaitingForServerToBeReady from './waiting-for-server-to-be-ready';
import UploadForm from './upload-form';

import text from './text.json';

const isServerReady = true;
import { periodicPingServer } from 'requests/ping-server';

const AnalyzeSleep = () => {
const [serverReady, setServerReady] = useState(false);

useEffect(() => {
const subscription = periodicPingServer(200).subscribe(
(ready) => setServerReady(ready),
() => null,
);
return () => subscription.unsubscribe();
});

return (
<div>
<Header
Expand All @@ -19,7 +26,14 @@ const AnalyzeSleep = () => {
subtitle={text['header_subtitle']}
description={text['header_description']}
/>
<Container className="mt-5 text-justify">{isServerReady ? <UploadForm /> : <WaitingForServerToBeReady />}</Container>
<Container className="mt-5 text-justify">
<span hidden={!serverReady}>
<UploadForm />
</span>
<span hidden={serverReady}>
<WaitingForServerToBeReady />
</span>
</Container>
</div>
);
};
Expand Down
111 changes: 82 additions & 29 deletions web/src/views/analyze-sleep/upload-form.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { Button, Container, CustomInput, Form, FormGroup, Label, Input, InputGroup, Col, Row } from 'reactstrap';
import { useForm } from 'react-hook-form';
import { analyzeSleep } from 'requests/analayze-sleep';

const dateFieldSuffix = '-date';
const timeFieldSuffix = '-time';
Expand All @@ -11,7 +12,7 @@ const filterInDateTimeFields = (data) =>
.map((field) => field.replace(timeFieldSuffix, ''));

const filterOutDateTimeFields = (data) =>
Object.entries(data).filter(([fieldName, value]) => !(fieldName.endsWith(dateFieldSuffix) || fieldName.endsWith(timeFieldSuffix)));
Object.entries(data).filter(([name, value]) => !(name.endsWith(dateFieldSuffix) || name.endsWith(timeFieldSuffix)));

const mergeDateTimeFields = (data) =>
filterInDateTimeFields(data).map((fieldPrefix) => [
Expand All @@ -21,15 +22,22 @@ const mergeDateTimeFields = (data) =>
.filter(([fieldName, value]) => fieldName.startsWith(fieldPrefix))
.map(([fieldName, value]) => value)
.join(' '),
),
).getTime(),
]);

const onSubmit = async (data) => {
let formData = Object.fromEntries([...filterOutDateTimeFields(data), ...mergeDateTimeFields(data)]);
formData = { ...formData, file: formData.file[0] };
try {
const results = await analyzeSleep(formData).toPromise();
console.log(results);
} catch (error) {
console.error(error);
}
};

const UploadForm = () => {
const { register, handleSubmit } = useForm();
const onSubmit = (data) => {
const newFormData = Object.fromEntries([...filterOutDateTimeFields(data), ...mergeDateTimeFields(data)]);
console.log(newFormData);
};

return (
<Container style={{ padding: '2em 0' }}>
Expand All @@ -44,8 +52,8 @@ const UploadForm = () => {
accept=".csv, text/plain"
bsSize="lg"
type="file"
id="openbci-file"
name="openbci-file"
id="file"
name="file"
label="Upload an OpenBCI CSV file"
/>

Expand All @@ -62,18 +70,6 @@ const UploadForm = () => {
</Row>
</FormGroup>

<FormGroup inline>
<Label>Name</Label>
<Row form>
<Col md={6}>
<Input innerRef={register} required type="text" name="firstName" id="firstName" placeholder="First name" />
</Col>
<Col md={6}>
<Input innerRef={register} required type="text" name="lastName" id="lastName" placeholder="Last name" />
</Col>
</Row>
</FormGroup>

<Row form>
<Col md={6}>
<FormGroup inline>
Expand All @@ -85,7 +81,16 @@ const UploadForm = () => {
<Col md={6}>
<FormGroup>
<Label for="age">Age</Label>
<Input innerRef={register} required type="number" name="age" id="age" min="0" max="125" placeholder="Enter your age" />
<Input
innerRef={register}
required
type="number"
name="age"
id="age"
min="0"
max="125"
placeholder="Enter your age"
/>
</FormGroup>
</Col>
</Row>
Expand All @@ -96,17 +101,41 @@ const UploadForm = () => {
<FormGroup>
<Label>Time when OpenBCI stream started</Label>
<InputGroup>
<Input innerRef={register} required type="date" name={`stream-start${dateFieldSuffix}`} id={`stream-start${dateFieldSuffix}`} />
<Input innerRef={register} required type="time" name={`stream-start${timeFieldSuffix}`} id={`stream-start${timeFieldSuffix}`} />
<Input
innerRef={register}
required
type="date"
name={`stream_start${dateFieldSuffix}`}
id={`stream_start${dateFieldSuffix}`}
/>
<Input
innerRef={register}
required
type="time"
name={`stream_start${timeFieldSuffix}`}
id={`stream_start${timeFieldSuffix}`}
/>
</InputGroup>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label>I went to bed at</Label>
<InputGroup>
<Input innerRef={register} required type="date" name={`bedtime${dateFieldSuffix}`} id={`bedtime${dateFieldSuffix}`} />
<Input innerRef={register} required type="time" name={`bedtime${timeFieldSuffix}`} id={`bedtime${timeFieldSuffix}`} />
<Input
innerRef={register}
required
type="date"
name={`bedtime${dateFieldSuffix}`}
id={`bedtime${dateFieldSuffix}`}
/>
<Input
innerRef={register}
required
type="time"
name={`bedtime${timeFieldSuffix}`}
id={`bedtime${timeFieldSuffix}`}
/>
</InputGroup>
</FormGroup>
</Col>
Expand All @@ -116,17 +145,41 @@ const UploadForm = () => {
<FormGroup>
<Label>I think I fell asleep at</Label>
<InputGroup>
<Input innerRef={register} required type="date" name={`sleeping${dateFieldSuffix}`} id={`sleeping${dateFieldSuffix}`} />
<Input innerRef={register} required type="time" name={`sleeping${timeFieldSuffix}`} id={`sleeping${timeFieldSuffix}`} />
<Input
innerRef={register}
required
type="date"
name={`sleeping${dateFieldSuffix}`}
id={`sleeping${dateFieldSuffix}`}
/>
<Input
innerRef={register}
required
type="time"
name={`sleeping${timeFieldSuffix}`}
id={`sleeping${timeFieldSuffix}`}
/>
</InputGroup>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label>And woke up at</Label>
<InputGroup>
<Input innerRef={register} required type="date" name={`wakeup${dateFieldSuffix}`} id={`wakeup${dateFieldSuffix}`} />
<Input innerRef={register} required type="time" name={`wakeup${timeFieldSuffix}`} id={`wakeup${timeFieldSuffix}`} />
<Input
innerRef={register}
required
type="date"
name={`wakeup${dateFieldSuffix}`}
id={`wakeup${dateFieldSuffix}`}
/>
<Input
innerRef={register}
required
type="time"
name={`wakeup${timeFieldSuffix}`}
id={`wakeup${timeFieldSuffix}`}
/>
</InputGroup>
</FormGroup>
</Col>
Expand Down
7 changes: 6 additions & 1 deletion web/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2202,6 +2202,11 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428"
integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==

axios-observable@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/axios-observable/-/axios-observable-1.1.3.tgz#258055be37e5567c1c03be3860acf15645f658f9"
integrity sha512-XY0Q+D6bjiqmyLiXEmg2GXcwMfnbHDMbKNJkkADPOEUlCYsSmpISaZB8s9tZxUSY42S3RTuTHjLiLP6HuVxuRA==

axios@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
Expand Down Expand Up @@ -10048,7 +10053,7 @@ rw@1:
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=

rxjs@^6.5.3, rxjs@^6.6.0:
rxjs@^6.5.3, rxjs@^6.6.0, rxjs@^6.6.3:
version "6.6.3"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552"
integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==
Expand Down