Commit 424c9d2d authored by Djordje's avatar Djordje

Generate voting keys upon registration

parent 20979336
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
"@types/node": "^16.11.41", "@types/node": "^16.11.41",
"@types/react": "^18.0.14", "@types/react": "^18.0.14",
"@types/react-dom": "^18.0.5", "@types/react-dom": "^18.0.5",
"buffer": "^6.0.3",
"i18next": "^21.9.1", "i18next": "^21.9.1",
"i18next-browser-languagedetector": "^6.1.5", "i18next-browser-languagedetector": "^6.1.5",
"react": "^18.2.0", "react": "^18.2.0",
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
"react-i18next": "^11.18.4", "react-i18next": "^11.18.4",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"tweetnacl": "^1.0.3",
"typescript": "^4.7.4", "typescript": "^4.7.4",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
} }
...@@ -5348,6 +5350,25 @@ ...@@ -5348,6 +5350,25 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/batch": { "node_modules/batch": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
...@@ -5519,6 +5540,29 @@ ...@@ -5519,6 +5540,29 @@
"node-int64": "^0.4.0" "node-int64": "^0.4.0"
} }
}, },
"node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/buffer-from": { "node_modules/buffer-from": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
...@@ -9017,6 +9061,25 @@ ...@@ -9017,6 +9061,25 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
...@@ -15922,6 +15985,11 @@ ...@@ -15922,6 +15985,11 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}, },
"node_modules/tweetnacl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
},
"node_modules/type-check": { "node_modules/type-check": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
...@@ -20794,6 +20862,11 @@ ...@@ -20794,6 +20862,11 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
},
"batch": { "batch": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
...@@ -20929,6 +21002,15 @@ ...@@ -20929,6 +21002,15 @@
"node-int64": "^0.4.0" "node-int64": "^0.4.0"
} }
}, },
"buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"buffer-from": { "buffer-from": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
...@@ -23459,6 +23541,11 @@ ...@@ -23459,6 +23541,11 @@
"harmony-reflect": "^1.4.6" "harmony-reflect": "^1.4.6"
} }
}, },
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
},
"ignore": { "ignore": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
...@@ -28311,6 +28398,11 @@ ...@@ -28311,6 +28398,11 @@
} }
} }
}, },
"tweetnacl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
},
"type-check": { "type-check": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
"@types/node": "^16.11.41", "@types/node": "^16.11.41",
"@types/react": "^18.0.14", "@types/react": "^18.0.14",
"@types/react-dom": "^18.0.5", "@types/react-dom": "^18.0.5",
"buffer": "^6.0.3",
"i18next": "^21.9.1", "i18next": "^21.9.1",
"i18next-browser-languagedetector": "^6.1.5", "i18next-browser-languagedetector": "^6.1.5",
"react": "^18.2.0", "react": "^18.2.0",
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
"react-i18next": "^11.18.4", "react-i18next": "^11.18.4",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"tweetnacl": "^1.0.3",
"typescript": "^4.7.4", "typescript": "^4.7.4",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
......
...@@ -8,10 +8,17 @@ import { Application } from './components/Application'; ...@@ -8,10 +8,17 @@ import { Application } from './components/Application';
import { createTheme, ThemeProvider } from '@mui/material'; import { createTheme, ThemeProvider } from '@mui/material';
const theme = createTheme({ const theme = createTheme({
palette: {
primary: {
main: 'rgb(19, 71, 175)'
// dark: "#D24944"
}
},
typography: { typography: {
fontFamily: 'Inter', fontFamily: 'Inter',
body1: { body1: {
fontSize: '1rem', fontSize: '1rem',
color: 'rgb(30, 41, 60)'
}, },
}, },
}); });
......
...@@ -239,7 +239,7 @@ export function getTenentVoting(buildingId, callback) { ...@@ -239,7 +239,7 @@ export function getTenentVoting(buildingId, callback) {
return return
} }
dsp(genericAction(TENANT_VOTING_RECEIVED, data)) dsp(genericAction(TENANT_VOTING_RECEIVED, data))
}, "GET", false) }, "GET", false)(null)
} }
export function getTenantInfo(callback) { export function getTenantInfo(callback) {
......
import { Box } from "@mui/material" import { Box } from "@mui/material"
import { Navigate, Route, Routes } from "react-router-dom"; import { Navigate, Route, Routes } from "react-router-dom";
import { BuildingInvoices } from "./BuildingInvoices/BuildingInvoices"; import { BuildingInvoices } from "./BuildingInvoices/BuildingInvoices";
import { TabWrapper } from "./TabWrapper/TabWrapper";
const classes = { const classes = {
wrapper: { wrapper: {
backgroundColor: 'rgb(241, 245, 249)', backgroundColor: 'rgb(241, 245, 249)',
minHeight: '95vh', minHeight: '95vh',
width: '100%', width: '100%',
boxSizing: 'border-box',
paddingBlock: '3%',
paddingInline: '11%',
} }
} as const; } as const ;
export const ApplicationTab = () => { export const ApplicationTab = () => {
return ( return (
...@@ -20,8 +22,9 @@ export const ApplicationTab = () => { ...@@ -20,8 +22,9 @@ export const ApplicationTab = () => {
<Route path='issues' element={<div>Hello from issues</div>} /> <Route path='issues' element={<div>Hello from issues</div>} />
<Route path='voting' element={<div>Hello from voting</div>} /> <Route path='voting' element={<div>Hello from voting</div>} />
<Route path='invoices' element={<div>Hello from invoices</div>} /> <Route path='invoices' element={<div>Hello from invoices</div>} />
<Route path='building-invoices' element={<TabWrapper><BuildingInvoices/></TabWrapper>} /> <Route path='building-invoices' element={<BuildingInvoices />} />
<Route path='documents' element={<div>Hello from documents</div>} /> <Route path='documents' element={<div>Hello from documents</div>} />
<Route path='settings' element={<div>Hello from settings</div>} />
<Route path='*' element={<Navigate replace to="overview" />} /> <Route path='*' element={<Navigate replace to="overview" />} />
</Routes> </Routes>
</Box> </Box>
......
...@@ -59,7 +59,6 @@ const classes = { ...@@ -59,7 +59,6 @@ const classes = {
loginButton: { loginButton: {
alignSelf: 'flex-end', alignSelf: 'flex-end',
'&.MuiButton-root': { '&.MuiButton-root': {
backgroundColor: 'rgb(19, 71, 175)',
borderRadius: 40, borderRadius: 40,
padding: '10px', padding: '10px',
paddingInline: '25px' paddingInline: '25px'
......
...@@ -30,7 +30,7 @@ export const subMenu: SubMenu[] = [ ...@@ -30,7 +30,7 @@ export const subMenu: SubMenu[] = [
{ {
title: 'Aplikacija', title: 'Aplikacija',
items: [ items: [
{ title: 'Podešavanja', icon: <SettingsIcon /> }, { title: 'Podešavanja', icon: <SettingsIcon />, path: 'settings' },
{ title: 'English', icon: <LanguageIcon /> }] { title: 'English', icon: <LanguageIcon /> }]
} }
......
...@@ -57,7 +57,7 @@ export const SideMenuItem = ({ content, selectedItem, changeSelectedItem }: { co ...@@ -57,7 +57,7 @@ export const SideMenuItem = ({ content, selectedItem, changeSelectedItem }: { co
} }
}}> }}>
{!!item.icon && item.icon} {!!item.icon && item.icon}
<Typography>{item.title}</Typography> <Typography sx={{color: 'white'}}>{item.title}</Typography>
</Box> </Box>
))} ))}
</Box> </Box>
......
...@@ -21,4 +21,11 @@ ...@@ -21,4 +21,11 @@
flex: 1; flex: 1;
padding-block: 10%; padding-block: 10%;
padding-inline: 5%; padding-inline: 5%;
}
@media only screen and (max-width: 800px) {
.Logo {
display: none;
}
} }
\ No newline at end of file
import './Icons.css';
export const HelperIcon = ({helperRef, handleClick}: {helperRef: React.MutableRefObject<null>, handleClick: () => void}) => {
return (
<svg ref={helperRef} onClick={handleClick} xmlns="http://www.w3.org/2000/svg" className="icons-stroke questionMark" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" />
</svg>
);
}
\ No newline at end of file
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
cursor: pointer; cursor: pointer;
} }
.questionMark{
width: 3%;
}
.logout:hover { .logout:hover {
stroke: white; stroke: white;
} }
......
import { TextField, Box, Button, Select, FormControl, InputLabel, MenuItem, Typography } from "@mui/material"; import { TextField, Box, Button, Select, FormControl, InputLabel, MenuItem, Typography, FormControlLabel, Checkbox, Collapse, Popper, Fade } from "@mui/material";
import React, { useEffect, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import nacl from "tweetnacl";
import { getPreRegisterData, registerUser } from "../../actions/data-manager"; import { getPreRegisterData, registerUser } from "../../actions/data-manager";
import { RegistrationInfo } from "../../internal-types"; import { RegistrationInfo } from "../../internal-types";
import { Buffer } from "buffer";
import { HelperIcon } from "../icons/HelperIcon";
export const PUBLIC_KEY = 'publicKey'
export const PRIVATE_KEY = "privateKey"
const classes = { const classes = {
wrapper: { wrapper: {
...@@ -17,7 +23,13 @@ const classes = { ...@@ -17,7 +23,13 @@ const classes = {
}, },
nameWrapper: { nameWrapper: {
display: 'flex', display: 'flex',
gap: '20px' gap: '20px',
'& .MuiFormControl-root': {
flex: 1
},
"@media (max-width: 800px)": {
flexDirection: 'column'
},
}, },
textField: { textField: {
'& label.Mui-focused': { '& label.Mui-focused': {
...@@ -59,17 +71,47 @@ const classes = { ...@@ -59,17 +71,47 @@ const classes = {
}, },
}, },
voting: {
display: 'flex',
flexDirection: 'column',
gap: '20px'
},
digitalVoting: {
color: 'rgb(30, 41, 60)'
},
popperWrapper: {
display: 'flex',
alignItems: 'center'
},
helperCloud: {
width: '300px',
backgroundColor: 'rgba(255,255,255,1)',
padding: 2,
borderRadius: 5,
boxShadow: 'rgba(0, 0, 0, 0.24) 0px 3px 8px',
userSelect: 'none'
},
helperText: {
color: 'rgb(30, 41, 60)',
fontSize: '0.8rem'
},
registerButton: { registerButton: {
alignSelf: 'flex-end', alignSelf: 'flex-end',
'&.MuiButton-root': { '&.MuiButton-root': {
backgroundColor: 'rgb(19, 71, 175)',
borderRadius: 40, borderRadius: 40,
padding: '10px', padding: '10px',
paddingInline: '25px' paddingInline: '25px',
'&:disabled': {
backgroundColor: 'lightgray'
}
} }
} }
} as const; } as const;
export function keyToBase64(key: Uint8Array) {
return Buffer.from(key).toString('base64');
}
export const RegisterForm = (): JSX.Element => { export const RegisterForm = (): JSX.Element => {
// TODO Add proper frontend validation // TODO Add proper frontend validation
...@@ -83,6 +125,15 @@ export const RegisterForm = (): JSX.Element => { ...@@ -83,6 +125,15 @@ export const RegisterForm = (): JSX.Element => {
{ firstName: '', lastName: '', email: '', username: '', password: '', mobile: '', pendingBuildings: { id: buildingId!, units: [] } }); { firstName: '', lastName: '', email: '', username: '', password: '', mobile: '', pendingBuildings: { id: buildingId!, units: [] } });
const [errorField, setErrorField] = useState(''); const [errorField, setErrorField] = useState('');
const [errorMessage, setErrorMessage] = useState(''); const [errorMessage, setErrorMessage] = useState('');
const [digitalVoting, setDigitalVoting] = useState(true);
const [privateKeyWritten, setPrivateKeyWritten] = useState(false);
const [keyPair, setKeyPair] = useState(nacl.sign.keyPair());
const [toggleHelp, setToggleHelp] = useState(false);
const helperRef = useRef(null);
const handleIconClick = () => {
setToggleHelp(!toggleHelp);
}
const registerCallBack = (err: any, data: any, dsp: any) => { const registerCallBack = (err: any, data: any, dsp: any) => {
...@@ -94,6 +145,11 @@ export const RegisterForm = (): JSX.Element => { ...@@ -94,6 +145,11 @@ export const RegisterForm = (): JSX.Element => {
return; return;
} }
if (digitalVoting) {
localStorage.setItem(PUBLIC_KEY, keyToBase64(keyPair.publicKey));
localStorage.setItem(PRIVATE_KEY, keyToBase64(keyPair.secretKey));
}
navigate('../../login', { replace: true }); navigate('../../login', { replace: true });
} }
...@@ -107,6 +163,14 @@ export const RegisterForm = (): JSX.Element => { ...@@ -107,6 +163,14 @@ export const RegisterForm = (): JSX.Element => {
}); });
}, [buildingId, navigate]); }, [buildingId, navigate]);
useEffect(() => {
if (digitalVoting) {
setRegisterInfo({ ...registerInfo, publicKey: keyToBase64(keyPair.publicKey) });
} else {
setRegisterInfo({ ...registerInfo, publicKey: undefined });
}
}, [digitalVoting])
const handleKeyUp = (event: React.KeyboardEvent<HTMLDivElement>): void => { const handleKeyUp = (event: React.KeyboardEvent<HTMLDivElement>): void => {
if (event.key === 'Enter') { if (event.key === 'Enter') {
registerUser(buildingId, registerInfo, registerCallBack); registerUser(buildingId, registerInfo, registerCallBack);
...@@ -116,7 +180,11 @@ export const RegisterForm = (): JSX.Element => { ...@@ -116,7 +180,11 @@ export const RegisterForm = (): JSX.Element => {
return ( return (
<> <>
{buildingUnits && {buildingUnits &&
<Box style={classes.wrapper} onKeyUp={handleKeyUp}> <Box style={classes.wrapper} onKeyUp={handleKeyUp} onClick={() => {
if (toggleHelp) {
setToggleHelp(false);
}
}}>
<Typography sx={classes.title} variant='h4'>Create Account</Typography> <Typography sx={classes.title} variant='h4'>Create Account</Typography>
<Box sx={classes.nameWrapper}> <Box sx={classes.nameWrapper}>
<TextField <TextField
...@@ -124,7 +192,7 @@ export const RegisterForm = (): JSX.Element => { ...@@ -124,7 +192,7 @@ export const RegisterForm = (): JSX.Element => {
variant="outlined" variant="outlined"
size='small' size='small'
label="First name" label="First name"
sx={{...classes.textField, flex: 1}} sx={classes.textField}
value={registerInfo.firstName} value={registerInfo.firstName}
onChange={(e) => { onChange={(e) => {
setRegisterInfo({ ...registerInfo, firstName: e.target.value }) setRegisterInfo({ ...registerInfo, firstName: e.target.value })
...@@ -138,7 +206,7 @@ export const RegisterForm = (): JSX.Element => { ...@@ -138,7 +206,7 @@ export const RegisterForm = (): JSX.Element => {
variant="outlined" variant="outlined"
size='small' size='small'
label="Last name" label="Last name"
sx={{...classes.textField, flex: 1}} sx={classes.textField}
value={registerInfo.lastName} value={registerInfo.lastName}
onChange={(e) => { onChange={(e) => {
setRegisterInfo({ ...registerInfo, lastName: e.target.value }) setRegisterInfo({ ...registerInfo, lastName: e.target.value })
...@@ -148,6 +216,7 @@ export const RegisterForm = (): JSX.Element => { ...@@ -148,6 +216,7 @@ export const RegisterForm = (): JSX.Element => {
/> />
</Box> </Box>
<Box sx={classes.nameWrapper}>
<TextField <TextField
variant="outlined" variant="outlined"
size='small' size='small'
...@@ -160,6 +229,22 @@ export const RegisterForm = (): JSX.Element => { ...@@ -160,6 +229,22 @@ export const RegisterForm = (): JSX.Element => {
error={"email" === errorField} error={"email" === errorField}
helperText={"email" === errorField ? errorMessage : null} helperText={"email" === errorField ? errorMessage : null}
/> />
<TextField
variant="outlined"
size='small'
label="Mobile number"
type="number"
sx={classes.textField}
value={registerInfo.mobile}
onChange={(e) => {
setRegisterInfo({ ...registerInfo, mobile: e.target.value })
}}
error={"mobile" === errorField}
helperText={"mobile" === errorField ? errorMessage : null}
/>
</Box>
<Box sx={classes.nameWrapper}>
<TextField <TextField
variant="outlined" variant="outlined"
size='small' size='small'
...@@ -183,20 +268,8 @@ export const RegisterForm = (): JSX.Element => { ...@@ -183,20 +268,8 @@ export const RegisterForm = (): JSX.Element => {
setRegisterInfo({ ...registerInfo, password: e.target.value }) setRegisterInfo({ ...registerInfo, password: e.target.value })
}} }}
/> />
<TextField </Box>
variant="outlined" <FormControl fullWidth size="small" onKeyUp={(e) => { e.stopPropagation(); }}>
size='small'
label="Mobile number"
type="number"
sx={classes.textField}
value={registerInfo.mobile}
onChange={(e) => {
setRegisterInfo({ ...registerInfo, mobile: e.target.value })
}}
error={"mobile" === errorField}
helperText={"mobile" === errorField ? errorMessage : null}
/>
<FormControl fullWidth size="small" onKeyUp={(e) => {e.stopPropagation();}}>
<InputLabel>Select your units</InputLabel> <InputLabel>Select your units</InputLabel>
<Select <Select
label="Select your units" label="Select your units"
...@@ -212,10 +285,49 @@ export const RegisterForm = (): JSX.Element => { ...@@ -212,10 +285,49 @@ export const RegisterForm = (): JSX.Element => {
{buildingUnits.map((unit: any, index) => <MenuItem value={unit} key={index}>{unit.address}</MenuItem>)} {buildingUnits.map((unit: any, index) => <MenuItem value={unit} key={index}>{unit.address}</MenuItem>)}
</Select> </Select>
</FormControl> </FormControl>
<Box sx={classes.voting}>
<FormControlLabel
label="Želim da koristim digitalno glasanje u aplikaciji"
control={<Checkbox checked={digitalVoting} onChange={(event) => setDigitalVoting(event.target.checked)} />}
sx={classes.digitalVoting}
/>
<Collapse in={digitalVoting} >
<TextField
variant="outlined"
size='small'
fullWidth
value={keyToBase64(keyPair.secretKey)}
disabled
minRows={2}
maxRows={3}
multiline
/>
<Box sx={classes.popperWrapper}>
<FormControlLabel
label="Zapisao/la sam privatan kljuc"
control={<Checkbox checked={privateKeyWritten} onChange={(event) => setPrivateKeyWritten(event.target.checked)} />}
/>
<HelperIcon helperRef={helperRef} handleClick={handleIconClick} />
<Popper open={toggleHelp} anchorEl={helperRef.current} placement='top' disablePortal transition>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<Box sx={classes.helperCloud}>
<Typography sx={classes.helperText}>U slučaju da izgubite pristup ovom uređaju, ovaj ključ će vam biti potreban kako bi na novom uređaju mogli da učestvujete u glasanju!</Typography>
</Box>
</Fade>
)}
</Popper>
</Box>
</Collapse>
</Box>
<Button <Button
sx={classes.registerButton} sx={classes.registerButton}
variant='contained' variant='contained'
disabled={digitalVoting && !privateKeyWritten}
onClick={() => { onClick={() => {
registerUser(buildingId, registerInfo, registerCallBack); registerUser(buildingId, registerInfo, registerCallBack);
}} }}
......
...@@ -10,7 +10,8 @@ export type RegistrationInfo = { ...@@ -10,7 +10,8 @@ export type RegistrationInfo = {
pendingBuildings: { pendingBuildings: {
id: string, id: string,
units: string[] units: string[]
} },
publicKey?: string
} }
export type LoginInfo = { export type LoginInfo = {
......
...@@ -4,8 +4,6 @@ import LanguageDetector from "i18next-browser-languagedetector"; ...@@ -4,8 +4,6 @@ import LanguageDetector from "i18next-browser-languagedetector";
import en from '../locale/en.json'; import en from '../locale/en.json';
import sr from '../locale/sr.json'; import sr from '../locale/sr.json';
console.log(navigator.language);
const resources = { const resources = {
en, en,
sr, sr,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment