diff --git a/README.md b/README.md
index 05643243..a01bd8cb 100644
--- a/README.md
+++ b/README.md
@@ -5,11 +5,10 @@ Frontend Web Application for FileFighter.



-[](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter.frontend)
+[](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter.frontend)
[](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter.frontend)
[](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter.frontend)
[](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter.frontend)
-[](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter.frontend)
[](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter.frontend)
## Deployment
diff --git a/webapp_frontend/package-lock.json b/webapp_frontend/package-lock.json
index 6c81b16a..c2431845 100644
--- a/webapp_frontend/package-lock.json
+++ b/webapp_frontend/package-lock.json
@@ -15878,6 +15878,11 @@
}
}
},
+ "opencollective-postinstall": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
+ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q=="
+ },
"opn": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
@@ -20400,6 +20405,14 @@
}
}
},
+ "super-tiny-icons": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/super-tiny-icons/-/super-tiny-icons-0.4.0.tgz",
+ "integrity": "sha512-PEHlUQsSdEtQNeP4pNOBCDU9cJe6bsrMmG3yV62icvMDgjCC+srl9AfJ5RGwfKbyvGNbYRUtcmkka+k7yhZxOA==",
+ "requires": {
+ "opencollective-postinstall": "^2.0.2"
+ }
+ },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
diff --git a/webapp_frontend/package.json b/webapp_frontend/package.json
index 62be03df..b05ebeb5 100644
--- a/webapp_frontend/package.json
+++ b/webapp_frontend/package.json
@@ -27,6 +27,7 @@
"react-toastify": "^6.1.0",
"redux": "^4.0.5",
"redux-types": "^2.0.3",
+ "super-tiny-icons": "^0.4.0",
"typescript": "^3.8.3"
},
"scripts": {
diff --git a/webapp_frontend/public/favicon.ico b/webapp_frontend/public/favicon.ico
index bcd5dfd6..e0a96e5e 100644
Binary files a/webapp_frontend/public/favicon.ico and b/webapp_frontend/public/favicon.ico differ
diff --git a/webapp_frontend/public/index.html b/webapp_frontend/public/index.html
index aa069f27..f654b812 100644
--- a/webapp_frontend/public/index.html
+++ b/webapp_frontend/public/index.html
@@ -1,5 +1,5 @@
-
+
@@ -24,20 +24,25 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
- React App
+ FileFighter
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webapp_frontend/public/logo192.png b/webapp_frontend/public/logo192.png
index fc44b0a3..6f131e0d 100644
Binary files a/webapp_frontend/public/logo192.png and b/webapp_frontend/public/logo192.png differ
diff --git a/webapp_frontend/public/logo512.png b/webapp_frontend/public/logo512.png
index a4e47a65..d082d9f7 100644
Binary files a/webapp_frontend/public/logo512.png and b/webapp_frontend/public/logo512.png differ
diff --git a/webapp_frontend/src/assets/images/logos/logo.png b/webapp_frontend/src/assets/images/logos/logo.png
index 07f2b0ec..74bea3c9 100644
Binary files a/webapp_frontend/src/assets/images/logos/logo.png and b/webapp_frontend/src/assets/images/logos/logo.png differ
diff --git a/webapp_frontend/src/background/constants.tsx b/webapp_frontend/src/background/constants.ts
similarity index 63%
rename from webapp_frontend/src/background/constants.tsx
rename to webapp_frontend/src/background/constants.ts
index 7bb02ead..80a76f49 100644
--- a/webapp_frontend/src/background/constants.tsx
+++ b/webapp_frontend/src/background/constants.ts
@@ -11,7 +11,8 @@ const prod: constants = {
const dev: constants = {
url: {
- API_URL: 'http://filefighter.ddns.net:1081/http://filefighter.ddns.net:3001',
+ API_URL: 'http://filefighter.ddns.net:1081/http://filefighter.ddns.net:3001',
+ // API_URL: 'https://cors-anywhere.herokuapp.com/http://filefighter.ddns.net:3001',
// API_URL: 'http://localhost:8080',
}
};
diff --git a/webapp_frontend/src/background/methods/redirect.ts b/webapp_frontend/src/background/methods/redirect.ts
index a6aa7e95..00d17183 100644
--- a/webapp_frontend/src/background/methods/redirect.ts
+++ b/webapp_frontend/src/background/methods/redirect.ts
@@ -1,15 +1,16 @@
-const internRedirect = (history: any, path: string, event?: { preventDefault: () => void; }): void => {
- if (event) event.preventDefault();
- if (path) {
- const element = document.getElementById(path)
- if (element) {
- element.scrollIntoView()
- }
+const scrollToElement = (history: { push: (path:string) => void; }, id: string, event?: { preventDefault: () => void; }): void => {
+ //Replaces anchor for React
+ console.log("Scrolled to " + id)
+ event?.preventDefault();
+ if (id) {
+ const element = document.getElementById(id)
+ element?.scrollIntoView()
}
};
-const externRedirect = (event: { preventDefault: () => void; }, history: any[], path: string): void => {
- event.preventDefault();
- history.push(path);
+const redirect = (history:{ push: (path:string) => void; } , path: string, event?: { preventDefault: () => void; }): void => {
+ console.log("Redirected to " + path)
+ event?.preventDefault();
+ if (path !== window.location.pathname) history.push(path);
};
-export {externRedirect, internRedirect}
\ No newline at end of file
+export {redirect, scrollToElement}
\ No newline at end of file
diff --git a/webapp_frontend/src/background/methods/style.js b/webapp_frontend/src/background/methods/style.js
new file mode 100644
index 00000000..0287f6d3
--- /dev/null
+++ b/webapp_frontend/src/background/methods/style.js
@@ -0,0 +1,13 @@
+export function getStyleValue(element, strCssRule) {
+ //https://stackoverflow.com/questions/5227909/how-to-get-an-elements-padding-value-using-javascript
+ let strValue = "";
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ strValue = document.defaultView.getComputedStyle(element, "").getPropertyValue(strCssRule);
+ } else if (element.currentStyle) {
+ strCssRule = strCssRule.replace(/(\w)/g, function (strMatch, p1) {
+ return p1.toUpperCase();
+ });
+ strValue = element.currentStyle[strCssRule];
+ }
+ return strValue;
+}
\ No newline at end of file
diff --git a/webapp_frontend/src/background/methods/windowSize.ts b/webapp_frontend/src/background/methods/windowSize.ts
new file mode 100644
index 00000000..0c93e6cc
--- /dev/null
+++ b/webapp_frontend/src/background/methods/windowSize.ts
@@ -0,0 +1,35 @@
+export interface getWindowSize_Interface {
+ viewportWidth: number,
+ viewportHeight: number
+}
+export function getWindowSize():getWindowSize_Interface {
+
+ let viewportwidth:number;
+ let viewportheight:number;
+
+// the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight
+
+ if (typeof window.innerWidth != 'undefined') {
+ viewportwidth = window.innerWidth
+ viewportheight = window.innerHeight
+ }
+
+// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)
+
+ else if (typeof document.documentElement != 'undefined' &&
+ typeof document.documentElement.clientWidth != ('undefined' || 0)){
+ viewportwidth = document.documentElement.clientWidth
+ viewportheight = document.documentElement.clientHeight
+ }
+
+// older versions of IE
+
+ else {
+ viewportwidth = document.getElementsByTagName('body')[0].clientWidth
+ viewportheight = document.getElementsByTagName('body')[0].clientHeight
+ }
+ return {
+ viewportHeight: viewportheight,
+ viewportWidth: viewportwidth
+ }
+}
\ No newline at end of file
diff --git a/webapp_frontend/src/components/App.css b/webapp_frontend/src/components/App.css
index 74b5e053..673d0063 100644
--- a/webapp_frontend/src/components/App.css
+++ b/webapp_frontend/src/components/App.css
@@ -1,10 +1,5 @@
-.App {
- text-align: center;
-}
-
-.App-logo {
- height: 40vmin;
- pointer-events: none;
+main > .container {
+ padding: 60px 15px 0;
}
@media (prefers-reduced-motion: no-preference) {
@@ -13,21 +8,6 @@
}
}
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
-}
-
-.App-link {
- color: #61dafb;
-}
-
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
diff --git a/webapp_frontend/src/components/App.tsx b/webapp_frontend/src/components/App.tsx
index 087440a0..68710fa9 100644
--- a/webapp_frontend/src/components/App.tsx
+++ b/webapp_frontend/src/components/App.tsx
@@ -13,11 +13,15 @@ import {SystemState} from "../background/redux/actions/sytemState";
import Login from "./basicElements/Login";
import {checkForCookie} from "../background/api/auth";
-
+import {TopBanner} from "./basicElements/TopBanner";
// this takes the redux store and maps everything that is needed to the function props
const mapState = (state: SystemState) => ({
- tokens: {refreshToken: state.tokens.refreshToken, accessToken: state.tokens.accessToken, checkedCookies: state.tokens.checkedCookies},
+ tokens: {
+ refreshToken: state.tokens.refreshToken,
+ accessToken: state.tokens.accessToken,
+ checkedCookies: state.tokens.checkedCookies
+ },
user: state.user
})
@@ -40,17 +44,23 @@ function App(props: Props): ReactElement {
console.log(props.tokens.refreshToken)
console.log(props.tokens)
console.log(props.user)
+ console.log("[App]---------------")
if (props.tokens.checkedCookies) {
- if (props.tokens.refreshToken && props.tokens.accessToken) {
+ if ((props.tokens.refreshToken && props.tokens.accessToken)) {
return (
-
+
diff --git a/webapp_frontend/src/components/Constants.tsx b/webapp_frontend/src/components/Constants.tsx
index 4a6bfc76..42a2ec9a 100644
--- a/webapp_frontend/src/components/Constants.tsx
+++ b/webapp_frontend/src/components/Constants.tsx
@@ -10,7 +10,10 @@ function Constants(): ReactElement {
// url + host of backend
- return (
);
+ return (
+
+
+ );
}
diff --git a/webapp_frontend/src/components/Health.tsx b/webapp_frontend/src/components/Health.tsx
deleted file mode 100644
index 46032370..00000000
--- a/webapp_frontend/src/components/Health.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React, {ReactElement, useCallback, useEffect, useState} from "react";
-import {callBackendHealth} from "../background/api/api";
-import Header from "./basicElements/Header";
-import {Button, Container, Table} from "react-bootstrap";
-import logo from "../assets/images/logos/logo.png";
-
-function Health(): ReactElement {
-
-
- const [backendLiveTime, setBackendLiveTime] = useState
("not reachable");
- const [backendUserCount, setBackendUserCount] = useState("not reachable");
-
- const callInitialBackendRequests = useCallback(():void => {
- updateVariables()
- },[]);
-
- useEffect(() => {
- callInitialBackendRequests()
- }, [callInitialBackendRequests]);
-
- function updateVariables(): void {
- Promise.all([callBackendHealth()])
- .then(([backendHealthData]) => {
- setBackendLiveTime(backendHealthData.uptimeInSeconds);
- setBackendUserCount(backendHealthData.userCount)
- })
- }
-
- return (
-
-
-
-
- FileFighter
-
-
-
-
-
-
-
-
-
-
-
- Backend information |
-
-
-
-
-
- Uptime |
- {backendLiveTime} |
-
-
- Usercount |
- {backendUserCount} |
-
-
-
-
-
-
- );
-}
-
-export default Health;
\ No newline at end of file
diff --git a/webapp_frontend/src/components/Router/Router.tsx b/webapp_frontend/src/components/Router/Router.tsx
index 26b52aff..cc277103 100644
--- a/webapp_frontend/src/components/Router/Router.tsx
+++ b/webapp_frontend/src/components/Router/Router.tsx
@@ -11,14 +11,17 @@ export default function Router(): ReactElement {
return (
-
+
+
+
+
-
-
+
+
)
-}
+}
\ No newline at end of file
diff --git a/webapp_frontend/src/components/basicElements/Footer.tsx b/webapp_frontend/src/components/basicElements/Footer.tsx
index 8aab8e8c..cf6ebabc 100644
--- a/webapp_frontend/src/components/basicElements/Footer.tsx
+++ b/webapp_frontend/src/components/basicElements/Footer.tsx
@@ -1,17 +1,20 @@
import React, {ReactElement} from 'react';
+import {Container} from 'react-bootstrap';
+import github from "super-tiny-icons/images/svg/github.svg"
export default function Footer(): ReactElement {
return (
-
-
-
-
- Footer |
- Footer |
-
-
-
-
+
+
+

+
Made by
+
+ Gimleux
+ Open-Schnick
+ qvalentin
+
+
+
);
}
diff --git a/webapp_frontend/src/components/basicElements/Header.tsx b/webapp_frontend/src/components/basicElements/Header.tsx
index 5b2e9f86..23462253 100644
--- a/webapp_frontend/src/components/basicElements/Header.tsx
+++ b/webapp_frontend/src/components/basicElements/Header.tsx
@@ -1,11 +1,75 @@
import React, {ReactElement} from 'react';
-import { useHistory } from "react-router-dom";
-import {Button} from "react-bootstrap";
+import {useHistory} from "react-router-dom";
+import {redirect} from "../../background/methods/redirect";
+import logo from "../../assets/images/logos/logo.png"
+import {Nav, Navbar, NavbarBrand} from "react-bootstrap";
-function Header():ReactElement {
+export interface navBarElement_Interface {
+ name: string,
+ text: string,
+ link: string,
+ deviantVisibleLink?: string,
+ logo: string | null,
+ onClick?: (...sth: any) => any,
+}
+
+function Header(): ReactElement {
const history = useHistory();
+ const navBarElements: navBarElement_Interface[] = [
+ {
+ name: "main",
+ text: "Main",
+ link: "/",
+ deviantVisibleLink: "/start",
+ logo: null
+ },
+ {
+ name: "files",
+ text: "Files",
+ link: "/file",
+ logo: null,
+ },
+ {
+ name: "registration",
+ text: "Registration",
+ link: "/registration",
+ logo: null,
+ }
+ ]
+
+ const final: ReactElement[] = []
+ navBarElements.forEach((element) => {
+ final.push(
+ {
+ redirect(history, element.link, event);
+ if (element.onClick) element.onClick()
+ }}
+ >{element.text}
+ )
+ })
- return()
+ return (
+
+
+
+ {redirect(history, "/", event);}}>
+
+ FileFighter
+
+
+
+
+
+
+
+
+ )
}
-export default Header;
\ No newline at end of file
+export default Header;
diff --git a/webapp_frontend/src/components/basicElements/Login.tsx b/webapp_frontend/src/components/basicElements/Login.tsx
index adea9893..4f64bb30 100644
--- a/webapp_frontend/src/components/basicElements/Login.tsx
+++ b/webapp_frontend/src/components/basicElements/Login.tsx
@@ -5,7 +5,7 @@ import {loginWithUsernameAndPassword} from "../../background/api/auth";
function Login(): ReactElement {
const [userName, setUsername] = useState("");
const [password, setPassword] = useState("");
- const [stayLoggedIn, setStayLoggedIn] = useState(false);
+ const [stayLoggedIn, setStayLoggedIn] = useState(true);
const [errorMessage, setErrorMessage] = useState("");
const [loading,setLoading]=useState(false);
@@ -47,7 +47,7 @@ function Login(): ReactElement {
- setStayLoggedIn(!stayLoggedIn)}/>
+ setStayLoggedIn(!stayLoggedIn)}/>
+ )
+}
\ No newline at end of file
diff --git a/webapp_frontend/src/components/pages/Health.tsx b/webapp_frontend/src/components/pages/Health.tsx
index b83eb255..ff48e58d 100644
--- a/webapp_frontend/src/components/pages/Health.tsx
+++ b/webapp_frontend/src/components/pages/Health.tsx
@@ -7,12 +7,20 @@ import {logout} from "../../background/api/auth";
export default function Health() {
- const [backendLiveTime, setBackendLiveTime] = useState("not reachable");
- const [backendUserCount, setBackendUserCount] = useState("not reachable");
+ const [backendLiveTime, setBackendLiveTime] = useState("not reachable");
+ const [backendUserCount, setBackendUserCount] = useState("not reachable");
useEffect(() => {
- updateVariables()
- }, []);
+ updateVariables();
+ }, [])
+
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ updateVariables()
+ }, 60000)
+ // Clear timeout if the component is unmounted
+ return () => clearTimeout(timer);
+ });
function updateVariables(): void {
Promise.all([callBackendHealth()])
@@ -20,6 +28,10 @@ export default function Health() {
setBackendLiveTime(backendHealthData.uptimeInSeconds);
setBackendUserCount(backendHealthData.userCount)
})
+ .catch(() => {
+ setBackendLiveTime("not reachable");
+ setBackendUserCount("not reachable");
+ })
}
return (
@@ -39,7 +51,7 @@ export default function Health() {
-
+ {/*
*/}
diff --git a/webapp_frontend/src/components/pages/Registration.tsx b/webapp_frontend/src/components/pages/Registration.tsx
index 98bbb1ca..bd3b8dfe 100644
--- a/webapp_frontend/src/components/pages/Registration.tsx
+++ b/webapp_frontend/src/components/pages/Registration.tsx
@@ -5,11 +5,15 @@ import {biggerMaxStrLength, notMinStrLength} from "../../background/methods/chec
import info_svg from "../../assets/images/icons/material.io/info-24px.svg";
import check_svg from "../../assets/images/icons/material.io/check_circle-24px.svg";
import error_svg from "../../assets/images/icons/material.io/error-24px.svg";
+import fileFighter from "../../assets/images/logos/logo.png";
import {registerNewUser} from "../../background/api/registration";
+import {getWindowSize, getWindowSize_Interface} from "../../background/methods/windowSize";
+import {getStyleValue} from "../../background/methods/style";
export default function Registration(): ReactElement {
const MIN_PASSWORD_LENGTH = 8;
const MAX_PASSWORD_LENGTH = 20;
+ const DEFAULT_ALERT_DURATION = 3500;
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
@@ -23,6 +27,26 @@ export default function Registration(): ReactElement {
const [alertVariant, setAlertColor] = useState<"primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark">("success");
const [alertVisibility, setAlertVisibility] = useState(false);
+ const registrationContainer = document.getElementById("registrationContainer")
+ const logoSubmit = document.getElementById("logoSubmit")
+
+ useEffect(() => {
+ function repositionSubmitLogo() {
+ const logo = document.getElementById("logoSubmit")
+ if (logo){
+ const container: HTMLElement | null = document.getElementById("registrationContainer");
+ const leftContainerOffset: number = container?.getBoundingClientRect().left ?? 0;
+
+ let containerPadding:string|number|null = getStyleValue(container, "padding-left");
+ const pxPosition = containerPadding.indexOf("px");
+ containerPadding = pxPosition === -1 ? null : Number(containerPadding.substr(0, pxPosition))
+
+ logo.style.left = -(leftContainerOffset+logo.offsetWidth*2+(containerPadding ?? 20)) + "px";
+ }
+ }
+ repositionSubmitLogo()
+ },[registrationContainer, logoSubmit])
+
const reviewPasswordMatch = useCallback(():void => {
setPasswordsMatch(password === passwordConfirmation);
},[password, passwordConfirmation]);
@@ -35,55 +59,48 @@ export default function Registration(): ReactElement {
console.log("[REGISTRATION] handleSubmit")
event.preventDefault();
reviewPasswordMatch();
- if (!username){
- setAlertColor("danger");
- setAlertMessage("Error: Please choose an username.")
- handleAlertVisibility(3500)
+ if (!username) {
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "danger", "Error: Please choose an username.")
} else if (!passwordsMatch) {
- setAlertColor("danger");
- setAlertMessage("Error: Password and password confirmation must match.")
- handleAlertVisibility(3500)
- } else if (!passwordInformationNumber || !passwordInformationLowercase || !passwordInformationUppercase || !passwordInformationLength){
- setAlertColor("danger");
- setAlertMessage("Error: Please pay attention to the notes below the input field.");
- handleAlertVisibility(3500)
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "danger", "Error: Password and password confirmation must match.")
+ } else if (!passwordInformationNumber || !passwordInformationLowercase || !passwordInformationUppercase || !passwordInformationLength) {
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "danger", "Error: Please pay attention to the notes below the input fields.")
} else {
await registerNewUser(username, password, passwordConfirmation)
.then(res => {
- setAlertMessage("Worked: " + (res.outputMessage ? res.outputMessage : (res.httpStatus + " " + res.httpMessage)));
- setAlertColor("success");
- console.table(res);
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "success", "Worked: " + (res.outputMessage ? res.outputMessage : (res.httpStatus + " " + res.httpMessage)));
+ toggleSubmitLogo();
})
.catch(err => {
- setAlertColor("danger");
- setAlertMessage("Error: " + (err.outputMessage ? err.outputMessage : (err.httpStatus + " " + err.httpMessage)))
- console.table(err)
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "danger", "Error: " + (err.outputMessage ? err.outputMessage : (err.httpStatus + " " + err.httpMessage)))
})
- .finally(() => handleAlertVisibility(3500))
}
}
- const handleAlertVisibility = (duration: number) => {
+ const handleAlertVisibility = (duration: number, color: "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark", message: string) => {
if (!alertVisibility) {
+ setAlertMessage(message);
+ setAlertColor(color);
setAlertVisibility(true);
setTimeout(() => {
- setAlertVisibility(false)
- }, duration)
+ setAlertVisibility(false);
+ }, duration);
}
}
- const makePasswordInputFitRules = (input:string):[string,boolean] => {
+ const makePasswordInputFitRules = (input: string): [string, boolean] => {
input = deleteSpaces(input);
- if (biggerMaxStrLength(input, MAX_PASSWORD_LENGTH)){
- return [input,false];
+ if (biggerMaxStrLength(input, MAX_PASSWORD_LENGTH)) {
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "warning", "Maximum password length exceeded. Input was undone.");
+ return [input, false];
}
- return [input,true];
+ return [input, true];
}
const handlePasswordChange = (event: ChangeEvent) => {
event.preventDefault();
- let value:[string,boolean]|string = makePasswordInputFitRules(event.target.value);
- if (!value[1]){
+ let value: [string, boolean] | string = makePasswordInputFitRules(event.target.value);
+ if (!value[1]) {
value = password;
} else {
value = value[0]
@@ -97,8 +114,8 @@ export default function Registration(): ReactElement {
const handlePasswordConfirmationChange = async (event: ChangeEvent) => {
event.preventDefault();
- let value:[string,boolean]|string = makePasswordInputFitRules(event.target.value);
- if (!value[1]){
+ let value: [string, boolean] | string = makePasswordInputFitRules(event.target.value);
+ if (!value[1]) {
value = passwordConfirmation;
} else {
value = value[0]
@@ -107,7 +124,7 @@ export default function Registration(): ReactElement {
}
return (
-
+
Create new account
@@ -173,6 +190,35 @@ export default function Registration(): ReactElement {
+
)
+
+ function toggleSubmitLogo() {
+ const logo = document.getElementById("logoSubmit")
+ if (logo) {
+ const size:getWindowSize_Interface = getWindowSize();
+
+ setTimeout(() => { //run right
+ logo.style.transition = "4s";
+ logo.classList.remove("invisible")
+ logo.classList.add("visible")
+ logo.style.transform = "translateX(" + (logo.offsetWidth + size.viewportWidth) + "px)";
+ }, 1000);
+ setTimeout(() => { //turn around
+ logo.style.transition = "2s";
+ logo.style.transform = "translateX(" + (logo.offsetWidth + size.viewportWidth) + "px) scaleX(-1)";
+ }, 4000);
+ setTimeout(() => { //run left
+ logo.style.transition = "4s";
+ logo.style.transform = "scaleX(-1)";
+ }, 5000);
+ setTimeout(() => { //turn around
+ logo.style.transform = "";
+ logo.classList.add("invisible")
+ logo.classList.remove("visible")
+ }, 8000);
+ }
+ }
}
diff --git a/webapp_frontend/src/style/custom.scss b/webapp_frontend/src/style/custom.scss
index 7ff5c51b..1dc8f0d7 100644
--- a/webapp_frontend/src/style/custom.scss
+++ b/webapp_frontend/src/style/custom.scss
@@ -1,7 +1,7 @@
//read this: https://getbootstrap.com/docs/4.1/getting-started/theming
// Override default variables before the import (see node_modules/bootstrap/scss/_variables.scss for all)
-$body-bg: #2a313d;;
+$body-bg: #2a313d;
$body-color: #FFF;
$blue: #1a4965;
@@ -26,6 +26,9 @@ $blue: #1a4965;
@import "~bootstrap/scss/forms";
@import "~bootstrap/scss/spinners";
@import "~bootstrap/scss/alert";
+@import "~bootstrap/scss/navbar";
+@import "~bootstrap/scss/nav";
+@import "~bootstrap/scss/transitions";
@import "~bootstrap/scss/breadcrumb";