Merge pull request #835 from ZmagoD/zd_SCI_1706

disables invite user button if no emails present [fixes SCI-1706]
This commit is contained in:
Zmago Devetak 2017-10-18 15:48:48 +02:00 committed by GitHub
commit 6702265b1e
7 changed files with 97 additions and 49 deletions

View file

@ -1,28 +1,34 @@
// @flow
import React from "react";
import { func } from "prop-types";
import { FormattedMessage } from "react-intl";
import { DropdownButton, MenuItem } from "react-bootstrap";
const InviteUsersButton = props => (
type Props = {
handleClick: Function,
status: boolean
};
const InviteUsersButton = ({
handleClick,
status
} : Props) => (
<DropdownButton
bsStyle={"primary"}
title={<FormattedMessage id="invite_users.dropdown_button.invite" />}
id="invite_users.submit_button"
disabled={status}
>
<MenuItem onClick={() => props.handleClick("guest")}>
<MenuItem onClick={() => handleClick("guest")}>
<FormattedMessage id="invite_users.dropdown_button.guest" />
</MenuItem>
<MenuItem onClick={() => props.handleClick("normal_user")}>
<MenuItem onClick={() => handleClick("normal_user")}>
<FormattedMessage id="invite_users.dropdown_button.normal_user" />
</MenuItem>
<MenuItem onClick={() => props.handleClick("admin")}>
<MenuItem onClick={() => handleClick("admin")}>
<FormattedMessage id="invite_users.dropdown_button.admin" />
</MenuItem>
</DropdownButton>
);
InviteUsersButton.propTypes = {
handleClick: func.isRequired
};
export default InviteUsersButton;

View file

@ -1,14 +1,14 @@
// @flow
import React, { Component } from "react";
import { bool, func, shape, number, string } from "prop-types";
import { FormattedMessage } from "react-intl";
import { Modal, ButtonToolbar, Button } from "react-bootstrap";
import styled from "styled-components";
import axios from "../../config/axios";
import type { Team } from "flow-typed";
import { inviteUsersToTeam } from "../../services/api/user_team_api";
import { getTeamDetails } from "../../services/api/teams_api";
import {
INVITE_USERS_PATH,
TEAM_DETAILS_PATH
} from "../../config/api_endpoints";
import InviteUsersForm from "./components/InviteUsersForm";
import InviteUsersResults from "./components/InviteUsersResults";
import InviteUsersButton from "./components/InviteUsersButton";
@ -17,52 +17,68 @@ const StyledButtonToolbar = styled(ButtonToolbar)`
float: right;
`;
class InviteUsersModal extends Component {
constructor(props) {
type Props = {
showModal: boolean,
onCloseModal: Function,
team: Team,
updateUsersCallback: Function
};
type State = {
inviteUserButtonDisabled: boolean,
showInviteUsersResults: boolean,
inputTags: Array<string>,
inviteResults: Array<string>
};
class InviteUsersModal extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
(this: any).state = {
inviteUserButtonDisabled: true,
showInviteUsersResults: false,
inputTags: [],
inviteResults: []
};
this.handleInputChange = this.handleInputChange.bind(this);
this.inviteAs = this.inviteAs.bind(this);
this.handleCloseModal = this.handleCloseModal.bind(this);
(this: any).handleInputChange = this.handleInputChange.bind(this);
(this: any).inviteAs = this.inviteAs.bind(this);
(this: any).handleCloseModal = this.handleCloseModal.bind(this);
}
handleCloseModal() {
const path = TEAM_DETAILS_PATH.replace(":team_id", this.props.team.id);
handleCloseModal(): void {
this.props.onCloseModal();
this.setState({
(this: any).setState({
showInviteUsersResults: false,
inputTags: [],
inviteResults: []
});
// Update team members table
axios.get(path).then(response => {
const { users } = response.data.team_details;
getTeamDetails(this.props.team.id).then(response => {
const { users } = response;
this.props.updateUsersCallback(users);
});
}
handleInputChange(inputTags) {
this.setState({ inputTags });
handleInputChange(inputTags: Array<string>): void {
if (inputTags.length > 0) {
(this: any).setState({ inputTags, inviteUserButtonDisabled: false });
} else {
(this: any).setState({ inputTags, inviteUserButtonDisabled: true });
}
}
inviteAs(role) {
axios
.put(INVITE_USERS_PATH, {
user_role: role,
emails: this.state.inputTags,
team_id: this.props.team.id
})
.then(({ data }) => {
this.setState({ inviteResults: data, showInviteUsersResults: true });
inviteAs(role: number): void {
inviteUsersToTeam(role, this.state.inputTags, this.props.team.id)
.then(response => {
(this: any).setState({
inviteResults: response,
showInviteUsersResults: true
});
})
.catch(error => {
console.log("Invite As Error: ", error);
if (error.response) {
console.log("Error message:", error.response.data);
console.log("Error message: ", error.response.data);
// TO DO: put this error in flash msg
}
});
@ -82,7 +98,12 @@ class InviteUsersModal extends Component {
teamName={this.props.team.name}
/>
);
inviteButton = <InviteUsersButton handleClick={this.inviteAs} />;
inviteButton = (
<InviteUsersButton
handleClick={this.inviteAs}
status={this.state.inviteUserButtonDisabled}
/>
);
}
return (
@ -119,11 +140,4 @@ class InviteUsersModal extends Component {
}
}
InviteUsersModal.propTypes = {
showModal: bool.isRequired,
onCloseModal: func.isRequired,
team: shape({ id: number.isRequired, name: string.isRequired }).isRequired,
updateUsersCallback: func.isRequired
};
export default InviteUsersModal;

View file

@ -14,8 +14,6 @@ export const SEARCH_PATH = "/search";
// notifications
export const RECENT_NOTIFICATIONS_PATH = "/client_api/recent_notifications";
export const INVITE_USERS_PATH = "/client_api/users/invite_users";
// info dropdown_title
export const CUSTOMER_SUPPORT_LINK = "http://scinote.net/support";
export const TUTORIALS_LINK = "http://scinote.net/product/tutorials/";

View file

@ -38,6 +38,7 @@ export const CONTACT_US_LINK =
export const LEAVE_TEAM_PATH = "/client_api/users/leave_team";
export const UPDATE_USER_TEAM_ROLE_PATH = "/client_api/users/update_role";
export const REMOVE_USER_FROM_TEAM_PATH = "/client_api/users/remove_user";
export const INVITE_USERS_PATH = "/client_api/users/invite_users";
// settings
export const SETTINGS_TEAMS = "/settings/teams";

View file

@ -0,0 +1,9 @@
// @flow
import { axiosInstance } from "./config";
import { TEAM_DETAILS_PATH } from "./endpoints";
export const getTeamDetails = (teamID: number): Promise<*> => {
const path = TEAM_DETAILS_PATH.replace(":team_id", teamID);
return axiosInstance.get(path).then(({ data }) => data.team_details);
};

View file

@ -1,6 +1,7 @@
// @flow
import { axiosInstance } from "./config";
import { REMOVE_USER_FROM_TEAM_PATH } from "./endpoints";
import { REMOVE_USER_FROM_TEAM_PATH, INVITE_USERS_PATH } from "./endpoints";
export const removeUserFromTeam = (
teamId: number,
@ -15,3 +16,17 @@ export const removeUserFromTeam = (
}
}).then(({ data }) => data.team_users);
};
export const inviteUsersToTeam = (
role: number,
emails: Array<string>,
teamID: number
): Promise<*> => {
return axiosInstance
.put(INVITE_USERS_PATH, {
user_role: role,
team_id: teamID,
emails
})
.then(({ data }) => data);
};

5
flow-typed/types.js vendored
View file

@ -5,3 +5,8 @@ export type Activity = {
message: string,
created_at :string
}
export type Team = {
id: number,
name: string
}