From 2aed51502621465db066be196fce4a26a3fec2d7 Mon Sep 17 00:00:00 2001 From: Navin IR Date: Wed, 28 Mar 2018 15:10:45 +0545 Subject: [PATCH] Seperate Requests --- .scss-lint.yml | 2 + src/redux/initial-state/lang.js | 2 + src/views/UserProfile/UserEdit/index.js | 164 ++++-------------- src/views/UserProfile/UserEdit/styles.scss | 6 +- .../UserGroup/UserGroupAdd/index.js | 87 ++-------- src/views/UserProfile/UserGroup/index.js | 128 ++++---------- src/views/UserProfile/UserProject/index.js | 125 ++++--------- src/views/UserProfile/index.js | 59 ++----- .../requests/ProjectDeleteRequest.js | 60 +++++++ .../UserProfile/requests/UserGetRequest.js | 44 +++++ .../requests/UserGroupDeleteRequest.js | 60 +++++++ .../requests/UserGroupGetRequest.js | 31 ++++ .../requests/UserGroupPostRequest.js | 74 ++++++++ .../requests/UserImageUploadRequest.js | 51 ++++++ .../UserProfile/requests/UserPatchRequest.js | 78 +++++++++ .../requests/UserProjectsGetRequest.js | 38 ++++ src/views/UserProfile/styles.scss | 4 - 17 files changed, 581 insertions(+), 432 deletions(-) create mode 100644 src/views/UserProfile/requests/ProjectDeleteRequest.js create mode 100644 src/views/UserProfile/requests/UserGetRequest.js create mode 100644 src/views/UserProfile/requests/UserGroupDeleteRequest.js create mode 100644 src/views/UserProfile/requests/UserGroupGetRequest.js create mode 100644 src/views/UserProfile/requests/UserGroupPostRequest.js create mode 100644 src/views/UserProfile/requests/UserImageUploadRequest.js create mode 100644 src/views/UserProfile/requests/UserPatchRequest.js create mode 100644 src/views/UserProfile/requests/UserProjectsGetRequest.js diff --git a/.scss-lint.yml b/.scss-lint.yml index bc9ddbe006..c8fd9527dc 100644 --- a/.scss-lint.yml +++ b/.scss-lint.yml @@ -9,3 +9,5 @@ linters: max_depth: 9 NestingDepth: max_depth: 9 + SpaceAfterPropertyColon: + style: one_space_or_newline diff --git a/src/redux/initial-state/lang.js b/src/redux/initial-state/lang.js index d2b9b3ea5e..b3de859793 100644 --- a/src/redux/initial-state/lang.js +++ b/src/redux/initial-state/lang.js @@ -166,6 +166,7 @@ const initialLangState = { 191: 'Delete Lead', 192: 'Add Member', 193: 'Are you sure you want to delete the project {title}?', + 194: 'Are you sure you want to delete the usergroup {title}?', 195: 'Revoke admin rights form', 196: 'Grant admin rights to', 198: 'User Group Not Found', @@ -1288,6 +1289,7 @@ const initialLangState = { deleteMemberLinkTitle: 190, placeholderSearch: 9, addMemberButtonLabel: 192, + confirmTextDeleteUserGroup: 194, confirmTextDeleteProject: 193, confirmTextRevokeAdmin: 195, confirmTextGrantAdmin: 196, diff --git a/src/views/UserProfile/UserEdit/index.js b/src/views/UserProfile/UserEdit/index.js index 7baacb4500..5ee50b37f8 100644 --- a/src/views/UserProfile/UserEdit/index.js +++ b/src/views/UserProfile/UserEdit/index.js @@ -9,8 +9,6 @@ import React from 'react'; import { connect } from 'react-redux'; import { InternalGallery } from '../../../components/DeepGallery'; -import { FgRestBuilder } from '../../../vendor/react-store/utils/rest'; -import { UploadBuilder } from '../../../vendor/react-store/utils/upload'; import Form, { requiredCondition } from '../../../vendor/react-store/components/Input/Form'; import NonFieldErrors from '../../../vendor/react-store/components/Input/NonFieldErrors'; import ImageInput from '../../../vendor/react-store/components/Input/FileInput/ImageInput'; @@ -20,21 +18,15 @@ import DangerButton from '../../../vendor/react-store/components/Action/Button/D import PrimaryButton from '../../../vendor/react-store/components/Action/Button/PrimaryButton'; import LoadingAnimation from '../../../vendor/react-store/components/View/LoadingAnimation'; -import { - transformResponseErrorToFormError, - createParamsForFileUpload, - createParamsForUserPatch, - createUrlForUserPatch, - urlForUpload, -} from '../../../rest'; import { setUserInformationAction, notificationStringsSelector, userStringsSelector, } from '../../../redux'; -import schema from '../../../schema'; import notify from '../../../notify'; +import UserPatchRequest from '../requests/UserPatchRequest'; +import UserImageUploadRequest from '../requests/UserImageUploadRequest'; import styles from './styles.scss'; const propTypes = { @@ -93,73 +85,36 @@ export default class UserEdit extends React.PureComponent { if (this.userPatchRequest) { this.userPatchRequest.stop(); } - if (this.uploader) { - this.uploader.stop(); + if (this.userImageUploader) { + this.userImageUploader.stop(); } } - createRequestForUserPatch = (userId, { firstName, lastName, organization, displayPicture }) => { - const urlForUser = createUrlForUserPatch(userId); - const userPatchRequest = new FgRestBuilder() - .url(urlForUser) - .params( - () => createParamsForUserPatch({ - firstName, lastName, organization, displayPicture, - }), - ) - .preLoad(() => { - this.setState({ pending: true }); - }) - .postLoad(() => { - this.setState({ pending: false }); - }) - .success((response) => { - try { - schema.validate(response, 'userPatchResponse'); - this.props.setUserInformation({ - userId, - information: response, - }); - notify.send({ - title: this.props.notificationStrings('userProfileEdit'), - type: notify.type.SUCCESS, - message: this.props.notificationStrings('userEditSuccess'), - duration: notify.duration.MEDIUM, - }); - this.props.handleModalClose(); - } catch (er) { - console.error(er); - } - }) - .failure((response) => { - notify.send({ - title: this.props.notificationStrings('userProfileEdit'), - type: notify.type.ERROR, - message: this.props.notificationStrings('userEditFailure'), - duration: notify.duration.MEDIUM, - }); - const { - formFieldErrors, - formErrors, - } = transformResponseErrorToFormError(response.errors); - this.setState({ - formFieldErrors, - formErrors, - }); - }) - .fatal(() => { - notify.send({ - title: this.props.notificationStrings('userProfileEdit'), - type: notify.type.ERROR, - message: this.props.notificationStrings('userEditFatal'), - duration: notify.duration.MEDIUM, - }); - this.setState({ - formErrors: { errors: ['Error while trying to save user.'] }, - }); - }) - .build(); - return userPatchRequest; + startRequestForUserPatch = (userId, values) => { + if (this.userPatchRequest) { + this.userPatchRequest.stop(); + } + const userPatchRequest = new UserPatchRequest({ + setUserInformation: this.props.setUserInformation, + notificationStrings: this.props.notificationStrings, + handleModalClose: this.props.handleModalClose, + setState: v => this.setState(v), + }); + this.userPatchRequest = userPatchRequest.create(userId, values); + this.userPatchRequest.start(); + } + + startRequestForUserImageUpload = (file) => { + if (this.userImageUploader) { + this.userImageUploader.stop(); + } + const userImageUploader = new UserImageUploadRequest({ + handleImageUploadSuccess: this.handleImageUploadSuccess, + notificationStrings: this.props.notificationStrings, + setState: v => this.setState(v), + }); + this.userImageUploader = userImageUploader.create(file); + this.userImageUploader.start(); } // FORM RELATED @@ -181,15 +136,8 @@ export default class UserEdit extends React.PureComponent { }; successCallback = (values) => { - // Stop old patch request - if (this.userPatchRequest) { - this.userPatchRequest.stop(); - } - const userId = this.props.userId; - // Create new patch request and start it - this.userPatchRequest = this.createRequestForUserPatch(userId, values); - this.userPatchRequest.start(); + this.startRequestForUserPatch(userId, values); }; // BUTTONS @@ -214,51 +162,15 @@ export default class UserEdit extends React.PureComponent { } const file = files[0]; + this.startRequestForUserImageUpload(file); + } - if (this.uploader) { - this.uploader.stop(); - } - - this.uploader = new UploadBuilder() - .file(file) - .url(urlForUpload) - .params(() => createParamsForFileUpload({ is_public: true })) - .preLoad(() => { - this.setState({ pending: true }); - }) - .postLoad(() => { - this.setState({ pending: false }); - }) - .success((response) => { - this.setState({ - formValues: { ...this.state.formValues, displayPicture: response.id }, - pristine: true, - pending: false, - }); - }) - .failure((response) => { - console.warn('Failure', response); - notify.send({ - title: this.props.notificationStrings('userProfileEdit'), - type: notify.type.ERROR, - message: this.props.notificationStrings('userEditImageUploadFailure'), - duration: notify.duration.SLOW, - }); - }) - .fatal((response) => { - console.warn('Failure', response); - notify.send({ - title: this.props.notificationStrings('userProfileEdit'), - type: notify.type.ERROR, - message: this.props.notificationStrings('userEditImageUploadFailure'), - duration: notify.duration.SLOW, - }); - }) - .progress((progress) => { - console.warn(progress); - }) - .build(); - this.uploader.start(); + handleImageUploadSuccess = (displayPicture) => { + this.setState({ + formValues: { ...this.state.formValues, displayPicture }, + pristine: true, + pending: false, + }); } render() { diff --git a/src/views/UserProfile/UserEdit/styles.scss b/src/views/UserProfile/UserEdit/styles.scss index 904793e691..7e1d821fa6 100644 --- a/src/views/UserProfile/UserEdit/styles.scss +++ b/src/views/UserProfile/UserEdit/styles.scss @@ -12,14 +12,14 @@ } .gallery-image-select { - @extend %button-like-link; - @include background-color($color-primary); margin: auto; width: auto; + // FIXME: use component props for primary styling :global { label { - padding: 0; + @extend %button-like-link; + @include background-color($color-primary); } } } diff --git a/src/views/UserProfile/UserGroup/UserGroupAdd/index.js b/src/views/UserProfile/UserGroup/UserGroupAdd/index.js index 76aadcf21f..bb5ffa9170 100644 --- a/src/views/UserProfile/UserGroup/UserGroupAdd/index.js +++ b/src/views/UserProfile/UserGroup/UserGroupAdd/index.js @@ -6,7 +6,6 @@ import PropTypes from 'prop-types'; import React from 'react'; import { connect } from 'react-redux'; -import { FgRestBuilder } from '../../../../vendor/react-store/utils/rest'; import Form, { requiredCondition } from '../../../../vendor/react-store/components/Input/Form'; import NonFieldErrors from '../../../../vendor/react-store/components/Input/NonFieldErrors'; import TextInput from '../../../../vendor/react-store/components/Input/TextInput'; @@ -14,19 +13,14 @@ import DangerButton from '../../../../vendor/react-store/components/Action/Butto import PrimaryButton from '../../../../vendor/react-store/components/Action/Button/PrimaryButton'; import LoadingAnimation from '../../../../vendor/react-store/components/View/LoadingAnimation'; -import { - transformResponseErrorToFormError, - createParamsForUserGroupsCreate, - urlForUserGroups, -} from '../../../../rest'; import { activeUserSelector, setUserGroupAction, notificationStringsSelector, userStringsSelector, } from '../../../../redux'; -import notify from '../../../../notify'; -import schema from '../../../../schema'; + +import UserGroupPostRequest from '../../requests/UserGroupPostRequest'; import styles from './styles.scss'; @@ -80,63 +74,18 @@ export default class UserGroupAdd extends React.PureComponent { } } - createRequestForUserGroupCreate = ({ title }) => { - const userGroupCreateRequest = new FgRestBuilder() - .url(urlForUserGroups) - .params(() => createParamsForUserGroupsCreate({ title })) - .preLoad(() => { - this.setState({ pending: true }); - }) - .postLoad(() => { - this.setState({ pending: false }); - }) - .success((response) => { - try { - schema.validate(response, 'userGroupCreateResponse'); - this.props.setUserGroup({ - userId: this.props.activeUser.userId, - userGroup: response, - }); - notify.send({ - title: this.props.notificationStrings('userGroupCreate'), - type: notify.type.SUCCESS, - message: this.props.notificationStrings('userGroupCreateSuccess'), - duration: notify.duration.MEDIUM, - }); - this.props.handleModalClose(); - } catch (er) { - console.error(er); - } - }) - .failure((response) => { - notify.send({ - title: this.props.notificationStrings('userGroupCreate'), - type: notify.type.ERROR, - message: this.props.notificationStrings('userGroupCreateFailure'), - duration: notify.duration.MEDIUM, - }); - const { - formFieldErrors, - formErrors, - } = transformResponseErrorToFormError(response.errors); - this.setState({ - formFieldErrors, - formErrors, - }); - }) - .fatal(() => { - notify.send({ - title: this.props.notificationStrings('userGroupCreate'), - type: notify.type.ERROR, - message: this.props.notificationStrings('userGroupCreateFatal'), - duration: notify.duration.MEDIUM, - }); - this.setState({ - formErrors: { errors: ['Error while trying to save user group.'] }, - }); - }) - .build(); - return userGroupCreateRequest; + startRequestForUserGroupCreate = (values, userId) => { + if (this.userGroupCreateRequest) { + this.userGroupCreateRequest.stop(); + } + const userGroupCreateRequest = new UserGroupPostRequest({ + setUserGroup: this.props.setUserGroup, + notificationStrings: this.props.notificationStrings, + handleModalClose: this.props.handleModalClose, + setState: v => this.setState(v), + }); + this.userGroupCreateRequest = userGroupCreateRequest.create(values, userId); + this.userGroupCreateRequest.start(); } // FORM RELATED @@ -158,12 +107,8 @@ export default class UserGroupAdd extends React.PureComponent { }; successCallback = (values) => { - if (this.userGroupCreateRequest) { - this.userGroupCreateRequest.stop(); - } - - this.userGroupCreateRequest = this.createRequestForUserGroupCreate(values); - this.userGroupCreateRequest.start(); + const { userId } = this.props.activeUser; + this.startRequestForUserGroupCreate(values, userId); }; // BUTTONS diff --git a/src/views/UserProfile/UserGroup/index.js b/src/views/UserProfile/UserGroup/index.js index c94daa9f02..30fac537e8 100644 --- a/src/views/UserProfile/UserGroup/index.js +++ b/src/views/UserProfile/UserGroup/index.js @@ -14,7 +14,6 @@ import { compareString, compareDate, } from '../../../vendor/react-store/utils/common'; -import { FgRestBuilder } from '../../../vendor/react-store/utils/rest'; import DangerButton from '../../../vendor/react-store/components/Action/Button/DangerButton'; import PrimaryButton from '../../../vendor/react-store/components/Action/Button/PrimaryButton'; import LoadingAnimation from '../../../vendor/react-store/components/View/LoadingAnimation'; @@ -25,12 +24,6 @@ import ModalBody from '../../../vendor/react-store/components/View/Modal/Body'; import ModalHeader from '../../../vendor/react-store/components/View/Modal/Header'; import Table from '../../../vendor/react-store/components/View/Table'; -import { - createParamsForUserGroups, - createParamsForUserGroupsDelete, - createUrlForUserGroup, - createUrlForUserGroupsOfUser, -} from '../../../rest'; import { userGroupsSelector, setUserGroupsAction, @@ -44,8 +37,9 @@ import { iconNames, pathNames, } from '../../../constants'; -import schema from '../../../schema'; -import notify from '../../../notify'; + +import UserGroupGetRequest from '../requests/UserGroupGetRequest'; +import UserGroupDeleteRequest from '../requests/UserGroupDeleteRequest'; import UserGroupAdd from './UserGroupAdd'; import styles from './styles.scss'; @@ -191,90 +185,50 @@ export default class UserGroup extends React.PureComponent { componentWillMount() { const { userId } = this.props; - this.userGroupsRequest = this.createRequestForUserGroups(userId); - this.userGroupsRequest.start(); + this.startRequestForUserGroups(userId); } componentWillReceiveProps(nextProps) { const { userId } = nextProps; if (this.props.userId !== userId) { - this.userGroupsRequest.stop(); - this.userGroupsRequest = this.createRequestForUserGroups(userId); - this.userGroupsRequest.start(); + this.startRequestForUserGroups(userId); } } componentWillUnmount() { - this.userGroupsRequest.stop(); + if (this.userGroupsRequest) { + this.userGroupsRequest.stop(); + } + if (this.userGroupDeleteRequest) { + this.userGroupDeleteRequest.stop(); + } } - createRequestForUserGroupDelete = (userGroupId) => { - const urlForUserGroup = createUrlForUserGroup(userGroupId); - const userId = this.props.activeUser.userId; - - const userGroupDeletRequest = new FgRestBuilder() - .url(urlForUserGroup) - .params(() => createParamsForUserGroupsDelete()) - .success(() => { - // FIXME: write schema - try { - this.props.unSetUserGroup({ - userGroupId, - userId, - }); - notify.send({ - title: this.props.notificationStrings('userGroupDelete'), - type: notify.type.SUCCESS, - message: this.props.notificationStrings('userGroupDeleteSuccess'), - duration: notify.duration.MEDIUM, - }); - } catch (er) { - console.error(er); - } - }) - .preLoad(() => { - this.setState({ deletePending: true }); - }) - .postLoad(() => { - this.setState({ deletePending: false }); - }) - .failure(() => { - notify.send({ - title: this.props.notificationStrings('userGroupDelete'), - type: notify.type.ERROR, - message: this.props.notificationStrings('userGroupDeleteFailure'), - duration: notify.duration.MEDIUM, - }); - }) - .fatal(() => { - notify.send({ - title: this.props.notificationStrings('userGroupDelete'), - type: notify.type.ERROR, - message: this.props.notificationStrings('userGroupDeleteFatal'), - duration: notify.duration.MEDIUM, - }); - }) - .build(); - return userGroupDeletRequest; + startRequestForUserGroups = (userId) => { + if (this.userGroupsRequest) { + this.userGroupsRequest.stop(); + } + const userGroupsRequest = new UserGroupGetRequest({ + setUserGroups: this.props.setUserGroups, + // setState: v => this.setState(v), + }); + this.userGroupsRequest = userGroupsRequest.create(userId); + this.userGroupsRequest.start(); } - createRequestForUserGroups = (userId) => { - const userGroupsRequest = new FgRestBuilder() - .url(createUrlForUserGroupsOfUser(userId)) - .params(() => createParamsForUserGroups()) - .success((response) => { - try { - schema.validate(response, 'userGroupsGetResponse'); - this.props.setUserGroups({ - userId, - userGroups: response.results, - }); - } catch (er) { - console.error(er); - } - }) - .build(); - return userGroupsRequest; + startRequestForUserGroupDelete = (userGroupId, userId) => { + if (this.userGroupDeleteRequest) { + this.userGroupDeleteRequest.stop(); + } + const userGroupDeleteRequest = new UserGroupDeleteRequest({ + unSetUserGroup: this.props.unSetUserGroup, + notificationStrings: this.props.notificationStrings, + setState: v => this.setState(v), + }); + this.userGroupDeleteRequest = userGroupDeleteRequest.create({ + userGroupId, userId, + }); + this.userGroupDeleteRequest.start(); } // BUTTONS @@ -291,9 +245,7 @@ export default class UserGroup extends React.PureComponent { // Delete Click handleDeleteUserGroupClick = (userGroup) => { - const confirmText = `Are you sure you want to delete the usergroup - ${userGroup.title}?`; - + const confirmText = `${this.props.userStrings('confirmTextDeleteUserGroup')} ${userGroup.title} ?`; this.setState({ deleteUserGroup: true, activeUserGroup: userGroup, @@ -304,13 +256,9 @@ export default class UserGroup extends React.PureComponent { // Delete Close handleDeleteUserGroupClose = (confirm) => { if (confirm) { - if (this.userGroupDeleteRequest) { - this.userGroupDeleteRequest.stop(); - } - this.userGroupDeleteRequest = this.createRequestForUserGroupDelete( - this.state.activeUserGroup.id, - ); - this.userGroupDeleteRequest.start(); + const { id } = this.state.activeUserGroup; + const userId = this.props.activeUser.userId; + this.startRequestForUserGroupDelete(id, userId); } this.setState({ deleteUserGroup: false }); } diff --git a/src/views/UserProfile/UserProject/index.js b/src/views/UserProfile/UserProject/index.js index 28d85dc121..94c074477d 100644 --- a/src/views/UserProfile/UserProject/index.js +++ b/src/views/UserProfile/UserProject/index.js @@ -15,7 +15,6 @@ import { compareLength, compareString, } from '../../../vendor/react-store/utils/common'; -import { FgRestBuilder } from '../../../vendor/react-store/utils/rest'; import DangerButton from '../../../vendor/react-store/components/Action/Button/DangerButton'; import PrimaryButton from '../../../vendor/react-store/components/Action/Button/PrimaryButton'; import LoadingAnimation from '../../../vendor/react-store/components/View/LoadingAnimation'; @@ -26,12 +25,6 @@ import ModalBody from '../../../vendor/react-store/components/View/Modal/Body'; import ModalHeader from '../../../vendor/react-store/components/View/Modal/Header'; import Table from '../../../vendor/react-store/components/View/Table'; -import { - createParamsForProjectDelete, - createParamsForProjects, - createUrlForProject, - createUrlForProjectsOfUser, -} from '../../../rest'; import { userProjectsSelector, setUserProjectsAction, @@ -47,8 +40,9 @@ import { pathNames, } from '../../../constants'; import UserProjectAdd from '../../../components/UserProjectAdd'; -import schema from '../../../schema'; -import notify from '../../../notify'; + +import UserProjectsGetRequest from '../requests/UserProjectsGetRequest'; +import ProjectDeleteRequest from '../requests/ProjectDeleteRequest'; import styles from './styles.scss'; @@ -208,16 +202,13 @@ export default class UserProject extends React.PureComponent { componentWillMount() { const { userId } = this.props; - this.projectsRequest = this.createRequestForProjects(userId); - this.projectsRequest.start(); + this.startRequestForProjects(userId); } componentWillReceiveProps(nextProps) { const { userId } = nextProps; if (this.props.userId !== userId) { - this.projectsRequest.stop(); - this.projectsRequest = this.createRequestForProjects(userId); - this.projectsRequest.start(); + this.startRequestForProjects(userId); } } @@ -225,80 +216,29 @@ export default class UserProject extends React.PureComponent { this.projectsRequest.stop(); } - createRequestForProjectDelete = (projectId) => { - const urlForProject = createUrlForProject(projectId); - const userId = this.props.activeUser.userId; - - const projectDeleteRequest = new FgRestBuilder() - .url(urlForProject) - .params(() => createParamsForProjectDelete()) - .success(() => { - // FIXME: write schema - try { - this.props.unSetProject({ - userId, - projectId, - }); - notify.send({ - title: this.props.notificationStrings('userProjectDelete'), - type: notify.type.SUCCESS, - message: this.props.notificationStrings('userProjectDeleteSuccess'), - duration: notify.duration.MEDIUM, - }); - } catch (er) { - console.error(er); - } - }) - .preLoad(() => { - this.setState({ deletePending: true }); - }) - .postLoad(() => { - this.setState({ deletePending: false }); - }) - .failure(() => { - notify.send({ - title: this.props.notificationStrings('userProjectDelete'), - type: notify.type.ERROR, - message: this.props.notificationStrings('userProjectDeleteFailure'), - duration: notify.duration.MEDIUM, - }); - }) - .fatal(() => { - notify.send({ - title: this.props.notificationStrings('userProjectDelete'), - type: notify.type.ERROR, - message: this.props.notificationStrings('userProjectDeleteFatal'), - duration: notify.duration.SLOW, - }); - }) - .build(); - return projectDeleteRequest; + startRequestForProjects = (userId) => { + if (this.projectsRequest) { + this.projectsRequest.stop(); + } + const projectsRequest = new UserProjectsGetRequest({ + setUserProjects: this.props.setUserProjects, + // setState: v => this.setState(v), + }); + this.projectsRequest = projectsRequest.create(userId); + this.projectsRequest.start(); } - createRequestForProjects = (userId) => { - const projectsRequest = new FgRestBuilder() - .url(createUrlForProjectsOfUser(userId)) - .params(() => createParamsForProjects()) - .success((response) => { - try { - schema.validate(response, 'projectsGetResponse'); - this.props.setUserProjects({ - userId, - projects: response.results, - extra: response.extra, - }); - } catch (er) { - console.error(er); - } - }) - .failure((response) => { - console.info('FAILURE:', response); - }) - .fatal((response) => { - console.info('FATAL:', response); - }) - .build(); - return projectsRequest; + startRequestForProjectDelete = (projectId, userId) => { + if (this.projectDeleteRequest) { + this.projectDeleteRequest.stop(); + } + const projectDeleteRequest = new ProjectDeleteRequest({ + unSetProject: this.props.unSetProject, + notificationStrings: this.props.notificationStrings, + setState: v => this.setState(v), + }); + this.projectDeleteRequest = projectDeleteRequest.create({ projectId, userId }); + this.projectDeleteRequest.start(); } // BUTTONS @@ -315,8 +255,7 @@ export default class UserProject extends React.PureComponent { // Delete Click handleDeleteProjectClick = (project) => { - const confirmText = `Are you sure you want to delete the project - ${project.title}?`; + const confirmText = `${this.props.userStrings('confirmTextDeleteProject')} ${project.title} ?`; this.setState({ deleteProject: true, @@ -328,15 +267,9 @@ export default class UserProject extends React.PureComponent { // Delete Close handleDeleteProjectClose = (confirm) => { if (confirm) { - if (this.projectDeleteRequest) { - this.projectDeleteRequest.stop(); - } - const { selectedProject } = this.state; - this.projectDeleteRequest = this.createRequestForProjectDelete( - selectedProject.id, - ); - this.projectDeleteRequest.start(); + const { userId } = this.props.activeUser; + this.startRequestForProjectDelete(selectedProject.id, userId); } this.setState({ deleteProject: false }); } diff --git a/src/views/UserProfile/index.js b/src/views/UserProfile/index.js index 3033074f49..d82e1063d5 100644 --- a/src/views/UserProfile/index.js +++ b/src/views/UserProfile/index.js @@ -9,7 +9,6 @@ import { connect } from 'react-redux'; import BoundError from '../../vendor/react-store/components/General/BoundError'; import AppError from '../../components/AppError'; -import { FgRestBuilder } from '../../vendor/react-store/utils/rest'; import PrimaryButton from '../../vendor/react-store/components/Action/Button/PrimaryButton'; import Modal from '../../vendor/react-store/components/View/Modal'; import ModalBody from '../../vendor/react-store/components/View/Modal/Body'; @@ -17,10 +16,6 @@ import ModalHeader from '../../vendor/react-store/components/View/Modal/Header'; import LoadingAnimation from '../../vendor/react-store/components/View/LoadingAnimation'; import { InternalGallery } from '../../components/DeepGallery'; -import { - createParamsForUser, - createUrlForUser, -} from '../../rest'; import { userInformationSelector, setUserInformationAction, @@ -30,9 +25,9 @@ import { userStringsSelector, } from '../../redux'; -import schema from '../../schema'; import { iconNames } from '../../constants'; +import UserGetRequest from './requests/UserGetRequest'; import UserProject from './UserProject'; import UserGroup from './UserGroup'; import UserEdit from './UserEdit'; @@ -82,53 +77,33 @@ export default class UserProfile extends React.PureComponent { componentDidMount() { const { userId } = this.props; - this.userRequest = this.createRequestForUser(userId); - this.userRequest.start(); + this.startRequestForUser(userId); } componentWillReceiveProps(nextProps) { const { userId } = nextProps; if (this.props.userId !== userId) { - this.userRequest.stop(); - this.userRequest = this.createRequestForUser(userId); - this.userRequest.start(); + this.startRequestForUser(userId); } } componentWillUnmount() { - this.userRequest.stop(); + if (this.userRequest) { + this.userRequest.stop(); + } } - createRequestForUser = (userId) => { - const urlForUser = createUrlForUser(userId); - const userRequest = new FgRestBuilder() - .url(urlForUser) - .params(() => createParamsForUser()) - .preLoad(() => { this.setState({ pending: true }); }) - .postLoad(() => { this.setState({ pending: false }); }) - .success((response) => { - try { - schema.validate(response, 'userGetResponse'); - this.props.setUserInformation({ - userId, - information: response, - }); - } catch (er) { - console.error(er); - } - }) - .failure((response) => { - if (response.errorCode === 404) { - this.props.unsetUser({ userId }); - } else { - console.info('FAILURE:', response); - } - }) - .fatal((response) => { - console.info('FATAL:', response); - }) - .build(); - return userRequest; + startRequestForUser = (userId) => { + if (this.userRequest) { + this.userRequest.stop(); + } + const userRequest = new UserGetRequest({ + unsetUser: this.props.unsetUser, + setUserInformation: this.props.setUserInformation, + setState: v => this.setState(v), + }); + this.userRequest = userRequest.create(userId); + this.userRequest.start(); } // BUTTONS diff --git a/src/views/UserProfile/requests/ProjectDeleteRequest.js b/src/views/UserProfile/requests/ProjectDeleteRequest.js new file mode 100644 index 0000000000..92e06d64d5 --- /dev/null +++ b/src/views/UserProfile/requests/ProjectDeleteRequest.js @@ -0,0 +1,60 @@ +import { FgRestBuilder } from '../../../vendor/react-store/utils/rest'; +import { + createUrlForProject, + createParamsForProjectDelete, +} from '../../../rest'; +import notify from '../../../notify'; + +export default class ProjectDeleteRequest { + constructor(props) { + this.props = props; + } + + create = ({ projectId, userId }) => { + const urlForProject = createUrlForProject(projectId); + + const projectDeleteRequest = new FgRestBuilder() + .url(urlForProject) + .params(() => createParamsForProjectDelete()) + .success(() => { + try { + this.props.unSetProject({ + userId, + projectId, + }); + notify.send({ + title: this.props.notificationStrings('userProjectDelete'), + type: notify.type.SUCCESS, + message: this.props.notificationStrings('userProjectDeleteSuccess'), + duration: notify.duration.MEDIUM, + }); + } catch (er) { + console.error(er); + } + }) + .preLoad(() => { + this.props.setState({ deletePending: true }); + }) + .postLoad(() => { + this.props.setState({ deletePending: false }); + }) + .failure(() => { + notify.send({ + title: this.props.notificationStrings('userProjectDelete'), + type: notify.type.ERROR, + message: this.props.notificationStrings('userProjectDeleteFailure'), + duration: notify.duration.MEDIUM, + }); + }) + .fatal(() => { + notify.send({ + title: this.props.notificationStrings('userProjectDelete'), + type: notify.type.ERROR, + message: this.props.notificationStrings('userProjectDeleteFatal'), + duration: notify.duration.SLOW, + }); + }) + .build(); + return projectDeleteRequest; + } +} diff --git a/src/views/UserProfile/requests/UserGetRequest.js b/src/views/UserProfile/requests/UserGetRequest.js new file mode 100644 index 0000000000..dddece675c --- /dev/null +++ b/src/views/UserProfile/requests/UserGetRequest.js @@ -0,0 +1,44 @@ +import { FgRestBuilder } from '../../../vendor/react-store/utils/rest'; +import { + createUrlForUser, + commonParamsForGET, +} from '../../../rest'; +import schema from '../../../schema'; + +export default class UserGetResponse { + constructor(props) { + this.props = props; + } + + create = (userId) => { + const urlForUser = createUrlForUser(userId); + const userRequest = new FgRestBuilder() + .url(urlForUser) + .params(() => commonParamsForGET()) + .preLoad(() => { this.props.setState({ pending: true }); }) + .postLoad(() => { this.props.setState({ pending: false }); }) + .success((response) => { + try { + schema.validate(response, 'userGetResponse'); + this.props.setUserInformation({ + userId, + information: response, + }); + } catch (er) { + console.error(er); + } + }) + .failure((response) => { + if (response.errorCode === 404) { + this.props.unsetUser({ userId }); + } else { + console.info('FAILURE:', response); + } + }) + .fatal((response) => { + console.info('FATAL:', response); + }) + .build(); + return userRequest; + } +} diff --git a/src/views/UserProfile/requests/UserGroupDeleteRequest.js b/src/views/UserProfile/requests/UserGroupDeleteRequest.js new file mode 100644 index 0000000000..cad1189021 --- /dev/null +++ b/src/views/UserProfile/requests/UserGroupDeleteRequest.js @@ -0,0 +1,60 @@ +import { FgRestBuilder } from '../../../vendor/react-store/utils/rest'; +import { + createUrlForUserGroup, + createParamsForUserGroupsDelete, +} from '../../../rest'; +import notify from '../../../notify'; + +export default class UserGroupDeleteRequest { + constructor(props) { + this.props = props; + } + + create = ({ userGroupId, userId }) => { + const urlForUserGroup = createUrlForUserGroup(userGroupId); + + const userGroupDeletRequest = new FgRestBuilder() + .url(urlForUserGroup) + .params(() => createParamsForUserGroupsDelete()) + .success(() => { + try { + this.props.unSetUserGroup({ + userGroupId, + userId, + }); + notify.send({ + title: this.props.notificationStrings('userGroupDelete'), + type: notify.type.SUCCESS, + message: this.props.notificationStrings('userGroupDeleteSuccess'), + duration: notify.duration.MEDIUM, + }); + } catch (er) { + console.error(er); + } + }) + .preLoad(() => { + this.props.setState({ deletePending: true }); + }) + .postLoad(() => { + this.props.setState({ deletePending: false }); + }) + .failure(() => { + notify.send({ + title: this.props.notificationStrings('userGroupDelete'), + type: notify.type.ERROR, + message: this.props.notificationStrings('userGroupDeleteFailure'), + duration: notify.duration.MEDIUM, + }); + }) + .fatal(() => { + notify.send({ + title: this.props.notificationStrings('userGroupDelete'), + type: notify.type.ERROR, + message: this.props.notificationStrings('userGroupDeleteFatal'), + duration: notify.duration.MEDIUM, + }); + }) + .build(); + return userGroupDeletRequest; + } +} diff --git a/src/views/UserProfile/requests/UserGroupGetRequest.js b/src/views/UserProfile/requests/UserGroupGetRequest.js new file mode 100644 index 0000000000..2037b7552f --- /dev/null +++ b/src/views/UserProfile/requests/UserGroupGetRequest.js @@ -0,0 +1,31 @@ +import { FgRestBuilder } from '../../../vendor/react-store/utils/rest'; +import { + createUrlForUserGroupsOfUser, + createParamsForUserGroups, +} from '../../../rest'; +import schema from '../../../schema'; + +export default class UserGroupGetRequest { + constructor(props) { + this.props = props; + } + + create = (userId) => { + const userGroupsRequest = new FgRestBuilder() + .url(createUrlForUserGroupsOfUser(userId)) + .params(() => createParamsForUserGroups()) + .success((response) => { + try { + schema.validate(response, 'userGroupsGetResponse'); + this.props.setUserGroups({ + userId, + userGroups: response.results, + }); + } catch (er) { + console.error(er); + } + }) + .build(); + return userGroupsRequest; + } +} diff --git a/src/views/UserProfile/requests/UserGroupPostRequest.js b/src/views/UserProfile/requests/UserGroupPostRequest.js new file mode 100644 index 0000000000..84641c2ce5 --- /dev/null +++ b/src/views/UserProfile/requests/UserGroupPostRequest.js @@ -0,0 +1,74 @@ +import { FgRestBuilder } from '../../../vendor/react-store/utils/rest'; +import { + urlForUserGroups, + createParamsForUserGroupsCreate, + transformResponseErrorToFormError, +} from '../../../rest'; +import notify from '../../../notify'; +import schema from '../../../schema'; + +export default class UserGroupPostRequest { + constructor(props) { + this.props = props; + } + + create = ({ title }, userId) => { + const userGroupCreateRequest = new FgRestBuilder() + .url(urlForUserGroups) + .params(() => createParamsForUserGroupsCreate({ title })) + .preLoad(() => { + this.props.setState({ pending: true }); + }) + .postLoad(() => { + this.props.setState({ pending: false }); + }) + .success((response) => { + try { + schema.validate(response, 'userGroupCreateResponse'); + this.props.setUserGroup({ + userId, + userGroup: response, + }); + notify.send({ + title: this.props.notificationStrings('userGroupCreate'), + type: notify.type.SUCCESS, + message: this.props.notificationStrings('userGroupCreateSuccess'), + duration: notify.duration.MEDIUM, + }); + this.props.handleModalClose(); + } catch (er) { + console.error(er); + } + }) + .failure((response) => { + notify.send({ + title: this.props.notificationStrings('userGroupCreate'), + type: notify.type.ERROR, + message: this.props.notificationStrings('userGroupCreateFailure'), + duration: notify.duration.MEDIUM, + }); + const { + formFieldErrors, + formErrors, + } = transformResponseErrorToFormError(response.errors); + this.props.setState({ + formFieldErrors, + formErrors, + }); + }) + .fatal(() => { + notify.send({ + title: this.props.notificationStrings('userGroupCreate'), + type: notify.type.ERROR, + message: this.props.notificationStrings('userGroupCreateFatal'), + duration: notify.duration.MEDIUM, + }); + this.props.setState({ + // FIXME: use strings + formErrors: { errors: ['Error while trying to save user group.'] }, + }); + }) + .build(); + return userGroupCreateRequest; + } +} diff --git a/src/views/UserProfile/requests/UserImageUploadRequest.js b/src/views/UserProfile/requests/UserImageUploadRequest.js new file mode 100644 index 0000000000..cd737823c4 --- /dev/null +++ b/src/views/UserProfile/requests/UserImageUploadRequest.js @@ -0,0 +1,51 @@ +import { UploadBuilder } from '../../../vendor/react-store/utils/upload'; +import { + urlForUpload, + createParamsForFileUpload, +} from '../../../rest'; +import notify from '../../../notify'; + +export default class UserImageUploadRequest { + constructor(props) { + this.props = props; + } + + create = (file) => { + const uploader = new UploadBuilder() + .file(file) + .url(urlForUpload) + .params(() => createParamsForFileUpload({ is_public: true })) + .preLoad(() => { + this.props.setState({ pending: true }); + }) + .postLoad(() => { + this.props.setState({ pending: false }); + }) + .success((response) => { + this.props.handleImageUploadSuccess(response.id); + }) + .failure((response) => { + console.warn('Failure', response); + notify.send({ + title: this.props.notificationStrings('userProfileEdit'), + type: notify.type.ERROR, + message: this.props.notificationStrings('userEditImageUploadFailure'), + duration: notify.duration.SLOW, + }); + }) + .fatal((response) => { + console.warn('Failure', response); + notify.send({ + title: this.props.notificationStrings('userProfileEdit'), + type: notify.type.ERROR, + message: this.props.notificationStrings('userEditImageUploadFailure'), + duration: notify.duration.SLOW, + }); + }) + .progress((progress) => { + console.warn(progress); + }) + .build(); + return uploader; + } +} diff --git a/src/views/UserProfile/requests/UserPatchRequest.js b/src/views/UserProfile/requests/UserPatchRequest.js new file mode 100644 index 0000000000..1eadc2cd26 --- /dev/null +++ b/src/views/UserProfile/requests/UserPatchRequest.js @@ -0,0 +1,78 @@ +import { FgRestBuilder } from '../../../vendor/react-store/utils/rest'; +import { + createUrlForUserPatch, + createParamsForUserPatch, + transformResponseErrorToFormError, +} from '../../../rest'; +import notify from '../../../notify'; +import schema from '../../../schema'; + +export default class UserPatchRequest { + constructor(props) { + this.props = props; + } + + create = (userId, { firstName, lastName, organization, displayPicture }) => { + const urlForUser = createUrlForUserPatch(userId); + const userPatchRequest = new FgRestBuilder() + .url(urlForUser) + .params( + () => createParamsForUserPatch({ + firstName, lastName, organization, displayPicture, + }), + ) + .preLoad(() => { + this.props.setState({ pending: true }); + }) + .postLoad(() => { + this.props.setState({ pending: false }); + }) + .success((response) => { + try { + schema.validate(response, 'userPatchResponse'); + this.props.setUserInformation({ + userId, + information: response, + }); + notify.send({ + title: this.props.notificationStrings('userProfileEdit'), + type: notify.type.SUCCESS, + message: this.props.notificationStrings('userEditSuccess'), + duration: notify.duration.MEDIUM, + }); + this.props.handleModalClose(); + } catch (er) { + console.error(er); + } + }) + .failure((response) => { + notify.send({ + title: this.props.notificationStrings('userProfileEdit'), + type: notify.type.ERROR, + message: this.props.notificationStrings('userEditFailure'), + duration: notify.duration.MEDIUM, + }); + const { + formFieldErrors, + formErrors, + } = transformResponseErrorToFormError(response.errors); + this.props.setState({ + formFieldErrors, + formErrors, + }); + }) + .fatal(() => { + notify.send({ + title: this.props.notificationStrings('userProfileEdit'), + type: notify.type.ERROR, + message: this.props.notificationStrings('userEditFatal'), + duration: notify.duration.MEDIUM, + }); + this.props.setState({ + formErrors: { errors: ['Error while trying to save user.'] }, + }); + }) + .build(); + return userPatchRequest; + } +} diff --git a/src/views/UserProfile/requests/UserProjectsGetRequest.js b/src/views/UserProfile/requests/UserProjectsGetRequest.js new file mode 100644 index 0000000000..2004357e26 --- /dev/null +++ b/src/views/UserProfile/requests/UserProjectsGetRequest.js @@ -0,0 +1,38 @@ +import { FgRestBuilder } from '../../../vendor/react-store/utils/rest'; +import { + createUrlForProjectsOfUser, + createParamsForProjects, +} from '../../../rest'; +import schema from '../../../schema'; + +export default class UserProjectsGetRequest { + constructor(props) { + this.props = props; + } + + create = (userId) => { + const projectsRequest = new FgRestBuilder() + .url(createUrlForProjectsOfUser(userId)) + .params(() => createParamsForProjects()) + .success((response) => { + try { + schema.validate(response, 'projectsGetResponse'); + this.props.setUserProjects({ + userId, + projects: response.results, + extra: response.extra, + }); + } catch (er) { + console.error(er); + } + }) + .failure((response) => { + console.info('FAILURE:', response); + }) + .fatal((response) => { + console.info('FATAL:', response); + }) + .build(); + return projectsRequest; + } +} diff --git a/src/views/UserProfile/styles.scss b/src/views/UserProfile/styles.scss index ef2d763938..3ca54d35de 100644 --- a/src/views/UserProfile/styles.scss +++ b/src/views/UserProfile/styles.scss @@ -68,10 +68,6 @@ $info-height: 144px; button { margin-left: $spacing-small; - .ion-edit { - margin: $spacing-small; - } - &:hover { background-color: $color-background-hover; }