From a9e60d2a875e05e7f0939d99b7e75f750d00f277 Mon Sep 17 00:00:00 2001 From: Larbi Gharib <larbi.gharib@savoirfairelinux.com> Date: Fri, 23 Oct 2020 15:02:33 -0400 Subject: [PATCH] Add user to group Change-Id: I640daaa58d820e572919817fec70ea3f380f4d9b --- .../public/locales/en/translation.json | 5 +- .../public/locales/fr/translation.json | 5 +- jams-react-client/src/api.js | 44 +-- .../components/devicesStyle.js | 4 +- jams-react-client/src/auth.js | 19 +- .../CustomPopupState/CustomPopupState.js | 3 +- .../CustomizedSteppers/CustomizedSteppers.js | 20 +- .../src/components/Drawer/Drawer.js | 312 +++--------------- .../LanguagePicker/LanguagePicker.js | 13 - .../components/Navbars/AdminNavbarLinks.js | 21 +- .../src/components/Navbars/Navbar.js | 12 - .../PasswordDialog/PasswordDialog.js | 3 +- .../ServerParameters/ServerParameters.js | 2 +- jams-react-client/src/configured.route.js | 9 +- jams-react-client/src/layouts/Admin.js | 28 +- jams-react-client/src/layouts/SignIn.js | 3 - jams-react-client/src/layouts/SignUp.js | 12 +- .../src/views/Blueprint/Blueprint.js | 6 - .../Blueprint/EditBlueprintConfiguration.js | 23 +- .../Blueprint/EditBlueprintPermissions.js | 8 +- .../src/views/Blueprints/Blueprints.js | 11 +- .../src/views/Contacts/Contacts.js | 93 +++++- .../src/views/Groups/EditGroup.js | 138 ++++++-- jams-react-client/src/views/Groups/Groups.js | 70 ++-- .../src/views/Settings/General.js | 4 - .../src/views/Settings/Settings.js | 5 - .../src/views/Settings/Subscription.js | 13 +- .../views/UserProfile/DisplayUserProfile.js | 257 ++++++++------- .../UserProfile/EditCreateUserProfile.js | 68 ++-- .../src/views/UserProfile/UserProfile.js | 29 +- jams-react-client/src/views/Users/Users.js | 33 +- 31 files changed, 536 insertions(+), 737 deletions(-) diff --git a/jams-react-client/public/locales/en/translation.json b/jams-react-client/public/locales/en/translation.json index 43510d7e..970cc1a4 100644 --- a/jams-react-client/public/locales/en/translation.json +++ b/jams-react-client/public/locales/en/translation.json @@ -231,5 +231,8 @@ "validate": "Validate", "change_language": "Change language", "general": "General", - "device_id": "Device Id" + "device_id": "Device Id", + "add_user_to_group": "Add user to group ...", + "add_user_to_a_group": "Add user to a group", + "remove_from_group": "Remove from group" } diff --git a/jams-react-client/public/locales/fr/translation.json b/jams-react-client/public/locales/fr/translation.json index c2a4e407..29ccf3e9 100644 --- a/jams-react-client/public/locales/fr/translation.json +++ b/jams-react-client/public/locales/fr/translation.json @@ -231,5 +231,8 @@ "validate": "Valider", "change_language": "Change language", "general": "General", - "device_id": "Identifiant de l'appareil" + "device_id": "Identifiant de l'appareil", + "add_user_to_group": "Add user to group ...", + "add_user_to_a_group": "Add user to a group", + "remove_from_group": "Remove from group" } diff --git a/jams-react-client/src/api.js b/jams-react-client/src/api.js index 74d30367..d4325371 100644 --- a/jams-react-client/src/api.js +++ b/jams-react-client/src/api.js @@ -19,41 +19,15 @@ */ import { - uri, - current_uri, - backend_address, url_path, url_port, - api_path_post_install_admin, - api_path_post_auth_login, - api_path_post_install_ca, - api_path_post_install_auth, - api_path_post_install_server, - api_path_get_install_lastKnownStep, api_path_get_auth_user_search, api_path_get_auth_devices, api_path_get_admin_devices, - api_path_delete_admin_user_revoke, - api_path_delete_auth_user_revoke, - api_path_delete_auth_device_revoke, - api_path_rename_device, - api_path_get_server_status, - api_path_get_post_configuration_auth_service, - api_path_get_post_configuration_global_settings, api_path_post_configuration_change_password, - api_path_post_configuration_register_license, - api_path_get_subscription_status, - api_path_get_directories, - api_path_get_needs_update, - api_path_get_start_update, api_path_post_create_user, - api_path_get_auth_user, api_path_post_update_user, - api_path_get_exists_user, api_path_get_user_directory_search, - api_path_post_create_user_profile, - api_path_put_update_user_profile, - api_path_get_user_search, api_path_blueprints, } from "globalUrls"; @@ -92,20 +66,20 @@ export default function configApiCall( // pass data in the header if (data) { if ( - api_path == api_path_get_user_directory_search || - api_path == api_path_get_auth_user_search || - (api_path == api_path_post_create_user && request_type == "POST") || - (api_path.includes(api_path_blueprints) && request_type == "POST") || - api_path == api_path_post_update_user || - api_path == api_path_get_auth_devices || - api_path == api_path_get_admin_devices || - api_path == api_path_post_configuration_change_password + api_path === api_path_get_user_directory_search || + api_path === api_path_get_auth_user_search || + (api_path === api_path_post_create_user && request_type === "POST") || + (api_path.includes(api_path_blueprints) && request_type === "POST") || + api_path === api_path_post_update_user || + api_path === api_path_get_auth_devices || + api_path === api_path_get_admin_devices || + api_path === api_path_post_configuration_change_password ) isSearch = true; // search dataType if (isSearch) { - if (request_type == "GET" || request_type == "DELETE") { + if (request_type === "GET" || request_type === "DELETE") { config["params"] = data; } else { config["data"] = data; diff --git a/jams-react-client/src/assets/jss/material-dashboard-react/components/devicesStyle.js b/jams-react-client/src/assets/jss/material-dashboard-react/components/devicesStyle.js index a5699e82..e3505a06 100644 --- a/jams-react-client/src/assets/jss/material-dashboard-react/components/devicesStyle.js +++ b/jams-react-client/src/assets/jss/material-dashboard-react/components/devicesStyle.js @@ -26,11 +26,11 @@ const tasksStyle = { }, tableCell: { ...defaultFont, - padding: "8px", verticalAlign: "middle", border: "none", lineHeight: "1.42857143", - fontSize: "14px" + fontSize: "14px", + textAlign: "left" }, tableCellRTL: { textAlign: "right" diff --git a/jams-react-client/src/auth.js b/jams-react-client/src/auth.js index 217e576b..b7164001 100644 --- a/jams-react-client/src/auth.js +++ b/jams-react-client/src/auth.js @@ -8,8 +8,7 @@ import { api_path_get_install_lastKnownStep, api_path_get_directories, api_path_get_subscription_status, - api_path_get_needs_update, - api_path_get_start_update + api_path_get_needs_update } from "globalUrls"; class Auth { @@ -56,9 +55,9 @@ class Auth { login(jsonData, cb) { this.deleteJWT() axios(configApiCall(api_path_post_auth_login, "POST", jsonData, null)).then((response) => { - if(response.status == 200){ + if(response.status === 200){ this.setJWT(response.data['access_token']); - this.setScope(response.data["scope"] == "ADMIN" ? true : false); + this.setScope(response.data["scope"] === "ADMIN" ? true : false); this.setUsername(jsonData.username); this.authenticated = true; } @@ -85,10 +84,10 @@ class Auth { checkDirectoryType(cb){ axios(configApiCall(api_path_get_directories, "GET", null, null)).then((response) => { - if (response.data.length == 1) { + if (response.data.length === 1) { this.setLocalDirectory(true); } - else if (response.data.length == 2){ + else if (response.data.length === 2){ this.setLocalDirectory(false); }else{ console.log("Error getting on checkDirectoryType: Size of directory types is " + response.data.length); @@ -102,12 +101,12 @@ class Auth { checkAdminAccountStatus(cb) { axios(configApiCall(api_path_post_install_admin, "GET", null, null)).then((response) => { - if (response['headers']['showlogin'] == "true") { + if (response['headers']['showlogin'] === "true") { this.admin = true; } cb() }).catch((error) => { - if(error.response.status == 404){ + if(error.response.status === 404){ this.admin = true; } else{ @@ -119,7 +118,7 @@ class Auth { isServerInstalled(cb) { axios(configApiCall(api_path_get_server_status, "GET", null, null)).then((response) => { - if (response.data['installed'] == 'true') { + if (response.data['installed'] === 'true') { this.installed = true console.log("Server is installed") } else { @@ -143,7 +142,7 @@ class Auth { this.authenticated = true; cb() }).catch((error) => { - if(error.response.status == 401){ + if(error.response.status === 401){ this.authenticated = false; console.log("Error during API request on checkLastKnowStep not authenticated!"); } diff --git a/jams-react-client/src/components/CustomPopupState/CustomPopupState.js b/jams-react-client/src/components/CustomPopupState/CustomPopupState.js index 09d69ee7..b58a3814 100644 --- a/jams-react-client/src/components/CustomPopupState/CustomPopupState.js +++ b/jams-react-client/src/components/CustomPopupState/CustomPopupState.js @@ -9,7 +9,6 @@ import Typography from '@material-ui/core/Typography'; export default function CustomPopupState(props) { - const [message, setMessage] = React.useState(props.message); return( <IconButton> @@ -29,7 +28,7 @@ export default function CustomPopupState(props) { }} > <Box p={1}> - <Typography>{message}</Typography> + <Typography>{props.message}</Typography> </Box> </Popover> </div> diff --git a/jams-react-client/src/components/CustomizedSteppers/CustomizedSteppers.js b/jams-react-client/src/components/CustomizedSteppers/CustomizedSteppers.js index 914f6c76..71518121 100644 --- a/jams-react-client/src/components/CustomizedSteppers/CustomizedSteppers.js +++ b/jams-react-client/src/components/CustomizedSteppers/CustomizedSteppers.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { makeStyles, withStyles } from '@material-ui/core/styles'; +import { makeStyles } from '@material-ui/core/styles'; import clsx from 'clsx'; import Stepper from '@material-ui/core/Stepper'; import Step from '@material-ui/core/Step'; @@ -9,9 +9,6 @@ import Check from '@material-ui/icons/Check'; import SettingsIcon from '@material-ui/icons/Settings'; import GroupAddIcon from '@material-ui/icons/GroupAdd'; import VideoLabelIcon from '@material-ui/icons/VideoLabel'; -import StepConnector from '@material-ui/core/StepConnector'; -import Button from '@material-ui/core/Button'; -import Typography from '@material-ui/core/Typography'; import i18next from 'i18next'; @@ -143,24 +140,11 @@ function getSteps() { export default function CustomizedSteppers(props) { const classes = useStyles(); - const [activeStep, setActiveStep] = React.useState(props.step); const steps = getSteps(); - const handleNext = () => { - setActiveStep((prevActiveStep) => prevActiveStep + 1); - }; - - const handleBack = () => { - setActiveStep((prevActiveStep) => prevActiveStep - 1); - }; - - const handleReset = () => { - setActiveStep(0); - }; - return ( <div className={classes.root}> - <Stepper alternativeLabel activeStep={activeStep}> + <Stepper alternativeLabel activeStep={props.step}> {steps.map((label) => ( <Step key={label}> <StepLabel>{label}</StepLabel> diff --git a/jams-react-client/src/components/Drawer/Drawer.js b/jams-react-client/src/components/Drawer/Drawer.js index 32e22b9b..293bc95b 100644 --- a/jams-react-client/src/components/Drawer/Drawer.js +++ b/jams-react-client/src/components/Drawer/Drawer.js @@ -7,32 +7,18 @@ import List from "@material-ui/core/List"; import Divider from "@material-ui/core/Divider"; import ListItem from "@material-ui/core/ListItem"; import ListItemText from "@material-ui/core/ListItemText"; -import AddCircleOutlineIcon from "@material-ui/icons/AddCircleOutline"; import Avatar from "@material-ui/core/Avatar"; import noProfilePicture from "assets/img/faces/no-profile-picture.png"; -import { - api_path_get_user_directory_search, - api_path_get_auth_contacts, - api_path_get_admin_contacts, - api_path_put_update_group, -} from "globalUrls"; -import { useHistory } from "react-router-dom"; -import axios from "axios"; -import configApiCall from "api.js"; -import auth from "auth.js"; - import { debounce } from "lodash"; -import i18next from "i18next"; - const useStyles = makeStyles({ list: { - width: 500, + width: "100%", }, fullList: { - width: "auto", + width: "100%", }, search: { width: "100%", @@ -45,259 +31,67 @@ const useStyles = makeStyles({ export default function TemporaryDrawer(props) { const classes = useStyles(); - const history = useHistory(); - const [direction, setDirection] = React.useState(props.direction); - const [users, setUsers] = React.useState([]); - const [existingContacts, setExistingContacts] = React.useState([]); - const [userAdded, setUserAdded] = React.useState(false); - let addingToGroup = props.addingToGroup; useEffect(() => { - /** - * Get users list to pass to the drawer to add contacts to user or users to group - */ - - axios( - configApiCall( - api_path_get_admin_contacts + "?username=" + props.username, - "GET", - null, - null - ) - ) - .then((response) => { - /* - TODO: Include the username of the user of witch we want to display contacts - at the moment the admin sees his contacts in each user profile he visits - */ - let originalContacts = response.data; - originalContacts.map((contact) => { - contact.display = ""; - }); - setExistingContacts(originalContacts); - }) - .catch((error) => { - console.log(error); - if (error.response.status == 401) { - auth.authenticated = false; - history.push("/"); - } - }); - - axios( - configApiCall( - api_path_get_user_directory_search, - "GET", - { queryString: "*", page: "1" }, - null - ) - ) - .then((response) => { - let resp = response.data.profiles; - if (!addingToGroup) { - let contacts = resp.filter((data) => { - if (data.username !== props.username) return data; - }); - setUsers(contacts); - } else setUsers(resp); - }) - .catch((error) => { - console.log(error); - if (error.response.status == 401) { - auth.authenticated = false; - history.push("/"); - } - }); - }, [userAdded]); - - const addContactToUser = (firstName, lastName, jamiId) => { - var displayName = firstName + " " + lastName; - var owner = props.username; - const data = { - owner: owner, - uri: jamiId, - displayName: displayName, - timestamp: "", - status: "", - banned: false, - confirmed: false, - }; - if (props.isAdmin) { - axios( - configApiCall( - api_path_get_admin_contacts + "?username=" + props.username, - "PUT", - data, - null - ) - ) - .then((response) => { - setUserAdded(true); - props.setOpenDrawer(false); - }) - .catch((error) => { - console.log("Error adding user: " + error); - props.setOpenDrawer(false); - }); - } else { - axios(configApiCall(api_path_get_auth_contacts, "PUT", data, null)) - .then((response) => { - setUserAdded(true); - props.setOpenDrawer(false); - }) - .catch((error) => { - console.log("Error adding user: " + error); - props.setOpenDrawer(false); - }); - } - }; - - const addUserToGroup = (username) => { - let url = ""; - console.log(props.blueprintLabel); - - if (props.blueprintLabel == null) { - url = - api_path_put_update_group + - "?groupName=" + - props.groupName + - "&newName=" + - props.groupName + - "&blueprintName=&groupMembers=" + - username; - } else { - url = - api_path_put_update_group + - "?groupName=" + - props.groupName + - "&newName=" + - props.groupName + - "&blueprintName=" + - props.blueprintLabel + - "&groupMembers=" + - username; - } - - axios(configApiCall(url, "PUT", null, null)) - .then((response) => { - setUserAdded(true); - props.getGroup(); - props.setOpenDrawer(false); - }) - .catch((error) => { - console.log("Error adding user: " + error); - props.setOpenDrawer(false); - }); - }; + console.log(props.targets) + }, []); - const searchUsers = (value) => { - axios( - configApiCall( - api_path_get_user_directory_search, - "GET", - { queryString: value ? value : "*", page: "1" }, - null - ) - ) - .then((response) => { - let resp = response.data.profiles; - if (!addingToGroup) { - let contacts = resp.filter((data) => { - if (data.username !== props.username) return data; - }); - setUsers(contacts); - } else setUsers(resp); - }) - .catch((error) => { - console.log(error); - setUsers([]); - if (error.response.status == 401) { - auth.authenticated = false; - history.push("/"); - } - }); - }; const listUsers = () => ( <List> - {addingToGroup - ? users.map((user) => ( - <ListItem - button - key={user.username} - onClick={() => { - addUserToGroup(user.username); - }} - > - {/* <AddCircleOutlineIcon style={{ marginRight: "10px" }} /> */} - <Avatar - style={{ marginRight: "10px" }} - alt={user.username} - src={ - user.profilePicture - ? "data:image/png;base64, " + user.profilePicture - : noProfilePicture - } - /> - <ListItemText - primary={ - user.username === "" - ? user.id - : user.firstName === "" || user.lastName === "" - ? user.username - : user.firstName + " " + user.lastName - } - /> - </ListItem> - )) - : users - .filter((data) => { - var added = false; - existingContacts.forEach((contact) => { - if (contact.uri === data.id) added = true; - }); - if (!added) return data; - }) - .map((user) => ( - <ListItem - button - key={user.username} - onClick={() => { - addContactToUser(user.firstName, user.lastName, user.id); - }} - > - {/* <AddCircleOutlineIcon style={{ marginRight: "10px" }} /> */} - <Avatar - style={{ marginRight: "10px" }} - alt={user.username} - src={ - user.profilePicture - ? "data:image/png;base64, " + user.profilePicture - : noProfilePicture - } - /> - <ListItemText - primary={ - user.username === "" - ? user.id - : user.firstName === "" || user.lastName === "" - ? user.username - : user.firstName + " " + user.lastName - } - /> - </ListItem> - ))} + {props.type === "user" ? props.targets.map((target) => ( + <ListItem + button + key={target.username} + onClick={() => { + props.addElementToTarget(target); + props.setOpenDrawer(false); + }} + > + <Avatar + style={{ marginRight: "10px" }} + alt={target.username} + src={ + target.profilePicture + ? "data:image/png;base64, " + target.profilePicture + : noProfilePicture + } + /> + <ListItemText + primary={ + target.username === "" + ? target.id + : target.firstName === "" || target.lastName === "" + ? target.username + : target.firstName + " " + target.lastName + } + /> + </ListItem> + )) : props.targets.map((target) => ( + <ListItem + button + key={target.name} + onClick={() => { + props.addElementToTarget(target.name); + props.setOpenDrawer(false); + }} + > + <ListItemText + primary={target.name} + /> + </ListItem> + ))} </List> ); - const initSearchUsers = useCallback( - debounce((searchValue) => searchUsers(searchValue), 500), + const initSearchTargets = useCallback( + debounce((searchValue) => props.searchTargets(searchValue), 500), [] ); - const handleSearchUsers = (e) => { + const handleSearchTargets = (e) => { const searchValue = e.target.value; - initSearchUsers(searchValue); + initSearchTargets(searchValue); }; return ( @@ -312,7 +106,7 @@ export default function TemporaryDrawer(props) { > <div className={clsx(classes.list, { - [classes.fullList]: direction === "top" || direction === "bottom", + [classes.fullList]: props.direction === "top" || props.direction === "bottom", })} role="presentation" > @@ -324,9 +118,9 @@ export default function TemporaryDrawer(props) { inputProps={{ placeholder: props.placeholder, inputProps: { - "aria-label": i18next.t("add_a_contact", "Add contact"), + "aria-label": props.placeholder, }, - onKeyUp: handleSearchUsers, + onKeyUp: handleSearchTargets, }} /> </div> diff --git a/jams-react-client/src/components/LanguagePicker/LanguagePicker.js b/jams-react-client/src/components/LanguagePicker/LanguagePicker.js index 1eafd230..a87d64fa 100644 --- a/jams-react-client/src/components/LanguagePicker/LanguagePicker.js +++ b/jams-react-client/src/components/LanguagePicker/LanguagePicker.js @@ -1,28 +1,15 @@ import React, { useEffect } from "react"; import { useHistory } from "react-router-dom"; -import { makeStyles } from "@material-ui/core/styles"; import Button from "@material-ui/core/Button"; import Menu from "@material-ui/core/Menu"; import MenuItem from "@material-ui/core/MenuItem"; import PopupState, { bindTrigger, bindMenu } from "material-ui-popup-state"; -import TranslateIcon from "@material-ui/icons/Translate"; - import i18next from "i18next"; import { useTranslation } from "react-i18next"; -const useStyles = makeStyles((theme) => ({ - root: { - "& .MuiTextField-root": { - margin: theme.spacing(1), - width: "25ch", - backgrounColor: "white", - }, - }, -})); - export default function LanguagePicker(props) { const history = useHistory(); const [language, setLanguage] = React.useState(i18next.language || window.localStorage.i18nextLng || "en"); diff --git a/jams-react-client/src/components/Navbars/AdminNavbarLinks.js b/jams-react-client/src/components/Navbars/AdminNavbarLinks.js index 7a158056..1b9ff7d3 100644 --- a/jams-react-client/src/components/Navbars/AdminNavbarLinks.js +++ b/jams-react-client/src/components/Navbars/AdminNavbarLinks.js @@ -1,5 +1,4 @@ import React from "react"; -import { useHistory } from 'react-router-dom' import classNames from "classnames"; // @material-ui/core components import { makeStyles } from "@material-ui/core/styles"; @@ -13,32 +12,18 @@ import Poppers from "@material-ui/core/Popper"; import Divider from "@material-ui/core/Divider"; // @material-ui/icons import Person from "@material-ui/icons/Person"; -import Notifications from "@material-ui/icons/Notifications"; -import Dashboard from "@material-ui/icons/Dashboard"; -import Search from "@material-ui/icons/Search"; + // core components -import CustomInput from "components/CustomInput/CustomInput.js"; import Button from "components/CustomButtons/Button.js"; import styles from "assets/jss/material-dashboard-react/components/headerLinksStyle.js"; -import auth from "../../auth" + const useStyles = makeStyles(styles); export default function AdminNavbarLinks(props) { const classes = useStyles(); - const history = useHistory(); - const [openNotification, setOpenNotification] = React.useState(null); const [openProfile, setOpenProfile] = React.useState(null); - const handleClickNotification = event => { - if (openNotification && openNotification.contains(event.target)) { - setOpenNotification(null); - } else { - setOpenNotification(event.currentTarget); - } - }; - const handleCloseNotification = () => { - setOpenNotification(null); - }; + const handleClickProfile = event => { if (openProfile && openProfile.contains(event.target)) { setOpenProfile(null); diff --git a/jams-react-client/src/components/Navbars/Navbar.js b/jams-react-client/src/components/Navbars/Navbar.js index 2b6a4356..370ac08b 100755 --- a/jams-react-client/src/components/Navbars/Navbar.js +++ b/jams-react-client/src/components/Navbars/Navbar.js @@ -10,8 +10,6 @@ import Hidden from "@material-ui/core/Hidden"; // @material-ui/icons import Menu from "@material-ui/icons/Menu"; // core components -import AdminNavbarLinks from "./AdminNavbarLinks.js"; -import RTLNavbarLinks from "./RTLNavbarLinks.js"; import Button from "components/CustomButtons/Button.js"; import styles from "assets/jss/material-dashboard-react/components/headerStyle.js"; @@ -20,16 +18,6 @@ const useStyles = makeStyles(styles); export default function Header(props) { const classes = useStyles(); - function makeBrand() { - var name; - props.routes.map(prop => { - if (window.location.href.indexOf(prop.layout + prop.path) !== -1) { - name = props.rtlActive ? prop.rtlName : prop.name; - } - return null; - }); - return name; - } const { color } = props; const appBarClasses = classNames({ [" " + classes[color]]: color diff --git a/jams-react-client/src/components/PasswordDialog/PasswordDialog.js b/jams-react-client/src/components/PasswordDialog/PasswordDialog.js index 5fc9da56..2d70194b 100644 --- a/jams-react-client/src/components/PasswordDialog/PasswordDialog.js +++ b/jams-react-client/src/components/PasswordDialog/PasswordDialog.js @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React from "react"; // @material-ui/core components import { makeStyles } from "@material-ui/core/styles"; // core components @@ -9,7 +9,6 @@ import Dialog from "@material-ui/core/Dialog"; import DialogActions from "@material-ui/core/DialogActions"; import DialogContent from "@material-ui/core/DialogContent"; import DialogContentText from "@material-ui/core/DialogContentText"; -import DialogTitle from "@material-ui/core/DialogTitle"; import Grid from "@material-ui/core/Grid"; diff --git a/jams-react-client/src/components/ServerParameters/ServerParameters.js b/jams-react-client/src/components/ServerParameters/ServerParameters.js index 69bcee65..6c8c6e30 100644 --- a/jams-react-client/src/components/ServerParameters/ServerParameters.js +++ b/jams-react-client/src/components/ServerParameters/ServerParameters.js @@ -4,7 +4,7 @@ import Button from "@material-ui/core/Button"; import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; import { makeStyles } from "@material-ui/core/styles"; -import { Formik, Field } from "formik"; +import { Formik } from "formik"; import CustomPopupState from "../CustomPopupState/CustomPopupState"; import Select from "@material-ui/core/Select"; diff --git a/jams-react-client/src/configured.route.js b/jams-react-client/src/configured.route.js index d0434b94..32200089 100644 --- a/jams-react-client/src/configured.route.js +++ b/jams-react-client/src/configured.route.js @@ -1,10 +1,9 @@ import React from 'react' -import { Route, Redirect } from 'react-router-dom' +import { Route } from 'react-router-dom' import auth from './auth' import SignUp from "layouts/SignUp"; import SignIn from "layouts/SignIn"; -import Admin from 'layouts/Admin'; export const ConfiguredRoute = ({ component: Component, ...rest }) => { return ( @@ -15,12 +14,12 @@ export const ConfiguredRoute = ({ component: Component, ...rest }) => { if(auth.isInstalled()){ return <Component {...props} /> }else if(!auth.isInstalled() && auth.isAuthenticated()){ - if(auth.uri == '/api/install/ca' || auth.uri == 'start'){ + if(auth.uri === '/api/install/ca' || auth.uri === 'start'){ return <SignUp step={1}/> } - else if (auth.uri == '/api/install/auth'){ + else if (auth.uri === '/api/install/auth'){ return <SignUp step={2}/> - } else if (auth.uri == '/api/install/settings'){ + } else if (auth.uri === '/api/install/settings'){ return <SignUp step={3}/> } else { console.log('Error no matching path for configuration') diff --git a/jams-react-client/src/layouts/Admin.js b/jams-react-client/src/layouts/Admin.js index 9d92b5a6..df779bcc 100644 --- a/jams-react-client/src/layouts/Admin.js +++ b/jams-react-client/src/layouts/Admin.js @@ -9,7 +9,6 @@ import { makeStyles } from "@material-ui/core/styles"; import Navbar from "components/Navbars/Navbar.js"; import Footer from "components/Footer/Footer.js"; import Sidebar from "components/Sidebar/Sidebar.js"; -import Snackbar from "@material-ui/core/Snackbar"; // @material-ui/icons import Person from "@material-ui/icons/Person"; @@ -31,21 +30,15 @@ import logo from "assets/img/logo-jams.svg"; import auth from "auth"; import configApiCall from "api.js"; import { - api_path_get_start_update, - api_path_get_subscription_status, + api_path_get_start_update } from "globalUrls"; import axios from "axios"; -import ReactDOM from "react-dom"; -import { ConfiguredRoute } from "../configured.route"; -import SignIn from "./SignIn"; -import { ProtectedRoute } from "../protected.route"; + import Dialog from "@material-ui/core/Dialog/Dialog"; import DialogTitle from "@material-ui/core/DialogTitle/DialogTitle"; -import { Field, Formik } from "formik"; import DialogContent from "@material-ui/core/DialogContent/DialogContent"; -import TextField from "@material-ui/core/TextField/TextField"; import DialogActions from "@material-ui/core/DialogActions/DialogActions"; import DialogContentText from "@material-ui/core/DialogContentText/DialogContentText"; import Button from "@material-ui/core/Button"; @@ -68,10 +61,6 @@ export default function Admin({ ...rest }) { const [mobileOpen, setMobileOpen] = React.useState(false); const [open, setOpen] = React.useState(false); const [message, setMessage] = React.useState(false); - const [signedUp, setSignedUp] = React.useState(false); - const [signedIn, setSignedIn] = React.useState(false); - const [token, setToken] = React.useState(false); - const [severity, setSeverity] = React.useState("success"); const [openUpdate, setOpenUpdate] = React.useState(false); const [dialogMessage, setDialogMessage] = React.useState(""); const [messageYes, setMessageYes] = React.useState(""); @@ -137,19 +126,6 @@ export default function Admin({ ...rest }) { </Switch> ); - const handleImageClick = (image) => { - setImage(image); - }; - const handleColorClick = (color) => { - setColor(color); - }; - const handleFixedClick = () => { - if (fixedClasses === "dropdown") { - setFixedClasses("dropdown show"); - } else { - setFixedClasses("dropdown"); - } - }; const handleDrawerToggle = () => { setMobileOpen(!mobileOpen); }; diff --git a/jams-react-client/src/layouts/SignIn.js b/jams-react-client/src/layouts/SignIn.js index ecc8d71c..094d9a65 100644 --- a/jams-react-client/src/layouts/SignIn.js +++ b/jams-react-client/src/layouts/SignIn.js @@ -4,10 +4,7 @@ import { Formik } from "formik"; import Button from "@material-ui/core/Button"; import CssBaseline from "@material-ui/core/CssBaseline"; import TextField from "@material-ui/core/TextField"; -import FormControlLabel from "@material-ui/core/FormControlLabel"; -import Checkbox from "@material-ui/core/Checkbox"; import Link from "@material-ui/core/Link"; -import Grid from "@material-ui/core/Grid"; import Box from "@material-ui/core/Box"; import Typography from "@material-ui/core/Typography"; import { makeStyles } from "@material-ui/core/styles"; diff --git a/jams-react-client/src/layouts/SignUp.js b/jams-react-client/src/layouts/SignUp.js index aa5aeb34..901dd534 100644 --- a/jams-react-client/src/layouts/SignUp.js +++ b/jams-react-client/src/layouts/SignUp.js @@ -7,7 +7,6 @@ import { makeStyles } from "@material-ui/core/styles"; import Container from "@material-ui/core/Container"; import MuiAlert from "@material-ui/lab/Alert"; import Paper from "@material-ui/core/Paper"; -import Button from "@material-ui/core/Button"; import logo from "assets/img/logo-jams-blue.svg"; @@ -69,27 +68,26 @@ export default function SignUp(props) { const classes = useStyles(); const [error, setError] = React.useState(false); const [errorMessage, setErrorMessage] = React.useState("Test"); - const [step, setStep] = React.useState(props.step); useEffect(() => { //request the server to check for the step to return }); function returnStep() { - if (step === 0) { + if (props.step === 0) { return ( <CreateAdmin setError={setError} setErrorMessage={setErrorMessage} /> ); - } else if (step === 1) { + } else if (props.step === 1) { return <CaSetup setError={setError} setErrorMessage={setErrorMessage} />; - } else if (step === 2) { + } else if (props.step === 2) { return ( <IdentityManagement setError={setError} setErrorMessage={setErrorMessage} /> ); - } else if (step === 3) { + } else if (props.step === 3) { return ( <ServerParameters setError={setError} @@ -103,7 +101,7 @@ export default function SignUp(props) { <Paper className={classes.paper}> <CssBaseline /> <img src={logo} className={classes.logo} alt="Logo Jami" /> - <CustomizedSteppers step={step} /> + <CustomizedSteppers step={props.step} /> {error && errorMessage && ( <Alert severity="error">{errorMessage}</Alert> )} diff --git a/jams-react-client/src/views/Blueprint/Blueprint.js b/jams-react-client/src/views/Blueprint/Blueprint.js index eb47e88d..7ea53ff7 100644 --- a/jams-react-client/src/views/Blueprint/Blueprint.js +++ b/jams-react-client/src/views/Blueprint/Blueprint.js @@ -1,7 +1,4 @@ import React from "react"; -// @material-ui/core components -import { makeStyles } from "@material-ui/core/styles"; - import PropTypes from 'prop-types'; import AppBar from '@material-ui/core/AppBar'; @@ -71,10 +68,7 @@ const styles = { } }; -const useStyles = makeStyles(styles); - export default function Blueprint(props) { - const classes = useStyles(); const [value, setValue] = React.useState(0); diff --git a/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.js b/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.js index a64d2ac6..5b08391a 100644 --- a/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.js +++ b/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.js @@ -1,6 +1,4 @@ import React from "react"; -import { useHistory } from "react-router-dom"; - import clsx from "clsx"; // @material-ui/core components @@ -171,7 +169,6 @@ const StyledRadio = (props) => { export default function EditBlueprintConfiguration(props) { const classes = useStyles(); - const history = useHistory(); const [videoEnabled, setVideoEnabled] = React.useState(true); const [publicInCalls, setPublicInCalls] = React.useState(true); @@ -250,7 +247,7 @@ export default function EditBlueprintConfiguration(props) { error ); }); - }, []); + }, [props.blueprintName, props.username]); const handleUpdateConfiguration = (field, value, selectedOptions = []) => { let data = { @@ -287,17 +284,17 @@ export default function EditBlueprintConfiguration(props) { delete data.dhtProxyListUrl; } - if (selectedOption == "customTurn") { + if (selectedOption === "customTurn") { data.turnEnabled = true; } - if (selectedOption == "customDHTProxy") { + if (selectedOption === "customDHTProxy") { data.proxyEnabled = true; } - if (selectedOption == "disabledTurn") { + if (selectedOption === "disabledTurn") { data.turnEnabled = false; } - if (selectedOption == "disabledDHTProxy") { + if (selectedOption === "disabledDHTProxy") { data.proxyEnabled = false; } }); @@ -441,7 +438,7 @@ export default function EditBlueprintConfiguration(props) { row style={{ display: - selectedTurnOption == "customTurn" + selectedTurnOption === "customTurn" ? "block" : "none", }} @@ -473,7 +470,7 @@ export default function EditBlueprintConfiguration(props) { row style={{ display: - selectedTurnOption == "customTurn" + selectedTurnOption === "customTurn" ? "block" : "none", }} @@ -505,7 +502,7 @@ export default function EditBlueprintConfiguration(props) { row style={{ display: - selectedTurnOption == "customTurn" + selectedTurnOption === "customTurn" ? "block" : "none", }} @@ -582,7 +579,7 @@ export default function EditBlueprintConfiguration(props) { size="large" style={{ display: - selectedDHTProxyOption == "customDHTProxy" + selectedDHTProxyOption === "customDHTProxy" ? "block" : "none", }} @@ -615,7 +612,7 @@ export default function EditBlueprintConfiguration(props) { size="large" style={{ display: - selectedDHTProxyOption == "customDHTProxy" + selectedDHTProxyOption === "customDHTProxy" ? "block" : "none", }} diff --git a/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.js b/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.js index cb08a58b..8e25bee7 100644 --- a/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.js +++ b/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.js @@ -1,5 +1,4 @@ import React from "react"; -import { useHistory } from "react-router-dom"; // @material-ui/core components import { makeStyles } from "@material-ui/core/styles"; import Checkbox from "@material-ui/core/Checkbox"; @@ -93,7 +92,6 @@ function Alert(props) { export default function EditBlueprintPermissions(props) { const classes = useStyles(); - const history = useHistory(); const [videoEnabled, setVideoEnabled] = React.useState(true); const [publicInCalls, setPublicInCalls] = React.useState(true); @@ -148,7 +146,7 @@ export default function EditBlueprintPermissions(props) { error ); }); - }, []); + }, [props.blueprintName]); const handleUpdatePermissions = (field, value) => { let data = { @@ -177,14 +175,14 @@ export default function EditBlueprintPermissions(props) { data[field] = value; } - if (turnEnabled == undefined) { + if (turnEnabled === undefined) { delete data.turnEnabled; delete data.turnServer; delete data.turnServerUserName; delete data.turnServerPassword; } - if (proxyEnabled == undefined) { + if (proxyEnabled === undefined) { delete data.proxyEnabled; delete data.proxyServer; delete data.dhtProxyListUrl; diff --git a/jams-react-client/src/views/Blueprints/Blueprints.js b/jams-react-client/src/views/Blueprints/Blueprints.js index 9cb58bcc..b7333a9f 100644 --- a/jams-react-client/src/views/Blueprints/Blueprints.js +++ b/jams-react-client/src/views/Blueprints/Blueprints.js @@ -29,7 +29,6 @@ import auth from "auth.js"; import { api_path_blueprints } from "globalUrls"; import AddCircleOutlineIcon from "@material-ui/icons/AddCircleOutline"; -import KeyboardReturnIcon from "@material-ui/icons/KeyboardReturn"; import LinearProgress from "@material-ui/core/LinearProgress"; @@ -290,7 +289,7 @@ export default function Blueprints() { {disableCreate && blueprintName.length > 0 && ( <p>{i18next.t("blueprint_name_already_exists", "Blueprint name already exists!")}</p> )} - {disableCreate && blueprintName.length == 0 && ( + {disableCreate && blueprintName.length === 0 && ( <p>{i18next.t("blueprint_name_is_empty", "Blueprint name is empty")}</p> )} </DialogContentText> @@ -376,7 +375,13 @@ export default function Blueprints() { </div> ) : ( blueprints.map((blueprint) => ( - <GridItem xs={12} sm={12} md={2} key={blueprint.name}> + <GridItem + xs={12} + sm={6} + md={3} + lg={2} + xl={2} + key={blueprint.name}> <Card profile> <a href="#" diff --git a/jams-react-client/src/views/Contacts/Contacts.js b/jams-react-client/src/views/Contacts/Contacts.js index 7506403f..cbce942d 100644 --- a/jams-react-client/src/views/Contacts/Contacts.js +++ b/jams-react-client/src/views/Contacts/Contacts.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useEffect } from "react"; import { useHistory } from "react-router-dom"; // @material-ui/core components import { makeStyles } from "@material-ui/core/styles"; @@ -26,6 +26,7 @@ import { api_path_delete_admin_contacts, api_path_get_ns_name_from_addr, api_path_get_user_profile, + api_path_get_user_directory_search } from "globalUrls"; import AddCircleOutlineIcon from "@material-ui/icons/AddCircleOutline"; @@ -79,6 +80,7 @@ export default function Users(props) { const classes = useStyles(); const history = useHistory(); const [contacts, setContacts] = React.useState([]); + const [users, setUsers] = React.useState([]); const [searchValue, setSearchValue] = React.useState(null); const [loading, setLoading] = React.useState(false); const [progress, setProgress] = React.useState(0); @@ -87,7 +89,30 @@ export default function Users(props) { const [removedContactName, setRemovedContactName] = React.useState(); const [open, setOpen] = React.useState(false); + const searchContacts = (value) => { + axios( + configApiCall( + api_path_get_user_directory_search, + "GET", + { queryString: value ? value : "*", page: "1" }, + null + ) + ) + .then((response) => { + setUsers(response.data.profiles); + }) + .catch((error) => { + console.log(error); + setUsers([]); + if (error.response.status === 401) { + auth.authenticated = false; + history.push("/"); + } + }); + } + const getAllContacts = () => { + if (auth.hasAdminScope()) { axios( configApiCall( @@ -176,7 +201,7 @@ export default function Users(props) { }) .catch((error) => { console.log(error); - if (error.response.status == 401) { + if (error.response.status === 401) { auth.authenticated = false; history.push("/"); } @@ -184,6 +209,47 @@ export default function Users(props) { } }; + const addContactToUser = (value) => { + + const data = { + owner: props.username, + uri: value.id, + displayName: `${value.firstName} ${value.lastName}`, + timestamp: "", + status: "", + banned: false, + confirmed: false, + }; + if (auth.hasAdmin()) { + axios( + configApiCall( + api_path_get_admin_contacts + "?username=" + props.username, + "PUT", + data, + null + ) + ) + .then((response) => { + getAllContacts(); + setOpenDrawer(false); + }) + .catch((error) => { + console.log("Error adding user: " + error); + setOpenDrawer(false); + }); + } else { + axios(configApiCall(api_path_get_auth_contacts, "PUT", data, null)) + .then((response) => { + getAllContacts(); + setOpenDrawer(false); + }) + .catch((error) => { + console.log("Error adding user: " + error); + setOpenDrawer(false); + }); + } + }; + useEffect(() => { setLoading(true); const timer = setInterval(() => { @@ -195,6 +261,7 @@ export default function Users(props) { return Math.min(oldProgress + diff, 100); }); }, 500); + searchContacts(); getAllContacts(); return () => { clearInterval(timer); @@ -251,14 +318,16 @@ export default function Users(props) { return ( <div> - <TemporaryDrawer - isAdmin={auth.hasAdminScope()} - username={props.username} - openDrawer={openDrawer} - setOpenDrawer={setOpenDrawer} - direction="right" - addingToGroup={false} + <TemporaryDrawer + openDrawer={openDrawer} + setOpenDrawer={setOpenDrawer} + direction="right" placeholder={i18next.t("add_contact", "Add contact…")} + searchTargets={searchContacts} + targets={users} + addElementToTarget={addContactToUser} + targetName={props.username} + type="user" /> <Dialog open={open} @@ -348,10 +417,10 @@ export default function Users(props) { /> </CardAvatar> <h4 className={classes.cardTitle}> - {contact.firstName != "" + {contact.firstName !== "" ? contact.firstName : "No first name"}{" "} - {contact.lastName != "" ? contact.lastName : "No last name"} + {contact.lastName !== "" ? contact.lastName : "No last name"} </h4> <ul> <li> @@ -385,7 +454,7 @@ export default function Users(props) { </Card> </GridItem> ))} - {contacts == [] && props.username + i18next.t("has_no_contacts", " has no contacts")} + {contacts === [] && props.username + i18next.t("has_no_contacts", " has no contacts")} </GridContainer> </div> ); diff --git a/jams-react-client/src/views/Groups/EditGroup.js b/jams-react-client/src/views/Groups/EditGroup.js index 163bdf0b..22a1d5d2 100644 --- a/jams-react-client/src/views/Groups/EditGroup.js +++ b/jams-react-client/src/views/Groups/EditGroup.js @@ -1,5 +1,5 @@ import React from "react"; -import { useHistory } from 'react-router-dom'; +import { useHistory } from "react-router-dom"; import classnames from "classnames"; // @material-ui/core components @@ -26,8 +26,6 @@ import TableCell from "@material-ui/core/TableCell"; import Select from "@material-ui/core/Select"; -import { hexToRgb, blackColor } from "assets/jss/material-dashboard-react.js"; - import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; import EditIcon from '@material-ui/icons/Edit'; import PeopleOutlineIcon from '@material-ui/icons/PeopleOutline'; @@ -40,19 +38,23 @@ import configApiCall from "../../api" import { api_path_get_list_group, api_path_put_update_group, - api_path_blueprints, - api_path_get_auth_contacts + api_path_get_user_directory_search, + api_path_get_user_profile } from "../../globalUrls" import dashboardStyle from "assets/jss/material-dashboard-react/views/dashboardStyle.js"; import devicesStyle from "assets/jss/material-dashboard-react/components/devicesStyle.js"; +import Avatar from "@material-ui/core/Avatar"; + +import noProfilePicture from "assets/img/faces/no-profile-picture.png"; import TemporaryDrawer from "components/Drawer/Drawer" import * as tool from "../../tools"; -import auth from 'auth.js' import i18next from "i18next"; +import auth from "auth.js"; + const useStyles = makeStyles((theme) => ({ ...devicesStyle, ...dashboardStyle, @@ -98,37 +100,74 @@ const useStyles = makeStyles((theme) => ({ export default function EditGroup(props) { const classes = useStyles(); + const history = useHistory(); const [name, setName] = React.useState(props.groupName); const [newName, setNewName] = React.useState(props.groupName); const [blueprint, setBlueprint] = React.useState(null); const [groupMembers, setGroupMembers] = React.useState([]); const [openDrawer, setOpenDrawer] = React.useState(false); + const [users, setUsers] = React.useState([]); + + const getUserInfo = username => new Promise((resolve, reject) => { + axios( + configApiCall( + api_path_get_user_profile + username, + "GET", + null, + null + ) + ) + .then((response) => { + resolve(response.data); + }) + .catch((error) => { + reject(error); + }); + }) + + const getUsersInformation = userNames => { + userNames.forEach((username)=> { + getUserInfo(username).then((userInfo) => setGroupMembers(groupMembers.push(userInfo))) + }) + } const getGroup = () => { axios(configApiCall(api_path_get_list_group+"?groupName="+props.groupName, 'GET', null, null)).then((response) => { let groups=response.data; if(groups.length > 1){ groups.map((group) => { - if(group.name == props.groupName){ + if(group.name === props.groupName){ props.getBlueprintsOptions().forEach((blueprintOption) => { if(blueprintOption.label === group["blueprint"]){ console.log("Group option value : " + blueprintOption.value); setBlueprint(blueprintOption.value); } }) - setGroupMembers(group["groupMembers"]); + + getUserInfo(group["groupMembers"]).then((userInfo) => { + let newGroupMembers = groupMembers; + newGroupMembers.push(userInfo); + setGroupMembers(newGroupMembers); +  }) } }) } else{ - if(groups.name == props.groupName){ + if(groups.name === props.groupName){ props.getBlueprintsOptions().forEach((blueprintOption) => { if(blueprintOption.label === groups["blueprint"]){ setBlueprint(blueprintOption.value) } }) - setGroupMembers(groups.groupMembers) + groups["groupMembers"].forEach((username)=> { + getUserInfo(username).then((userInfo) => { + let newGroupMembers = groupMembers; + newGroupMembers.push(userInfo); + setGroupMembers(newGroupMembers); +  }) + }) + } } @@ -155,6 +194,7 @@ export default function EditGroup(props) { React.useEffect(()=>{ getGroup(); + searchUsers(); }, []) const handleUpdateGroup = (blueprintValue) => { @@ -168,23 +208,47 @@ export default function EditGroup(props) { axios(configApiCall(url, 'PUT', null, null)).then((response) => { setNewName(name); - getGroup(); + setBlueprint(blueprintValue); }).catch((error) => { console.log("Error updating group: " + error) }) } - const removeUserFromGroup = (user) => { + const searchUsers = (value) => { + axios( + configApiCall( + api_path_get_user_directory_search, + "GET", + { queryString: value ? value : "*", page: "1" }, + null + ) + ) + .then((response) => { + setUsers(response.data.profiles); + }) + .catch((error) => { + console.log(error); + setUsers([]); + if (error.response.status === 401) { + auth.authenticated = false; + history.push("/"); + } + }); + }; + const updateUserInGroup = (user) => { let url = ''; if(blueprint == null){ - url = api_path_put_update_group+"?groupName="+props.groupName+"&newName="+props.groupName+"&blueprintName=&groupMembers="+[user,]; + url = api_path_put_update_group+"?groupName="+props.groupName+"&newName="+props.groupName+"&blueprintName=&groupMembers="+[user.username,]; }else{ - url = api_path_put_update_group+"?groupName="+props.groupName+"&newName="+props.groupName+"&blueprintName="+props.getBlueprintsOptions()[blueprint].label+"&groupMembers="+[user,]; + url = api_path_put_update_group+"?groupName="+props.groupName+"&newName="+props.groupName+"&blueprintName="+props.getBlueprintsOptions()[blueprint].label+"&groupMembers="+[user.username,]; } axios(configApiCall(url, 'PUT', null, null)).then((response) => { - getGroup() + let newGroupMembers = groupMembers; + if(newGroupMembers.includes(user)) newGroupMembers.splice(newGroupMembers.indexOf(user), 1); + else newGroupMembers.push(user); + setGroupMembers(newGroupMembers); }).catch((error) => { console.log("Error updating group: " + error) }) @@ -199,7 +263,17 @@ export default function EditGroup(props) { return( <div> - <TemporaryDrawer openDrawer={openDrawer} setOpenDrawer={setOpenDrawer} direction="right" addingToGroup={true} placeholder="Add user ..." groupName={name === ''?props.groupName:name} blueprintLabel={ blueprint == null ? null : props.getBlueprintsOptions()[blueprint].label} getGroup={getGroup}/> + <TemporaryDrawer + openDrawer={openDrawer} + setOpenDrawer={setOpenDrawer} + direction="right" + placeholder={i18next.t("add_user_to_group", "Add user to group ...")} + searchTargets={searchUsers} + targets={users} + addElementToTarget={updateUserInGroup} + targetName={name} + type="user" + /> <GridContainer> <GridItem xs={12} sm={12} md={6}> <Card profile> @@ -263,21 +337,41 @@ export default function EditGroup(props) { <Table className={classes.table}> <TableHead> <TableRow> - <TableCell>{i18next.t("username", "Username")}</TableCell> + <TableCell align="left"></TableCell> + <TableCell align="left">{i18next.t("username", "Username")}</TableCell> + <TableCell align="left">{i18next.t("first_name", "First name")}</TableCell> + <TableCell align="left">{i18next.t("last_name", "Last name")}</TableCell> <TableCell align="right">{i18next.t("action", "Action")}</TableCell> </TableRow> </TableHead> <TableBody> - {groupMembers.map(user => - <TableRow key={user} className={classes.tableRow}> + {groupMembers.map(user => + <TableRow key={user.username} className={classes.tableRow}> + <TableCell className={tableCellClasses}> + <Avatar + style={{ marginRight: "10px" }} + alt={user.username} + src={ + user.profilePicture + ? "data:image/png;base64, " + user.profilePicture + : noProfilePicture + } + /> + </TableCell> + <TableCell className={tableCellClasses}> + {user.username} + </TableCell> + <TableCell className={tableCellClasses}> + {user.firstName} + </TableCell> <TableCell className={tableCellClasses}> - {user} + {user.lastName} </TableCell> <TableCell align="right" className={classes.tableActions}> - <Button color="primary" onClick={() => removeUserFromGroup(user)}>{i18next.t("remove_user", "Remove user")}</Button> + <Button color="primary" onClick={() => updateUserInGroup(user)}>{i18next.t("remove_user", "Remove user")}</Button> </TableCell> </TableRow> - ) } + )} </TableBody> </Table> </GridItem> diff --git a/jams-react-client/src/views/Groups/Groups.js b/jams-react-client/src/views/Groups/Groups.js index 9679db81..be38fe72 100644 --- a/jams-react-client/src/views/Groups/Groups.js +++ b/jams-react-client/src/views/Groups/Groups.js @@ -15,7 +15,6 @@ import CustomInput from "components/CustomInput/CustomInput.js"; import IconButton from "@material-ui/core/IconButton"; import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline"; -import EditOutlinedIcon from "@material-ui/icons/EditOutlined"; import Search from "@material-ui/icons/Search"; import PeopleOutlineIcon from "@material-ui/icons/PeopleOutline"; import MailOutlineIcon from "@material-ui/icons/MailOutline"; @@ -36,7 +35,6 @@ import { } from "globalUrls"; import AddCircleOutlineIcon from "@material-ui/icons/AddCircleOutline"; -import KeyboardReturnIcon from "@material-ui/icons/KeyboardReturn"; import EditGroup from "views/Groups/EditGroup"; import FormControl from "@material-ui/core/FormControl"; @@ -137,22 +135,18 @@ export default function Groups() { history.push("/admin/groups"); }; - const loadBlueprints = () => { - axios(configApiCall(api_path_blueprints + "?name=*", "GET", null, null)) - .then((response) => { - setBlueprints(response.data); - setSelectedBlueprint(getBlueprintsOptions()[0]); - }) - .catch((error) => { - console.log(error); - if (error.response.status === 401) { - auth.authenticated = false; - history.push("/"); - } - if (error.response.status === 500) { - setBlueprints([]); - } + const getBlueprintsOptions = () => { + let blueprintsOptions = []; + let index = 0; + if (blueprints.length === 0) + blueprintsOptions.push({ value: index, label: "No blueprint found" }); + else { + blueprints.map((blueprint) => { + blueprintsOptions.push({ value: index, label: blueprint.name }); + index += 1; }); + } + return blueprintsOptions; }; useEffect(() => { @@ -177,6 +171,21 @@ export default function Groups() { setZeroGroup(false); } setGroups(allGroups); + axios(configApiCall(api_path_blueprints + "?name=*", "GET", null, null)) + .then((response) => { + setBlueprints(response.data); + setSelectedBlueprint(getBlueprintsOptions()[0]); + }) + .catch((error) => { + console.log(error); + if (error.response.status === 401) { + auth.authenticated = false; + history.push("/"); + } + if (error.response.status === 500) { + setBlueprints([]); + } + }); setLoading(false); }) .catch((error) => { @@ -186,11 +195,10 @@ export default function Groups() { history.push("/"); } }); - loadBlueprints(); return () => { clearInterval(timer); }; - }, [openCreate, openRemoveDialog]); + }, [openCreate, openRemoveDialog, history]); const [selectedGroup, setSelectedGroup] = useState(false); @@ -262,20 +270,6 @@ export default function Groups() { history.push("/admin/groups"); }; - const getBlueprintsOptions = () => { - let blueprintsOptions = []; - let index = 0; - if (blueprints.length === 0) - blueprintsOptions.push({ value: index, label: "No blueprint found" }); - else { - blueprints.map((blueprint) => { - blueprintsOptions.push({ value: index, label: blueprint.name }); - index += 1; - }); - } - return blueprintsOptions; - }; - const blueprintsOptionsItems = tool.buildSelectMenuItems( getBlueprintsOptions() ); @@ -349,7 +343,7 @@ export default function Groups() { {disableCreate && groupName.length > 0 && ( <p>{i18next.t("group_name_already_exists", "Group name already exists!")}</p> )} - {disableCreate && groupName.length == 0 && ( + {disableCreate && groupName.length === 0 && ( <p>{i18next.t("group_name_is_empty", "Group name is empty")}</p> )} </Grid> @@ -453,7 +447,13 @@ export default function Groups() { } }) .map((group) => ( - <GridItem xs={12} sm={12} md={2} key={group.name}> + <GridItem + xs={12} + sm={6} + md={3} + lg={2} + xl={2} + key={group.name}> <Card profile> <a href="#" diff --git a/jams-react-client/src/views/Settings/General.js b/jams-react-client/src/views/Settings/General.js index 43ae3166..0f715201 100644 --- a/jams-react-client/src/views/Settings/General.js +++ b/jams-react-client/src/views/Settings/General.js @@ -1,10 +1,8 @@ import React from "react"; -import { useHistory } from "react-router-dom"; import { Formik } from "formik"; import FormikField from "components/FormikField/FormikField"; import * as Yup from "yup"; import Button from "@material-ui/core/Button"; -import TextField from "@material-ui/core/TextField"; import Grid from "@material-ui/core/Grid"; import Typography from "@material-ui/core/Typography"; import { makeStyles } from "@material-ui/core/styles"; @@ -20,7 +18,6 @@ import InputAdornment from "@material-ui/core/InputAdornment"; import GridContainer from "components/Grid/GridContainer.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 axios from "axios"; @@ -58,7 +55,6 @@ const useStyles = makeStyles((theme) => ({ export default function General(props) { const classes = useStyles(); - const history = useHistory(); const [copied, setCopied] = React.useState(false); const [generated, setGenerated] = React.useState(false); diff --git a/jams-react-client/src/views/Settings/Settings.js b/jams-react-client/src/views/Settings/Settings.js index 0736d9e4..e8dde972 100644 --- a/jams-react-client/src/views/Settings/Settings.js +++ b/jams-react-client/src/views/Settings/Settings.js @@ -1,6 +1,4 @@ import React from "react"; -// @material-ui/core components -import { makeStyles } from "@material-ui/core/styles"; // core components import General from "./General"; import Subscription from "./Subscription"; @@ -75,10 +73,7 @@ const styles = { }, }; -const useStyles = makeStyles(styles); - export default function Settings(props) { - const classes = useStyles(); const [value, setValue] = React.useState(0); const [error, setError] = React.useState(false); diff --git a/jams-react-client/src/views/Settings/Subscription.js b/jams-react-client/src/views/Settings/Subscription.js index 6509844e..a5ab8a6b 100644 --- a/jams-react-client/src/views/Settings/Subscription.js +++ b/jams-react-client/src/views/Settings/Subscription.js @@ -1,5 +1,4 @@ -import React, {useEffect, useState} from "react"; -import { useHistory } from "react-router-dom"; +import React, {useEffect} from "react"; import { useFormik } from 'formik'; import * as Yup from 'yup'; import Button from '@material-ui/core/Button'; @@ -11,15 +10,12 @@ import { makeStyles } from '@material-ui/core/styles'; import GridContainer from "components/Grid/GridContainer.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 axios from 'axios'; import configApiCall from '../../api' import { api_path_post_configuration_register_license } from '../../globalUrls' -import auth from '../../auth' - import i18next from "i18next"; const useStyles = makeStyles((theme) => ({ @@ -44,14 +40,13 @@ const useStyles = makeStyles((theme) => ({ export default function Subscription(props) { const classes = useStyles(); - const history = useHistory(); const [activated, setActivated] = React.useState(false); useEffect(()=>{ axios(configApiCall(api_path_post_configuration_register_license, "GET", null, null)).then((response)=>{ - if(response.data["activated"] == true) setActivated(true); + if(response.data["activated"] === true) setActivated(true); }).catch((error)=>{ - if(error.response.status == 500){ + if(error.response.status === 500){ props.setErrorMessage(i18next.t("an_error_occured_while_getting_license_information", "An error occurred while getting subscription information!")); props.setSeverity("error"); props.setError(true); @@ -86,7 +81,7 @@ export default function Subscription(props) { props.setSeverity("success"); props.setError(true); }).catch((error)=>{ - if(error.response.status == 500){ + if(error.response.status === 500){ props.setErrorMessage(i18next.t("a_generic_occured_while_trying_to_load_license_or_license_could_not_be_found", "A generic occurred while trying to load your subscription or your subscription could not be found!")); props.setSeverity("error"); props.setError(true); diff --git a/jams-react-client/src/views/UserProfile/DisplayUserProfile.js b/jams-react-client/src/views/UserProfile/DisplayUserProfile.js index 95672189..8b416f4c 100644 --- a/jams-react-client/src/views/UserProfile/DisplayUserProfile.js +++ b/jams-react-client/src/views/UserProfile/DisplayUserProfile.js @@ -1,5 +1,7 @@ import React, { useEffect } from "react"; import { useHistory } from "react-router-dom"; +import classnames from "classnames"; + // @material-ui/core components import { makeStyles } from "@material-ui/core/styles"; // core components @@ -17,22 +19,29 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import DialogTitle from "@material-ui/core/DialogTitle"; import EditIcon from "@material-ui/icons/Edit"; import DeleteIcon from "@material-ui/icons/Delete"; -import GroupIcon from "@material-ui/icons/Group"; +import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; + +import Table from "@material-ui/core/Table"; +import TableHead from '@material-ui/core/TableHead'; +import TableRow from "@material-ui/core/TableRow"; +import TableBody from "@material-ui/core/TableBody"; +import TableCell from "@material-ui/core/TableCell"; import Grid from "@material-ui/core/Grid"; +import GridItem from "components/Grid/GridItem.js"; import BusinessCenterOutlinedIcon from "@material-ui/icons/BusinessCenterOutlined"; import AlternateEmailOutlinedIcon from "@material-ui/icons/AlternateEmailOutlined"; import PhoneInTalkOutlinedIcon from "@material-ui/icons/PhoneInTalkOutlined"; 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 Avatar from "@material-ui/core/Avatar"; import Chip from "@material-ui/core/Chip"; -import DoneIcon from "@material-ui/icons/Done"; import CardAvatar from "components/Card/CardAvatar"; +import PersonIcon from "../../../node_modules/@material-ui/icons/Person"; +import VpnKeyIcon from "@material-ui/icons/VpnKey"; import List from "@material-ui/core/List"; import ListItem from "@material-ui/core/ListItem"; @@ -56,12 +65,12 @@ import dashboardStyle from "assets/jss/material-dashboard-react/views/dashboardS import { hexToRgb, blackColor } from "assets/jss/material-dashboard-react.js"; import axios from "axios"; -import PersonIcon from "../../../node_modules/@material-ui/icons/Person"; -import VpnKeyIcon from "@material-ui/icons/VpnKey"; import PasswordDialog from "components/PasswordDialog/PasswordDialog"; +import TemporaryDrawer from "components/Drawer/Drawer" + import i18next from "i18next"; const styles = (theme) => ({ @@ -161,6 +170,7 @@ export default function DisplayUserProfile(props) { const classes = useStyles(); const history = useHistory(); const [user, setUser] = React.useState([]); + const [groupMemberships, setGroupMemberships] = React.useState([]); const [revoked, setRevoked] = React.useState(false); const [open, setOpen] = React.useState(false); const [revokedUser, setRevokedUser] = React.useState(""); @@ -168,7 +178,78 @@ export default function DisplayUserProfile(props) { const [loading, setLoading] = React.useState(false); const [progress, setProgress] = React.useState(0); const [groups, setGroups] = React.useState([]); - const [zeroGroup, setZeroGroup] = React.useState(false); + const [openDrawer, setOpenDrawer] = React.useState(false); + + const searchGroups = (value) => { + if(value === "") value = "*"; + axios( + configApiCall( + api_path_get_list_group + "?groupName=" + value, + "GET", + null, + null + ) + ) + .then((response) => { + if(response.data.length > 1) setGroups(response.data); + else setGroups([response.data]) + }) + .catch((error) => { + console.log(error); + if (error.response.status === 401) { + auth.authenticated = false; + history.push("/"); + } + }); + } + + const updateUserInGroup = (group) => { + axios( + configApiCall( + api_path_get_list_group + "?groupName=" + group, + "GET", + null, + null + ) + ).then((response)=>{ + + let url = ""; + let oldGroup = response.data.name; + if (response.blueprint == null) { + url = + api_path_put_update_group + + "?groupName=" + + response.data.name + + "&newName=" + + response.data.name + + "&blueprintName=&groupMembers=" + + [props.username]; + } else { + url = + api_path_put_update_group + + "?groupName=" + + response.data.name + + "&newName=" + + response.data.name + + "&blueprintName=" + + group.data.blueprint + + "&groupMembers=" + + [props.username]; + } + + axios(configApiCall(url, "PUT", null, null)) + .then(() => { + let newGroupMemberships = groupMemberships; + if(newGroupMemberships.includes(oldGroup)) newGroupMemberships.splice(newGroupMemberships.indexOf(oldGroup), 1); + else newGroupMemberships.push(oldGroup); + setGroupMemberships(newGroupMemberships); + }) + .catch((error) => { + console.log("Error updating group: " + error); + }); + }).catch((error)=>{console.log(error)}) + + }; useEffect(() => { setLoading(true); @@ -202,43 +283,10 @@ export default function DisplayUserProfile(props) { ) .then((response) => { setUser(response.data); - const groupMemberships = response.data.groupMemberships; - axios( - configApiCall( - api_path_get_list_group + "?groupName=*", - "GET", - null, - null - ) - ) - .then((response) => { - let allGroups = response.data; - if (allGroups.length === 0) setZeroGroup(true); - else { - setZeroGroup(false); - - allGroups.forEach((group) => { - group.actif = false; - }); - - allGroups.forEach((group) => { - groupMemberships.forEach((userGroup) => { - if (group.name === userGroup) { - group.actif = true; - } - }); - }); - } - setGroups(allGroups); - setLoading(false); - }) - .catch((error) => { - console.log(error); - if (error.response.status === 401) { - auth.authenticated = false; - history.push("/"); - } - }); + if(response.data.groupMemberships == [""]) setGroupMemberships([]) + else setGroupMemberships(response.data.groupMemberships) + searchGroups("*") + setLoading(false); }) .catch((error) => { console.log(error); @@ -271,6 +319,7 @@ export default function DisplayUserProfile(props) { ) .then((response) => { setUser(response.data); + setGroupMemberships(response.data.groupMemberships) setLoading(false); }) .catch((error) => { @@ -342,46 +391,7 @@ export default function DisplayUserProfile(props) { setChangePasswordOpen(false); }; - const updateUserGroup = (group) => { - const newGroups = groups; - newGroups.forEach((g) => { - if (g === group) { - if (group.actif) g.actif = false; - else g.actif = true; - } - }); - let url = ""; - if (group.blueprint == null) { - url = - api_path_put_update_group + - "?groupName=" + - group.name + - "&newName=" + - group.name + - "&blueprintName=&groupMembers=" + - [props.username]; - } else { - url = - api_path_put_update_group + - "?groupName=" + - group.name + - "&newName=" + - group.name + - "&blueprintName=" + - group.blueprint + - "&groupMembers=" + - [props.username]; - } - - axios(configApiCall(url, "PUT", null, null)) - .then(() => { - setGroups(newGroups); - }) - .catch((error) => { - console.log("Error updating group: " + error); - }); - }; - + const tableCellClasses = classnames(classes.tableCell); return ( <div> @@ -419,8 +429,19 @@ export default function DisplayUserProfile(props) { <LinearProgress variant="determinate" value={progress} /> )} </div> + <TemporaryDrawer + openDrawer={openDrawer} + setOpenDrawer={setOpenDrawer} + direction="right" + placeholder={i18next.t("add_user_to_group", "Add user to group ...")} + searchTargets={searchGroups} + targets={groups} + addElementToTarget={updateUserInGroup} + targetName={props.username} + type="group" + /> {!loading && (<GridContainer> - <Grid item xs={12} sm={12} md={8}> + <Grid item xs={12} sm={12} md={6}> <Card profile> <CardBody profile> <div className={classes.root}> @@ -473,31 +494,29 @@ export default function DisplayUserProfile(props) { <ListItemText primary={user.phoneNumber} /> </ListItem> )} - {user.email && ( + {user.organization && ( <ListItem> <ListItemAvatar> <Avatar> - <AlternateEmailOutlinedIcon /> + <BusinessCenterOutlinedIcon /> </Avatar> </ListItemAvatar> - <ListItemText primary={user.email} /> + <ListItemText primary={user.organization} /> </ListItem> )} - {user.organization && ( + </List> + + <List dense={false}> + {user.email && ( <ListItem> <ListItemAvatar> <Avatar> - <BusinessCenterOutlinedIcon /> + <AlternateEmailOutlinedIcon /> </Avatar> </ListItemAvatar> - <ListItemText primary={user.organization} /> + <ListItemText primary={user.email} /> </ListItem> )} - </List> - </Grid> - - <Grid item xs={12} sm={12} md={6}> - <List dense={false}> {user.phoneNumberExtension && ( <ListItem> <ListItemAvatar> @@ -528,29 +547,6 @@ export default function DisplayUserProfile(props) { <ListItemText primary={user.faxNumber} /> </ListItem> )} - {auth.hasAdminScope() && !zeroGroup && ( - <ListItem> - <ListItemAvatar> - <Avatar> - <GroupIcon /> - </Avatar> - </ListItemAvatar> - <div className={classes.groups}> - {groups.map((group) => ( - <Chip - style={{ flex: 1 }} - label={group.name} - variant="default" - clickable - size="medium" - onClick={() => updateUserGroup(group)} - color={group.actif ? "primary" : "default"} - icon={group.actif ? <DoneIcon /> : ""} - /> - ))} - </div> - </ListItem> - )} </List> </Grid> </Grid> @@ -597,6 +593,31 @@ export default function DisplayUserProfile(props) { </CardFooter> </Card> </Grid> + {auth.hasAdminScope() && ( + <GridItem xs={12} sm={12} md={12}> + <Button color="primary" onClick={() => {setOpenDrawer(true)}}><AddCircleOutlineIcon /> {i18next.t("add_user_to_a_group", "Add user to a group")}</Button> + <Table className={classes.table}> + <TableHead> + <TableRow> + <TableCell align="left">{i18next.t("group_name", "Group name")}</TableCell> + <TableCell align="right">{i18next.t("action", "Action")}</TableCell> + </TableRow> + </TableHead> + <TableBody> + {groupMemberships.map(group => + <TableRow key={group} className={classes.tableRow}> + <TableCell className={tableCellClasses}> + {group} + </TableCell> + <TableCell align="right" className={classes.tableActions}> + <Button color="primary" onClick={() => updateUserInGroup(group)}>{i18next.t("remove_from_group", "Remove from group")}</Button> + </TableCell> + </TableRow> + ) } + </TableBody> + </Table> + </GridItem> + )} </GridContainer> )} </div> diff --git a/jams-react-client/src/views/UserProfile/EditCreateUserProfile.js b/jams-react-client/src/views/UserProfile/EditCreateUserProfile.js index 6cf7c40d..3830d690 100644 --- a/jams-react-client/src/views/UserProfile/EditCreateUserProfile.js +++ b/jams-react-client/src/views/UserProfile/EditCreateUserProfile.js @@ -3,7 +3,6 @@ import { useHistory } from "react-router-dom"; // @material-ui/core components import { makeStyles } from "@material-ui/core/styles"; -import InputLabel from "@material-ui/core/InputLabel"; // core components import Grid from "@material-ui/core/Grid"; @@ -13,11 +12,8 @@ import Button from "components/CustomButtons/Button.js"; import Card from "components/Card/Card.js"; import CardAvatar from "components/Card/CardAvatar.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 FormControl from "@material-ui/core/FormControl"; -import Input from "@material-ui/core/Input"; import InputAdornment from "@material-ui/core/InputAdornment"; import Slider from "@material-ui/core/Slider"; import Typography from "@material-ui/core/Typography"; @@ -25,7 +21,6 @@ import Typography from "@material-ui/core/Typography"; import Dialog from "@material-ui/core/Dialog"; import DialogActions from "@material-ui/core/DialogActions"; import DialogContent from "@material-ui/core/DialogContent"; -import DialogContentText from "@material-ui/core/DialogContentText"; import DialogTitle from "@material-ui/core/DialogTitle"; import Cropper from "react-easy-crop"; import getCroppedImg from "./cropImage"; @@ -225,7 +220,6 @@ const useStyles = makeStyles(styles); export default function EditCreateUserProfile(props) { const classes = useStyles(); const history = useHistory(); - const [createUser, setCreateUser] = React.useState(props.createUser); const [copied, setCopied] = React.useState(false); const [generated, setGenerated] = React.useState(true); const [userExists, setUserExists] = React.useState(false); @@ -242,9 +236,20 @@ export default function EditCreateUserProfile(props) { const [open, setOpen] = React.useState(false); const [crop, setCrop] = React.useState({ x: 0, y: 0 }); const [zoom, setZoom] = React.useState(1); - const [aspect, setAspect] = React.useState(1); const [rotation, setRotation] = React.useState(0); const [passwordVisible, setPasswordVisible] = React.useState(false); + + const passwordGenerator = () => { + return generator.generate({ + length: 10, + uppercase: false, + numbers: true, + symbols: true, + }); + }; + + const intialyGeneratedPassword = passwordGenerator(); + const [initialValues, setInitialValues] = React.useState({ username: "", password: intialyGeneratedPassword, @@ -261,20 +266,9 @@ export default function EditCreateUserProfile(props) { jamiId: "", }); - const passwordGenerator = () => { - return generator.generate({ - length: 10, - uppercase: false, - numbers: true, - symbols: true, - }); - }; - - const intialyGeneratedPassword = passwordGenerator(); - React.useEffect(() => { - if (!createUser) { + if (!props.createUser) { setLoading(true); const timer = setInterval(() => { setProgress((oldProgress) => { @@ -310,7 +304,7 @@ export default function EditCreateUserProfile(props) { } setInitialValues(values); setProfilePicture(user.profilePicture); - if (user.profilePicture != "") { + if (user.profilePicture !== "") { setProfilePicturePreview( "data:image/png;base64, " + user.profilePicture ); @@ -327,7 +321,7 @@ export default function EditCreateUserProfile(props) { clearInterval(timer); }; } - }, []); + }, [props.createUser, props.username]); const resizeFile = (file, outputFormat) => new Promise((resolve) => { @@ -386,9 +380,7 @@ export default function EditCreateUserProfile(props) { }) .catch((error) => { console.log( - "Failed to create new user. This is either because the username is already in use" + - " on the public nameserver, or another unknown error has occurred. " + - "Please choose another one." + "Failed to create new user. This is either because the username is already in use on the public nameserver, or another unknown error has occurred. Please choose another one." ); }); }; @@ -429,7 +421,7 @@ export default function EditCreateUserProfile(props) { const handleFormikSubmit = (values) => { values.profilePicture = profilePicture; - if (createUser) { + if (props.createUser) { handleCreateUser(values); } else { handleUpdateUser(values); @@ -476,10 +468,10 @@ export default function EditCreateUserProfile(props) { .max(32, i18next.t("maximum_32_characters", "Maximum 32 characters!")) .required(i18next.t("username_is_required", "Username is required!")) .matches(/^[A-Za-z_][A-Za-z0-9_]*$/, i18next.t("only_alphanumeric_characters", "Only alphanumeric characters!")), - password: createUser + password: props.createUser ? Yup.string().required(i18next.t("only_alphanumeric_characters", "Password is required!")) : null, - confirmPassword: createUser + confirmPassword: props.createUser ? Yup.string().oneOf([Yup.ref("password"), null], i18next.t("password_must_match", "Passwords must match")) : null, firstName: Yup.string().min(2, i18next.t("first_name_is_too_short", "First name is too short!")), @@ -520,7 +512,7 @@ export default function EditCreateUserProfile(props) { crop={crop} rotation={rotation} zoom={zoom} - aspect={aspect} + aspect={1} onCropChange={setCrop} onRotationChange={setRotation} onCropComplete={onCropComplete} @@ -587,9 +579,9 @@ export default function EditCreateUserProfile(props) { <Card profile> <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")} + {props.createUser ? i18next.t("create_new_profile", "Create new profile") : i18next.t("edit_profile", "Edit profile")} </p> - {createUser ? ( + {props.createUser ? ( "" ) : ( <h3 className={classes.cardTitle}>{userName}</h3> @@ -631,7 +623,7 @@ export default function EditCreateUserProfile(props) { {i18next.t("change_profile_image", "Change profile image")} </label> </Grid> - {createUser && ( + {props.createUser && ( <Grid item xs={12} sm={12} md={6}> <FormikField name="username" @@ -661,10 +653,10 @@ export default function EditCreateUserProfile(props) { /> </Grid> )} - {createUser && ( + {props.createUser && ( <Grid item xs={12} sm={12} md={6}></Grid> )} - {createUser && ( + {props.createUser && ( <Grid item xs={12} sm={12} md={6}> <FormikField type={passwordVisible ? "text" : "password"} @@ -697,7 +689,7 @@ export default function EditCreateUserProfile(props) { /> </Grid> )} - {createUser && ( + {props.createUser && ( <Grid item xs={12} sm={12} md={6}> <FormikField type={passwordVisible ? "text" : "password"} @@ -730,10 +722,10 @@ export default function EditCreateUserProfile(props) { /> </Grid> )} - {createUser && ( + {props.createUser && ( <Grid item align="left" xs={12} sm={12} md={6}></Grid> )} - {createUser && ( + {props.createUser && ( <Grid item align="left" xs={12} sm={12} md={6}> <Button variant="contained" @@ -910,12 +902,12 @@ export default function EditCreateUserProfile(props) { </div> </CardBody> <CardFooter className={classes.alignRight}> - {!createUser && ( + {!props.createUser && ( <Button color="info" onClick={handleCancelUpdate}> {i18next.t("cancel", "Cancel")} </Button> )} - {createUser ? ( + {props.createUser ? ( <Button type="submit" disabled={!isValid || !dirty || userExists} diff --git a/jams-react-client/src/views/UserProfile/UserProfile.js b/jams-react-client/src/views/UserProfile/UserProfile.js index 472a6a3a..cf6ee46a 100755 --- a/jams-react-client/src/views/UserProfile/UserProfile.js +++ b/jams-react-client/src/views/UserProfile/UserProfile.js @@ -1,6 +1,4 @@ import React from "react"; -// @material-ui/core components -import { makeStyles } from "@material-ui/core/styles"; // core components import Devices from "components/Devices/Devices.js"; @@ -53,32 +51,9 @@ function a11yProps(index) { }; } -const styles = { - cardCategoryWhite: { - color: "rgba(255,255,255,.62)", - margin: "0", - fontSize: "14px", - marginTop: "0", - marginBottom: "0", - }, - cardTitleWhite: { - color: "#FFFFFF", - marginTop: "0px", - minHeight: "auto", - fontWeight: "300", - fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", - marginBottom: "3px", - textDecoration: "none", - }, -}; - -const useStyles = makeStyles(styles); - export default function UserProfile(props) { - const classes = useStyles(); const [value, setValue] = React.useState(0); - const [username, setUsername] = React.useState(props.username); const [displayUser, setDisplayUser] = React.useState(true); const handleChange = (event, newValue) => { @@ -103,12 +78,12 @@ export default function UserProfile(props) { <TabPanel value={value} index={0}> {displayUser ? ( <DisplayUserProfile - username={username} + username={props.username} setDisplayUser={setDisplayUser} /> ) : ( <EditCreateUserProfile - username={username} + username={props.username} createUser={false} setDisplayUser={setDisplayUser} /> diff --git a/jams-react-client/src/views/Users/Users.js b/jams-react-client/src/views/Users/Users.js index 402b7eb4..715c9867 100644 --- a/jams-react-client/src/views/Users/Users.js +++ b/jams-react-client/src/views/Users/Users.js @@ -1,9 +1,7 @@ import React, { useState, useEffect, useCallback } from "react"; import { useHistory } from "react-router-dom"; -import { Switch, Route, Redirect } from "react-router-dom"; // @material-ui/core components import { makeStyles } from "@material-ui/core/styles"; -import InputLabel from "@material-ui/core/InputLabel"; import Pagination from "@material-ui/lab/Pagination"; // core components import GridItem from "components/Grid/GridItem.js"; @@ -11,25 +9,19 @@ import GridContainer from "components/Grid/GridContainer.js"; import CustomInput from "components/CustomInput/CustomInput.js"; import Button from "components/CustomButtons/Button.js"; import Card from "components/Card/Card.js"; -import CardHeader from "components/Card/CardHeader.js"; + import CardAvatar from "components/Card/CardAvatar.js"; import CardBody from "components/Card/CardBody.js"; -import CardFooter from "components/Card/CardFooter.js"; + import UserProfile from "views/UserProfile/UserProfile.js"; -import Divider from "@material-ui/core/Divider"; -import PersonIcon from "@material-ui/icons/Person"; -import PermIdentityIcon from "@material-ui/icons/PermIdentity"; -import PhoneOutlinedIcon from "@material-ui/icons/PhoneOutlined"; import InfoIcon from "@material-ui/icons/Info"; import BusinessOutlinedIcon from "@material-ui/icons/BusinessOutlined"; import Search from "@material-ui/icons/Search"; -import MailOutlineIcon from "@material-ui/icons/MailOutline"; import axios from "axios"; import configApiCall from "api.js"; import auth from "auth.js"; import { api_path_get_user_directory_search } from "globalUrls"; import AddCircleOutlineIcon from "@material-ui/icons/AddCircleOutline"; -import KeyboardReturnIcon from "@material-ui/icons/KeyboardReturn"; import jami from "assets/img/faces/jami.png"; import noProfilePicture from "assets/img/faces/no-profile-picture.png"; import EditCreateUserProfile from "views/UserProfile/EditCreateUserProfile"; @@ -113,7 +105,7 @@ export default function Users(props) { ) ) .then((response) => { - if (response.status != 204) { + if (response.status !== 204) { setUsers(response.data.profiles); setNumberPages(response.data.numPages); @@ -124,7 +116,7 @@ export default function Users(props) { }) .catch((error) => { console.log(error); - if (error.response.status == 401) { + if (error.response.status === 401) { auth.authenticated = false; history.push("/"); } @@ -144,15 +136,6 @@ export default function Users(props) { setLoading(true); setNoMatchFound(false); setUsers([]); - const timer = setInterval(() => { - setProgress((oldProgress) => { - if (oldProgress === 100) { - return 0; - } - const diff = Math.random() * 10; - return Math.min(oldProgress + diff, 100); - }); - }, 500); axios( configApiCall( api_path_get_user_directory_search, @@ -163,7 +146,7 @@ export default function Users(props) { ) .then((response) => { setLoading(false); - if (response.status != 204) { + if (response.status !== 204) { setUsers(response.data.profiles); setNumberPages(response.data.numPages); } else { @@ -175,7 +158,7 @@ export default function Users(props) { setUsers([]); setNoMatchFound(true); - if (error.response.status == 401) { + if (error.response.status === 401) { auth.authenticated = false; history.push("/"); } @@ -193,13 +176,13 @@ export default function Users(props) { const handleChangePage = (e, page) => { searchUsers(searchValue, page); }; - if (!auth.hasAdminScope() && auth.getUsername() != "") { + if (!auth.hasAdminScope() && auth.getUsername() !== "") { return ( <div> <UserProfile username={auth.getUsername()} /> </div> ); - } else if (selectedProfile && auth.hasAdminScope() && selectedUsername != "") { + } else if (selectedProfile && auth.hasAdminScope() && selectedUsername !== "") { return ( <div> <UserProfile username={selectedUsername} /> -- GitLab