adds custom query to fetch teams data

This commit is contained in:
zmagod 2017-08-25 16:07:37 +02:00
parent 782daabce1
commit db16da7bd6
12 changed files with 141 additions and 39 deletions

View file

@ -37,11 +37,11 @@ module ClientApi
end end
def teams def teams
{ teams: current_user.teams } { teams: current_user.teams_data }
end end
def change_current_team def change_current_team
team_id = params.fetch(:team_id) { raise MissingTeamError } team_id = params.fetch(:team_id) { raise MissingTeamError }
unless current_user.teams.pluck(:id).include? team_id unless current_user.teams.pluck(:id).include? team_id
raise MissingTeamError raise MissingTeamError
end end

View file

@ -14,6 +14,9 @@ export default {
all_teams: "All teams", all_teams: "All teams",
in_team: "You are member of {num} team", in_team: "You are member of {num} team",
in_teams: "You are member of {num} team", in_teams: "You are member of {num} team",
leave_team_modal: {
title: "Leave team {teamName}"
},
account: "Account", account: "Account",
team: "Team", team: "Team",
avatar: "Avatar", avatar: "Avatar",

View file

@ -1,8 +1,8 @@
import { SHOW_LEAVE_TEAM_MODAL } from "../../app/action_types"; import { SHOW_LEAVE_TEAM_MODAL } from "../../app/action_types";
export function leaveTeamModalShow(show, id) { export function leaveTeamModalShow(show, id, teamName) {
return({ return({
payload: { show, id }, payload: { show, id, teamName },
type: SHOW_LEAVE_TEAM_MODAL type: SHOW_LEAVE_TEAM_MODAL
}); });
} }

View file

@ -1,15 +1,21 @@
import React, { Component } from "react"; import React, { Component } from "react";
import PropTypes, { bool, number, string } from "prop-types";
import { Modal, Button } from "react-bootstrap"; import { Modal, Button } from "react-bootstrap";
import _ from "lodash";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import { connect } from "react-redux"; import { connect } from "react-redux";
class LeaveTeamModal extends Component { class LeaveTeamModal extends Component {
render() { render() {
return ( return (
<Modal show={this.props.showModal}> <Modal show={this.props.showModal}>
<Modal.Header closeButton> <Modal.Header closeButton>
<Modal.Title> <Modal.Title>
<FormattedMessage id="activities.modal_title" /> <FormattedMessage
id="settings_page.leave_team_modal.title"
values={{ teamName: this.props.teamName }}
/>
</Modal.Title> </Modal.Title>
</Modal.Header> </Modal.Header>
<Modal.Body>BANANAN</Modal.Body> <Modal.Body>BANANAN</Modal.Body>
@ -23,9 +29,24 @@ class LeaveTeamModal extends Component {
} }
} }
LeaveTeamModal.propTypes = {
showModal: bool.isRequired,
teamId: number.isRequired,
teamName: string.isRequired,
teams: PropTypes.arrayOf(
PropTypes.shape({
id: number.isRequired,
name: string.isRequired,
current_team: bool.isRequired,
role: string.isRequired,
members: number.isRequired,
}).isRequired
)
};
const mapStateToProps = ({ showLeaveTeamModal }) => ({ const mapStateToProps = ({ showLeaveTeamModal }) => ({
showModal: showLeaveTeamModal.show, showModal: showLeaveTeamModal.show,
teamId: showLeaveTeamModal.id teamId: showLeaveTeamModal.id,
teamName: showLeaveTeamModal.teamName
}); });
export default connect(mapStateToProps)(LeaveTeamModal); export default connect(mapStateToProps)(LeaveTeamModal);

View file

@ -1,8 +1,11 @@
import { SHOW_LEAVE_TEAM_MODAL } from '../../app/action_types' import { SHOW_LEAVE_TEAM_MODAL } from "../../app/action_types";
export function showLeaveTeamModal(state = {show: false, id: 0}, action) { export function showLeaveTeamModal(
if(action.type ===SHOW_LEAVE_TEAM_MODAL) { state = { show: false, id: 0, teamName: "" },
return {...state, ...action.payload} action
) {
if (action.type === SHOW_LEAVE_TEAM_MODAL) {
return { ...state, ...action.payload };
} }
return state return state;
} }

View file

@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import PropTypes from "prop-types"; import PropTypes, { number, string, bool } from "prop-types";
import styled from "styled-components"; import styled from "styled-components";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
@ -38,9 +38,11 @@ const SettingsTeams = ({ teams }) =>
SettingsTeams.propTypes = { SettingsTeams.propTypes = {
teams: PropTypes.arrayOf( teams: PropTypes.arrayOf(
PropTypes.shape({ PropTypes.shape({
id: PropTypes.number.isRequired, id: number.isRequired,
name: PropTypes.string.isRequired, name: string.isRequired,
current_team: PropTypes.bool.isRequired current_team: bool.isRequired,
role: string.isRequired,
members: number.isRequired,
}).isRequired }).isRequired
) )
}; };

View file

@ -1,5 +1,4 @@
import React, { Component } from "react"; import React, { Component } from "react";
import { TableHeaderColumn } from "react-bootstrap-table";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Button } from "react-bootstrap"; import { Button } from "react-bootstrap";
import { leaveTeamModalShow } from "../../../../../shared/actions/LeaveTeamActions"; import { leaveTeamModalShow } from "../../../../../shared/actions/LeaveTeamActions";
@ -8,12 +7,14 @@ import DataTable from "../../../../../shared/data_table";
class TeamsDataTable extends Component { class TeamsDataTable extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.leaveTeamModal = this.leaveTeamModal.bind(this); this.leaveTeamModal = this.leaveTeamModal.bind(this);
this.leaveTeamButton = this.leaveTeamButton.bind(this);
} }
leaveTeamModal(e, id) { leaveTeamModal(e, id) {
e.peventDefault(); const team = _.find(this.props.teams, el => el.id === id);
this.props.leaveTeamModalShow(true, id); this.props.leaveTeamModalShow(true, id, team.name);
} }
leaveTeamButton(id) { leaveTeamButton(id) {
@ -23,23 +24,33 @@ class TeamsDataTable extends Component {
} }
render() { render() {
return ( const columns = [
<DataTable data={this.props.teams}> { id: "name", name: "Name", isKey: false, textId: "name", position: 0 },
<TableHeaderColumn isKey dataField="name"> { id: "role", name: "Role", isKey: false, textId: "role", position: 1 },
Name {
</TableHeaderColumn> id: "members",
<TableHeaderColumn dataField="role">Role</TableHeaderColumn> name: "Members",
<TableHeaderColumn dataField="members">Memebers</TableHeaderColumn> isKey: false,
<TableHeaderColumn dataField="id" dataFormat={this.leaveTeamButton} /> textId: "members",
</DataTable> position: 2
); },
{
id: "id",
name: "",
isKey: true,
textId: "id",
dataFormat: this.leaveTeamButton,
position: 3
}
];
return <DataTable data={this.props.teams} columns={columns} />;
} }
} }
//
// const mapDispatchToProps = dispatch => ({
// leaveTeamModalShow(show, id) {
// dispatch(leaveTeamModalShow(show, id));
// }
// });
const mapDispatchToProps = dispatch => ({ export default connect(null, { leaveTeamModalShow })(TeamsDataTable);
leaveTeamModalShow(show, id) {
dispatch(leaveTeamModalShow(show, id));
}
});
export default connect(null, mapDispatchToProps)(TeamsDataTable);

View file

@ -204,6 +204,21 @@ class User < ApplicationRecord
Team.find_by_id(self.current_team_id) Team.find_by_id(self.current_team_id)
end end
# Retrieves the data needed in all teams page
def teams_data
ActiveRecord::Base.connection.execute(
ActiveRecord::Base.send(
:sanitize_sql_array,
['SELECT teams.id AS id, teams.name AS name, user_teams.role ' \
'AS role, (SELECT COUNT(*) FROM user_teams WHERE ' \
'user_teams.team_id = teams.id) AS members, ' \
'CASE WHEN teams.id=? THEN true ELSE false END AS current_team ' \
'FROM teams INNER JOIN user_teams ON teams.id=user_teams.team_id ' \
'WHERE user_teams.user_id=?', self.current_team_id, self.id]
)
)
end
# Search all active users for username & email. Can # Search all active users for username & email. Can
# also specify which team to ignore. # also specify which team to ignore.
def self.search( def self.search(

View file

@ -1,7 +1,9 @@
json.teams do json.teams do
json.collection teams do |team| json.collection teams do |team|
json.id team.id json.id team.fetch('id')
json.name team.name json.name team.fetch('name')
json.current_team team == current_user.current_team json.members team.fetch('members')
json.role UserTeam.roles.keys[team.fetch('role')]
json.current_team team.fetch('current_team')
end end
end end

View file

@ -0,0 +1,5 @@
FactoryGirl.define do
factory :user_team do
role 'admin'
end
end

View file

@ -149,4 +149,44 @@ describe User, type: :model do
expect(user.name).to eq 'Axe' expect(user.name).to eq 'Axe'
end end
end end
describe 'teams_data should return a list of teams' do
# needs persistence because is testing a sql query
let(:team) { create :team }
let(:user_one) do
create :user, email: 'user1@asdf.com', current_team_id: team.id
end
let(:user_two) { create :user, email: 'user2@asdf.com' }
it 'in a specific format' do
create :user_team, team: team, user: user_one
expected_result = {
id: team.id,
name: team.name,
members: 1,
role: 2,
current_team: true
}
user_one.teams_data.first.each do |k, v|
expect(v).to eq(expected_result.fetch(k.to_sym))
end
end
it 'should return correct number of team members' do
create :user_team, team: team, user: user_one
create :user_team, team: team, user: user_two
expected_result = {
id: team.id,
name: team.name,
members: 2,
role: 2,
current_team: true
}
user_one.teams_data.first.each do |k, v|
expect(v).to eq(expected_result.fetch(k.to_sym))
end
end
end
end end