diff --git a/jams-react-client/src/assets/jss/material-dashboard-react/components/cardAvatarStyle.js b/jams-react-client/src/assets/jss/material-dashboard-react/components/cardAvatarStyle.js index 5bf38201f76cf7bf0465c42a7dd68bac92a09aba..7df7304d05efb3472e66e537859bdd66bdcab95f 100644 --- a/jams-react-client/src/assets/jss/material-dashboard-react/components/cardAvatarStyle.js +++ b/jams-react-client/src/assets/jss/material-dashboard-react/components/cardAvatarStyle.js @@ -10,7 +10,7 @@ const cardAvatarStyle = { cardAvatarProfile: { maxWidth: "80px", maxHeight: "80px", - margin: "-50px 10px 0", + margin: "-50px 0 0", borderRadius: "50%", overflow: "hidden", padding: "0", @@ -27,42 +27,10 @@ const cardAvatarStyle = { }, }, cardAvatarDisplayProfile: { - maxWidth: "200px", - maxHeight: "200px", margin: "-50px 10px 0", - borderRadius: "50%", - overflow: "hidden", - padding: "0", - boxShadow: - "0 6px 8px -12px rgba(" + - hexToRgb(blackColor) + - ", 0.56), 0 4px 25px 0px rgba(" + - hexToRgb(blackColor) + - ", 0.12), 0 8px 10px -5px rgba(" + - hexToRgb(blackColor) + - ", 0.2)", - "&$cardAvatarPlain": { - marginTop: "0", - }, }, cardAvatarEditProfile: { - maxWidth: "200px", - maxHeight: "200px", margin: "-50px 10px 0", - borderRadius: "50%", - overflow: "hidden", - padding: "0", - boxShadow: - "0 6px 8px -12px rgba(" + - hexToRgb(blackColor) + - ", 0.56), 0 4px 25px 0px rgba(" + - hexToRgb(blackColor) + - ", 0.12), 0 8px 10px -5px rgba(" + - hexToRgb(blackColor) + - ", 0.2)", - "&$cardAvatarPlain": { - marginTop: "0", - }, }, cardAvatarPlain: {}, }; diff --git a/jams-react-client/src/assets/jss/material-dashboard-react/components/cardFooterStyle.js b/jams-react-client/src/assets/jss/material-dashboard-react/components/cardFooterStyle.js index 1bed25c89b2b00b35dc68fe48659e514b8038172..b3ca458b8f6f2c68e2d781807b0f1a144cf265a8 100644 --- a/jams-react-client/src/assets/jss/material-dashboard-react/components/cardFooterStyle.js +++ b/jams-react-client/src/assets/jss/material-dashboard-react/components/cardFooterStyle.js @@ -1,6 +1,6 @@ import { grayColor } from "assets/jss/material-dashboard-react.js"; -const cardFooterStyle = { +const cardFooterStyle = theme => ({ cardFooter: { padding: "0", paddingTop: "10px", @@ -10,7 +10,18 @@ const cardFooterStyle = { alignItems: "center", display: "flex", backgroundColor: "transparent", - border: "0" + border: "0", + [theme.breakpoints.down("xs")]: { + display: "flex", + flexDirection: "column", + "& div": { + display: "flex", + flexDirection: "column", + "& button": { + width: "100%" + }, + }, + }, }, cardFooterProfile: { marginTop: "-15px" @@ -42,6 +53,6 @@ const cardFooterStyle = { cardFooterChart: { borderTop: "1px solid " + grayColor[10] } -}; +}); export default cardFooterStyle; diff --git a/jams-react-client/src/assets/jss/material-dashboard-react/components/cardStyle.js b/jams-react-client/src/assets/jss/material-dashboard-react/components/cardStyle.js index 9c8ad53ad516e6eff5a22610efd642190db75dfb..bbe39ea33d3d26ab72872d1f78cb02afafc18991 100644 --- a/jams-react-client/src/assets/jss/material-dashboard-react/components/cardStyle.js +++ b/jams-react-client/src/assets/jss/material-dashboard-react/components/cardStyle.js @@ -41,8 +41,9 @@ const cardStyle = { boxShadow: "none" }, cardProfile: { - marginTop: "30px", - textAlign: "left" + marginTop: "50px", + textAlign: "left", + height: "calc(100% - 4em)" }, cardChart: { "& p": { diff --git a/jams-react-client/src/assets/jss/material-dashboard-react/layouts/adminStyle.js b/jams-react-client/src/assets/jss/material-dashboard-react/layouts/adminStyle.js index 8864411d2524a5ab67b32f6bddb9d8624d205bc8..fa699b3298046f84b44635e8da82396b14107bde 100644 --- a/jams-react-client/src/assets/jss/material-dashboard-react/layouts/adminStyle.js +++ b/jams-react-client/src/assets/jss/material-dashboard-react/layouts/adminStyle.js @@ -24,6 +24,9 @@ const appStyle = theme => ({ }, content: { marginTop: "0px", + [theme.breakpoints.down("md")]: { + marginTop: "30px", + }, padding: "30px 15px", minHeight: "calc(100vh - 123px)" }, diff --git a/jams-react-client/src/views/UserProfile/DisplayUserProfile.js b/jams-react-client/src/views/UserProfile/DisplayUserProfile.js index 996ebf43d39699b6fcb8809f1e5c28108281264c..24298103ba42a127d68be10bdf08a8bd768bf3d9 100644 --- a/jams-react-client/src/views/UserProfile/DisplayUserProfile.js +++ b/jams-react-client/src/views/UserProfile/DisplayUserProfile.js @@ -6,8 +6,6 @@ import { makeStyles } from "@material-ui/core/styles"; import GridContainer from "components/Grid/GridContainer.js"; import Button from "components/CustomButtons/Button.js"; import Card from "components/Card/Card.js"; -import CardHeader from "components/Card/CardHeader.js"; -import CardIcon from "components/Card/CardIcon.js"; import CardBody from "components/Card/CardBody.js"; import CardFooter from "components/Card/CardFooter.js"; import noProfilePicture from "assets/img/faces/no-profile-picture.png"; @@ -29,12 +27,11 @@ import SmartphoneOutlinedIcon from "@material-ui/icons/SmartphoneOutlined"; import LocalPrintshopOutlinedIcon from "@material-ui/icons/LocalPrintshopOutlined"; import PhoneForwardedOutlinedIcon from "@material-ui/icons/PhoneForwardedOutlined"; import PersonOutlinedIcon from "@material-ui/icons/PersonOutlined"; -import PermIdentityOutlinedIcon from "@material-ui/icons/PermIdentityOutlined"; + import Avatar from "@material-ui/core/Avatar"; import Chip from "@material-ui/core/Chip"; import DoneIcon from "@material-ui/icons/Done"; -import CancelIcon from "@material-ui/icons/Cancel"; import CardAvatar from "components/Card/CardAvatar"; import List from "@material-ui/core/List"; @@ -42,6 +39,8 @@ import ListItem from "@material-ui/core/ListItem"; import ListItemAvatar from "@material-ui/core/ListItemAvatar"; import ListItemText from "@material-ui/core/ListItemText"; +import LinearProgress from "@material-ui/core/LinearProgress"; + import auth from "auth.js"; import configApiCall from "api.js"; import { @@ -118,12 +117,17 @@ const styles = (theme) => ({ minWidth: "80vh", maxWidth: "80vh", }, - footerActionButtons: { - [theme.breakpoints.down("sm")]: { - display: "flex", - flexDirection: "column", + footerActionButtons:{ + display: "flex", + flexDirection: "row", + "& button": { + marginRight: "1rem" }, }, + footerActionButtonsRight:{ + display: "flex", + justifyContent: "flex-end", + }, userProfileHeader: { display: "flex", justifyContent: "space-between", @@ -142,10 +146,13 @@ const styles = (theme) => ({ }, }, cardAvatarMobile: { - [theme.breakpoints.down("md")]: { + [theme.breakpoints.down("sm")]: { margin: "-50px 50px 0", }, }, + loading: { + width: "100%", + }, }); const useStyles = makeStyles(styles); @@ -158,11 +165,23 @@ export default function DisplayUserProfile(props) { const [open, setOpen] = React.useState(false); const [revokedUser, setRevokedUser] = React.useState(""); const [changePasswordOpen, setChangePasswordOpen] = React.useState(false); - + const [loading, setLoading] = React.useState(false); + const [progress, setProgress] = React.useState(0); + const [groups, setGroups] = React.useState([]); const [zeroGroup, setZeroGroup] = React.useState(false); useEffect(() => { + setLoading(true); + const timer = setInterval(() => { + setProgress((oldProgress) => { + if (oldProgress === 100) { + return 0; + } + const diff = Math.random() * 10; + return Math.min(oldProgress + diff, 100); + }); + }, 500); const userData = { username: props.username, }; @@ -212,6 +231,7 @@ export default function DisplayUserProfile(props) { }); } setGroups(allGroups); + setLoading(false); }) .catch((error) => { console.log(error); @@ -252,6 +272,7 @@ export default function DisplayUserProfile(props) { ) .then((response) => { setUser(response.data); + setLoading(false); }) .catch((error) => { console.log(error); @@ -262,6 +283,9 @@ export default function DisplayUserProfile(props) { }); } }); + return () => { + clearInterval(timer); + }; }, []); const getUserStatus = () => { @@ -359,7 +383,15 @@ export default function DisplayUserProfile(props) { }); }; + return ( + <div> + <div className={classes.loading}> + {loading && ( + <LinearProgress variant="determinate" value={progress} /> + )} + </div> + <div> <Dialog open={open} @@ -390,6 +422,7 @@ export default function DisplayUserProfile(props) { setChangePasswordOpen={setChangePasswordOpen} handleClosechangePassword={handleClosechangePassword} /> + {!loading && ( <GridContainer> <Grid item xs={12} sm={12} md={8}> <Card profile> @@ -420,16 +453,6 @@ export default function DisplayUserProfile(props) { </h3> {getUserStatus()} </div> - <div> - {auth.hasAdminScope() && revoked === false && ( - <Button - color="info" - onClick={() => handleClickOpen(user.username)} - > - <DeleteIcon fontSize="small" /> {i18next.t("revoke_user", "Revoke user")} - </Button> - )} - </div> </div> </Grid> <Grid item xs={12} sm={12} md={6}> @@ -537,29 +560,50 @@ export default function DisplayUserProfile(props) { </Grid> </div> </CardBody> - <CardFooter className={classes.footerActionButtons}> - {auth.isLocalDirectory() && ( - <Button - color="info" - onClick={() => props.setDisplayUser(false)} - > - <EditIcon /> {i18next.t("edit_profile", "Edit Profile")} - </Button> - )} - {auth.isLocalDirectory() && auth.hasAdminScope() && ( - <Button - color="info" - onClick={() => { - setChangePasswordOpen(true); - }} - > - <VpnKeyIcon /> {i18next.t("change_password", "Change password")} - </Button> - )} + <CardFooter> + <Grid container className={classes.footerActionButtons}> + <Grid item > + {auth.isLocalDirectory() && ( + <Button + color="info" + onClick={() => props.setDisplayUser(false)} + > + <EditIcon /> {i18next.t("edit_profile", "Edit Profile")} + </Button> + )} + </Grid> + <Grid item > + {auth.isLocalDirectory() && auth.hasAdminScope() && ( + <Button + color="info" + onClick={() => { + setChangePasswordOpen(true); + }} + > + <VpnKeyIcon /> {i18next.t("change_password", "Change password")} + </Button> + )} + </Grid> + </Grid> + + <Grid container className={classes.footerActionButtonsRight}> + <Grid item> + {auth.hasAdminScope() && revoked === false && ( + <Button + color="info" + onClick={() => handleClickOpen(user.username)} + > + <DeleteIcon fontSize="small" /> {i18next.t("revoke_user", "Revoke user")} + </Button> + )} + </Grid> + </Grid> </CardFooter> </Card> </Grid> </GridContainer> + )} + </div> </div> ); } diff --git a/jams-react-client/src/views/UserProfile/EditCreateUserProfile.js b/jams-react-client/src/views/UserProfile/EditCreateUserProfile.js index e0b2fcda2cd057a26c7fd22bd29e1162f64303d7..bbc98da3a4e70629864a847cb1b24e843baf7a16 100644 --- a/jams-react-client/src/views/UserProfile/EditCreateUserProfile.js +++ b/jams-react-client/src/views/UserProfile/EditCreateUserProfile.js @@ -139,9 +139,12 @@ const styles = (theme) => ({ }, alignRight: { float: "right", - [theme.breakpoints.down("sm")]: { + [theme.breakpoints.down("xs")]: { display: "flex", flexDirection: "column", + "& button": { + width: "100%" + } }, }, button: { @@ -190,6 +193,29 @@ const styles = (theme) => ({ margin: "0 16px", }, }, + profileEditHeaderMobile: { + [theme.breakpoints.down("xs")]: { + display: "flex", + flexDirection: "column", + alignItems: "center" + } + }, + profileEditAvatarMobile: { + [theme.breakpoints.down("xs")]: { + display: "flex", + flexDirection: "column", + alignItems: "center", + marginTop: 10 + } + }, + profileEditAvatarInputMobile: { + [theme.breakpoints.down("xs")]: { + display: "flex", + flexDirection: "row", + justifyContent: "center", + alignItems: "center" + } + } }); const useStyles = makeStyles(styles); @@ -534,7 +560,7 @@ export default function EditCreateUserProfile(props) { {({ isValid, dirty, handleSubmit, setFieldValue, values }) => ( <form onSubmit={handleSubmit}> <Card profile> - <CardHeader color="info" stats icon> + <CardHeader color="info" stats icon className={classes.profileEditHeaderMobile}> <p className={classes.cardCategory}> {createUser ? i18next.t("create_new_profile", "Create new profile") : i18next.t("edit_profile", "Edit profile")} </p> @@ -545,7 +571,7 @@ export default function EditCreateUserProfile(props) { )} </CardHeader> <CardBody profile> - <CardAvatar editProfile> + <CardAvatar editProfile className={classes.profileEditAvatarMobile}> <img src={profilePicturePreview} alt="..." @@ -560,7 +586,7 @@ export default function EditCreateUserProfile(props) { </CardAvatar> <div className={classes.root}> <Grid container spacing={5}> - <Grid item xs={12} sm={12} md={12}> + <Grid item xs={12} sm={12} md={12} className={classes.profileEditAvatarInputMobile} > <input accept="image/*" className={classes.input} diff --git a/jams-react-client/src/views/Users/Users.js b/jams-react-client/src/views/Users/Users.js index c5a718d5c482a22b8a8a213d2b6ecda2eaeda034..b0c0011318c1b0bdd4567a4ae043545a1405f944 100644 --- a/jams-react-client/src/views/Users/Users.js +++ b/jams-react-client/src/views/Users/Users.js @@ -71,6 +71,10 @@ const styles = { display: "flex", alignItems: "center", }, + cardBodyContent: { + + wordWrap: "break-word" + } }; const useStyles = makeStyles(styles); export default function Users(props) { @@ -236,7 +240,7 @@ export default function Users(props) { }} inputProps={{ placeholder: - i18next.t("search_users_using", "Search users using (username, name, phone, email, ...)"), + i18next.t("search_users_using", "Search users using (username, first name, last name)"), inputProps: { "aria-label": i18next.t("search_users", "Search users"), }, @@ -285,17 +289,19 @@ export default function Users(props) { .map((user) => ( <GridItem xs={12} - sm={12} - md={2} - wrap="nowrap" + sm={6} + md={3} + lg={2} + xl={2} + key={user.username} > <Card profile> - <CardBody profile> <a href="#" onClick={(e) => redirectToUserProfile(e, user.username)} > + <CardBody profile> <CardAvatar profile> <img src={ @@ -307,34 +313,43 @@ export default function Users(props) { alt="..." /> </CardAvatar> - <h4 className={classes.cardTitle}> - {user.firstName != "" - ? user.firstName - : "No first name"}{" "} - {user.lastName != "" ? user.lastName : "No last name"} - </h4> - <ul> - <li> - <img - src={jami} - width="20" - alt="Jami" - style={{ marginRight: "10px" }} - />{" "} - {user.username} - </li> - <li> - <BusinessOutlinedIcon - fontSize="small" - style={{ marginRight: "10px" }} - />{" "} - {user.organization - ? user.organization - : "No organization"} - </li> - </ul> + + <GridContainer + container + direction="column" + justify="flex-end" + alignItems="flex-start" + > + <GridItem style={{ minHeight:"50px"}}> + <h4 className={classes.cardTitle}> + {`${user.firstName} ${user.lastName}`} + </h4> + </GridItem> + <GridItem> + <ul className={classes.cardBodyContent}> + <li> + <img + src={jami} + width="20px" + alt="Jami" + style={{ minWidth:"20px", marginRight: "10px" }} + />{" "} + {user.username} + </li> + <li> + <BusinessOutlinedIcon + fontSize="small" + style={{ marginRight: "10px" }} + />{" "} + {user.organization + ? user.organization + : "No organization"} + </li> + </ul> + </GridItem> + </GridContainer> + </CardBody> </a> - </CardBody> </Card> </GridItem> ))}