-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
update: Update app state and landing page
- Loading branch information
Showing
66 changed files
with
10,211 additions
and
9,966 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
322 changes: 161 additions & 161 deletions
322
src/components/activities/loginActivity/LoginActivity.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,161 +1,161 @@ | ||
import { FC, useEffect } from "react"; | ||
import { InputAdornment } from "@material-ui/core"; | ||
import { Link as RouterLink } from "react-router-dom"; | ||
import Link from "@material-ui/core/Link"; | ||
import { RemoveRedEye } from "@material-ui/icons"; | ||
import classNames from "classnames"; | ||
import { useFormik } from "formik"; | ||
import get from "lodash.get"; | ||
import has from "lodash.has"; | ||
import { default as React, useState } from "react"; | ||
import { useTranslation } from "react-i18next"; | ||
import { useDispatch, useSelector } from "react-redux"; | ||
import { object, string } from "yup"; | ||
import logo from "../../../assets/logo-color.svg"; | ||
import { HospitalDTO } from "../../../generated"; | ||
import { useAuthentication } from "../../../libraries/authUtils/useAuthentication"; | ||
import { setAuthenticationThunk } from "../../../state/main/actions"; | ||
import { IState } from "../../../types"; | ||
import Button from "../../accessories/button/Button"; | ||
import Footer from "../../accessories/footer/Footer"; | ||
import TextField from "../../accessories/textField/TextField"; | ||
import "./styles.scss"; | ||
import { IValues } from "./types"; | ||
import { getHospital } from "../../../state/hospital/actions"; | ||
|
||
const LoginActivity: FC = () => { | ||
useAuthentication(); | ||
const { t } = useTranslation(); | ||
const dispatch = useDispatch(); | ||
|
||
const initialValues: IValues = { | ||
username: "", | ||
password: "", | ||
}; | ||
|
||
const validationSchema = object({ | ||
username: string().required(t("login.insertavalidusername")), | ||
password: string().required(t("login.insertthepassword")), | ||
}); | ||
|
||
const formik = useFormik({ | ||
initialValues, | ||
validationSchema, | ||
onSubmit: (values: IValues) => { | ||
dispatch(setAuthenticationThunk(values.username, values.password)); | ||
}, | ||
}); | ||
|
||
const [state, setState] = useState({ isPasswordVisible: false }); | ||
|
||
const isValid = (fieldName: string): boolean => { | ||
return has(formik.touched, fieldName) && has(formik.errors, fieldName); | ||
}; | ||
|
||
const getErrorText = (fieldName: string): string => { | ||
return has(formik.touched, fieldName) ? get(formik.errors, fieldName) : ""; | ||
}; | ||
const errorMessage = useSelector<IState>((state) => { | ||
const error = state.main.authentication.error; | ||
return error?.status == 401 | ||
? t("errors.incorrectcredentials") | ||
: error?.message ?? t("errors.somethingwrong"); | ||
}); | ||
|
||
const status = useSelector<IState>( | ||
(state) => state.main.authentication.status || "IDLE" | ||
); | ||
|
||
useEffect(() => { | ||
dispatch(getHospital()); | ||
}, [dispatch]); | ||
|
||
const hospital = useSelector<IState>( | ||
(state) => state.hospital.getHospital.data | ||
) as HospitalDTO; | ||
|
||
return ( | ||
<div className="login"> | ||
<div className="container login__background"> | ||
<img | ||
src={logo} | ||
alt="Open Hospital" | ||
className="login__logo" | ||
width="150px" | ||
/> | ||
<div className="login__title"> | ||
{hospital?.description ?? t("login.signin")} | ||
</div> | ||
<div className="login__panel"> | ||
<form className="login__panel__form" onSubmit={formik.handleSubmit}> | ||
<div className="login__panel__textField"> | ||
<TextField | ||
field={formik.getFieldProps("username")} | ||
theme="regular" | ||
label={t("login.username")} | ||
isValid={isValid("username")} | ||
errorText={getErrorText("username")} | ||
onBlur={formik.handleBlur} | ||
/> | ||
</div> | ||
<div className="login__panel__textField"> | ||
<TextField | ||
field={formik.getFieldProps("password")} | ||
theme="regular" | ||
label={t("login.password")} | ||
type={state.isPasswordVisible ? "text" : "password"} | ||
isValid={isValid("password")} | ||
errorText={getErrorText("password")} | ||
onBlur={formik.handleBlur} | ||
InputProps={{ | ||
endAdornment: ( | ||
<InputAdornment position="end"> | ||
<div | ||
className="login__passwordToggler" | ||
onClick={() => | ||
setState({ | ||
isPasswordVisible: !state.isPasswordVisible, | ||
}) | ||
} | ||
> | ||
<RemoveRedEye /> | ||
</div> | ||
</InputAdornment> | ||
), | ||
}} | ||
/> | ||
</div> | ||
<div | ||
className={classNames("login__invalidCredentials", { | ||
hidden: status !== "FAIL", | ||
})} | ||
> | ||
{errorMessage} | ||
</div> | ||
<div className="login__buttonContainer"> | ||
<Button | ||
type="submit" | ||
variant="contained" | ||
color="primary" | ||
disabled={status === "LOADING"} | ||
> | ||
{t("login.login")} | ||
</Button> | ||
</div> | ||
</form> | ||
<div> | ||
<RouterLink to="/forgot"> | ||
<Link className="login__panel__resetPassword" component="button"> | ||
{t("login.forgotpassword")} | ||
</Link> | ||
</RouterLink> | ||
</div> | ||
  | ||
</div> | ||
</div> | ||
<Footer /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default LoginActivity; | ||
import { FC, useEffect } from "react"; | ||
import { InputAdornment } from "@material-ui/core"; | ||
import { Link as RouterLink } from "react-router-dom"; | ||
import Link from "@material-ui/core/Link"; | ||
import { RemoveRedEye } from "@material-ui/icons"; | ||
import classNames from "classnames"; | ||
import { useFormik } from "formik"; | ||
import get from "lodash.get"; | ||
import has from "lodash.has"; | ||
import { default as React, useState } from "react"; | ||
import { useTranslation } from "react-i18next"; | ||
import { useDispatch, useSelector } from "react-redux"; | ||
import { object, string } from "yup"; | ||
import logo from "../../../assets/logo-color.svg"; | ||
import { HospitalDTO } from "../../../generated"; | ||
import { useAuthentication } from "../../../libraries/authUtils/useAuthentication"; | ||
import { setAuthenticationThunk } from "../../../state/main/actions"; | ||
import { IState } from "../../../types"; | ||
import Button from "../../accessories/button/Button"; | ||
import Footer from "../../accessories/footer/Footer"; | ||
import TextField from "../../accessories/textField/TextField"; | ||
import "./styles.scss"; | ||
import { IValues } from "./types"; | ||
import { getHospital } from "../../../state/hospital/actions"; | ||
|
||
const LoginActivity: FC = () => { | ||
useAuthentication(); | ||
const { t } = useTranslation(); | ||
const dispatch = useDispatch(); | ||
|
||
const initialValues: IValues = { | ||
username: "", | ||
password: "", | ||
}; | ||
|
||
const validationSchema = object({ | ||
username: string().required(t("login.insertavalidusername")), | ||
password: string().required(t("login.insertthepassword")), | ||
}); | ||
|
||
const formik = useFormik({ | ||
initialValues, | ||
validationSchema, | ||
onSubmit: (values: IValues) => { | ||
dispatch(setAuthenticationThunk(values.username, values.password)); | ||
}, | ||
}); | ||
|
||
const [state, setState] = useState({ isPasswordVisible: false }); | ||
|
||
const isValid = (fieldName: string): boolean => { | ||
return has(formik.touched, fieldName) && has(formik.errors, fieldName); | ||
}; | ||
|
||
const getErrorText = (fieldName: string): string => { | ||
return has(formik.touched, fieldName) ? get(formik.errors, fieldName) : ""; | ||
}; | ||
const errorMessage = useSelector<IState>((state) => { | ||
const error = state.main.authentication.error; | ||
return error?.status == 401 | ||
? t("errors.incorrectcredentials") | ||
: error?.message ?? t("errors.somethingwrong"); | ||
}); | ||
|
||
const status = useSelector<IState>( | ||
(state) => state.main.authentication.status || "IDLE" | ||
); | ||
|
||
useEffect(() => { | ||
dispatch(getHospital()); | ||
}, [dispatch]); | ||
|
||
const hospital = useSelector<IState>( | ||
(state) => state.hospital.getHospital.data | ||
) as HospitalDTO; | ||
|
||
return ( | ||
<div className="login"> | ||
<div className="container login__background"> | ||
<img | ||
src={logo} | ||
alt="Open Hospital" | ||
className="login__logo" | ||
width="150px" | ||
/> | ||
<div className="login__title"> | ||
{hospital?.description ?? t("login.signin")} | ||
</div> | ||
<div className="login__panel"> | ||
<form className="login__panel__form" onSubmit={formik.handleSubmit}> | ||
<div className="login__panel__textField"> | ||
<TextField | ||
field={formik.getFieldProps("username")} | ||
theme="regular" | ||
label={t("login.username")} | ||
isValid={isValid("username")} | ||
errorText={getErrorText("username")} | ||
onBlur={formik.handleBlur} | ||
/> | ||
</div> | ||
<div className="login__panel__textField"> | ||
<TextField | ||
field={formik.getFieldProps("password")} | ||
theme="regular" | ||
label={t("login.password")} | ||
type={state.isPasswordVisible ? "text" : "password"} | ||
isValid={isValid("password")} | ||
errorText={getErrorText("password")} | ||
onBlur={formik.handleBlur} | ||
InputProps={{ | ||
endAdornment: ( | ||
<InputAdornment position="end"> | ||
<div | ||
className="login__passwordToggler" | ||
onClick={() => | ||
setState({ | ||
isPasswordVisible: !state.isPasswordVisible, | ||
}) | ||
} | ||
> | ||
<RemoveRedEye /> | ||
</div> | ||
</InputAdornment> | ||
), | ||
}} | ||
/> | ||
</div> | ||
<div | ||
className={classNames("login__invalidCredentials", { | ||
hidden: status !== "FAIL", | ||
})} | ||
> | ||
{errorMessage} | ||
</div> | ||
<div className="login__buttonContainer"> | ||
<Button | ||
type="submit" | ||
variant="contained" | ||
color="primary" | ||
disabled={status === "LOADING"} | ||
> | ||
{t("login.login")} | ||
</Button> | ||
</div> | ||
</form> | ||
<div> | ||
<RouterLink to="/forgot"> | ||
<Link className="login__panel__resetPassword" component="button"> | ||
{t("login.forgotpassword")} | ||
</Link> | ||
</RouterLink> | ||
</div> | ||
  | ||
</div> | ||
</div> | ||
<Footer /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default LoginActivity; |
62 changes: 34 additions & 28 deletions
62
src/components/activities/loginActivity/RedirectAfterLogin.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,34 @@ | ||
import React, { useMemo } from "react"; | ||
import { useSelector } from "react-redux"; | ||
import { Navigate, useLocation } from "react-router"; | ||
import { useLandingPageRoute } from "../../../libraries/hooks/useLandingPageRoute"; | ||
import { TAPIResponseStatus } from "../../../state/types"; | ||
import { IState } from "../../../types"; | ||
import { IRedirectAfterLogin } from "./types"; | ||
|
||
export const RedirectAfterLogin: React.FC<IRedirectAfterLogin> = ({ | ||
children, | ||
}) => { | ||
const location = useLocation(); | ||
const landingPageRoute = useLandingPageRoute(); | ||
const to = useMemo( | ||
() => location.state?.from || landingPageRoute, | ||
[landingPageRoute, location] | ||
); | ||
|
||
const status = useSelector<IState, TAPIResponseStatus>( | ||
(state) => state.main.authentication.status || "IDLE" | ||
); | ||
|
||
if (status === "SUCCESS") { | ||
return <Navigate to={to} />; | ||
} | ||
|
||
return <>{children}</>; | ||
}; | ||
import React, { useMemo } from "react"; | ||
import { useSelector } from "react-redux"; | ||
import { Navigate, useLocation } from "react-router"; | ||
import { useLandingPageRoute } from "../../../libraries/hooks/useLandingPageRoute"; | ||
import { TAPIResponseStatus } from "../../../state/types"; | ||
import { IState } from "../../../types"; | ||
import { IRedirectAfterLogin } from "./types"; | ||
|
||
export const RedirectAfterLogin: React.FC<IRedirectAfterLogin> = ({ | ||
children, | ||
}) => { | ||
const location = useLocation(); | ||
const landingPageRoute = useLandingPageRoute(); | ||
const to = useMemo( | ||
() => location.state?.from || landingPageRoute, | ||
[landingPageRoute, location] | ||
); | ||
|
||
const state = useSelector<IState, IState>((state) => state); | ||
|
||
const status = useMemo( | ||
() => | ||
["SUCCESS", "FAIL"].includes(state.main.settings.status!) | ||
? state.main.authentication.status! | ||
: state.main.settings.status!, | ||
[state.main.settings.status, state.main.authentication.status] | ||
); | ||
|
||
if (status === "SUCCESS") { | ||
return <Navigate to={to} />; | ||
} | ||
|
||
return <>{children}</>; | ||
}; |
Oops, something went wrong.