From 2cb9cb4950283b0ff96deed881e33fbad6a89b32 Mon Sep 17 00:00:00 2001 From: Oleksandr Semchenkov Date: Tue, 21 Jul 2020 23:16:43 +0300 Subject: [PATCH 1/6] Major fixes for Auth and user editing --- src/components/header/header.component.js | 22 +- src/components/login/login.component.js | 2 +- .../photo-uploader.component.js | 4 +- .../photo-uploader/photo-uploader.css | 6 +- .../user-editor/user-editor.component.js | 384 ++++++++------- .../partials/user-editor/user-editor.css | 36 +- .../partials/user-photo/user-photo.css | 3 +- src/components/profile/profile.component.js | 17 +- .../users/edit-user/edit-user.component.js | 450 +++++++++++++++++- src/components/users/edit-user/edit-user.css | 89 ++++ .../users/new-user/new-user.component.js | 16 +- src/config.js | 53 +-- src/helpers/i18n/en/translation.json | 7 +- src/helpers/map-routing.js | 4 +- src/index.js | 2 +- src/root/root.component.js | 34 +- src/root/root.css | 4 + src/root/root.routes.js | 4 +- src/services/auth.service.js | 32 +- src/services/stitch.service.js | 2 +- src/styles/shared.css | 9 + 21 files changed, 868 insertions(+), 312 deletions(-) create mode 100644 src/components/users/edit-user/edit-user.css diff --git a/src/components/header/header.component.js b/src/components/header/header.component.js index 3efe5249..b4506f72 100644 --- a/src/components/header/header.component.js +++ b/src/components/header/header.component.js @@ -29,6 +29,7 @@ const authService = AuthService.getInstance(); class Header extends Component { state = { activeMenu: "", + currentUser: null }; showActiveMenu = (value) => { @@ -49,11 +50,18 @@ class Header extends Component { window.location.href = "/"; }; + componentDidMount(){ + authService.on("user-object-changed", (user) => { + this.setState({user: {...user}}) + }); + } + render() { - const { activeMenu } = this.state; + const { activeMenu, currentUser } = this.state; const { t } = this.props; - - return ( + const isAuthenticated = authService.isAuthenticated; + const user = currentUser ? currentUser : authService.user; + return isAuthenticated ? (
@@ -200,11 +208,11 @@ class Header extends Component { onClick={() => this.showActiveMenu("profile")} >
- +
- {authService.isAuthenticated - ? `${authService.user.name.first} ${authService.user.name.last}` + {isAuthenticated && user.name + ? `${user.name.first} ${user.name.last}` : t("WARNINGS.NOT_AUTHENTICATED")}
- ); + ): ""; } } diff --git a/src/components/login/login.component.js b/src/components/login/login.component.js index 22257ac6..f3489fc8 100644 --- a/src/components/login/login.component.js +++ b/src/components/login/login.component.js @@ -34,7 +34,7 @@ class Login extends Component { this.setState({ loading: false, }); - history.replace(HOME_PAGE); + history.push(HOME_PAGE); }) .catch((error) => { this.setState({ diff --git a/src/components/partials/photo-uploader/photo-uploader.component.js b/src/components/partials/photo-uploader/photo-uploader.component.js index a69160ad..278bae72 100644 --- a/src/components/partials/photo-uploader/photo-uploader.component.js +++ b/src/components/partials/photo-uploader/photo-uploader.component.js @@ -76,6 +76,7 @@ export default class PhotoUploader extends Component { className="hidden-uploader" onChange={($event) => this.fileSelected($event)} /> + {loading ? :
no logo -
- {loading ? : ""} + } ); } diff --git a/src/components/partials/photo-uploader/photo-uploader.css b/src/components/partials/photo-uploader/photo-uploader.css index f5032a9d..81944fe2 100644 --- a/src/components/partials/photo-uploader/photo-uploader.css +++ b/src/components/partials/photo-uploader/photo-uploader.css @@ -1,5 +1,9 @@ .photo-uploader { - + display: flex; + justify-content: center; + align-items: center; + width: 130px; + height: 130px; } .photo-uploader .hidden-uploader{ diff --git a/src/components/partials/user-editor/user-editor.component.js b/src/components/partials/user-editor/user-editor.component.js index 60e76eeb..99d2d699 100644 --- a/src/components/partials/user-editor/user-editor.component.js +++ b/src/components/partials/user-editor/user-editor.component.js @@ -21,6 +21,7 @@ import AgencyService from "./../../../services/agency.service"; import "./user-editor.css"; + const stitchService = StitchService.getInstance(); const userService = UserService.getInstance(); const agencyService = AgencyService.getInstance(); @@ -57,6 +58,7 @@ class UserEditor extends Component { last: values.lastName, }, active: true, + profilePic: values.profilePic, userGroup: values.userGroup, }; @@ -68,48 +70,61 @@ class UserEditor extends Component { newUser = { ...newUser, global: { admin: true }, - agency: { name: values.agency }, + agency: { name: values.agency, admin: true }, }; } else if (values.adminType === "agency") { - newUser = { ...newUser, agency: { name: values.agency, admin: true } }; + newUser = { ...newUser, agency: { name: values.agency, admin: true }, global: { admin: false } }; } else { - newUser = { ...newUser, agency: { name: values.agency } }; + newUser = { ...newUser, agency: { name: values.agency, admin: false }, global: { admin: false } }; } const saveUserFunc = () => { if (userId) { + newUser.realmUserID = values.realmUserID; + const userId = user._id; userService - .updateUser(user._id, newUser) - .then(() => this.goRedirect()) - .catch((error) => { - error.message - ? this.setState({ error: `${error.name}: ${error.message}` }) - : this.setState({ error: "An unexpected error occurred!" }); - }); + .updateUser(userId, newUser) + .then(() => { + newUser._id = userId; + if (this.props.onSave){ + this.props.onSave(newUser); + } + this.goRedirect() + }) + .catch((error) => { + error.message + ? this.setState({ error: `${error.name}: ${error.message}` }) + : this.setState({ error: "An unexpected error occurred!" }); + }); } else { userService - .createUser(newPassword ? values.password : values.email, newUser) - .then(() => this.goRedirect()) - .catch((error) => { - error.message - ? this.setState({ error: `${error.name}: ${error.message}` }) - : this.setState({ error: "An unexpected error occurred!" }); - }); + .createUser(newPassword ? values.password : values.email, newUser) + .then((user) => { + if (this.props.onSave){ + this.props.onSave(user); + } + this.goRedirect() + }) + .catch((error) => { + error.message + ? this.setState({ error: `${error.name}: ${error.message}` }) + : this.setState({ error: "An unexpected error occurred!" }); + }); } }; if (imgData) { stitchService - .uploadImage(imgData, newUser.agency.name) - .then((result) => { - newUser.profilePic = result.insertedId.toString(); - saveUserFunc(); - }) - .catch((error) => { - error.message - ? this.setState({ error: `${error.name}: ${error.message}` }) - : this.setState({ error: "An unexpected error occurred!" }); - }); + .uploadImage(imgData, newUser.agency.name) + .then((result) => { + newUser.profilePic = result.insertedId.toString(); + saveUserFunc(); + }) + .catch((error) => { + error.message + ? this.setState({ error: `${error.name}: ${error.message}` }) + : this.setState({ error: "An unexpected error occurred!" }); + }); } else { saveUserFunc(); } @@ -128,26 +143,26 @@ class UserEditor extends Component { componentDidMount() { const { userId } = this.props; agencyService - .getAgencies(50, 0, "", null) - .then((data) => { - this.setState({ - agencies: data.agencies.map((agency) => agency.name) || [], - }); + .getAgencies(50, 0, "", null) + .then((data) => { + this.setState({ + agencies: data.agencies.map((agency) => agency.name) || [], + }); + }) + .catch((error) => { + this.setState({ error: error }); + console.error(error); + }); + if (userId) { + userService + .getUserById(userId) + .then((user) => { + this.setState({ isLoaded: true, user: user }); }) .catch((error) => { this.setState({ error: error }); console.error(error); }); - if (userId) { - userService - .getUserById(userId) - .then((user) => { - this.setState({ isLoaded: true, user: user }); - }) - .catch((error) => { - this.setState({ error: error }); - console.error(error); - }); } else { this.setState({ isLoaded: true, user: null }); } @@ -155,58 +170,60 @@ class UserEditor extends Component { render() { const { user, isLoaded, error, agencies } = this.state; - const { t, changePassword, newPassword, saveText, allowRoleEditing } = this.props; + let { t, showingOptions } = this.props; - if (!saveText) saveText = t("BUTTONS.SAVE") + if (!showingOptions) showingOptions = {}; + if (!showingOptions.saveText) showingOptions.saveText = t("BUTTONS.SAVE") const initialValues = user - ? { - profilePic: user.profilePic, - firstName: user.name.first, - lastName: user.name.last, - password: "", - agency: user.agency.name, - adminType: checkUserRole(user), - email: user.email, - userGroup: user.userGroup, - } - : { - firstName: "", - lastName: "", - password: "", - agency: "", - adminType: "", - email: "", - userGroup: "", - }; + ? { + profilePic: user.profilePic, + firstName: user.name.first, + lastName: user.name.last, + password: "", + agency: user.agency.name, + adminType: checkUserRole(user), + email: user.email, + userGroup: user.userGroup, + realmUserID: user.realmUserID + } + : { + firstName: "", + lastName: "", + password: "", + agency: "", + adminType: "", + email: "", + userGroup: "", + }; return ( - -
- {!isLoaded ? ( - - ) : ( - ( -
+ {!isLoaded ? ( + + ) : ( + ( + -
- -
+
+ + +
+ /> + />
setFieldValue("email", e.target.value)} value={values.email} - /> - {changePassword && ( + /> + {showingOptions.changePassword && (
+ />
)} - {newPassword && ( + {showingOptions.newPassword && ( + /> )} - {allowRoleEditing && ( - - - - {t("CREATE_USER_PAGE.ROLE")} - - - - - - {t("TABLE.AGENCY")} - - + setFieldValue("active", e.target.value) + } + value={values.active} + > + + {t("CREATE_USER_PAGE.ACTIVE")} + + + {t("CREATE_USER_PAGE.INACTIVE")} + + + + )} + {showingOptions.role && ( + + + + {t("CREATE_USER_PAGE.ROLE")} + + - - - - {t("CREATE_USER_PAGE.USER_GROUP")} - - + + + + {t("TABLE.AGENCY")} + + - - - )} -
-
- -
+ + + + {t("CREATE_USER_PAGE.USER_GROUP")} + + + + + )} +
+ +
- {t("BUTTONS.CANCEL")} -
+ {t("BUTTONS.CANCEL")}
- - )} - /> - )} -
+
+ + )} + > +
+ )} {error && (
-
+
{error}
close @@ -365,7 +403,7 @@ class UserEditor extends Component {
)} - +
); } } diff --git a/src/components/partials/user-editor/user-editor.css b/src/components/partials/user-editor/user-editor.css index 430e04f0..d943d598 100644 --- a/src/components/partials/user-editor/user-editor.css +++ b/src/components/partials/user-editor/user-editor.css @@ -1,12 +1,12 @@ -.edit-user-form { +.user-editor-form { margin: 20px 0; } -.edit-user-form .new-user-box { +.user-editor-form .new-user-box { padding: 30px; } -.edit-user-form .user-type-select { +.user-editor-form .user-type-select { height: 40px; margin-top: 30px; color: #6f6d6d; @@ -15,54 +15,48 @@ border-bottom: 1px solid #979797; } -.edit-user-form .user-type-menu { +.user-editor-form .user-type-menu { margin-top: 72px; } -.edit-user-form .user-type-option { +.user-editor-form .user-type-option { margin-top: 72px; } -.edit-user-form form { +.user-editor-form form { width: 37%; padding: 40px 0; } -.edit-user-form .add-img { +.user-editor-form .add-img { width: 130px; height: 130px; } -.edit-user-form .blue-btn { +.user-editor-form .blue-btn { padding: 10px 30px; } -.edit-user-form .white-btn { +.user-editor-form .white-btn { padding: 9px; } -.edit-user-form .form-input { +.user-editor-form .form-input { margin-top: 30px; + margin-left: 2%; + margin-right: 2%; } -.user-editor-error-message-box{ - width: 100%; - background: #f6d4d4; - color: #8d1621; - border: 1px solid #8d1621; - border-radius: 5px; - padding: 10px; -} -.edit-user-form .password-line{ +.user-editor-form .password-line{ position: relative; } -.edit-user-form .password-line .form-input{ +.user-editor-form .password-line .form-input{ width: 100%; } -.edit-user-form .password-line button{ +.user-editor-form .password-line button{ position: absolute; right: 0; margin: 0; diff --git a/src/components/partials/user-photo/user-photo.css b/src/components/partials/user-photo/user-photo.css index d7662289..0cdff72a 100644 --- a/src/components/partials/user-photo/user-photo.css +++ b/src/components/partials/user-photo/user-photo.css @@ -1,8 +1,9 @@ .user-photo { padding: 5px; - width: 45px; } .user-photo .profile-pic { border-radius: 30px; + width: 45px; + height: 45px; } diff --git a/src/components/profile/profile.component.js b/src/components/profile/profile.component.js index 4d70a53e..962d9049 100644 --- a/src/components/profile/profile.component.js +++ b/src/components/profile/profile.component.js @@ -14,7 +14,7 @@ export default withTranslation("translation")(function Profile(props){
{ - authService.user ? + authService.user && authService.user.name? authService.user.name.first + " " + authService.user.name.last : "Unauthenticated user" } @@ -22,12 +22,15 @@ export default withTranslation("translation")(function Profile(props){
{t("NAVIGATION.ACCOUNT")}
- history.push("/home")}> - + authService.reloadCurrentUser(user)} + onRedirect={() => history.push("/home")}> +
); }) diff --git a/src/components/users/edit-user/edit-user.component.js b/src/components/users/edit-user/edit-user.component.js index 1de806d2..66a401f8 100644 --- a/src/components/users/edit-user/edit-user.component.js +++ b/src/components/users/edit-user/edit-user.component.js @@ -1,34 +1,432 @@ -import React from "react"; +import React, { Component, Fragment } from "react"; import { withTranslation } from "react-i18next"; import { withRouter } from "react-router"; - +import { Formik, Form } from "formik"; +import { TextField } from "@material-ui/core"; +import Icon from "@material-ui/core/Icon"; +import Select from "@material-ui/core/Select"; +import MenuItem from "@material-ui/core/MenuItem"; +import InputLabel from "@material-ui/core/InputLabel"; +import FormControl from "@material-ui/core/FormControl"; import history from "../../../root/root.history"; +import LoadingPanel from "./../../partials/loading-panel/loading-panel.component"; +import PhotoUploader from "./../../partials/photo-uploader/photo-uploader.component"; +import { checkUserRole } from "./../../../helpers/get-data"; +import StitchService from "./../../../services/stitch.service"; +import AuthService from "./../../../services/auth.service"; +import UserService from "./../../../services/user.service"; +import AgencyService from "./../../../services/agency.service"; -import UserEditor from "../../partials/user-editor/user-editor.component" +import { + USERS_PAGE +} from "../../../root/root.constants.js"; -import AuthService from "./../../../services/auth.service"; +import "./edit-user.css"; +const authService = AuthService.getInstance(); +const stitchService = StitchService.getInstance(); +const userService = UserService.getInstance(); +const agencyService = AgencyService.getInstance(); + + +export default withRouter(withTranslation("translation")( + class EditUser extends Component{ + state = { + activeTab: 1, + user: null, + isLoaded: false, + error: null, + agencies: [], + imgData: null, + imageId: null, + }; + + removeErrMsg = () => { + this.setState({ error: null }); + }; + + imageUploaded = (data) => { + this.setState({ imgData: data }); + }; + + changePassword = (event) => { + userService.resetPasswordRequest(this.state.user, event.target.value); + }; + + saveUser = (values) => { + const { imgData, user } = this.state; + let newUser = { + email: values.email, + name: { + first: values.firstName, + last: values.lastName, + }, + userGroup: values.userGroup, + realmUserID: values.realmUserID, + profilePic: values.profilePic, + active: values.active + }; + + if (values.adminType === "global") { + newUser = { + ...newUser, + global: { admin: true }, + agency: { name: values.agency, admin: true }, + }; + } else if (values.adminType === "agency") { + newUser = { ...newUser, agency: { name: values.agency, admin: true }, global: { admin: false } }; + } else { + newUser = { ...newUser, agency: { name: values.agency, admin: false }, global: { admin: false } }; + } -const authService = AuthService.getInstance(); - -export default withRouter(withTranslation("translation")(function EditUser(props){ - const { t } = props; - const id = props.match.params.id; - const isAdminUser = authService.userRole == "global" || authService.userRole == "agency"; - return ( -
-
-
-
{t("CREATE_USER_PAGE.USER")}
-
{t("PROFILE_PAGE.EDIT_USER")}
+ const saveUserFunc = () => { + userService + .updateUser(user._id, newUser) + .then(() => this.goRedirect()) + .catch((error) => { + error.message + ? this.setState({ error: `${error.name}: ${error.message}` }) + : this.setState({ error: "An unexpected error occurred!" }); + }); + }; + + if (imgData) { + stitchService + .uploadImage(imgData, newUser.agency.name) + .then((result) => { + newUser.profilePic = result.insertedId.toString(); + saveUserFunc(); + }) + .catch((error) => { + error.message + ? this.setState({ error: `${error.name}: ${error.message}` }) + : this.setState({ error: "An unexpected error occurred!" }); + }); + } else { + saveUserFunc(); + } + }; + + goRedirect() { + history.push(USERS_PAGE); + } + + clearForm = () => { + this.goRedirect(); + }; + + handleChangeTab = (newTab) => { + this.setState({ + activeTab: newTab, + }); + }; + + componentDidMount() { + const userId = this.props.match.params.id; + agencyService + .getAgencies(50, 0, "", null) + .then((data) => { + this.setState({ + agencies: data.agencies.map((agency) => agency.name) || [], + }); + }) + .catch((error) => { + this.setState({ error: error }); + console.error(error); + }); + if (userId) { + userService + .getUserById(userId) + .then((user) => { + this.setState({ isLoaded: true, user: user }); + }) + .catch((error) => { + this.setState({ error: error.message }); + console.error(error); + }); + } else { + this.setState({ isLoaded: true, user: null }); + } + } + + render() { + const { t } = this.props; + const { user, isLoaded, error, activeTab, agencies } = this.state; + const isAdminUser = authService.userRole == "global" || authService.userRole == "agency"; + + const initialValues = user + ? { + profilePic: user.profilePic, + firstName: user.name.first, + lastName: user.name.last, + password: "", + agency: user.agency.name, + adminType: checkUserRole(user), + email: user.email, + userGroup: user.userGroup, + realmUserID: user.realmUserID, + active: true + } + : { + firstName: "", + lastName: "", + password: "", + agency: "", + adminType: "", + email: "", + userGroup: "", + active: true + }; + + return ( +
+
+
+
{t("CREATE_USER_PAGE.USER")}
+
{isLoaded && user ? user.name.first + " " + user.name.last: t("LOADING.LOADING")}
+
+
+ {error && + (
+
+
{error}
+ + close + +
+
) + } +
+ {isLoaded ? ( +
+
this.handleChangeTab(1)} + > + {"Profile information"} +
+ {isAdminUser && +
this.handleChangeTab(2)} + > + {"Settings"} +
+ } +
+
+ {1 === activeTab ? ( + ( +
+
+ + +
+
+ + setFieldValue("firstName", e.target.value) + } + type="text" + value={values.firstName} + /> + + setFieldValue("lastName", e.target.value) + } + type="text" + value={values.lastName} + /> +
+ setFieldValue("email", e.target.value)} + value={values.email} + /> + {isAdminUser && ( +
+ + setFieldValue("password", e.target.value) + } + value={values.password} + /> + +
+ )} +
+ +
+ {t("BUTTONS.CANCEL")} +
+
+ + )} + >
):"" + } + {2 === activeTab && isAdminUser? ( + ( +
+ + + {t("CREATE_USER_PAGE.ACTIVE")} + + + + + + + {t("CREATE_USER_PAGE.ROLE")} + + + + + + {t("TABLE.AGENCY")} + + + + + + {t("CREATE_USER_PAGE.USER_GROUP")} + + + +
+ +
+ {t("BUTTONS.CANCEL")} +
+
+
+
+ )} + > +
+ ):""} +
+
): + (
)}
- history.push("/users")}> - -
- ); -})) + ); + } + })) diff --git a/src/components/users/edit-user/edit-user.css b/src/components/users/edit-user/edit-user.css new file mode 100644 index 00000000..df31dc69 --- /dev/null +++ b/src/components/users/edit-user/edit-user.css @@ -0,0 +1,89 @@ +.edit-user-form{ + padding: 2% 5%; + box-sizing: border-box; +} + +/* Tabs */ +.edit-user-component .tab { + padding: 15px; + cursor: pointer; + font-size: 120%; +} + +.edit-user-component .tab.active { + border-bottom: 2px solid #979797; +} + +.edit-user-component .tab-content { + padding: 0 20px 20px 20px; + margin-top: 15px; +} + +.edit-user-component .tab .tab-content table{ + color: black; +} + +/* Forms */ + +.edit-user-form { + margin: 20px 0; +} + +.edit-user-form .new-user-box { + padding: 30px; +} + +.edit-user-form .user-type-select { + height: 40px; + margin-top: 30px; + color: #6f6d6d; + font-size: 16px; + cursor: pointer; + border-bottom: 1px solid #979797; +} + +.edit-user-form .user-type-menu { + margin-top: 72px; +} + +.edit-user-form .user-type-option { + margin-top: 72px; +} + +.edit-user-form form { + padding: 40px 0; +} + +.edit-user-form .add-img { + width: 130px; + height: 130px; +} + +.edit-user-form .blue-btn { + padding: 10px 30px; +} + +.edit-user-form .white-btn { + padding: 9px; +} + +.edit-user-form .form-input { + margin-top: 30px; + margin-left: 2%; + margin-right: 2%; +} + +.edit-user-form .password-line{ + position: relative; +} + +.edit-user-form .password-line .form-input{ + width: 100%; +} + +.edit-user-form .password-line button{ + position: absolute; + right: 0; + margin: 0; + margin-top: 30px; +} diff --git a/src/components/users/new-user/new-user.component.js b/src/components/users/new-user/new-user.component.js index bb0ca81c..dbfdec7d 100644 --- a/src/components/users/new-user/new-user.component.js +++ b/src/components/users/new-user/new-user.component.js @@ -4,6 +4,10 @@ import history from "../../../root/root.history"; import UserEditor from "../../partials/user-editor/user-editor.component" import AuthService from "./../../../services/auth.service"; +import { + USERS_PAGE +} from "../../../root/root.constants.js"; + const authService = AuthService.getInstance(); class NewUser extends Component { @@ -19,11 +23,13 @@ class NewUser extends Component {
history.push("/users")}> - + showingOptions={{ + saveText: t("BUTTONS.CREATE_USER"), + role: true, + newPassword: authService.userRole == "global" || authService.userRole == "agency" + }} + onRedirect={() => history.push(USERS_PAGE)}> + ); } diff --git a/src/config.js b/src/config.js index b74fbac0..87d8254a 100644 --- a/src/config.js +++ b/src/config.js @@ -1,29 +1,28 @@ -const config = { - appName: 'WildAid O-FISH', - realmServiceName: 'mongodb-atlas', - realmAppId: '', - database: 'wildaid', - chartsConfig: { - baseUrl: "https://charts.mongodb.com/charts-wildaid-xxxxx", - "boardings": { - chartId: "chart-id" - }, - "boarding-compliance":{ - chartId: "chart-id" - }, - "patrol-hours":{ - chartId: "chart-id" - }, - "compliance-rate":{ - chartId: "chart-id" - }, - "boardings-count-chart":{ - chartId: "chart-id" - }, - "citations-and-warnings":{ - chartId: "chart-id" +module.exports = { + appName: 'wildaid', + realmServiceName: "mongodb-atlas", + realmAppId: 'wildaid-o-fish-sskep', + realmBaseUrl: 'https://realm.mongodb.com', + database: 'wildaid', + chartsConfig: { + baseUrl: "https://charts.mongodb.com/charts-tutorial-apps-tqqrp", + "boardings": { + chartId: "75e770e6-360e-4ccd-a4c7-19a2d8b20fe2" + }, + "boarding-compliance":{ + chartId: "21e3b3dd-3043-45a8-8cff-f3c5cb1f1b2a" + }, + "patrol-hours":{ + chartId: "2169a6c5-2011-4295-9418-516a688893bc" + }, + "compliance-rate":{ + chartId: "9e7569d7-d323-4df3-b4dc-a0f20c6a5545" + }, + "boardings-count-chart":{ + chartId: "f7578cc7-d052-4665-8dcb-30715fbaf586" + }, + "citations-and-warnings":{ + chartId: "df742c59-7265-42bd-b64a-fbe7f6d16204" + } } } -}; - -module.exports = config; diff --git a/src/helpers/i18n/en/translation.json b/src/helpers/i18n/en/translation.json index 60548054..cc28c182 100644 --- a/src/helpers/i18n/en/translation.json +++ b/src/helpers/i18n/en/translation.json @@ -37,7 +37,12 @@ "FIRST_NAME": "First Name", "LAST_NAME": "Last Name", "ROLE": "Role", - "USER_GROUP": "User Group" + "USER_GROUP": "User Group", + "ACTIVE": "Active", + "INACTIVE": "Inactive", + "PERMISSIONS": "Permissions", + "PROFILE_INFO": "Profile information", + "SETTINGS": "Settings" }, "BOARDING_PAGE": { "RECORDS_FOUND": "Records Found", diff --git a/src/helpers/map-routing.js b/src/helpers/map-routing.js index 86080bec..b047c422 100644 --- a/src/helpers/map-routing.js +++ b/src/helpers/map-routing.js @@ -13,13 +13,13 @@ const mapRouting = (routes) => { route.render = props => { const auth = authService.isStitchAuthenticated; - + if (route.auth){ if (!auth){ return ; } else { if (!authService.isAuthenticated){ - authService.getUserFromLocalStorage(); + authService.reauthenticateUser(); return } } diff --git a/src/index.js b/src/index.js index 6b730fd9..4f31cf4a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,6 @@ import React from "react"; import ReactDOM from "react-dom"; -import { Router, HashRouter } from "react-router-dom"; +import { HashRouter } from "react-router-dom"; import { renderRoutes } from "react-router-config"; import { I18nextProvider } from "react-i18next"; import i18next from "./helpers/i18n/index"; diff --git a/src/root/root.component.js b/src/root/root.component.js index 749ee92a..af868c9a 100644 --- a/src/root/root.component.js +++ b/src/root/root.component.js @@ -1,31 +1,17 @@ -import React, { Component } from "react"; +import React from "react"; import { renderRoutes } from "react-router-config"; - -import AuthService from "../services/auth.service"; - import Header from "../components/header/header.component"; import "./root.css"; -const authService = AuthService.getInstance(); +export default function Root(props){ + const { route } = props; + const routes = renderRoutes(route.routes); -class Root extends Component { - render() { - const { route } = this.props; - if (!authService.isStitchAuthenticated) { - if (!authService.isAuthenticated) { - authService.getUserFromLocalStorage(); - } - } - - const routes = renderRoutes(route.routes); - return ( -
- {authService.isAuthenticated &&
} -
{routes}
-
- ); - } + return ( +
+
+
{routes}
+
+ ); } - -export default Root; diff --git a/src/root/root.css b/src/root/root.css index 7c560fcd..57736aac 100644 --- a/src/root/root.css +++ b/src/root/root.css @@ -105,6 +105,10 @@ main { width: 100%; } +.form-view{ + width: 37%; +} + .standard-view { width: 78%; } diff --git a/src/root/root.routes.js b/src/root/root.routes.js index d9ec9dfc..d78d7168 100644 --- a/src/root/root.routes.js +++ b/src/root/root.routes.js @@ -68,13 +68,13 @@ const routes = [ { path: HOME_PAGE, component: Home, - auth: false, + auth: true, exact: false, }, { path: PROFILE_PAGE, component: Profile, - auth: false, + auth: true, exact: false, }, { diff --git a/src/services/auth.service.js b/src/services/auth.service.js index d1b0535c..dacc1935 100644 --- a/src/services/auth.service.js +++ b/src/services/auth.service.js @@ -1,8 +1,7 @@ import StitchService from "./stitch.service"; -import EventEmitter from "events"; import storage from '../helpers/localStorageData'; import {checkUserRole} from '../helpers/get-data'; - +import EventEmitter from "events"; const stitchService = StitchService.getInstance(); export default class AuthService extends EventEmitter { @@ -28,20 +27,33 @@ export default class AuthService extends EventEmitter { } get user(){ - return this._user ? this._user.customData : this._user; + return this._user ? this._user : null; } authenticate(login, pass) { - return stitchService.authenticateStitch(login, pass).then(user => { - this._user = user; - delete (user.auth); - storage.setAuthInfo(user); - this.emit("authorized", user); + return stitchService.authenticateStitch(login, pass).then((authData) => { + return stitchService.database.collection("User").findOne({realmUserID: authData.id}).then((user)=>{ + if (user || authData.customData){ + this.reloadCurrentUser(user ? user: authData.customData); + this.emit("authorized", this._user); + return this._user + } else { + throw(new Error("No user in database found for " + authData.id)); + } + }); }); } - getUserFromLocalStorage(user) { + reloadCurrentUser(user) { + this._user = user; + storage.setAuthInfo(this._user); + this.emit("user-object-changed", this._user); + return this._user; + } + + reauthenticateUser(user) { stitchService.reinitializeClient(); - return this._user = storage.getAuthInfo(); + this._user = storage.getAuthInfo(); + return this._user; } } diff --git a/src/services/stitch.service.js b/src/services/stitch.service.js index 3677ba65..1413fcd5 100644 --- a/src/services/stitch.service.js +++ b/src/services/stitch.service.js @@ -70,7 +70,7 @@ export default class StitchService { //After stitch authenticated, you could connect to database reinitializeClient() { - this._database = this._localStitchClient + return this._database = this._localStitchClient .getServiceClient(RemoteMongoClient.factory, config.realmServiceName) .db(config.database); } diff --git a/src/styles/shared.css b/src/styles/shared.css index d1413244..b4fe2abc 100644 --- a/src/styles/shared.css +++ b/src/styles/shared.css @@ -10,6 +10,15 @@ color: red; } +.error-message-box{ + width: 100%; + background: #f6d4d4; + color: #8d1621; + border: 1px solid #8d1621; + border-radius: 5px; + padding: 10px; +} + .success-message{ color: green; } From 5243fc53dfec85a355db93c7395d42afa98fc343 Mon Sep 17 00:00:00 2001 From: Oleksandr Semchenkov Date: Fri, 24 Jul 2020 13:47:45 +0300 Subject: [PATCH 2/6] Issues fixing --- README.md | 13 +- build.txt | 14 ++ .../boarding-view/crew/crew.section.js | 2 +- .../compliance-rate.section.js | 48 +++-- src/components/home/home.component.js | 32 ++- src/components/home/home.css | 5 + .../dates-range/dates-range.component.js | 195 ++++++++++++++++++ .../partials/dates-range/dates-range.css | 80 +++++++ .../user-editor/user-editor.component.js | 6 +- .../users/edit-user/edit-user.component.js | 4 +- src/config.js | 53 ++--- src/helpers/i18n/en/translation.json | 10 + src/root/root.css | 28 ++- src/services/auth.service.js | 22 +- src/services/stitch.service.js | 4 +- 15 files changed, 442 insertions(+), 74 deletions(-) create mode 100644 build.txt create mode 100644 src/components/partials/dates-range/dates-range.component.js create mode 100644 src/components/partials/dates-range/dates-range.css diff --git a/README.md b/README.md index 1f57682b..1fe0a229 100644 --- a/README.md +++ b/README.md @@ -133,14 +133,14 @@ This method checks if the user is already authenticated and redirects the user t ```js const auth = authService.isStitchAuthenticated; - if (route.auth){ if (!auth){ return ; } else { if (!authService.isAuthenticated){ - authService.getUserFromLocalStorage(); - return + return authService.reauthenticateUser().then(()=>{ + return + }); } } } @@ -152,6 +152,7 @@ if (route.routes){ } else { return ; } +}; ``` #### MongoDB Charts @@ -166,12 +167,12 @@ Example chart options: ```js const chartOptions = { - width: "100%", + width: "100%", height: "100%", refreshInterval: 1300, // in seconds. - useAuthenticatedAccess: true, + useAuthenticatedAccess: true, chartId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", - filter: {exampleField: "someValue"} + filter: {exampleField: "someValue"} }; ``` diff --git a/build.txt b/build.txt new file mode 100644 index 00000000..571f94d2 --- /dev/null +++ b/build.txt @@ -0,0 +1,14 @@ +Project Name: +Atlas Cluster Name: +Atlas Cluster Admin username: +Atlas Cluster Admin password: +Path to sample data: +Path to Realm code: +Atlas Cluster connection string: +Realm App name: +Realm App ID: +API Public Key: +API Private Key: +App Admin username: +App Admin password: +Realm User ID: diff --git a/src/components/boardings/boarding-view/crew/crew.section.js b/src/components/boardings/boarding-view/crew/crew.section.js index 8bdc9e45..8a4b14c5 100644 --- a/src/components/boardings/boarding-view/crew/crew.section.js +++ b/src/components/boardings/boarding-view/crew/crew.section.js @@ -31,7 +31,7 @@ class CrewSection extends Component { subText={t("BOARDING_PAGE.VIEW_BOARDING.PHOTOS")} /> diff --git a/src/components/home/compliance-rate-section/compliance-rate.section.js b/src/components/home/compliance-rate-section/compliance-rate.section.js index a2d81991..177c44a5 100644 --- a/src/components/home/compliance-rate-section/compliance-rate.section.js +++ b/src/components/home/compliance-rate-section/compliance-rate.section.js @@ -1,4 +1,4 @@ -import React, { memo } from "react"; +import React, { memo, Component } from "react"; import { withTranslation } from "react-i18next"; import ChartBox from "./../../charts/chart-box.component"; @@ -39,30 +39,34 @@ const chartComplianceRate = { ...stitchService.chartsConfig["compliance-rate"], }; -const ComplianceRateSection = ({ t }) => { - return ( -
-

{t("HOME_PAGE.COMPLIANCE_RATE")}

-
-
-
- -
-
-
- +class ComplianceRateSection extends Component{ + + render(){ + const { t } = this.props; + return ( +
+

{t("HOME_PAGE.COMPLIANCE_RATE")}

+
+
+
+
-
- +
+
+ +
+
+ +
+
+ +
-
- -
-
-
- ); -}; +
+ ); + }; +} export default withTranslation("translation")(memo(ComplianceRateSection)); diff --git a/src/components/home/home.component.js b/src/components/home/home.component.js index 4e0f601a..692a1091 100644 --- a/src/components/home/home.component.js +++ b/src/components/home/home.component.js @@ -5,11 +5,14 @@ import ComplianceRateSection from "./compliance-rate-section/compliance-rate.sec import BoardingsSection from "./boardings-section/boardings.section"; import PatrolHoursSection from "./patrol-hours-section/patrol-hours.section"; import SearchPanel from "./../partials/search-panel/search-panel.component"; +import DatesRange from "./../partials/dates-range/dates-range.component"; import SearchService from "./../../services/search.service"; +import AuthService from "./../../services/auth.service"; import "./home.css"; +const authService = AuthService.getInstance(); const searchService = SearchService.getInstance(); class Home extends Component { @@ -19,6 +22,8 @@ class Home extends Component { crew: [], searchQuery: "", highlighted: [], + isLoaded: true, + datesFilter: null }; search = (value) => { @@ -33,9 +38,20 @@ class Home extends Component { this.setState({ searchQuery: value }); }; + changeFilter = (filter) => { + let filterObject = { $and : [{ + Date: { $gt: filter.start} + }, { + Date: { $lte: filter.end} + }] + }; + this.setState({datesFilter: filter}) + } + render() { - const { vessels, boardings, crew, searchQuery, highlighted } = this.state; + const { vessels, boardings, crew, searchQuery, highlighted, isLoaded, datesFilter } = this.state; const { t } = this.props; + const user = authService.user; return (
@@ -48,10 +64,16 @@ class Home extends Component { searchWords={highlighted} isAutofill={true} /> -

{`${t("HOME_PAGE.OVERVIEW")} April 01, 2020 - April 25, 2020`}

- - - +
+
{t("HOME_PAGE.DASHBOARD")}
+
+
{isLoaded && user ? user.agency.name : t("LOADING.LOADING")}
+ +
+
+ + +
); } diff --git a/src/components/home/home.css b/src/components/home/home.css index 0e09c115..af0d0200 100644 --- a/src/components/home/home.css +++ b/src/components/home/home.css @@ -16,3 +16,8 @@ width: 100%; height: 100vh; } + +.home .page-header{ + margin-top: 1em; + margin-bottom: 2em; +} diff --git a/src/components/partials/dates-range/dates-range.component.js b/src/components/partials/dates-range/dates-range.component.js new file mode 100644 index 00000000..5da597a2 --- /dev/null +++ b/src/components/partials/dates-range/dates-range.component.js @@ -0,0 +1,195 @@ +import React, { Component } from "react"; +import SearchIcon from "@material-ui/icons/Search"; +import moment from "moment"; +import Icon from "@material-ui/core/Icon"; +import Select from "@material-ui/core/Select"; +import MenuItem from "@material-ui/core/MenuItem"; +import InputLabel from "@material-ui/core/InputLabel"; +import { + MuiPickersUtilsProvider, + TimePicker, + KeyboardTimePicker, + KeyboardDateTimePicker, + KeyboardDatePicker, +} from "@material-ui/pickers"; +import DateFnsUtils from "@date-io/moment"; +import { withTranslation } from "react-i18next"; + +import "./dates-range.css"; + +export default withTranslation("translation")(class DatesRange extends Component { + state = { + dateStart: moment().subtract(1, "week").toDate(), + dateEnd: new Date(), + currentRange: "week", + panelShown: false, + filterValue: "", + }; + + dateChanged = (start, end, customRange) => { + this.setState({ + dateStart: start, + dateEnd: end, + currentRange: customRange ? customRange : "custom" + }); + }; + + getFilterValue = () => { + return { start: this.state.dateStart, end: this.state.dateEnd } + } + + applyFilter = () => { + const { searchQuery } = this.state; + this.setState({ + panelShown: false + }); + if (this.props.onFilterChange) { + this.props.onFilterChange(this.getFilterValue()); + } + }; + + cancelFilter = () => { + const { filterValue } = this.state; + this.setState({ + dateStart: moment().subtract(1, "week").toDate(), + dateEnd: new Date(), + panelShown: false + }); + if (this.props.onFilterChange) { + this.props.onFilterChange(this.getFilterValue()); + } + }; + + render() { + const { panelShown, dateStart, dateEnd, currentRange } = this.state; + const { t } = this.props; + + return ( +
+
this.setState({panelShown: !panelShown})}> + { + moment(dateStart).format("LL") + " - " + moment(dateEnd).format("LL") + } + {panelShown ?
:
} +
+ {panelShown && +
+ +
+ + {t("FILTER.DATES_RANGE.RANGE")} + + +
+ +
+
+ this.dateChanged(date, dateEnd)} + onError={console.log} + format="yyyy/MM/DD" + /> + this.dateChanged(date, dateEnd)} + /> +
+ {t("FILTER.TO")} +
+ this.dateChanged(dateStart, date)} + onError={console.log} + format="yyyy/MM/DD" + /> + this.dateChanged(dateStart, date)} + /> +
+
+
+
+ this.dateChanged(date, dateEnd)} + KeyboardButtonProps={{ + "aria-label": "change date", + }} + > + +
+
+ this.dateChanged(dateStart, date)} + KeyboardButtonProps={{ + "aria-label": "change date", + }} + > +
+
+
+
+ + +
+
} +
+ ); + } + }); diff --git a/src/components/partials/dates-range/dates-range.css b/src/components/partials/dates-range/dates-range.css new file mode 100644 index 00000000..a169c4fd --- /dev/null +++ b/src/components/partials/dates-range/dates-range.css @@ -0,0 +1,80 @@ +.dates-range .dates-range-plate{ + border: solid 1px #DADADA; + background: white; + border-radius: 2em; + padding: 1em 1.5em; + font-size: 120%; + cursor: pointer; +} + +.dates-range .dates-range-plate .icon{ + margin-left: 1em; +} + +.dates-range .dates-range-panel{ + position: absolute; + border-radius: 0.5em; + background: white; + border: solid 1px #DADADA; + z-index: 10; + padding: 2em 1.5em 0em 1.5em; + right: 0; + margin-top: 0.5em; + box-shadow: -1px -1px 2px #ccc; +} + +.dates-range .dates-range-panel label{ + margin-bottom: 0.5em; +} + +.dates-range .range-select{ + height: 2.3em; +} + +.dates-range .date-time-row{ + margin-bottom: 1em; + margin-top: 1em; + align-items: center; + justify-content: space-between; +} + +.dates-range .date-picker{ + width: 50%; + margin-bottom: -2px; +} + +.dates-range .time-picker{ + width: 30%; + margin-bottom: -2px; +} + +.dates-range .date-time-row .flex-row{ + width: 45%; + background: #eee; + border-radius: 0.5em 0.5em 0 0; + border-bottom: solid 2px #818181; + padding-top: 0.5em; + align-items: flex-end; + box-sizing: border-box; +} +.dates-range .date-time-row .MuiIconButton-root{ + display: none; +} + +.dates-range .calendar{ + + border: solid 1px #DADADA; + overflow: hidden; +} + +.dates-range .calendar-from{ + border-radius: 0.5em 0 0 0.5em; +} + +.dates-range .calendar-to{ + border-radius: 0 0.5em 0.5em 0; +} + +.dates-range .buttons-row{ + justify-content: flex-end; +} diff --git a/src/components/partials/user-editor/user-editor.component.js b/src/components/partials/user-editor/user-editor.component.js index 99d2d699..09e2ed3f 100644 --- a/src/components/partials/user-editor/user-editor.component.js +++ b/src/components/partials/user-editor/user-editor.component.js @@ -58,7 +58,6 @@ class UserEditor extends Component { last: values.lastName, }, active: true, - profilePic: values.profilePic, userGroup: values.userGroup, }; @@ -81,6 +80,9 @@ class UserEditor extends Component { const saveUserFunc = () => { if (userId) { newUser.realmUserID = values.realmUserID; + if (values.profilePic && !newUser.profilePic){ + newUser.profilePic = values.profilePic; + } const userId = user._id; userService .updateUser(userId, newUser) @@ -396,7 +398,7 @@ class UserEditor extends Component { {error && (
-
{error}
+
{error ? error.message : "unexpected undefined error!"}
close diff --git a/src/components/users/edit-user/edit-user.component.js b/src/components/users/edit-user/edit-user.component.js index 66a401f8..8a852062 100644 --- a/src/components/users/edit-user/edit-user.component.js +++ b/src/components/users/edit-user/edit-user.component.js @@ -62,7 +62,6 @@ export default withRouter(withTranslation("translation")( }, userGroup: values.userGroup, realmUserID: values.realmUserID, - profilePic: values.profilePic, active: values.active }; @@ -79,6 +78,9 @@ export default withRouter(withTranslation("translation")( } const saveUserFunc = () => { + if (values.profilePic && !newUser.profilePic){ + newUser.profilePic = values.profilePic; + } userService .updateUser(user._id, newUser) .then(() => this.goRedirect()) diff --git a/src/config.js b/src/config.js index 87d8254a..b74fbac0 100644 --- a/src/config.js +++ b/src/config.js @@ -1,28 +1,29 @@ -module.exports = { - appName: 'wildaid', - realmServiceName: "mongodb-atlas", - realmAppId: 'wildaid-o-fish-sskep', - realmBaseUrl: 'https://realm.mongodb.com', - database: 'wildaid', - chartsConfig: { - baseUrl: "https://charts.mongodb.com/charts-tutorial-apps-tqqrp", - "boardings": { - chartId: "75e770e6-360e-4ccd-a4c7-19a2d8b20fe2" - }, - "boarding-compliance":{ - chartId: "21e3b3dd-3043-45a8-8cff-f3c5cb1f1b2a" - }, - "patrol-hours":{ - chartId: "2169a6c5-2011-4295-9418-516a688893bc" - }, - "compliance-rate":{ - chartId: "9e7569d7-d323-4df3-b4dc-a0f20c6a5545" - }, - "boardings-count-chart":{ - chartId: "f7578cc7-d052-4665-8dcb-30715fbaf586" - }, - "citations-and-warnings":{ - chartId: "df742c59-7265-42bd-b64a-fbe7f6d16204" - } +const config = { + appName: 'WildAid O-FISH', + realmServiceName: 'mongodb-atlas', + realmAppId: '', + database: 'wildaid', + chartsConfig: { + baseUrl: "https://charts.mongodb.com/charts-wildaid-xxxxx", + "boardings": { + chartId: "chart-id" + }, + "boarding-compliance":{ + chartId: "chart-id" + }, + "patrol-hours":{ + chartId: "chart-id" + }, + "compliance-rate":{ + chartId: "chart-id" + }, + "boardings-count-chart":{ + chartId: "chart-id" + }, + "citations-and-warnings":{ + chartId: "chart-id" } } +}; + +module.exports = config; diff --git a/src/helpers/i18n/en/translation.json b/src/helpers/i18n/en/translation.json index cc28c182..c092026e 100644 --- a/src/helpers/i18n/en/translation.json +++ b/src/helpers/i18n/en/translation.json @@ -22,6 +22,7 @@ "LOG_OUT": "Log out" }, "HOME_PAGE": { + "DASHBOARD": "Dashboard", "OVERVIEW": "Overview for", "COMPLIANCE_RATE": "Compliance Rate", "OFFICER_PATROL_HOURS": "Officer Patrol Hours" @@ -143,6 +144,8 @@ "OFFICERS": "Officers" }, "FILTER": { + "FROM": "From", + "TO": "to", "FILTER": "Filter", "MAIN": { "RISK": { @@ -175,6 +178,13 @@ "NAME": "Risks" } }, + "DATES_RANGE":{ + "RANGE": "Date Range", + "LAST7DAYS": "Last 7 days", + "TODAY": "Today", + "YESTERDAY": "Yesterday", + "CUSTOM": "Custom date range" + }, "HOME_PAGE": { "DATE_TIME": "Date & Time" } diff --git a/src/root/root.css b/src/root/root.css index 57736aac..ebd49eae 100644 --- a/src/root/root.css +++ b/src/root/root.css @@ -151,6 +151,12 @@ main { /* Icons */ .icon { + width: 1em; + height: 1em; + display: inline-block; +} + +img.icon { width: 100%; height: 100%; } @@ -190,11 +196,31 @@ main { border-radius: 25px; border: none; cursor: pointer; - outline-color: rgba(95, 95, 95, 0.6); font-weight: 600; outline-color: transparent; } +.blue-btn:hover{ + box-shadow: 2px 2px 2px #ccc; +} + +.simple-btn { + color: #0a4074; + margin: 18px 20px 20px 0; + padding: 10px 15px; + border-radius: 25px; + border: solid 1px transparent; + cursor: pointer; + font-weight: 600; + background: none; + outline-color: transparent; +} + +.simple-btn:hover{ + background: white; + border: 1px solid #0a4074; +} + .grey-btn { color: white; background-color: #797979; diff --git a/src/services/auth.service.js b/src/services/auth.service.js index dacc1935..bf6d1059 100644 --- a/src/services/auth.service.js +++ b/src/services/auth.service.js @@ -32,15 +32,21 @@ export default class AuthService extends EventEmitter { authenticate(login, pass) { return stitchService.authenticateStitch(login, pass).then((authData) => { - return stitchService.database.collection("User").findOne({realmUserID: authData.id}).then((user)=>{ - if (user || authData.customData){ - this.reloadCurrentUser(user ? user: authData.customData); + if (authData && authData.customData && authData.customData._id){ + this.reloadCurrentUser(authData.customData); this.emit("authorized", this._user); - return this._user - } else { - throw(new Error("No user in database found for " + authData.id)); - } - }); + return this._user; + } else { + return stitchService.database.collection("User").findOne({realmUserID: authData.id}).then((user)=>{ + if (user || authData.customData){ + this.reloadCurrentUser(user ? user: authData.customData); + this.emit("authorized", this._user); + return this._user + } else { + throw(new Error("No user in database found for " + authData.id)); + } + }); + } }); } diff --git a/src/services/stitch.service.js b/src/services/stitch.service.js index 1413fcd5..4aa68937 100644 --- a/src/services/stitch.service.js +++ b/src/services/stitch.service.js @@ -61,10 +61,10 @@ export default class StitchService { authenticateStitch(login, pass) { return this._localStitchClient.auth .loginWithCredential(new UserPasswordCredential(login, pass)) - .then((user) => { + .then((authData) => { //Connecting to database this.reinitializeClient(); - return user; + return authData; }); } From a88ced9fc97ba6586b325f676e598bc5bcfa0c93 Mon Sep 17 00:00:00 2001 From: Oleksandr Semchenkov Date: Tue, 28 Jul 2020 17:59:51 +0300 Subject: [PATCH 3/6] Date & Time filter for charts #83 --- .../boardings-section/boardings.section.js | 5 ++- .../compliance-rate.section.js | 7 ++- src/components/home/home.component.js | 35 ++++++++++----- .../patrol-hours.section.js | 6 ++- .../dates-range/dates-range.component.js | 45 ++++++++++++++++--- src/helpers/i18n/en/translation.json | 3 ++ 6 files changed, 83 insertions(+), 18 deletions(-) diff --git a/src/components/home/boardings-section/boardings.section.js b/src/components/home/boardings-section/boardings.section.js index b25c5cd0..21005c8e 100644 --- a/src/components/home/boardings-section/boardings.section.js +++ b/src/components/home/boardings-section/boardings.section.js @@ -41,8 +41,11 @@ class BoardingsSection extends Component { }; render() { - const { t } = this.props; + const { t, filter} = this.props; + if (filter && this.state.filter == ""){ + chartOptions.filter = filter; + } return (
diff --git a/src/components/home/compliance-rate-section/compliance-rate.section.js b/src/components/home/compliance-rate-section/compliance-rate.section.js index 177c44a5..077a8a47 100644 --- a/src/components/home/compliance-rate-section/compliance-rate.section.js +++ b/src/components/home/compliance-rate-section/compliance-rate.section.js @@ -42,7 +42,12 @@ const chartComplianceRate = { class ComplianceRateSection extends Component{ render(){ - const { t } = this.props; + const { t, filter } = this.props; + if (filter){ + chartBoardingsCompliance.filter = filter; + chartCitationsAndWarnings.filter = filter; + chartBoardingsCount.filter = filter; + } return (

{t("HOME_PAGE.COMPLIANCE_RATE")}

diff --git a/src/components/home/home.component.js b/src/components/home/home.component.js index 692a1091..8db42684 100644 --- a/src/components/home/home.component.js +++ b/src/components/home/home.component.js @@ -1,6 +1,6 @@ -import React, { Component } from "react"; +import React, { Component, Fragment } from "react"; import { withTranslation } from "react-i18next"; - +import moment from "moment"; import ComplianceRateSection from "./compliance-rate-section/compliance-rate.section"; import BoardingsSection from "./boardings-section/boardings.section"; import PatrolHoursSection from "./patrol-hours-section/patrol-hours.section"; @@ -23,7 +23,9 @@ class Home extends Component { searchQuery: "", highlighted: [], isLoaded: true, - datesFilter: null + datesFilter:{ + date: { $gt: moment().subtract(1, "week").toDate() } + } }; search = (value) => { @@ -39,13 +41,24 @@ class Home extends Component { }; changeFilter = (filter) => { - let filterObject = { $and : [{ - Date: { $gt: filter.start} + let filterObject = + { + date: { $gt: new Date(filter.start) } + }/*{ $and : [{ + date: { $gt: filter.start} + }, { + date: { $lte: filter.end} + }] + };*/ + let filterObject2 = { date: { $lte: new Date(filter.end)}}; + let filterObject3 = + { $and : [{ + date: { $gt: new Date(filter.start)} }, { - Date: { $lte: filter.end} + date: { $lte: new Date(filter.end)} }] }; - this.setState({datesFilter: filter}) + this.setState({datesFilter: filterObject3}); } render() { @@ -71,9 +84,11 @@ class Home extends Component {
- - - + {isLoaded && + + + + }
); } diff --git a/src/components/home/patrol-hours-section/patrol-hours.section.js b/src/components/home/patrol-hours-section/patrol-hours.section.js index 70dc6640..a272ae02 100644 --- a/src/components/home/patrol-hours-section/patrol-hours.section.js +++ b/src/components/home/patrol-hours-section/patrol-hours.section.js @@ -41,7 +41,11 @@ class PatrolHoursSection extends Component { }; render() { - const { t } = this.props; + const { t, filter } = this.props; + + if (filter && this.state.filter == ""){ + chartOptions.filter = filter; + } return (
diff --git a/src/components/partials/dates-range/dates-range.component.js b/src/components/partials/dates-range/dates-range.component.js index 5da597a2..62b0cd3a 100644 --- a/src/components/partials/dates-range/dates-range.component.js +++ b/src/components/partials/dates-range/dates-range.component.js @@ -20,13 +20,41 @@ import "./dates-range.css"; export default withTranslation("translation")(class DatesRange extends Component { state = { dateStart: moment().subtract(1, "week").toDate(), - dateEnd: new Date(), + dateEnd: moment().endOf('day').toDate(), currentRange: "week", panelShown: false, filterValue: "", }; dateChanged = (start, end, customRange) => { + if (customRange == "today"){ + start = moment().startOf('day').toDate(); + end = moment().endOf('day').toDate(); + } + if (customRange == "yesterday"){ + start = moment().subtract(1, 'days').startOf('day').toDate(); + end = moment().subtract(1, 'days').endOf('day').toDate(); + } + if (customRange == "week"){ + start = moment().subtract(1, 'week').startOf('day').toDate(); + end = moment().endOf('day').toDate(); + } + if (customRange == "last30"){ + start = moment().subtract(1, 'month').startOf('day').toDate(); + end = moment().endOf('day').toDate(); + } + if (customRange == "last60"){ + start = moment().subtract(2, 'month').startOf('day').toDate(); + end = moment().endOf('day').toDate(); + } + if (customRange == "last90"){ + start = moment().subtract(3, 'month').startOf('day').toDate(); + end = moment().endOf('day').toDate(); + } + if (new Date(end).valueOf() - new Date(start).valueOf() <= 1000){ + end = moment(start).add(1, 'minute').toDate(); + } + console.log(customRange) this.setState({ dateStart: start, dateEnd: end, @@ -35,7 +63,7 @@ export default withTranslation("translation")(class DatesRange extends Component }; getFilterValue = () => { - return { start: this.state.dateStart, end: this.state.dateEnd } + return { start: new Date(this.state.dateStart), end: new Date(this.state.dateEnd)} } applyFilter = () => { @@ -83,9 +111,7 @@ export default withTranslation("translation")(class DatesRange extends Component className="range-select" variant="outlined" labelId="range-label" - onChange={(e) => - this.setSearch("active", e.target.value) - } + onChange={(event) => this.dateChanged(dateStart, dateEnd, event.target.value)} value={currentRange} > @@ -97,6 +123,15 @@ export default withTranslation("translation")(class DatesRange extends Component {t("FILTER.DATES_RANGE.YESTERDAY")} + + {t("FILTER.DATES_RANGE.LAST30DAYS")} + + + {t("FILTER.DATES_RANGE.LAST60DAYS")} + + + {t("FILTER.DATES_RANGE.LAST90DAYS")} + {t("FILTER.DATES_RANGE.CUSTOM")} diff --git a/src/helpers/i18n/en/translation.json b/src/helpers/i18n/en/translation.json index c092026e..824062f8 100644 --- a/src/helpers/i18n/en/translation.json +++ b/src/helpers/i18n/en/translation.json @@ -181,6 +181,9 @@ "DATES_RANGE":{ "RANGE": "Date Range", "LAST7DAYS": "Last 7 days", + "LAST30DAYS": "Last 30 days", + "LAST60DAYS": "Last 60 days", + "LAST90DAYS": "Last 90 days", "TODAY": "Today", "YESTERDAY": "Yesterday", "CUSTOM": "Custom date range" From 00f29e9e35f57f40bbc04829a4e1c22e9593166b Mon Sep 17 00:00:00 2001 From: Oleksandr Semchenkov Date: Tue, 28 Jul 2020 18:11:45 +0300 Subject: [PATCH 4/6] Console.log and temporary fix removed --- src/components/home/home.component.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/components/home/home.component.js b/src/components/home/home.component.js index 8db42684..d77d7f06 100644 --- a/src/components/home/home.component.js +++ b/src/components/home/home.component.js @@ -42,23 +42,13 @@ class Home extends Component { changeFilter = (filter) => { let filterObject = - { - date: { $gt: new Date(filter.start) } - }/*{ $and : [{ - date: { $gt: filter.start} - }, { - date: { $lte: filter.end} - }] - };*/ - let filterObject2 = { date: { $lte: new Date(filter.end)}}; - let filterObject3 = { $and : [{ date: { $gt: new Date(filter.start)} }, { date: { $lte: new Date(filter.end)} }] }; - this.setState({datesFilter: filterObject3}); + this.setState({datesFilter: filterObject}); } render() { From 6cd2eb0cee2c53fc09209d0f3c1942021c4f7da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=D0=AFRoR?= Date: Tue, 28 Jul 2020 18:14:04 +0300 Subject: [PATCH 5/6] Delete build.txt --- build.txt | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 build.txt diff --git a/build.txt b/build.txt deleted file mode 100644 index 571f94d2..00000000 --- a/build.txt +++ /dev/null @@ -1,14 +0,0 @@ -Project Name: -Atlas Cluster Name: -Atlas Cluster Admin username: -Atlas Cluster Admin password: -Path to sample data: -Path to Realm code: -Atlas Cluster connection string: -Realm App name: -Realm App ID: -API Public Key: -API Private Key: -App Admin username: -App Admin password: -Realm User ID: From 0d97d8831de53eeb980409e492c7dfd282f5366b Mon Sep 17 00:00:00 2001 From: Oleksandr Semchenkov Date: Tue, 28 Jul 2020 18:18:21 +0300 Subject: [PATCH 6/6] Warnings fixed --- .../boardings-section/boardings.section.js | 2 +- .../patrol-hours.section.js | 2 +- .../dates-range/dates-range.component.js | 18 ++++++------------ .../users/edit-user/edit-user.component.js | 4 ++-- .../users/new-user/new-user.component.js | 2 +- 5 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/components/home/boardings-section/boardings.section.js b/src/components/home/boardings-section/boardings.section.js index 21005c8e..870390b8 100644 --- a/src/components/home/boardings-section/boardings.section.js +++ b/src/components/home/boardings-section/boardings.section.js @@ -43,7 +43,7 @@ class BoardingsSection extends Component { render() { const { t, filter} = this.props; - if (filter && this.state.filter == ""){ + if (filter && this.state.filter === ""){ chartOptions.filter = filter; } return ( diff --git a/src/components/home/patrol-hours-section/patrol-hours.section.js b/src/components/home/patrol-hours-section/patrol-hours.section.js index a272ae02..ae817255 100644 --- a/src/components/home/patrol-hours-section/patrol-hours.section.js +++ b/src/components/home/patrol-hours-section/patrol-hours.section.js @@ -43,7 +43,7 @@ class PatrolHoursSection extends Component { render() { const { t, filter } = this.props; - if (filter && this.state.filter == ""){ + if (filter && this.state.filter === ""){ chartOptions.filter = filter; } diff --git a/src/components/partials/dates-range/dates-range.component.js b/src/components/partials/dates-range/dates-range.component.js index 62b0cd3a..d970b438 100644 --- a/src/components/partials/dates-range/dates-range.component.js +++ b/src/components/partials/dates-range/dates-range.component.js @@ -1,14 +1,11 @@ import React, { Component } from "react"; -import SearchIcon from "@material-ui/icons/Search"; import moment from "moment"; -import Icon from "@material-ui/core/Icon"; import Select from "@material-ui/core/Select"; import MenuItem from "@material-ui/core/MenuItem"; import InputLabel from "@material-ui/core/InputLabel"; import { MuiPickersUtilsProvider, TimePicker, - KeyboardTimePicker, KeyboardDateTimePicker, KeyboardDatePicker, } from "@material-ui/pickers"; @@ -27,34 +24,33 @@ export default withTranslation("translation")(class DatesRange extends Component }; dateChanged = (start, end, customRange) => { - if (customRange == "today"){ + if (customRange === "today"){ start = moment().startOf('day').toDate(); end = moment().endOf('day').toDate(); } - if (customRange == "yesterday"){ + if (customRange === "yesterday"){ start = moment().subtract(1, 'days').startOf('day').toDate(); end = moment().subtract(1, 'days').endOf('day').toDate(); } - if (customRange == "week"){ + if (customRange === "week"){ start = moment().subtract(1, 'week').startOf('day').toDate(); end = moment().endOf('day').toDate(); } - if (customRange == "last30"){ + if (customRange === "last30"){ start = moment().subtract(1, 'month').startOf('day').toDate(); end = moment().endOf('day').toDate(); } - if (customRange == "last60"){ + if (customRange === "last60"){ start = moment().subtract(2, 'month').startOf('day').toDate(); end = moment().endOf('day').toDate(); } - if (customRange == "last90"){ + if (customRange === "last90"){ start = moment().subtract(3, 'month').startOf('day').toDate(); end = moment().endOf('day').toDate(); } if (new Date(end).valueOf() - new Date(start).valueOf() <= 1000){ end = moment(start).add(1, 'minute').toDate(); } - console.log(customRange) this.setState({ dateStart: start, dateEnd: end, @@ -67,7 +63,6 @@ export default withTranslation("translation")(class DatesRange extends Component } applyFilter = () => { - const { searchQuery } = this.state; this.setState({ panelShown: false }); @@ -77,7 +72,6 @@ export default withTranslation("translation")(class DatesRange extends Component }; cancelFilter = () => { - const { filterValue } = this.state; this.setState({ dateStart: moment().subtract(1, "week").toDate(), dateEnd: new Date(), diff --git a/src/components/users/edit-user/edit-user.component.js b/src/components/users/edit-user/edit-user.component.js index 8a852062..7f28536e 100644 --- a/src/components/users/edit-user/edit-user.component.js +++ b/src/components/users/edit-user/edit-user.component.js @@ -153,7 +153,7 @@ export default withRouter(withTranslation("translation")( render() { const { t } = this.props; const { user, isLoaded, error, activeTab, agencies } = this.state; - const isAdminUser = authService.userRole == "global" || authService.userRole == "agency"; + const isAdminUser = authService.userRole === "global" || authService.userRole === "agency"; const initialValues = user ? { @@ -335,7 +335,7 @@ export default withRouter(withTranslation("translation")(