| @@ -3,6 +3,9 @@ | |||
| <head> | |||
| <meta charset="utf-8" /> | |||
| <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> | |||
| <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans"> | |||
| <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Poppins"> | |||
| <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Mulish"> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |||
| <meta name="theme-color" content="#000000" /> | |||
| <meta | |||
| @@ -1,24 +1,27 @@ | |||
| import React from 'react'; | |||
| import { Router } from 'react-router-dom'; | |||
| import { Helmet } from 'react-helmet-async'; | |||
| import i18next from 'i18next'; | |||
| import history from './store/utils/history'; | |||
| import AppRoutes from './AppRoutes'; | |||
| import React from "react"; | |||
| import { Router } from "react-router-dom"; | |||
| import { Helmet } from "react-helmet-async"; | |||
| import i18next from "i18next"; | |||
| import history from "./store/utils/history"; | |||
| import AppRoutes from "./AppRoutes"; | |||
| import GlobalStyle from "./components/Styles/globalStyles"; | |||
| import { StyledEngineProvider } from "@mui/material"; | |||
| const App = () => ( | |||
| <> | |||
| <Router history={history}> | |||
| <Helmet> | |||
| <title> | |||
| {i18next.t('app.title')} | |||
| </title> | |||
| </Helmet> | |||
| <main className="l-page"> | |||
| <AppRoutes /> | |||
| </main> | |||
| </Router> | |||
| const App = () => { | |||
| return ( | |||
| <> | |||
| <Router history={history}> | |||
| <Helmet> | |||
| <title>{i18next.t("app.title")}</title> | |||
| </Helmet> | |||
| <main className="l-page"> | |||
| <StyledEngineProvider injectFirst> | |||
| <GlobalStyle /> | |||
| <AppRoutes /> | |||
| </StyledEngineProvider> | |||
| </main> | |||
| </Router> | |||
| </> | |||
| )}; | |||
| </> | |||
| ); | |||
| export default App; | |||
| export default App; | |||
| @@ -8,25 +8,33 @@ import { | |||
| NOT_FOUND_PAGE, | |||
| ERROR_PAGE, | |||
| BASE_PAGE, | |||
| FORGOT_PASSWORD_MAIL_SENT, | |||
| REGISTER_PAGE, | |||
| REGISTER_SUCCESSFUL_PAGE, | |||
| } from './constants/pages'; | |||
| // import LoginPage from './pages/LoginPage/LoginPage'; | |||
| import LoginPage from './pages/LoginPage/LoginPageMUI'; | |||
| // import HomePage from './pages/HomePage/HomePage'; | |||
| import HomePage from './pages/HomePage/HomePageMUI'; | |||
| import NotFoundPage from './pages/ErrorPages/NotFoundPage'; | |||
| import ErrorPage from './pages/ErrorPages/ErrorPage'; | |||
| // import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPage'; | |||
| import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPageMUI'; | |||
| import PrivateRoute from './components/Router/PrivateRoute'; | |||
| import MailSent from './pages/ForgotPasswordPage/ForgotPasswordMailSent/MailSent'; | |||
| import Register from './pages/RegisterPages/Register/Register'; | |||
| import RegisterSuccessful from './pages/RegisterPages/RegisterSuccessful.js/RegisterSuccessful'; | |||
| const AppRoutes = () => ( | |||
| const AppRoutes = () => { | |||
| return ( | |||
| <Switch> | |||
| <Route exact path={BASE_PAGE} component={LoginPage} /> | |||
| <Route exact path={LOGIN_PAGE} component={LoginPage} /> | |||
| <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | |||
| <Route path={REGISTER_SUCCESSFUL_PAGE} component={RegisterSuccessful} /> | |||
| <Route path={REGISTER_PAGE} component={Register} /> | |||
| <Route path={ERROR_PAGE} component={ErrorPage} /> | |||
| <Route path={FORGOT_PASSWORD_MAIL_SENT} component={MailSent} /> | |||
| <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | |||
| <PrivateRoute | |||
| exact | |||
| path={HOME_PAGE} | |||
| @@ -34,7 +42,7 @@ const AppRoutes = () => ( | |||
| /> | |||
| <Redirect from="*" to={NOT_FOUND_PAGE} /> | |||
| </Switch> | |||
| ); | |||
| )}; | |||
| export default AppRoutes; | |||
| @@ -0,0 +1,3 @@ | |||
| <svg width="23" height="18" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| <path d="M4.24741 12.2086L1.42675 15M7.02641 13.3083C7.51222 13.3992 8.00558 13.4448 8.5 13.4444C12.0193 13.4444 14.998 11.1554 16 8C15.7302 7.15074 15.3147 6.3538 14.7716 5.64411L7.02641 13.3083ZM10.1677 6.35033C9.72551 5.91271 9.12576 5.66686 8.50039 5.66686C7.87502 5.66686 7.27527 5.91271 6.83307 6.35033C6.39087 6.78796 6.14244 7.3815 6.14244 8.00039C6.14244 8.61928 6.39087 9.21282 6.83307 9.65044L10.1677 6.35033ZM10.1677 6.34956L6.83386 9.64889L10.1677 6.34956ZM10.1661 6.35111L12.7518 3.79222L10.1661 6.35111ZM6.83228 9.65044L4.24662 12.2093L6.83228 9.65044ZM15.5732 1L12.7518 3.79222L15.5732 1ZM12.7518 3.79222C11.4846 2.983 10.0081 2.55354 8.5 2.55556C4.98067 2.55556 2.00204 4.84456 1 8C1.55325 9.7348 2.702 11.2236 4.24741 12.2086L12.7518 3.79222Z" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/> | |||
| </svg> | |||
| @@ -0,0 +1,4 @@ | |||
| <svg width="22" height="16" viewBox="0 0 22 16" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| <path d="M13.9999 7.99994C13.9999 8.79557 13.6838 9.55862 13.1212 10.1212C12.5586 10.6838 11.7956 10.9999 10.9999 10.9999C10.2043 10.9999 9.44126 10.6838 8.87866 10.1212C8.31606 9.55862 8 8.79557 8 7.99994C8 7.20431 8.31606 6.44126 8.87866 5.87866C9.44126 5.31606 10.2043 5 10.9999 5C11.7956 5 12.5586 5.31606 13.1212 5.87866C13.6838 6.44126 13.9999 7.20431 13.9999 7.99994V7.99994Z" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <path d="M1.45898 7.99986C2.73296 3.94294 6.52388 1 11.0008 1C15.4787 1 19.2686 3.94294 20.5426 7.99986C19.2686 12.0568 15.4787 14.9997 11.0008 14.9997C6.52388 14.9997 2.73296 12.0568 1.45898 7.99986Z" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/> | |||
| </svg> | |||
| @@ -0,0 +1,3 @@ | |||
| <svg width="12" height="9" viewBox="0 0 12 9" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| <path d="M1 5.2L3.85714 8L11 1" stroke="#FEB005" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||
| </svg> | |||
| @@ -3,6 +3,7 @@ body { | |||
| -webkit-font-smoothing: antialiased; | |||
| -moz-osx-font-smoothing: grayscale; | |||
| overflow-anchor: none; | |||
| background-color: #F1F1F1; | |||
| } | |||
| * { | |||
| @@ -0,0 +1,19 @@ | |||
| import React from 'react' | |||
| import { IconButtonContainer, IconButtonStyled } from "./IconButton.styled" | |||
| import PropTypes from "prop-types"; | |||
| export const IconButton = (props) => { | |||
| return <IconButtonContainer style={props.containerStyle} className={props.className}> | |||
| <IconButtonStyled onClick={props.onClick} sx={props.style}> | |||
| {props.children} | |||
| </IconButtonStyled> | |||
| </IconButtonContainer> | |||
| } | |||
| IconButton.propTypes = { | |||
| children: PropTypes.node, | |||
| onClick: PropTypes.func, | |||
| containerStyle: PropTypes.any, | |||
| style: PropTypes.any, | |||
| className: PropTypes.string, | |||
| } | |||
| @@ -0,0 +1,8 @@ | |||
| import { Box, IconButton } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const IconButtonContainer = styled(Box)` | |||
| ` | |||
| export const IconButtonStyled = styled(IconButton)` | |||
| ` | |||
| @@ -1,16 +1,16 @@ | |||
| import React from "react"; | |||
| import { ComponentContainer, LoginButtonStyled } from "./LoginButton.styled"; | |||
| import { LoginButtonContainer, LoginButtonStyled } from "./LoginButton.styled"; | |||
| import PropTypes from "prop-types"; | |||
| //Currently not in use | |||
| export const LoginButton = (props) => { | |||
| return ( | |||
| <ComponentContainer style={props.containerStyle}> | |||
| <LoginButtonContainer style={props.containerStyle}> | |||
| <LoginButtonStyled {...props} sx={props.style} variant="contained"> | |||
| Dugme | |||
| </LoginButtonStyled> | |||
| </ComponentContainer> | |||
| </LoginButtonContainer> | |||
| ); | |||
| }; | |||
| @@ -22,4 +22,5 @@ LoginButton.propTypes = { | |||
| containerStyle: PropTypes.any, | |||
| fullWidth: PropTypes.string, | |||
| buttonColor: PropTypes.string, | |||
| onClick: PropTypes.func | |||
| }; | |||
| @@ -1,8 +1,8 @@ | |||
| import { Button } from "@mui/material"; | |||
| import { Box, Button } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const ComponentContainer = styled.div` | |||
| export const LoginButtonContainer = styled(Box)` | |||
| ` | |||
| export const LoginButtonStyled = styled(Button)` | |||
| @@ -1,27 +1,35 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| ComponentContainer, | |||
| PrimaryButtonContainer, | |||
| PrimaryButtonStyled, | |||
| } from "./PrimaryButton.styled"; | |||
| export const PrimaryButton = (props) => { | |||
| return ( | |||
| <ComponentContainer style={props.containerStyle}> | |||
| <PrimaryButtonStyled fullWidth {...props} sx={props.style}> | |||
| <PrimaryButtonContainer style={props.containerStyle} className={props.className}> | |||
| <PrimaryButtonStyled {...props} sx={props.style}> | |||
| {props.children} | |||
| </PrimaryButtonStyled> | |||
| </ComponentContainer> | |||
| </PrimaryButtonContainer> | |||
| ); | |||
| }; | |||
| PrimaryButton.propTypes = { | |||
| children: PropTypes.node, | |||
| type: PropTypes.string, | |||
| variant: PropTypes.string, | |||
| type: PropTypes.oneOf(["button", "reset", "submit"]), | |||
| variant: PropTypes.oneOf(["contained", "outlined", "text"]), | |||
| style: PropTypes.any, | |||
| containerStyle: PropTypes.any, | |||
| fullWidth: PropTypes.string, | |||
| buttonColor: PropTypes.string, | |||
| textColor: PropTypes.string, | |||
| fullWidth: PropTypes.bool, | |||
| buttoncolor: PropTypes.string, | |||
| textcolor: PropTypes.string, | |||
| className: PropTypes.string, | |||
| onClick: PropTypes.func, | |||
| font: PropTypes.string | |||
| }; | |||
| PrimaryButton.defaultProps = { | |||
| font: "Open Sans" | |||
| } | |||
| @@ -1,20 +1,31 @@ | |||
| import { Button } from "@mui/material"; | |||
| import { Box, Button } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| export const ComponentContainer = styled.div``; | |||
| export const PrimaryButtonContainer = styled(Box)``; | |||
| export const PrimaryButtonStyled = styled(Button)` | |||
| background-color: ${props => props.variant === "contained" ? props.buttonColor : "transparent"}; | |||
| border-color: ${props => props.variant === "outlined" ? props.buttonColor : "transparent"}; | |||
| color: ${props => props.textColor}; | |||
| background-color: ${(props) => props.disabled ? selectedTheme.primaryPurpleDisabled: ( | |||
| props.variant === "contained" ? props.buttoncolor : "transparent")} !important; | |||
| border-color: ${(props) => | |||
| props.variant === "outlined" ? props.buttoncolor : "transparent"}; | |||
| color: ${(props) => props.disabled ? selectedTheme.primaryTextDisabled : ( | |||
| props.textcolor)} !important; | |||
| box-shadow: 0 0 0 0; | |||
| font-size: 10px; | |||
| font-size: 12px; | |||
| letter-spacing: 1px; | |||
| font-weight: 100; | |||
| width: ${props => props.width}; | |||
| height: ${props => props.height}; | |||
| width: ${(props) => props.width}; | |||
| font-family: ${(props) => props.font}; | |||
| height: ${(props) => props.height}; | |||
| &:hover { | |||
| background-color: ${props => props.variant === "contained" ? props.buttonColor : "transparent"}; | |||
| background-color: ${(props) => | |||
| props.variant === "contained" ? props.buttoncolor : "transparent"}; | |||
| box-shadow: 0 0 0 0; | |||
| } | |||
| &:disabled { | |||
| background-color: ${selectedTheme.primaryPurpleDisabled}; | |||
| color: ${(props) => props.textcolor}; | |||
| } | |||
| `; | |||
| @@ -0,0 +1,34 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| PrimaryButtonWithIconContainer, | |||
| IconStyled, | |||
| PrimaryButtonWithIconStyled, | |||
| } from "./PrimaryButtonWithIcon.styled"; | |||
| const PrimaryButtonWithIcon = (props) => { | |||
| return ( | |||
| <PrimaryButtonWithIconContainer | |||
| style={props.containerStyle} | |||
| className={props.className} | |||
| > | |||
| <PrimaryButtonWithIconStyled sx={props.style} {...props.buttonProps} onClick={props.onClick}> | |||
| <IconStyled style={props.iconStyle}>{props.icon}</IconStyled> | |||
| {props.children} | |||
| </PrimaryButtonWithIconStyled> | |||
| </PrimaryButtonWithIconContainer> | |||
| ); | |||
| }; | |||
| PrimaryButtonWithIcon.propTypes = { | |||
| children: PropTypes.node, | |||
| icon: PropTypes.node, | |||
| className: PropTypes.string, | |||
| containerStyle: PropTypes.any, | |||
| style: PropTypes.any, | |||
| iconStyle: PropTypes.any, | |||
| buttonProps: PropTypes.any, | |||
| onClick: PropTypes.func, | |||
| }; | |||
| export default PrimaryButtonWithIcon; | |||
| @@ -0,0 +1,28 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { Icon } from "../../Icon/Icon"; | |||
| import { PrimaryButton } from "../PrimaryButton/PrimaryButton"; | |||
| export const PrimaryButtonWithIconContainer = styled(Box)``; | |||
| export const PrimaryButtonWithIconStyled = styled(PrimaryButton)` | |||
| position: relative; | |||
| `; | |||
| export const IconStyled = styled(Icon)` | |||
| position: absolute; | |||
| padding: 0; | |||
| left: 10px; | |||
| top: 0; | |||
| bottom: 0; | |||
| margin-top: auto; | |||
| margin-bottom: auto; | |||
| line-height: 21px; | |||
| & span { | |||
| position: absolute; | |||
| top: 0; | |||
| bottom: 0; | |||
| margin-top: auto; | |||
| margin-bottom: auto; | |||
| } | |||
| `; | |||
| @@ -0,0 +1,66 @@ | |||
| import React, { useState } from "react"; | |||
| import { | |||
| CheckBoxStyled, | |||
| CheckBoxContainer, | |||
| FormControlLabelStyled, | |||
| } from "./CheckBox.styled"; | |||
| import PropTypes from "prop-types"; | |||
| import { Label } from "./Label"; | |||
| import selectedTheme from "../../themes"; | |||
| export const CheckBox = (props) => { | |||
| const [checked, setChecked] = useState(false); | |||
| const handleClick = () => { | |||
| if (props.onChange) props.onChange(!checked); | |||
| setChecked((prevState) => !prevState); | |||
| }; | |||
| return ( | |||
| <CheckBoxContainer | |||
| style={props.containerStyle} | |||
| fullWidth={props.fullWidth} | |||
| className={props.className} | |||
| > | |||
| <FormControlLabelStyled | |||
| fullWidth={props.fullWidth} | |||
| control={ | |||
| <CheckBoxStyled | |||
| sx={props.checkBoxStyle} | |||
| boxcolor={props.color} | |||
| checked={props.value ? props.value : checked} | |||
| onClick={handleClick} | |||
| /> | |||
| } | |||
| label={ | |||
| <Label | |||
| sx={props.labelStyle} | |||
| onClick={handleClick} | |||
| leftText={props.leftText} | |||
| rightText={props.rightText} | |||
| maxWidth={props.maxWidth} | |||
| /> | |||
| } | |||
| /> | |||
| </CheckBoxContainer> | |||
| ); | |||
| }; | |||
| CheckBox.propTypes = { | |||
| fullWidth: PropTypes.bool, | |||
| color: PropTypes.string, | |||
| name: PropTypes.string, | |||
| leftText: PropTypes.string, | |||
| rightText: PropTypes.string, | |||
| maxWidth: PropTypes.string, | |||
| value: PropTypes.bool, | |||
| onChange: PropTypes.func, | |||
| containerStyle: PropTypes.any, | |||
| checkBoxStyle: PropTypes.any, | |||
| labelStyle: PropTypes.any, | |||
| className: PropTypes.string, | |||
| }; | |||
| CheckBox.defaultProps = { | |||
| color: selectedTheme.primaryPurple, | |||
| }; | |||
| @@ -0,0 +1,26 @@ | |||
| import { Box, Checkbox, FormControlLabel } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const CheckBoxContainer = styled(Box)` | |||
| ${props => props.fullWidth && (` | |||
| width: 100%; | |||
| display: flex; | |||
| flex: 1; | |||
| `)} | |||
| ` | |||
| export const CheckBoxStyled = styled(Checkbox)` | |||
| color: ${props => props.boxcolor} !important; | |||
| padding: 6px; | |||
| ` | |||
| export const FormControlLabelStyled = styled(FormControlLabel)` | |||
| ${props => props.fullWidth && (` | |||
| width: 100%; | |||
| display: flex; | |||
| flex: 1; | |||
| `)} | |||
| margin-right: 0; | |||
| & span:nth-child(2) { | |||
| flex: 1; | |||
| } | |||
| ` | |||
| @@ -0,0 +1,19 @@ | |||
| import React from "react"; | |||
| import { LabelContainer, LeftLabel, RightLabel } from "./Label.styled"; | |||
| import PropTypes from "prop-types"; | |||
| export const Label = (props) => { | |||
| return ( | |||
| <LabelContainer onClick={props.onClick} maxWidth={props.maxWidth}> | |||
| <LeftLabel>{props.leftText}</LeftLabel> | |||
| {props.rightText && <RightLabel>{props.rightText}</RightLabel>} | |||
| </LabelContainer> | |||
| ); | |||
| }; | |||
| Label.propTypes = { | |||
| onClick: PropTypes.func, | |||
| leftText: PropTypes.string, | |||
| rightText: PropTypes.string, | |||
| maxWidth: PropTypes.string, | |||
| }; | |||
| @@ -0,0 +1,26 @@ | |||
| import { Box, FormLabel } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const LabelContainer = styled(Box)` | |||
| display: flex; | |||
| flex: 1; | |||
| justify-content: space-between; | |||
| max-width: ${props => props.maxWidth}; | |||
| ` | |||
| export const LeftLabel = styled(FormLabel)` | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| white-space: nowrap; | |||
| max-width: 200px; | |||
| flex: 1; | |||
| cursor: pointer; | |||
| ` | |||
| export const RightLabel = styled(FormLabel)` | |||
| margin-left: 10px; | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| white-space: nowrap; | |||
| max-width: 100px; | |||
| cursor: pointer; | |||
| ` | |||
| @@ -0,0 +1,20 @@ | |||
| import React from 'react' | |||
| import PropTypes from 'prop-types' | |||
| import { DropdownItemContainer, DropdownItemStyled } from './DropdownItem.styled' | |||
| const DropdownItem = (props) => { | |||
| return ( | |||
| <DropdownItemContainer onClick={props.onClick}> | |||
| <DropdownItemStyled> | |||
| {props.children} | |||
| </DropdownItemStyled> | |||
| </DropdownItemContainer> | |||
| ) | |||
| } | |||
| DropdownItem.propTypes = { | |||
| children: PropTypes.node, | |||
| onClick: PropTypes.func, | |||
| } | |||
| export default DropdownItem; | |||
| @@ -0,0 +1,8 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const DropdownItemContainer = styled(Box)` | |||
| ` | |||
| export const DropdownItemStyled = styled(Box)` | |||
| ` | |||
| @@ -0,0 +1,59 @@ | |||
| import React, { useState } from "react"; | |||
| import { | |||
| DropdownListContainer, | |||
| DropdownHeader, | |||
| DropdownIcon, | |||
| DropdownTitle, | |||
| ListContainer, | |||
| ToggleIconClosed, | |||
| ToggleIconOpened, | |||
| } from "./DropdownList.styled"; | |||
| import PropTypes from "prop-types"; | |||
| const DropdownList = (props) => { | |||
| const [listShown, setListShown] = useState(props.defaultOpen); | |||
| return ( | |||
| <DropdownListContainer fullWidth={props.fullWidth}> | |||
| <DropdownHeader> | |||
| {props.dropdownIcon && ( | |||
| <DropdownIcon>{props.dropdownIcon}</DropdownIcon> | |||
| )} | |||
| <DropdownTitle onClick={() => setListShown((prevState) => !prevState)}> | |||
| {props.title} | |||
| </DropdownTitle> | |||
| {listShown ? ( | |||
| <ToggleIconOpened | |||
| onClick={() => setListShown((prevState) => !prevState)} | |||
| > | |||
| {props.toggleIconOpened} | |||
| </ToggleIconOpened> | |||
| ) : ( | |||
| <ToggleIconClosed | |||
| onClick={() => setListShown((prevState) => !prevState)} | |||
| > | |||
| {props.toggleIconClosed} | |||
| </ToggleIconClosed> | |||
| )} | |||
| </DropdownHeader> | |||
| <ListContainer shouldShow={listShown}>{props.children}</ListContainer> | |||
| </DropdownListContainer> | |||
| ); | |||
| }; | |||
| export default DropdownList; | |||
| DropdownList.propTypes = { | |||
| title: PropTypes.string, | |||
| dropdownIcon: PropTypes.node, | |||
| toggleIconOpened: PropTypes.node, | |||
| toggleIconClosed: PropTypes.node, | |||
| children: PropTypes.node, | |||
| fullWidth: PropTypes.bool, | |||
| defaultOpen: PropTypes.bool | |||
| }; | |||
| DropdownList.defaultProps = { | |||
| fullWidth: false, | |||
| defaultOpen: true | |||
| }; | |||
| @@ -0,0 +1,51 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { Icon } from "../../Icon/Icon"; | |||
| export const DropdownListContainer = styled(Box)` | |||
| width: ${props => props.fullWidth ? '100%' : (props.width ? props.width : '250px')}; | |||
| padding: 8px; | |||
| ` | |||
| export const DropdownTitle = styled(Typography)` | |||
| display: flex; | |||
| flex: 1; | |||
| cursor: pointer; | |||
| padding-left: 9px; | |||
| font-size: 18px; | |||
| font-weight: 100; | |||
| padding-bottom: 10px; | |||
| ` | |||
| export const ToggleIconOpened = styled(Icon)` | |||
| cursor: pointer; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| ` | |||
| export const ToggleIconClosed = styled(Icon)` | |||
| cursor: pointer; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| ` | |||
| export const DropdownIcon = styled(Icon)` | |||
| font-size: 24px !important; | |||
| & span { | |||
| font-size: 24px; | |||
| & svg { | |||
| font-size: 24px; | |||
| } | |||
| } | |||
| ` | |||
| export const ListContainer = styled(Box)` | |||
| padding-left: 15px; | |||
| display: ${props => props.shouldShow ? "block" : "none"}; | |||
| ` | |||
| export const DropdownHeader = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| ` | |||
| @@ -0,0 +1,25 @@ | |||
| import React from 'react'; | |||
| import { IconContainer, IconStyled } from './Icon.styled'; | |||
| import PropTypes from "prop-types"; | |||
| export const Icon = (props) => { | |||
| return ( | |||
| <IconContainer style={props.containerStyle} className={props.className} onClick={props.onClick}> | |||
| <IconStyled sx={props.style} color={props.color} size={props.size} fontSize={props.iconsize}> | |||
| {props.children} | |||
| </IconStyled> | |||
| </IconContainer> | |||
| ) | |||
| } | |||
| Icon.propTypes = { | |||
| children: PropTypes.node, | |||
| containerStyle: PropTypes.any, | |||
| style: PropTypes.any, | |||
| color: PropTypes.string, | |||
| size: PropTypes.string, | |||
| iconsize: PropTypes.string, | |||
| className: PropTypes.any, | |||
| onClick: PropTypes.func, | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| import { Box, Icon } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const IconContainer = styled(Box)` | |||
| ` | |||
| export const IconStyled = styled(Icon)` | |||
| color: ${props => props.color}; | |||
| width: ${props => props.size}; | |||
| height: ${props => props.size}; | |||
| ` | |||
| @@ -0,0 +1,25 @@ | |||
| import React from 'react' | |||
| import PropTypes from 'prop-types'; | |||
| import { LinkStyled } from './Link.styled'; | |||
| const Link = props => { | |||
| return ( | |||
| <LinkStyled {...props} href={props.href}>{props.children}</LinkStyled> | |||
| ) | |||
| } | |||
| Link.propTypes = { | |||
| href: PropTypes.string, | |||
| children: PropTypes.node, | |||
| font: PropTypes.string, | |||
| align: PropTypes.oneOf(["left", "right", "center"]), | |||
| textsize: PropTypes.string, | |||
| lineheight: PropTypes.string, | |||
| } | |||
| Link.defaultProps = { | |||
| font: "Poppins", | |||
| align: "left", | |||
| textsize: "14px" | |||
| } | |||
| export default Link | |||
| @@ -0,0 +1,17 @@ | |||
| import { Link } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../themes"; | |||
| export const LinkStyled = styled(Link)` | |||
| color: ${selectedTheme.primaryPurple}; | |||
| font-family: ${(props) => props.font}; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: ${props => props.textsize ? props.textsize : "14px"}; | |||
| line-height: ${props => props.lineheight ? props.lineheight : "14px"}; | |||
| text-decoration-line: underline; | |||
| display: block; | |||
| text-align: ${props => props.align === "right" ? "right" : (props.align === "center" ? "center" : "left")}; | |||
| /* ${props => props.align === "right" && "display: block; text-align: right;"} | |||
| ${props => props.align === "center" && "display: block; text-align: center;"} */ | |||
| `; | |||
| @@ -1,10 +1,12 @@ | |||
| import React from 'react'; | |||
| import {ReactComponent as Logo} from "../../assets/images/svg/big-logo-vertical.svg"; | |||
| import { FullPageLoaderContainer } from './FullPageLoader.styled'; | |||
| const FullPageLoader = () => { | |||
| return ( | |||
| <div className="c-loader c-loader--page"> | |||
| <div className="c-loader__icon" /> | |||
| </div> | |||
| <FullPageLoaderContainer> | |||
| <Logo /> | |||
| </FullPageLoaderContainer> | |||
| ); | |||
| }; | |||
| @@ -0,0 +1,10 @@ | |||
| import { Container } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const FullPageLoaderContainer = styled(Container)` | |||
| height: 100%; | |||
| width: 100vw; | |||
| padding-top: 250px; | |||
| text-align: center; | |||
| ` | |||
| @@ -0,0 +1,43 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { StepProgressContainer, Progress, StepBar, StepLine } from "./StepProgress.styled"; | |||
| import { ReactComponent as Checkmark } from "../../assets/images/svg/checkmark.svg"; | |||
| const StepProgress = (props) => { | |||
| const steps = []; | |||
| for (let i = 1; i <= props.numberOfSteps; i++) { | |||
| steps.push({ | |||
| done: i < props.current, | |||
| current: i === props.current, | |||
| }); | |||
| } | |||
| return ( | |||
| <StepProgressContainer done> | |||
| {steps.map((item, index) => | |||
| index === 0 ? ( | |||
| <StepBar current={item.current} done={item.done} key={index}> | |||
| {item.done ? <Checkmark /> : index+1} | |||
| </StepBar> | |||
| ) : ( | |||
| <React.Fragment key={index}> | |||
| <StepLine done={item.done || item.current} > | |||
| <Progress done={item.done || item.current} /> | |||
| </StepLine> | |||
| <StepBar current={item.current} done={item.done}> | |||
| {item.done ? <Checkmark /> : index+1} | |||
| </StepBar> | |||
| </React.Fragment> | |||
| ) | |||
| )} | |||
| </StepProgressContainer> | |||
| ); | |||
| }; | |||
| StepProgress.propTypes = { | |||
| children: PropTypes.node, | |||
| handleNext: PropTypes.node, | |||
| current: PropTypes.number, | |||
| numberOfSteps: PropTypes.number, | |||
| }; | |||
| export default StepProgress; | |||
| @@ -0,0 +1,44 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../themes"; | |||
| export const StepProgressContainer = styled(Box)` | |||
| display: flex; | |||
| height: 35px; | |||
| flex-direction: row; | |||
| position: relative; | |||
| left: 2px; | |||
| width: 100%; | |||
| `; | |||
| export const StepLine = styled(Box)` | |||
| margin-top: 13px; | |||
| background-color: white; | |||
| width: 100%; | |||
| margin-left: -1px; | |||
| height: 9px; | |||
| `; | |||
| export const StepBar = styled(Box)` | |||
| flex: 0 0 35px; | |||
| background-color: ${(props) => | |||
| props.done ? selectedTheme.primaryPurple : selectedTheme.primaryDarkGrayText}; | |||
| border-radius: 100%; | |||
| font-family: "Open Sans"; | |||
| text-align: center; | |||
| border: 5px solid | |||
| ${(props) => (props.current || props.done ? selectedTheme.primaryPurple : "white")}; | |||
| padding-top: 2px; | |||
| line-height: 19px; | |||
| margin-left: -2px; | |||
| font-size: 14px; | |||
| color: #1d1d1d; | |||
| z-index: 1; | |||
| transition: background-color 1s ease; | |||
| `; | |||
| export const Progress = styled(Box)` | |||
| height: 9px; | |||
| width: ${(props) => (props.done ? "100%" : "0")}; | |||
| background-color: ${selectedTheme.primaryPurple}; | |||
| transition: width 1s; | |||
| `; | |||
| @@ -0,0 +1,29 @@ | |||
| import { createGlobalStyle } from 'styled-components'; | |||
| // import OpenSans from "./fonts/OpenSans-Regular.ttf" | |||
| // import Poppins from "./fonts/Poppins-Regular.ttf" | |||
| // import Mulish from "./fonts/Mulish-Regular.ttf" | |||
| const GlobalStyle = createGlobalStyle` | |||
| ${'' /* @font-face { | |||
| font-family: 'Open Sans'; | |||
| src: url(${OpenSans}) format('truetype'); | |||
| font-weight: 400; | |||
| font-style: normal; | |||
| font-display: auto; | |||
| } | |||
| @font-face { | |||
| font-family: 'Poppins'; | |||
| src: url(${Poppins}) format('truetype'); | |||
| font-weight: 400; | |||
| font-style: normal; | |||
| font-display: auto; | |||
| } | |||
| @font-face { | |||
| font-family: "Mulish"; | |||
| src: url(${Mulish}) format('truetype'); | |||
| font-weight: 400; | |||
| font-style: normal; | |||
| font-display: auto; | |||
| } */} | |||
| `; | |||
| export default GlobalStyle; | |||
| @@ -1,14 +0,0 @@ | |||
| import { TextField } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| const backgroundColor = `rgb(241, 241, 241)`; | |||
| export const ComponentContainer = styled.div` | |||
| width: 100%; | |||
| `; | |||
| export const TextFieldMUIStyled = styled(TextField)` | |||
| background-color: ${backgroundColor}; | |||
| width: ${(props) => props.width}; | |||
| font-style: ${(props) => (props.italic === true ? "italic" : "normal")}; | |||
| `; | |||
| @@ -1,11 +1,11 @@ | |||
| import React, { useEffect, useState } from "react"; | |||
| import { ComponentContainer, TextFieldMUIStyled } from "./TextField.styled"; | |||
| import { TextFieldContainer, TextFieldStyled } from "./TextField.styled"; | |||
| import PropTypes from "prop-types"; | |||
| export const TextField = (props) => { | |||
| const [isFieldEmpty, setIsFieldEmpty] = useState(true); | |||
| //for italicPlaceholder | |||
| // for italicPlaceholder | |||
| useEffect(() => { | |||
| if (props.value.length === 0) { | |||
| setIsFieldEmpty(true); | |||
| @@ -15,14 +15,29 @@ export const TextField = (props) => { | |||
| }, [props.value]); | |||
| return ( | |||
| <ComponentContainer style={props.containerStyle}> | |||
| <TextFieldMUIStyled | |||
| {...props} | |||
| <TextFieldContainer style={props.containerStyle} className={props.className}> | |||
| <TextFieldStyled | |||
| placeholder={props.placeholder} | |||
| width={props.width} | |||
| height={props.height} | |||
| name={props.name} | |||
| value={props.value} | |||
| onChange={props.onChange} | |||
| error={props.error} | |||
| // helperText={props.helperText} | |||
| autoFocus={props.autoFocus} | |||
| fullWidth={props.fullWidth} | |||
| type={props.type} | |||
| textsize={props.textsize} | |||
| font={props.font} | |||
| InputProps={props.InputProps} | |||
| sx={props.style} | |||
| label={props.showAnimation ? props.placeholder : ""} | |||
| italic={props.italicPlaceholder && isFieldEmpty} | |||
| /> | |||
| </ComponentContainer> | |||
| > | |||
| {props.children} | |||
| </TextFieldStyled> | |||
| </TextFieldContainer> | |||
| ); | |||
| }; | |||
| @@ -34,6 +49,8 @@ TextField.propTypes = { | |||
| pathname: PropTypes.string, | |||
| }), | |||
| }), | |||
| children: PropTypes.node, | |||
| className: PropTypes.string, | |||
| placeholder: PropTypes.string, | |||
| style: PropTypes.any, | |||
| showAnimation: PropTypes.bool, | |||
| @@ -43,19 +60,24 @@ TextField.propTypes = { | |||
| height: PropTypes.string, | |||
| name: PropTypes.string, | |||
| label: PropTypes.string, | |||
| value: PropTypes.string, | |||
| value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | |||
| onChange: PropTypes.func, | |||
| error: PropTypes.string, | |||
| error: PropTypes.bool, | |||
| helperText: PropTypes.string, | |||
| autoFocus: PropTypes.bool, | |||
| fullWidth: PropTypes.bool, | |||
| type: PropTypes.string, | |||
| InputProps: { | |||
| textsize: PropTypes.string, | |||
| font: PropTypes.string, | |||
| InputProps: PropTypes.shape({ | |||
| startAdornment: PropTypes.node, | |||
| endAdornment: PropTypes.node, | |||
| }, | |||
| style: PropTypes.any, | |||
| }), | |||
| }; | |||
| TextField.defaultProps = { | |||
| italicPlaceholder: false, | |||
| showAnimation: false, | |||
| // font: "Open Sans" | |||
| }; | |||
| @@ -0,0 +1,31 @@ | |||
| import { Box, TextField } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { PRIMARY_BACKGROUND_COLOR } from "../../../constants/stylesConstants"; | |||
| export const TextFieldContainer = styled(Box)` | |||
| width: 100%; | |||
| height: 48px; | |||
| box-sizing: border-box; | |||
| margin: 16px 0; | |||
| padding-left: 0; | |||
| `; | |||
| export const TextFieldStyled = styled(TextField)` | |||
| background-color: ${PRIMARY_BACKGROUND_COLOR}; | |||
| width: ${(props) => props.width}; | |||
| font-style: ${(props) => (props.italic === true ? "italic" : "normal")}; | |||
| padding-left: 0; | |||
| margin: 0; | |||
| padding: 0; | |||
| height: 100%; | |||
| box-sizing: border-box; | |||
| & div { | |||
| padding-left: 2px; | |||
| } | |||
| & div input { | |||
| height: 48px; | |||
| box-sizing: border-box; | |||
| font-size: ${props => props.textsize ? props.textsize : "16px"} !important; | |||
| font-family: ${props => props.font ? props.font : ""} | |||
| } | |||
| `; | |||
| @@ -0,0 +1,24 @@ | |||
| import React from 'react'; | |||
| import PropTypes from 'prop-types'; | |||
| import { TextFieldWithIconContainer, IconStyled, TextFieldStyled } from './TextFieldWithIcon.styled'; | |||
| import { Visibility } from '@mui/icons-material'; | |||
| const TextFieldWithIcon = (props) => { | |||
| return ( | |||
| <TextFieldWithIconContainer> | |||
| <TextFieldStyled {...props.textFieldProps}> | |||
| <IconStyled color="green"> | |||
| <Visibility color="green"/> | |||
| </IconStyled> | |||
| {props.children} | |||
| </TextFieldStyled> | |||
| </TextFieldWithIconContainer> | |||
| ) | |||
| } | |||
| TextFieldWithIcon.propTypes = { | |||
| children: PropTypes.node, | |||
| textFieldProps: PropTypes.any, | |||
| } | |||
| export default TextFieldWithIcon; | |||
| @@ -0,0 +1,18 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { Icon } from "../../Icon/Icon"; | |||
| import { TextField } from "../TextField/TextField"; | |||
| export const TextFieldWithIconContainer = styled(Box)` | |||
| ` | |||
| export const TextFieldStyled = styled(TextField)` | |||
| position: relative; | |||
| ` | |||
| export const IconStyled = styled(Icon)` | |||
| position: absolute; | |||
| top: 5px; | |||
| left: 5px; | |||
| background-color: blue; | |||
| ` | |||
| @@ -3,4 +3,7 @@ export const LOGIN_PAGE = '/login'; | |||
| export const FORGOT_PASSWORD_PAGE = '/forgot-password'; | |||
| export const HOME_PAGE = '/home'; | |||
| export const ERROR_PAGE = '/error-page'; | |||
| export const NOT_FOUND_PAGE = '/not-found'; | |||
| export const NOT_FOUND_PAGE = '/not-found'; | |||
| export const FORGOT_PASSWORD_MAIL_SENT = '/forgot-password/mail-sent' | |||
| export const REGISTER_PAGE = "/register" | |||
| export const REGISTER_SUCCESSFUL_PAGE = "/register/success"; | |||
| @@ -1,2 +0,0 @@ | |||
| export const PRIMARY_PURPLE_COLOR = `rgb(90, 57, 131)`; | |||
| export const PRIMARY_YELLOW_COLOR = `rgb(247, 178, 38)`; | |||
| @@ -3,13 +3,17 @@ import i18n from 'i18next'; | |||
| import { initReactI18next } from 'react-i18next'; | |||
| import enTranslations from './resources/en'; | |||
| import rsTranslations from './resources/rs' | |||
| i18n.use(initReactI18next).init({ | |||
| lng: 'en', | |||
| fallbackLng: 'en', | |||
| lng: 'rs', | |||
| fallbackLng: 'rs', | |||
| debug: false, | |||
| supportedLngs: ['en'], | |||
| supportedLngs: ['rs', 'en'], | |||
| resources: { | |||
| rs: { | |||
| translation: rsTranslations, | |||
| }, | |||
| en: { | |||
| translation: enTranslations, | |||
| }, | |||
| @@ -0,0 +1,106 @@ | |||
| export default { | |||
| app: { | |||
| title: 'Trampa' | |||
| }, | |||
| refresh: { | |||
| title: 'Jel si aktivan?', | |||
| cta: | |||
| "You were registered as not active, please confirm that you are active in the next minute, if you don't you will be logged out.", | |||
| }, | |||
| common: { | |||
| close: 'Zatvori', | |||
| send: "Pošalji", | |||
| sendAgain: "Pošalji ponovo.", | |||
| trademark: 'TM', | |||
| search: 'Pretraga', | |||
| error: 'Greška', | |||
| continue: 'Nastavi', | |||
| labelUsername: 'Username', | |||
| labelEmail: 'Email', | |||
| labelPassword: 'Lozinka', | |||
| labelFirm: "Ime Firme", | |||
| labelPIB: "PIB", | |||
| labelPhone: "Telefon", | |||
| labelLocation: "Lokacija", | |||
| labelWebsite: "Adresa Websajta", | |||
| next: 'Sledeće', | |||
| nextPage: 'Sledeća strana', | |||
| previousPage: 'Prethodna strana', | |||
| back: 'Nazad', | |||
| goBack: 'Idi nazad', | |||
| ok: 'Ok', | |||
| done: 'Gotovo', | |||
| confirm: 'Potvrdi', | |||
| printDownload: 'Print/Download', | |||
| cancel: 'Obustavi', | |||
| remove: 'Izbriši', | |||
| invite: 'Pozovi', | |||
| save: 'Sačuvaj', | |||
| complete: 'Završi', | |||
| download: 'Download', | |||
| yes: 'Da', | |||
| no: 'Ne', | |||
| to: 'do', | |||
| select: 'Izaberi...', | |||
| none: 'Ni jedan', | |||
| date: { | |||
| range: '{{start}} do {{end}}', | |||
| }, | |||
| }, | |||
| login: { | |||
| welcome: 'React template', | |||
| welcomeText: 'Trampa sa kolegama na dohvat ruke', | |||
| dontHaveAccount: "Nemate nalog? ", | |||
| emailFormat: 'Nevalidan format email adrese!', | |||
| emailRequired: 'Email adresa je obavezna!', | |||
| noUsers: 'Ne postoji korisnik sa zadatom email adresom.', | |||
| passwordStrength: 'Your password is {{strength}}.', | |||
| passwordLength: 'Lozinka mora imati izmedju 8 i 50 karaktera!', | |||
| signUpRecommendation: 'Registrujte se.', | |||
| email: 'Unesite email adresu kako biste se prijavili', | |||
| logInTitle: 'Uloguj se', | |||
| logIn: 'Uloguj se', | |||
| signUp: 'Registrujte se.', | |||
| usernameRequired: 'Username je obavezan!', | |||
| passwordRequired: 'Lozinka je obavezna!', | |||
| forgotYourPassword: 'Zaboravili ste lozinku?', | |||
| forgotPasswordEmail:'Email', | |||
| useDifferentEmail: 'Iskoristite drugačiju lozinku.', | |||
| }, | |||
| password: { | |||
| weak: 'slaba', | |||
| average: 'srednja', | |||
| good: 'dobra', | |||
| strong: 'jaka', | |||
| }, | |||
| register: { | |||
| title: "Registruj se", | |||
| descriptionMain: "Trampa sa kolegama na dohvat ruke", | |||
| descriptionFirst: "Email i Lozinka biće Vam primarni način da se ulogujete u aplikaciju", | |||
| descriptionSecond: 'Ovaj korak nije obavezan za razgledanje artikla ali za proces trampe je obavezan. Uvek možete popuniti ova polja u podešavanjima naloga kasnije', | |||
| descriptionThird: 'Ovaj korak nije obavezan za razgledanje artikla ali za proces trampe je obavezan. Uvek možete popuniti ova polja u podešavanjima naloga kasnije', | |||
| loginText: "Već posedujete nalog?", | |||
| login: "Ulogujte se.", | |||
| acceptTerms: `Pri klikom na dugme "Registruj se", prihvatate naše`, | |||
| terms: "Uslove Korišćenja", | |||
| success: 'Registracija Uspešna', | |||
| welcome: 'Dobro došli na trampu, želimo vam uspešno trampovanje!' | |||
| }, | |||
| forgotPassword: { | |||
| title: 'Povrati lozinku', | |||
| description: 'Molimo vas unesite email sa koji cemo vam poslati link za povratak lozinke', | |||
| label: 'Pošalji email', | |||
| emailRequired: 'Email je obavezan!', | |||
| emailFormat: 'Nevalidan format email adrese!', | |||
| mailSent: "E-Mail poslat!", | |||
| mailSentDescription: "Poslat vam je email sa instrukcijama kako da resetujete lozinku", | |||
| notRecievedMail: "Niste dobili email?", | |||
| checkSpam: "U slučaju da Vam ne stigne email, pogledajte <strong>Spam</strong> folder email provajdera", | |||
| forgotPassword: { | |||
| title: 'Zaboravili ste lozinku', | |||
| subtitle: | |||
| 'Odgovorite na tajno pitanje kako biste povratili svoj nalog: ', | |||
| label: 'Obnovite lozinku', | |||
| }, | |||
| }, | |||
| } | |||
| @@ -0,0 +1,41 @@ | |||
| import { Box, Container, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../themes"; | |||
| export const ForgotPasswordPageContainer = styled(Container)` | |||
| margin-top: 200px; | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| `; | |||
| export const ForgotPasswordTitle = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| width: 328px; | |||
| height: 33px; | |||
| text-align: center; | |||
| flex: 1; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 24px; | |||
| line-height: 33px; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| margin-top: 36px; | |||
| `; | |||
| export const ForgotPasswordDescription = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| margin-top: 9px; | |||
| width: 221px; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 16px; | |||
| line-height: 22px; | |||
| display: flex; | |||
| align-items: center; | |||
| text-align: center; | |||
| color: ${selectedTheme.primaryGrayText}; | |||
| margin-bottom: 20px; | |||
| `; | |||
| export const FormContainer = styled(Box)` | |||
| width: 335px; | |||
| height: 216px; | |||
| `; | |||
| @@ -0,0 +1,86 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| MailSentContainer, | |||
| Description, | |||
| Footer, | |||
| FooterText, | |||
| FormContainer, | |||
| SendAgainTextContainer, | |||
| StandardText, | |||
| Title, | |||
| } from "./MailSent.styled"; | |||
| import { ReactComponent as MailSentImage } from "../../../assets/images/svg/mail-sent.svg"; | |||
| import { PrimaryButton } from "../../../components/Buttons/PrimaryButton/PrimaryButton"; | |||
| import { NavLink, useHistory } from "react-router-dom"; | |||
| import Link from "../../../components/Link/Link"; | |||
| import { Trans, useTranslation } from "react-i18next"; | |||
| import { LOGIN_PAGE } from "../../../constants/pages"; | |||
| import selectedTheme from "../../../themes"; | |||
| const MailSent = () => { | |||
| const { t } = useTranslation(); | |||
| const history = useHistory(); | |||
| const navigateLogin = () => { | |||
| history.replace(LOGIN_PAGE); | |||
| }; | |||
| return ( | |||
| <MailSentContainer> | |||
| <MailSentImage /> | |||
| <Title component="h1" variant="h5"> | |||
| {t("forgotPassword.mailSent")} | |||
| </Title> | |||
| <Description component="h1" variant="h6"> | |||
| {t("forgotPassword.mailSentDescription")} | |||
| </Description> | |||
| <FormContainer> | |||
| <PrimaryButton | |||
| type="submit" | |||
| variant="contained" | |||
| height="48px" | |||
| fullWidth={true} | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor="white" | |||
| onClick={navigateLogin} | |||
| > | |||
| {t("login.logIn")} | |||
| </PrimaryButton> | |||
| <SendAgainTextContainer> | |||
| <StandardText> | |||
| {t("forgotPassword.notRecievedMail")} | |||
| </StandardText> | |||
| <Link to="#" component={NavLink} underline="hover" align="center" textsize="16px"> | |||
| {t("common.sendAgain")} | |||
| </Link> | |||
| </SendAgainTextContainer> | |||
| </FormContainer> | |||
| <Footer> | |||
| <FooterText> | |||
| <Trans i18nKey="forgotPassword.checkSpam" /> | |||
| </FooterText> | |||
| </Footer> | |||
| </MailSentContainer> | |||
| ); | |||
| }; | |||
| MailSent.propTypes = { | |||
| children: PropTypes.node, | |||
| }; | |||
| export default MailSent; | |||
| @@ -0,0 +1,71 @@ | |||
| import { Box, Container, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| export const MailSentContainer = styled(Container)` | |||
| margin-top: 300px; | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| `; | |||
| export const Title = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| width: 328px; | |||
| height: 33px; | |||
| text-align: center; | |||
| flex: 1; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 24px; | |||
| line-height: 33px; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| margin-top: 6px; | |||
| `; | |||
| export const Description = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| margin-top: 9px; | |||
| width: 279px; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 16px; | |||
| line-height: 22px; | |||
| display: flex; | |||
| align-items: center; | |||
| text-align: center; | |||
| color: ${selectedTheme.primaryGrayText}; | |||
| margin-bottom: 36px; | |||
| `; | |||
| export const FormContainer = styled(Box)` | |||
| width: 335px; | |||
| height: 216px; | |||
| `; | |||
| export const StandardText = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| font-size: 16px; | |||
| padding-right: 6px; | |||
| line-height: 14px; | |||
| text-align: center; | |||
| ` | |||
| export const SendAgainTextContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| margin-top: 36px; | |||
| justify-content: center; | |||
| ` | |||
| export const Footer = styled(Box)` | |||
| position: absolute; | |||
| bottom: 36px; | |||
| display: flex; | |||
| width: 100%; | |||
| flex-direction: row; | |||
| justify-content: center; | |||
| ` | |||
| export const FooterText = styled(StandardText)` | |||
| width: 340px; | |||
| line-height: 22px; | |||
| font-weight: 400; | |||
| padding: 0; | |||
| font-size: 16px; | |||
| ` | |||
| @@ -1,96 +1,87 @@ | |||
| import React from 'react'; | |||
| import { useFormik } from 'formik'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import * as Yup from 'yup'; | |||
| import i18next from 'i18next'; | |||
| import React from "react"; | |||
| import { useFormik } from "formik"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import * as Yup from "yup"; | |||
| import i18next from "i18next"; | |||
| import { ReactComponent as Logo } from "../../assets/images/svg/logo-vertical.svg"; | |||
| import { | |||
| Box, | |||
| Container, | |||
| Typography, | |||
| Button, | |||
| TextField, | |||
| Link, | |||
| Grid, | |||
| } from '@mui/material'; | |||
| import Backdrop from '../../components/MUI/BackdropComponent'; | |||
| import { LOGIN_PAGE } from '../../constants/pages'; | |||
| import { NavLink } from 'react-router-dom'; | |||
| ForgotPasswordPageContainer, | |||
| ForgotPasswordDescription, | |||
| ForgotPasswordTitle, | |||
| FormContainer, | |||
| } from "./ForgotPassword.styled"; | |||
| import { TextField } from "../../components/TextFields/TextField/TextField"; | |||
| import { PrimaryButton } from "../../components/Buttons/PrimaryButton/PrimaryButton"; | |||
| import { useHistory } from "react-router-dom"; | |||
| import { FORGOT_PASSWORD_MAIL_SENT } from "../../constants/pages"; | |||
| import selectedTheme from "../../themes"; | |||
| const forgotPasswordValidationSchema = Yup.object().shape({ | |||
| email: Yup.string() | |||
| .required(i18next.t('forgotPassword.emailRequired')) | |||
| .email(i18next.t('forgotPassword.emailFormat')), | |||
| email: Yup.string() | |||
| .required(i18next.t("forgotPassword.emailRequired")) | |||
| .email(i18next.t("forgotPassword.emailFormat")), | |||
| }); | |||
| const ForgotPasswordPage = () => { | |||
| const { t } = useTranslation(); | |||
| const history = useHistory(); | |||
| const { t } = useTranslation(); | |||
| const handleSubmit = (values) => { | |||
| console.log('Values', values); | |||
| }; | |||
| const handleSubmit = (values) => { | |||
| console.log("Values", values); | |||
| history.push(FORGOT_PASSWORD_MAIL_SENT); | |||
| }; | |||
| const formik = useFormik({ | |||
| initialValues: { | |||
| email: '', | |||
| }, | |||
| validationSchema: forgotPasswordValidationSchema, | |||
| onSubmit: handleSubmit, | |||
| validateOnBlur: true, | |||
| enableReinitialize: true, | |||
| }); | |||
| const formik = useFormik({ | |||
| initialValues: { | |||
| email: "", | |||
| }, | |||
| validationSchema: forgotPasswordValidationSchema, | |||
| onSubmit: handleSubmit, | |||
| validateOnBlur: true, | |||
| enableReinitialize: true, | |||
| }); | |||
| return ( | |||
| <Container component="main" maxWidth="md"> | |||
| <Box | |||
| sx={{ | |||
| marginTop: 32, | |||
| display: 'flex', | |||
| flexDirection: 'column', | |||
| alignItems: 'center', | |||
| }} | |||
| > | |||
| <Typography component="h1" variant="h5"> | |||
| {t('forgotPassword.title')} | |||
| </Typography> | |||
| <Box | |||
| component="form" | |||
| onSubmit={formik.handleSubmit} | |||
| sx={{ position: 'relative', mt: 1, p: 1 }} | |||
| > | |||
| <Backdrop position="absolute" isLoading={false} /> | |||
| <TextField | |||
| name="email" | |||
| label={t('login.forgotPasswordEmail')} | |||
| margin="normal" | |||
| value={formik.values.email} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.email && Boolean(formik.errors.email)} | |||
| helperText={formik.touched.email && formik.errors.email} | |||
| autoFocus | |||
| fullWidth | |||
| /> | |||
| <Button | |||
| type="submit" | |||
| variant="contained" | |||
| sx={{ mt: 3, mb: 2 }} | |||
| fullWidth | |||
| > | |||
| {t('forgotPassword.label')} | |||
| </Button> | |||
| <Grid container justifyContent="center"> | |||
| <Link | |||
| to={LOGIN_PAGE} | |||
| component={NavLink} | |||
| variant="body2" | |||
| underline="hover" | |||
| > | |||
| {t('common.back')} | |||
| </Link> | |||
| </Grid> | |||
| </Box> | |||
| </Box> | |||
| </Container> | |||
| ); | |||
| return ( | |||
| <ForgotPasswordPageContainer> | |||
| <Logo /> | |||
| <ForgotPasswordTitle component="h1" variant="h5"> | |||
| {t("forgotPassword.title")} | |||
| </ForgotPasswordTitle> | |||
| <ForgotPasswordDescription component="h1" variant="h6"> | |||
| {t("forgotPassword.description")} | |||
| </ForgotPasswordDescription> | |||
| <FormContainer component="form" onSubmit={formik.handleSubmit}> | |||
| {/* <Backdrop position="absolute" isLoading={isLoading} /> */} | |||
| <TextField | |||
| name="email" | |||
| placeholder={t("common.labelEmail")} | |||
| margin="normal" | |||
| value={formik.values.email} | |||
| error={formik.touched.email && Boolean(formik.errors.email)} | |||
| helperText={formik.touched.email && formik.errors.email} | |||
| onChange={formik.handleChange} | |||
| autoFocus | |||
| fullWidth | |||
| /> | |||
| <PrimaryButton | |||
| type="submit" | |||
| variant="contained" | |||
| height="48px" | |||
| fullWidth={true} | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor="white" | |||
| disabled={formik.values.email?.length === 0} | |||
| > | |||
| {t("common.send")} | |||
| </PrimaryButton> | |||
| </FormContainer> | |||
| </ForgotPasswordPageContainer> | |||
| ); | |||
| }; | |||
| export default ForgotPasswordPage; | |||
| @@ -0,0 +1,54 @@ | |||
| import { Box, Container, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../themes"; | |||
| export const LoginPageContainer = styled(Container)` | |||
| margin-top: 150px; | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| `; | |||
| export const LoginTitle = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| width: 328px; | |||
| height: 33px; | |||
| text-align: center; | |||
| flex: 1; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 24px; | |||
| line-height: 33px; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| margin-top: 36px; | |||
| `; | |||
| export const LoginDescription = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| margin-top: 9px; | |||
| width: 221px; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 16px; | |||
| line-height: 22px; | |||
| display: flex; | |||
| align-items: center; | |||
| text-align: center; | |||
| color: ${selectedTheme.primaryGrayText}; | |||
| margin-bottom: 20px; | |||
| `; | |||
| export const LoginFormContainer = styled(Box)` | |||
| width: 335px; | |||
| height: 216px; | |||
| `; | |||
| export const RegisterAltText = styled(Typography)` | |||
| font-family: "Poppins"; | |||
| color: ${selectedTheme.primaryText}; | |||
| font-size: 14px; | |||
| padding-right: 6px; | |||
| line-height: 14px; | |||
| ` | |||
| export const RegisterTextContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| margin-top: 36px; | |||
| justify-content: center; | |||
| ` | |||
| @@ -1,36 +1,36 @@ | |||
| /* eslint-disable */ | |||
| import React, { useState } from "react"; | |||
| import React, { useEffect, useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { useFormik } from "formik"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { NavLink } from "react-router-dom"; | |||
| import * as Yup from "yup"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import i18next from "i18next"; | |||
| import { | |||
| clearLoginErrors, | |||
| fetchUser, | |||
| } from "../../store/actions/login/loginActions"; | |||
| import { selectLoginError } from "../../store/selectors/loginSelectors"; | |||
| import { FORGOT_PASSWORD_PAGE, HOME_PAGE } from "../../constants/pages"; | |||
| import { | |||
| Box, | |||
| Button, | |||
| Container, | |||
| Grid, | |||
| IconButton, | |||
| InputAdornment, | |||
| Link, | |||
| Typography, | |||
| } from "@mui/material"; | |||
| import { Visibility, VisibilityOff } from "@mui/icons-material"; | |||
| import { ReactComponent as VisibilityOn } from "../../assets/images/svg/VisibilityOn.svg"; | |||
| import { ReactComponent as VisibilityOff } from "../../assets/images/svg/VisibilityOff.svg"; | |||
| import Backdrop from "../../components/MUI/BackdropComponent"; | |||
| import ErrorMessage from "../../components/MUI/ErrorMessageComponent"; | |||
| import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | |||
| import { LOGIN_USER_LOADING } from "../../store/actions/login/loginActionConstants"; | |||
| import { TextField } from "../../components/TextFields/TextField"; | |||
| import { TextField } from "../../components/TextFields/TextField/TextField"; | |||
| import { PrimaryButton } from "../../components/Buttons/PrimaryButton/PrimaryButton"; | |||
| import { PRIMARY_PURPLE_COLOR } from "../../constants/stylesConstants"; | |||
| import { IconButton } from "../../components/Buttons/IconButton/IconButton"; | |||
| import Link from "../../components/Link/Link"; | |||
| import { ReactComponent as Logo } from "../../assets/images/svg/logo-vertical.svg"; | |||
| import { | |||
| LoginPageContainer, | |||
| LoginTitle, | |||
| LoginDescription, | |||
| LoginFormContainer, | |||
| RegisterAltText, | |||
| RegisterTextContainer, | |||
| } from "./Login.styled"; | |||
| import selectedTheme from "../../themes"; | |||
| const LoginPage = ({ history }) => { | |||
| const dispatch = useDispatch(); | |||
| @@ -92,105 +92,100 @@ const LoginPage = ({ history }) => { | |||
| }); | |||
| return ( | |||
| <Container component="main" maxWidth="md"> | |||
| <Box | |||
| sx={{ | |||
| marginTop: 32, | |||
| display: "flex", | |||
| flexDirection: "column", | |||
| alignItems: "center", | |||
| }} | |||
| > | |||
| <Typography component="h1" variant="h5"> | |||
| {t("login.logInTitle")} | |||
| </Typography> | |||
| {error && <ErrorMessage error={error} />} | |||
| <Box | |||
| component="form" | |||
| onSubmit={formik.handleSubmit} | |||
| sx={{ position: "relative", mt: 1, p: 1 }} | |||
| <LoginPageContainer> | |||
| <Logo /> | |||
| <LoginTitle component="h1" variant="h5"> | |||
| {t("login.logInTitle")} | |||
| </LoginTitle> | |||
| <LoginDescription component="h1" variant="h6"> | |||
| {t("login.welcomeText")} | |||
| </LoginDescription> | |||
| <LoginFormContainer component="form" onSubmit={formik.handleSubmit}> | |||
| <Backdrop position="absolute" isLoading={isLoading} /> | |||
| <TextField | |||
| name="username" | |||
| placeholder={t("common.labelEmail")} | |||
| margin="normal" | |||
| value={formik.values.username} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.username && Boolean(formik.errors.username)} | |||
| helperText={formik.touched.username && formik.errors.username} | |||
| autoFocus | |||
| fullWidth | |||
| /> | |||
| <TextField | |||
| name="password" | |||
| placeholder={t("common.labelPassword")} | |||
| margin="normal" | |||
| type={showPassword ? "text" : "password"} | |||
| value={formik.values.password} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.password && Boolean(formik.errors.password)} | |||
| helperText={formik.touched.password && formik.errors.password} | |||
| fullWidth={true} | |||
| InputProps={{ | |||
| endAdornment: ( | |||
| <IconButton | |||
| onClick={handleClickShowPassword} | |||
| onMouseDown={handleMouseDownPassword} | |||
| > | |||
| {showPassword ? <VisibilityOn /> : <VisibilityOff />} | |||
| </IconButton> | |||
| ), | |||
| }} | |||
| /> | |||
| <Link | |||
| to={FORGOT_PASSWORD_PAGE} | |||
| textsize="12px" | |||
| component={NavLink} | |||
| underline="hover" | |||
| align="right" | |||
| style={{ marginTop: "18px", marginBottom: "18px" }} | |||
| > | |||
| <Backdrop position="absolute" isLoading={isLoading} /> | |||
| <TextField | |||
| name="username" | |||
| placeholder={t("common.labelUsername")} | |||
| margin="normal" | |||
| value={formik.values.username} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.username && Boolean(formik.errors.username)} | |||
| helperText={formik.touched.username && formik.errors.username} | |||
| autoFocus | |||
| fullWidth | |||
| /> | |||
| <TextField | |||
| name="password" | |||
| placeholder={t("common.labelPassword")} | |||
| margin="normal" | |||
| type={showPassword ? "text" : "password"} | |||
| value={formik.values.password} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.password && Boolean(formik.errors.password)} | |||
| helperText={formik.touched.password && formik.errors.password} | |||
| fullWidth | |||
| InputProps={{ | |||
| endAdornment: ( | |||
| <InputAdornment position="end"> | |||
| <IconButton | |||
| onClick={handleClickShowPassword} | |||
| onMouseDown={handleMouseDownPassword} | |||
| > | |||
| {showPassword ? <Visibility /> : <VisibilityOff />} | |||
| </IconButton> | |||
| </InputAdornment> | |||
| ), | |||
| }} | |||
| /> | |||
| <PrimaryButton | |||
| type="submit" | |||
| variant="contained" | |||
| height="40px" | |||
| sx={{ mt: 3, mb: 2 }} | |||
| fullWidth | |||
| buttonColor={PRIMARY_PURPLE_COLOR} | |||
| textColor="white" | |||
| {t("login.forgotYourPassword")} | |||
| </Link> | |||
| <PrimaryButton | |||
| type="submit" | |||
| variant="contained" | |||
| height="48px" | |||
| fullWidth={true} | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor="white" | |||
| disabled={ | |||
| formik.values.username.length === 0 || | |||
| formik.values.password.length === 0 | |||
| } | |||
| > | |||
| {t("login.logIn")} | |||
| </PrimaryButton> | |||
| <RegisterTextContainer> | |||
| <RegisterAltText> | |||
| {t("login.dontHaveAccount").padEnd(2, " ")} | |||
| </RegisterAltText> | |||
| <Link | |||
| to="/register" | |||
| component={NavLink} | |||
| underline="hover" | |||
| align="center" | |||
| > | |||
| {t("login.logIn")} | |||
| </PrimaryButton> | |||
| <Grid container> | |||
| <Grid | |||
| item | |||
| xs={12} | |||
| md={6} | |||
| sx={{ textAlign: { xs: "center", md: "left" } }} | |||
| > | |||
| <Link | |||
| to={FORGOT_PASSWORD_PAGE} | |||
| component={NavLink} | |||
| variant="body2" | |||
| underline="hover" | |||
| > | |||
| {t("login.forgotYourPassword")} | |||
| </Link> | |||
| </Grid> | |||
| <Grid | |||
| item | |||
| xs={12} | |||
| md={6} | |||
| sx={{ textAlign: { xs: "center", md: "right" } }} | |||
| > | |||
| <Link | |||
| to="#" | |||
| component={NavLink} | |||
| variant="body2" | |||
| underline="hover" | |||
| > | |||
| {t("login.dontHaveAccount")} | |||
| </Link> | |||
| </Grid> | |||
| </Grid> | |||
| </Box> | |||
| </Box> | |||
| </Container> | |||
| {t("login.signUp")} | |||
| </Link> | |||
| </RegisterTextContainer> | |||
| </LoginFormContainer> | |||
| </LoginPageContainer> | |||
| ); | |||
| }; | |||
| @@ -0,0 +1,108 @@ | |||
| import React, { useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| FormContainer, | |||
| RegisterDescription, | |||
| } from "./FirstPartOfRegistration.styled"; | |||
| import { useFormik } from "formik"; | |||
| import * as Yup from "yup"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { TextField } from "../../../../components/TextFields/TextField/TextField"; | |||
| import { IconButton } from "../../../../components/Buttons/IconButton/IconButton"; | |||
| import { ReactComponent as VisibilityOn } from "../../../../assets/images/svg/VisibilityOn.svg"; | |||
| import { ReactComponent as VisibilityOff } from "../../../../assets/images/svg/VisibilityOff.svg"; | |||
| import { PrimaryButton } from "../../../../components/Buttons/PrimaryButton/PrimaryButton"; | |||
| import selectedTheme from "../../../../themes"; | |||
| const FirstPartOfRegistration = (props) => { | |||
| const [showPassword, setShowPassword] = useState(false); | |||
| const { t } = useTranslation(); | |||
| const formik = useFormik({ | |||
| initialValues: { | |||
| mail: "", | |||
| password: "", | |||
| }, | |||
| validationSchema: Yup.object().shape({ | |||
| mail: Yup.string().email().required(t("login.usernameRequired")), | |||
| password: Yup.string().required(t("login.passwordRequired")), | |||
| }), | |||
| onSubmit: props.handleSubmit, | |||
| validateOnBlur: true, | |||
| enableReinitialize: true, | |||
| }); | |||
| const handleClickShowPassword = () => { | |||
| setShowPassword((prevState) => !prevState); | |||
| }; | |||
| return ( | |||
| <FormContainer component="form" onSubmit={formik.handleSubmit}> | |||
| <RegisterDescription component="p" variant="p"> | |||
| {t("register.descriptionFirst")} | |||
| </RegisterDescription> | |||
| <TextField | |||
| name="mail" | |||
| placeholder={t("common.labelEmail")} | |||
| margin="normal" | |||
| value={formik.values.mail} | |||
| onChange={(value) => | |||
| formik.setFieldValue("mail", value.target.value) | |||
| } | |||
| error={formik.touched.mail && Boolean(formik.errors.mail)} | |||
| helperText={formik.touched.mail && formik.errors.mail} | |||
| autoFocus | |||
| fullWidth | |||
| /> | |||
| <TextField | |||
| name="password" | |||
| placeholder={t("common.labelPassword")} | |||
| margin="normal" | |||
| type={showPassword ? "text" : "password"} | |||
| value={formik.values.password} | |||
| onChange={(value) => | |||
| formik.setFieldValue("password", value.target.value) | |||
| } | |||
| error={ | |||
| formik.touched.passwordRegistration && | |||
| Boolean(formik.errors.passwordRegistration) | |||
| } | |||
| helperText={ | |||
| formik.touched.passwordRegistration && | |||
| formik.errors.passwordRegistration | |||
| } | |||
| fullWidth | |||
| InputProps={{ | |||
| endAdornment: ( | |||
| <IconButton onClick={handleClickShowPassword}> | |||
| {showPassword ? <VisibilityOn /> : <VisibilityOff />} | |||
| </IconButton> | |||
| ), | |||
| }} | |||
| /> | |||
| <PrimaryButton | |||
| type="submit" | |||
| variant="contained" | |||
| height="48px" | |||
| fullWidth={true} | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor="white" | |||
| disabled={ | |||
| formik.values.mail.length === 0 || | |||
| formik.values.password.length === 0 | |||
| } | |||
| > | |||
| {t("common.continue")} | |||
| </PrimaryButton> | |||
| </FormContainer> | |||
| ); | |||
| }; | |||
| FirstPartOfRegistration.propTypes = { | |||
| children: PropTypes.node, | |||
| handleSubmit: PropTypes.func, | |||
| }; | |||
| export default FirstPartOfRegistration; | |||
| @@ -0,0 +1,22 @@ | |||
| import { Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../../themes"; | |||
| export const FormContainer = styled.form` | |||
| width: 335px; | |||
| `; | |||
| export const RegisterDescription = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| display: flex; | |||
| align-items: center; | |||
| color: ${selectedTheme.primaryGrayText}; | |||
| font-size: 12px; | |||
| width: 100%; | |||
| text-align: left; | |||
| line-height: 16px; | |||
| margin-top: 31px; | |||
| margin-bottom: 2px; | |||
| letter-spacing: 0.02em; | |||
| `; | |||
| @@ -0,0 +1,91 @@ | |||
| import React, { useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| RegisterPageContainer, | |||
| Footer, | |||
| FooterText, | |||
| LoginAltText, | |||
| LoginTextContainer, | |||
| ProgressContainer, | |||
| RegisterDescription, | |||
| RegisterTitle, | |||
| } from "./Register.styled"; | |||
| import { ReactComponent as Logo } from "../../../assets/images/svg/logo-vertical.svg"; | |||
| import { NavLink, useHistory } from "react-router-dom"; | |||
| import { Trans, useTranslation } from "react-i18next"; | |||
| import Link from "../../../components/Link/Link"; | |||
| import StepProgress from "../../../components/StepProgress/StepProgress"; | |||
| import { REGISTER_SUCCESSFUL_PAGE } from "../../../constants/pages"; | |||
| import FirstPartOfRegistration from "./FirstPart/FirstPartOfRegistration"; | |||
| import SecondPartOfRegistration from "./SecondPart/SecondPartOfRegistration"; | |||
| import ThirdPartOfRegistration from "./ThirdPart/ThirdPartOfRegistration"; | |||
| const Register = () => { | |||
| const { t } = useTranslation(); | |||
| const history = useHistory(); | |||
| const [currentStep, setCurrentStep] = useState(1); | |||
| const [informations, setInformations] = useState({}); | |||
| const handleSubmit = (values) => { | |||
| setInformations({ ...informations, ...values }); | |||
| console.log({ ...informations, ...values }); | |||
| if (currentStep !== 3) { | |||
| setCurrentStep((prevState) => prevState + 1); | |||
| } else { | |||
| history.push(REGISTER_SUCCESSFUL_PAGE); | |||
| } | |||
| }; | |||
| return ( | |||
| <RegisterPageContainer> | |||
| <Logo /> | |||
| <RegisterTitle component="h1" variant="h5"> | |||
| {t("register.title")} | |||
| </RegisterTitle> | |||
| <RegisterDescription component="h1" variant="h6"> | |||
| {t("register.descriptionMain")} | |||
| </RegisterDescription> | |||
| <ProgressContainer> | |||
| <StepProgress current={currentStep} numberOfSteps={3} /> | |||
| </ProgressContainer> | |||
| {currentStep === 1 && ( | |||
| <FirstPartOfRegistration handleSubmit={handleSubmit} /> | |||
| )} | |||
| {currentStep === 2 && ( | |||
| <SecondPartOfRegistration handleSubmit={handleSubmit} /> | |||
| )} | |||
| {currentStep === 3 && ( | |||
| <ThirdPartOfRegistration handleSubmit={handleSubmit} /> | |||
| )} | |||
| <LoginTextContainer> | |||
| <LoginAltText>{t("register.loginText")}</LoginAltText> | |||
| <Link to="/login" component={NavLink} underline="hover" align="center"> | |||
| {t("register.login")} | |||
| </Link> | |||
| </LoginTextContainer> | |||
| <Footer> | |||
| <FooterText> | |||
| <Trans i18nKey="register.acceptTerms" />{" "} | |||
| <NavLink | |||
| to="#" | |||
| style={{ color: "black", fontWeight: "500", cursor: "pointer" }} | |||
| > | |||
| <Trans i18nKey="register.terms" /> | |||
| </NavLink> | |||
| </FooterText> | |||
| </Footer> | |||
| </RegisterPageContainer> | |||
| ); | |||
| }; | |||
| Register.propTypes = { | |||
| children: PropTypes.node, | |||
| }; | |||
| export default Register; | |||
| @@ -0,0 +1,86 @@ | |||
| import { Box, Container, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| export const RegisterPageContainer = styled(Container)` | |||
| margin-top: 100px; | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| width: 335px; | |||
| padding: 0; | |||
| `; | |||
| export const RegisterTitle = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| width: 328px; | |||
| height: 33px; | |||
| text-align: center; | |||
| flex: 1; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 24px; | |||
| line-height: 33px; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| margin-top: 34px; | |||
| `; | |||
| export const RegisterDescription = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| margin-top: 9px; | |||
| width: 221px; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 16px; | |||
| line-height: 22px; | |||
| display: flex; | |||
| align-items: center; | |||
| text-align: center; | |||
| color: ${selectedTheme.primaryGrayText}; | |||
| margin-bottom: 20px; | |||
| `; | |||
| export const FormContainer = styled(Box)` | |||
| width: 335px; | |||
| `; | |||
| export const LoginAltText = styled(Typography)` | |||
| font-family: "Poppins"; | |||
| color: ${selectedTheme.primaryText}; | |||
| font-size: 14px; | |||
| padding-right: 6px; | |||
| line-height: 14px; | |||
| ` | |||
| export const LoginTextContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| margin-top: 36px; | |||
| justify-content: center; | |||
| ` | |||
| export const ProgressContainer = styled(Container)` | |||
| width: 100%; | |||
| padding: 0; | |||
| ` | |||
| export const Footer = styled(Box)` | |||
| position: absolute; | |||
| bottom: 36px; | |||
| display: flex; | |||
| width: 100%; | |||
| flex-direction: row; | |||
| justify-content: center; | |||
| ` | |||
| export const FooterText = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| color: #505050; | |||
| text-align: center; | |||
| width: 330px; | |||
| line-height: 16px; | |||
| font-weight: 400; | |||
| padding: 0; | |||
| font-size: 12px; | |||
| ` | |||
| export const RegisterDescriptionPart = styled(RegisterDescription)` | |||
| font-size: 12px; | |||
| width: 100%; | |||
| text-align: left; | |||
| line-height: 16px; | |||
| margin-top: 31px; | |||
| margin-bottom: 2px; | |||
| letter-spacing: 0.02em; | |||
| ` | |||
| @@ -0,0 +1,83 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| FormContainer, | |||
| RegisterDescription, | |||
| } from "./SecondPartOfRegistration.styled"; | |||
| import { useFormik } from "formik"; | |||
| import * as Yup from "yup"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { TextField } from "../../../../components/TextFields/TextField/TextField"; | |||
| import { PrimaryButton } from "../../../../components/Buttons/PrimaryButton/PrimaryButton"; | |||
| import selectedTheme from "../../../../themes"; | |||
| const SecondPartOfRegistration = (props) => { | |||
| const { t } = useTranslation(); | |||
| const formik = useFormik({ | |||
| initialValues: { | |||
| nameOfFirm: "", | |||
| PIB: "", | |||
| }, | |||
| validationSchema: Yup.object().shape({ | |||
| nameOfFirm: Yup.string().required(t("login.usernameRequired")), | |||
| PIB: Yup.number().required(t("login.passwordRequired")), | |||
| }), | |||
| onSubmit: props.handleSubmit, | |||
| validateOnBlur: true, | |||
| enableReinitialize: true, | |||
| }); | |||
| return ( | |||
| <FormContainer component="form" onSubmit={formik.handleSubmit}> | |||
| <RegisterDescription component="p" variant="p"> | |||
| {t("register.descriptionSecond")} | |||
| </RegisterDescription> | |||
| <TextField | |||
| name="nameOfFirm" | |||
| placeholder={t("common.labelFirm")} | |||
| margin="normal" | |||
| value={formik.values.nameOfFirm} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.nameOfFirm && Boolean(formik.errors.nameOfFirm)} | |||
| helperText={formik.touched.nameOfFirm && formik.errors.nameOfFirm} | |||
| autoFocus | |||
| fullWidth | |||
| /> | |||
| <TextField | |||
| name="PIB" | |||
| placeholder={t("common.labelPIB")} | |||
| margin="normal" | |||
| type="number" | |||
| value={formik.values.PIB} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.PIB && Boolean(formik.errors.PIB)} | |||
| helperText={formik.touched.PIB && formik.errors.PIB} | |||
| fullWidth={true} | |||
| /> | |||
| <PrimaryButton | |||
| type="submit" | |||
| variant="contained" | |||
| height="48px" | |||
| fullWidth={true} | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor="white" | |||
| disabled={ | |||
| formik.values.PIB.length === 0 || | |||
| formik.values.nameOfFirm.length === 0 | |||
| } | |||
| > | |||
| {t("common.continue")} | |||
| </PrimaryButton> | |||
| </FormContainer> | |||
| ); | |||
| }; | |||
| SecondPartOfRegistration.propTypes = { | |||
| children: PropTypes.node, | |||
| handleSubmit: PropTypes.func, | |||
| }; | |||
| export default SecondPartOfRegistration; | |||
| @@ -0,0 +1,23 @@ | |||
| import { Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { PRIMARY_GRAY_TEXT_COLOR } from "../../../../constants/stylesConstants"; | |||
| export const FormContainer = styled.form` | |||
| width: 335px; | |||
| `; | |||
| export const RegisterDescription = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| display: flex; | |||
| align-items: center; | |||
| color: ${PRIMARY_GRAY_TEXT_COLOR}; | |||
| font-size: 12px; | |||
| width: 100%; | |||
| text-align: left; | |||
| line-height: 16px; | |||
| margin-top: 31px; | |||
| margin-bottom: 2px; | |||
| letter-spacing: 0.02em; | |||
| `; | |||
| @@ -0,0 +1,102 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| FormContainer, | |||
| RegisterDescription, | |||
| } from "./ThirdPartOfRegistration.styled"; | |||
| import { useFormik } from "formik"; | |||
| import * as Yup from "yup"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { TextField } from "../../../../components/TextFields/TextField/TextField"; | |||
| import { PrimaryButton } from "../../../../components/Buttons/PrimaryButton/PrimaryButton"; | |||
| import selectedTheme from "../../../../themes"; | |||
| const ThirdPartOfRegistration = (props) => { | |||
| const { t } = useTranslation(); | |||
| const formik = useFormik({ | |||
| initialValues: { | |||
| phoneNumber: "", | |||
| location: "", | |||
| website: "", | |||
| }, | |||
| validationSchema: Yup.object().shape({ | |||
| phoneNumber: Yup.number().required(t("login.usernameRequired")), | |||
| location: Yup.string().required(t("login.passwordRequired")), | |||
| website: Yup.string().matches( | |||
| /^((ftp|http|https):\/\/)?(www.)?(?!.*(ftp|http|https|www.))[a-zA-Z0-9_-]+(\.[a-zA-Z]+)+((\/)[\w#]+)*(\/\w+\?[a-zA-Z0-9_]+=\w+(&[a-zA-Z0-9_]+=\w+)*)?$/gm | |||
| ), | |||
| }), | |||
| onSubmit: props.handleSubmit, | |||
| validateOnBlur: true, | |||
| enableReinitialize: true, | |||
| }); | |||
| return ( | |||
| <FormContainer component="form" onSubmit={formik.handleSubmit}> | |||
| <RegisterDescription component="p" variant="p"> | |||
| {t("register.descriptionThird")} | |||
| </RegisterDescription> | |||
| <TextField | |||
| name="phoneNumber" | |||
| placeholder={t("common.labelPhone")} | |||
| margin="normal" | |||
| type="number" | |||
| value={formik.values.phoneNumber} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.phoneNumber && Boolean(formik.errors.phoneNumber)} | |||
| helperText={formik.touched.phoneNumber && formik.errors.phoneNumber} | |||
| autoFocus | |||
| fullWidth | |||
| /> | |||
| <TextField | |||
| name="location" | |||
| placeholder={t("common.labelLocation")} | |||
| margin="normal" | |||
| type="text" | |||
| value={formik.values.location} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.location && Boolean(formik.errors.location)} | |||
| helperText={formik.touched.location && formik.errors.location} | |||
| fullWidth={true} | |||
| /> | |||
| <TextField | |||
| name="website" | |||
| placeholder={t("common.labelWebsite")} | |||
| margin="normal" | |||
| type="text" | |||
| value={formik.values.website} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.website && Boolean(formik.errors.website)} | |||
| helperText={formik.touched.website && formik.errors.website} | |||
| fullWidth={true} | |||
| /> | |||
| <PrimaryButton | |||
| type="submit" | |||
| variant="contained" | |||
| height="48px" | |||
| fullWidth={true} | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor="white" | |||
| disabled={ | |||
| formik.values.location.length === 0 && | |||
| formik.values.phoneNumber.length === 0 && | |||
| formik.values.website.length === 0 | |||
| } | |||
| > | |||
| {t("common.continue")} | |||
| </PrimaryButton> | |||
| </FormContainer> | |||
| ); | |||
| }; | |||
| ThirdPartOfRegistration.propTypes = { | |||
| children: PropTypes.node, | |||
| handleSubmit: PropTypes.func, | |||
| }; | |||
| export default ThirdPartOfRegistration; | |||
| @@ -0,0 +1,22 @@ | |||
| import { Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { PRIMARY_GRAY_TEXT_COLOR } from "../../../../constants/stylesConstants"; | |||
| export const FormContainer = styled.form` | |||
| width: 335px; | |||
| `; | |||
| export const RegisterDescription = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| display: flex; | |||
| align-items: center; | |||
| color: ${PRIMARY_GRAY_TEXT_COLOR}; | |||
| font-size: 12px; | |||
| width: 100%; | |||
| text-align: left; | |||
| line-height: 16px; | |||
| margin-top: 31px; | |||
| margin-bottom: 2px; | |||
| letter-spacing: 0.02em; | |||
| `; | |||
| @@ -0,0 +1,43 @@ | |||
| import React, { useEffect } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| RegisterSuccessfulContainer, | |||
| RegisterDescription, | |||
| RegisterTitle, | |||
| } from "./RegisterSuccessful.styled"; | |||
| import { ReactComponent as Success } from "../../../assets/images/svg/register-success.svg"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { useHistory } from "react-router-dom"; | |||
| import { LOGIN_PAGE } from "../../../constants/pages"; | |||
| const RegisterSuccessful = () => { | |||
| const { t } = useTranslation(); | |||
| const history = useHistory(); | |||
| //Redirect to Login page when registration is successful | |||
| useEffect(() => { | |||
| setTimeout(() => { | |||
| history.replace(LOGIN_PAGE); | |||
| }, 2500); | |||
| }, []); | |||
| return ( | |||
| <RegisterSuccessfulContainer> | |||
| <Success /> | |||
| <RegisterTitle component="h1" variant="h5"> | |||
| {t("register.success")} | |||
| </RegisterTitle> | |||
| <RegisterDescription component="h1" variant="h6"> | |||
| {t("register.welcome")} | |||
| </RegisterDescription> | |||
| </RegisterSuccessfulContainer> | |||
| ); | |||
| }; | |||
| RegisterSuccessful.propTypes = { | |||
| children: PropTypes.node, | |||
| }; | |||
| export default RegisterSuccessful; | |||
| @@ -0,0 +1,38 @@ | |||
| import { Container, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| export const RegisterSuccessfulContainer = styled(Container)` | |||
| margin-top: 300px; | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| width: 536px; | |||
| padding: 0; | |||
| `; | |||
| export const RegisterTitle = styled(Typography)` | |||
| font-family: "Mulish"; | |||
| width: 430px; | |||
| text-align: center; | |||
| flex: 1; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 39px; | |||
| line-height: 48px; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| margin-top: 32px; | |||
| `; | |||
| export const RegisterDescription = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| margin-top: 36px; | |||
| width: 430px; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 25px; | |||
| line-height: 36px; | |||
| display: block; | |||
| align-items: center; | |||
| text-align: center; | |||
| color: ${selectedTheme.primaryGrayText}; | |||
| margin-bottom: 20px; | |||
| `; | |||
| @@ -1,71 +0,0 @@ | |||
| import { | |||
| deleteRequest, | |||
| getRequest, | |||
| patchRequest, | |||
| replaceInUrl, | |||
| postRequest, | |||
| } from './index'; | |||
| import apiEndpoints from './apiEndpoints'; | |||
| export const getAccount = (accountUid) => | |||
| getRequest(replaceInUrl(apiEndpoints.accounts.get, { accountUid })); | |||
| export const getAccountUsers = (accountUid) => | |||
| getRequest(replaceInUrl(apiEndpoints.accounts.getUsers, { accountUid })); | |||
| export const getUserPermissions = (currentAccountUid, currentUserUid) => | |||
| getRequest( | |||
| replaceInUrl(apiEndpoints.accounts.getCurrentUserPermissions, { | |||
| currentAccountUid, | |||
| currentUserUid, | |||
| }), | |||
| ); | |||
| export const getAccountAddresses = (accountUid) => | |||
| getRequest(replaceInUrl(apiEndpoints.accounts.getAddresses, { accountUid })); | |||
| export const getAccountSettingsRequest = (accountUid) => | |||
| getRequest(replaceInUrl(apiEndpoints.accounts.getSettings, { accountUid })); | |||
| export const updateAccountAddressRequest = (accountUid, addressUid, data) => | |||
| patchRequest( | |||
| replaceInUrl(apiEndpoints.accounts.updateAddress, { | |||
| accountUid, | |||
| addressUid, | |||
| }), | |||
| data, | |||
| ); | |||
| export const deleteAccountAddressRequest = (accountUid, addressUid) => | |||
| deleteRequest( | |||
| replaceInUrl(apiEndpoints.accounts.deleteAddress, { | |||
| accountUid, | |||
| addressUid, | |||
| }), | |||
| ); | |||
| export const postNewAccountUserRequest = (accountUid, data) => | |||
| postRequest( | |||
| replaceInUrl(apiEndpoints.accounts.createUser, { | |||
| accountUid, | |||
| }), | |||
| data, | |||
| ); | |||
| export const updateAccountUserRequest = ( | |||
| accountUid, | |||
| userUid, | |||
| actionType, | |||
| data, | |||
| ) => | |||
| patchRequest( | |||
| replaceInUrl(apiEndpoints.accounts.updateUser, { | |||
| accountUid, | |||
| userUid, | |||
| actionType, | |||
| }), | |||
| data, | |||
| ); | |||
| export const postAgreementRequest = (data) => | |||
| postRequest(apiEndpoints.accounts.agreement, data); | |||
| @@ -1,5 +1,6 @@ | |||
| import { APP_LOADING } from './appActionConstants'; | |||
| export const setAppReady = () => ({ | |||
| export const setAppReady = (payload) => ({ | |||
| type: APP_LOADING, | |||
| payload: payload | |||
| }); | |||
| @@ -0,0 +1,14 @@ | |||
| import { primaryThemeColors } from "./primaryTheme/primaryThemeColors"; | |||
| let selectedThemeNumber = 0; | |||
| const getTheme = () => { | |||
| if (selectedThemeNumber === 0) { | |||
| return {...primaryThemeColors} | |||
| } | |||
| } | |||
| const selectedTheme = getTheme(); | |||
| export default selectedTheme; | |||
| @@ -0,0 +1,10 @@ | |||
| export const primaryThemeColors = { | |||
| primaryPurple: "#5A3984", | |||
| primaryYellow: "#f7b126", | |||
| primaryPurpleDisabled: "#4D4D4D", | |||
| primaryBackgroundColor: "#F1F1F1", | |||
| primaryTextDisabled: "#F1F1F1", | |||
| primaryText: "#4D4D4D", | |||
| primaryGrayText: "#818181", | |||
| primaryDarkGrayText: "#DCDCDC" | |||
| } | |||