diff --git a/web/package.json b/web/package.json
index 3018e2c0..f17a4f56 100644
--- a/web/package.json
+++ b/web/package.json
@@ -37,6 +37,7 @@
"react": "16.12.0",
"react-datetime": "2.16.3",
"react-dom": "16.12.0",
+ "react-hook-form": "^6.8.4",
"react-router": "5.1.2",
"react-router-dom": "5.1.2",
"react-scripts": "3.4.0",
diff --git a/web/src/index.js b/web/src/index.js
index deafdc69..960a5894 100644
--- a/web/src/index.js
+++ b/web/src/index.js
@@ -13,6 +13,7 @@ import Footer from 'components/footer';
import Navbar from 'components/navbar';
import SleepAnalysis from 'views/sleep-analysis';
import Performance from 'views/performance';
+import AnalyzeSleep from 'views/analyze-sleep';
import ScrollToTop from 'components/scroll_to_top';
import Emoji from 'components/emoji';
@@ -48,7 +49,7 @@ ReactDOM.render(
} />
-
+ } />
} />
diff --git a/web/src/views/analyze-sleep/index.js b/web/src/views/analyze-sleep/index.js
new file mode 100644
index 00000000..d6d14810
--- /dev/null
+++ b/web/src/views/analyze-sleep/index.js
@@ -0,0 +1,27 @@
+import React 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;
+
+const AnalyzeSleep = () => {
+ return (
+
+
+ {isServerReady ? : }
+
+ );
+};
+
+export default AnalyzeSleep;
diff --git a/web/src/views/analyze-sleep/text.json b/web/src/views/analyze-sleep/text.json
new file mode 100644
index 00000000..fa5c5f0f
--- /dev/null
+++ b/web/src/views/analyze-sleep/text.json
@@ -0,0 +1,5 @@
+{
+ "header_title": "Your night",
+ "header_subtitle": "visualized and compared",
+ "header_description": "Upload your night of sleep"
+}
diff --git a/web/src/views/analyze-sleep/upload-form.js b/web/src/views/analyze-sleep/upload-form.js
new file mode 100644
index 00000000..11bf5635
--- /dev/null
+++ b/web/src/views/analyze-sleep/upload-form.js
@@ -0,0 +1,146 @@
+import React from 'react';
+import { Button, Container, CustomInput, Form, FormGroup, Label, Input, InputGroup, Col, Row } from 'reactstrap';
+import { useForm } from 'react-hook-form';
+
+const dateFieldSuffix = '-date';
+const timeFieldSuffix = '-time';
+
+const filterInDateTimeFields = (data) =>
+ Object.keys(data)
+ .filter((field) => field.endsWith(timeFieldSuffix))
+ .map((field) => field.replace(timeFieldSuffix, ''));
+
+const filterOutDateTimeFields = (data) =>
+ Object.entries(data).filter(([fieldName, value]) => !(fieldName.endsWith(dateFieldSuffix) || fieldName.endsWith(timeFieldSuffix)));
+
+const mergeDateTimeFields = (data) =>
+ filterInDateTimeFields(data).map((fieldPrefix) => [
+ fieldPrefix,
+ new Date(
+ Object.entries(data)
+ .filter(([fieldName, value]) => fieldName.startsWith(fieldPrefix))
+ .map(([fieldName, value]) => value)
+ .join(' '),
+ ),
+ ]);
+
+const UploadForm = () => {
+ const { register, handleSubmit } = useForm();
+ const onSubmit = (data) => {
+ const newFormData = Object.fromEntries([...filterOutDateTimeFields(data), ...mergeDateTimeFields(data)]);
+ console.log(newFormData);
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+export default UploadForm;
diff --git a/web/src/views/analyze-sleep/waiting-for-server-to-be-ready.js b/web/src/views/analyze-sleep/waiting-for-server-to-be-ready.js
new file mode 100644
index 00000000..547db5f7
--- /dev/null
+++ b/web/src/views/analyze-sleep/waiting-for-server-to-be-ready.js
@@ -0,0 +1,9 @@
+import React from 'react';
+
+const WaitingForServerToBeReady = () => (
+
+
Waiting for local server to be running...
+
+);
+
+export default WaitingForServerToBeReady;
diff --git a/web/yarn.lock b/web/yarn.lock
index 62aeb4e7..d7169dd3 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -10057,6 +10057,11 @@ react-error-overlay@^6.0.7:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108"
integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA==
+react-hook-form@^6.8.4:
+ version "6.8.4"
+ resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-6.8.4.tgz#1aed2f7badba3622324e37d68f7637868ea54cf2"
+ integrity sha512-qFd5SPPQUZWe+yXF6yjuJXKK8cLXywrzQuw74nL1jptW9Fad4HsEzfh+53Jg3c5TFPIwdIxrMNUvQfd0/p1y/w==
+
react-is@^16.6.0, react-is@^16.6.3, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"