From db16da7bd6fe1691a0460a4491013b1e7730968b Mon Sep 17 00:00:00 2001 From: zmagod Date: Fri, 25 Aug 2017 16:07:37 +0200 Subject: [PATCH] adds custom query to fetch teams data --- .../client_api/teams_controller.rb | 4 +- app/javascript/packs/locales/messages.js | 3 ++ .../packs/shared/actions/LeaveTeamActions.js | 4 +- .../packs/shared/data_table/index.jsx | 2 +- .../modals/LeaveTeamModal.jsx | 25 ++++++++- .../packs/shared/reducers/LeaveTeamReducer.js | 13 +++-- .../components/team/SettingsTeams.jsx | 10 ++-- .../team/components/TeamsDataTable.jsx | 51 +++++++++++-------- app/models/user.rb | 15 ++++++ .../client_api/teams/index.json.jbuilder | 8 +-- spec/factories/user_teams.rb | 5 ++ spec/models/user_spec.rb | 40 +++++++++++++++ 12 files changed, 141 insertions(+), 39 deletions(-) create mode 100644 spec/factories/user_teams.rb diff --git a/app/controllers/client_api/teams_controller.rb b/app/controllers/client_api/teams_controller.rb index 1aaff0425..e71e54d3f 100644 --- a/app/controllers/client_api/teams_controller.rb +++ b/app/controllers/client_api/teams_controller.rb @@ -37,11 +37,11 @@ module ClientApi end def teams - { teams: current_user.teams } + { teams: current_user.teams_data } end 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 raise MissingTeamError end diff --git a/app/javascript/packs/locales/messages.js b/app/javascript/packs/locales/messages.js index a09f1c488..250db8808 100644 --- a/app/javascript/packs/locales/messages.js +++ b/app/javascript/packs/locales/messages.js @@ -14,6 +14,9 @@ export default { all_teams: "All teams", in_team: "You are member of {num} team", in_teams: "You are member of {num} team", + leave_team_modal: { + title: "Leave team {teamName}" + }, account: "Account", team: "Team", avatar: "Avatar", diff --git a/app/javascript/packs/shared/actions/LeaveTeamActions.js b/app/javascript/packs/shared/actions/LeaveTeamActions.js index 1274795de..13912c785 100644 --- a/app/javascript/packs/shared/actions/LeaveTeamActions.js +++ b/app/javascript/packs/shared/actions/LeaveTeamActions.js @@ -1,8 +1,8 @@ import { SHOW_LEAVE_TEAM_MODAL } from "../../app/action_types"; -export function leaveTeamModalShow(show, id) { +export function leaveTeamModalShow(show, id, teamName) { return({ - payload: { show, id }, + payload: { show, id, teamName }, type: SHOW_LEAVE_TEAM_MODAL }); } diff --git a/app/javascript/packs/shared/data_table/index.jsx b/app/javascript/packs/shared/data_table/index.jsx index 25f37e657..7d75f861f 100644 --- a/app/javascript/packs/shared/data_table/index.jsx +++ b/app/javascript/packs/shared/data_table/index.jsx @@ -108,4 +108,4 @@ DataTable.propTypes = { data: PropTypes.arrayOf(PropTypes.object).isRequired }; -export default DataTable; \ No newline at end of file +export default DataTable; diff --git a/app/javascript/packs/shared/modals_container/modals/LeaveTeamModal.jsx b/app/javascript/packs/shared/modals_container/modals/LeaveTeamModal.jsx index 8e7e00860..616f6c054 100644 --- a/app/javascript/packs/shared/modals_container/modals/LeaveTeamModal.jsx +++ b/app/javascript/packs/shared/modals_container/modals/LeaveTeamModal.jsx @@ -1,15 +1,21 @@ import React, { Component } from "react"; +import PropTypes, { bool, number, string } from "prop-types"; import { Modal, Button } from "react-bootstrap"; +import _ from "lodash"; import { FormattedMessage } from "react-intl"; import { connect } from "react-redux"; class LeaveTeamModal extends Component { + render() { return ( - + BANANAN @@ -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 }) => ({ showModal: showLeaveTeamModal.show, - teamId: showLeaveTeamModal.id + teamId: showLeaveTeamModal.id, + teamName: showLeaveTeamModal.teamName }); export default connect(mapStateToProps)(LeaveTeamModal); diff --git a/app/javascript/packs/shared/reducers/LeaveTeamReducer.js b/app/javascript/packs/shared/reducers/LeaveTeamReducer.js index c09b097aa..a784bc582 100644 --- a/app/javascript/packs/shared/reducers/LeaveTeamReducer.js +++ b/app/javascript/packs/shared/reducers/LeaveTeamReducer.js @@ -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) { - if(action.type ===SHOW_LEAVE_TEAM_MODAL) { - return {...state, ...action.payload} +export function showLeaveTeamModal( + state = { show: false, id: 0, teamName: "" }, + action +) { + if (action.type === SHOW_LEAVE_TEAM_MODAL) { + return { ...state, ...action.payload }; } - return state + return state; } diff --git a/app/javascript/packs/src/settings/components/team/SettingsTeams.jsx b/app/javascript/packs/src/settings/components/team/SettingsTeams.jsx index 1aa6793e2..30dee1b5b 100644 --- a/app/javascript/packs/src/settings/components/team/SettingsTeams.jsx +++ b/app/javascript/packs/src/settings/components/team/SettingsTeams.jsx @@ -1,5 +1,5 @@ import React from "react"; -import PropTypes from "prop-types"; +import PropTypes, { number, string, bool } from "prop-types"; import styled from "styled-components"; import { connect } from "react-redux"; import { FormattedMessage } from "react-intl"; @@ -38,9 +38,11 @@ const SettingsTeams = ({ teams }) => SettingsTeams.propTypes = { teams: PropTypes.arrayOf( PropTypes.shape({ - id: PropTypes.number.isRequired, - name: PropTypes.string.isRequired, - current_team: PropTypes.bool.isRequired + id: number.isRequired, + name: string.isRequired, + current_team: bool.isRequired, + role: string.isRequired, + members: number.isRequired, }).isRequired ) }; diff --git a/app/javascript/packs/src/settings/components/team/components/TeamsDataTable.jsx b/app/javascript/packs/src/settings/components/team/components/TeamsDataTable.jsx index 0d528ceca..c4ac088f4 100644 --- a/app/javascript/packs/src/settings/components/team/components/TeamsDataTable.jsx +++ b/app/javascript/packs/src/settings/components/team/components/TeamsDataTable.jsx @@ -1,5 +1,4 @@ import React, { Component } from "react"; -import { TableHeaderColumn } from "react-bootstrap-table"; import { connect } from "react-redux"; import { Button } from "react-bootstrap"; import { leaveTeamModalShow } from "../../../../../shared/actions/LeaveTeamActions"; @@ -8,12 +7,14 @@ import DataTable from "../../../../../shared/data_table"; class TeamsDataTable extends Component { constructor(props) { super(props); + this.leaveTeamModal = this.leaveTeamModal.bind(this); + this.leaveTeamButton = this.leaveTeamButton.bind(this); } leaveTeamModal(e, id) { - e.peventDefault(); - this.props.leaveTeamModalShow(true, id); + const team = _.find(this.props.teams, el => el.id === id); + this.props.leaveTeamModalShow(true, id, team.name); } leaveTeamButton(id) { @@ -23,23 +24,33 @@ class TeamsDataTable extends Component { } render() { - return ( - - - Name - - Role - Memebers - - - ); + const columns = [ + { id: "name", name: "Name", isKey: false, textId: "name", position: 0 }, + { id: "role", name: "Role", isKey: false, textId: "role", position: 1 }, + { + id: "members", + name: "Members", + isKey: false, + textId: "members", + position: 2 + }, + { + id: "id", + name: "", + isKey: true, + textId: "id", + dataFormat: this.leaveTeamButton, + position: 3 + } + ]; + return ; } } +// +// const mapDispatchToProps = dispatch => ({ +// leaveTeamModalShow(show, id) { +// dispatch(leaveTeamModalShow(show, id)); +// } +// }); -const mapDispatchToProps = dispatch => ({ - leaveTeamModalShow(show, id) { - dispatch(leaveTeamModalShow(show, id)); - } -}); - -export default connect(null, mapDispatchToProps)(TeamsDataTable); +export default connect(null, { leaveTeamModalShow })(TeamsDataTable); diff --git a/app/models/user.rb b/app/models/user.rb index 561f1e2db..2b04722c9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -204,6 +204,21 @@ class User < ApplicationRecord Team.find_by_id(self.current_team_id) 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 # also specify which team to ignore. def self.search( diff --git a/app/views/client_api/teams/index.json.jbuilder b/app/views/client_api/teams/index.json.jbuilder index 31ffa78e3..ecb410c11 100644 --- a/app/views/client_api/teams/index.json.jbuilder +++ b/app/views/client_api/teams/index.json.jbuilder @@ -1,7 +1,9 @@ json.teams do json.collection teams do |team| - json.id team.id - json.name team.name - json.current_team team == current_user.current_team + json.id team.fetch('id') + json.name team.fetch('name') + json.members team.fetch('members') + json.role UserTeam.roles.keys[team.fetch('role')] + json.current_team team.fetch('current_team') end end diff --git a/spec/factories/user_teams.rb b/spec/factories/user_teams.rb new file mode 100644 index 000000000..b63ecffd4 --- /dev/null +++ b/spec/factories/user_teams.rb @@ -0,0 +1,5 @@ +FactoryGirl.define do + factory :user_team do + role 'admin' + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index aa55b0a06..516a6be2b 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -149,4 +149,44 @@ describe User, type: :model do expect(user.name).to eq 'Axe' 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