Commit f788caa6 by muzaffaryousaf

Edit team page for Instructor only.

TNL-1914
parent 406c9bc5
...@@ -205,7 +205,7 @@ class BrowseTeamsPage(CoursePage, PaginatedUIMixin): ...@@ -205,7 +205,7 @@ class BrowseTeamsPage(CoursePage, PaginatedUIMixin):
self.wait_for_ajax() self.wait_for_ajax()
class CreateTeamPage(CoursePage, FieldsMixin): class CreateOrEditTeamPage(CoursePage, FieldsMixin):
""" """
Create team page. Create team page.
""" """
...@@ -216,7 +216,7 @@ class CreateTeamPage(CoursePage, FieldsMixin): ...@@ -216,7 +216,7 @@ class CreateTeamPage(CoursePage, FieldsMixin):
representation of a topic following the same convention as a representation of a topic following the same convention as a
course module's topic. course module's topic.
""" """
super(CreateTeamPage, self).__init__(browser, course_id) super(CreateOrEditTeamPage, self).__init__(browser, course_id)
self.topic = topic self.topic = topic
self.url_path = "teams/#topics/{topic_id}/create-team".format(topic_id=self.topic['id']) self.url_path = "teams/#topics/{topic_id}/create-team".format(topic_id=self.topic['id'])
...@@ -410,3 +410,12 @@ class TeamPage(CoursePage, PaginatedUIMixin): ...@@ -410,3 +410,12 @@ class TeamPage(CoursePage, PaginatedUIMixin):
"""Navigate to the 'All Topics' page.""" """Navigate to the 'All Topics' page."""
self.q(css='.breadcrumbs a').results[0].click() self.q(css='.breadcrumbs a').results[0].click()
self.wait_for_ajax() self.wait_for_ajax()
@property
def edit_team_button_present(self):
""" Returns True if Edit Team button is present else False """
return self.q(css='.form-actions .action-edit-team').present
def click_edit_team_button(self):
""" Click on Edit Team button"""
self.q(css='.form-actions .action-edit-team').first.click()
...@@ -20,7 +20,7 @@ from ...pages.lms.auto_auth import AutoAuthPage ...@@ -20,7 +20,7 @@ from ...pages.lms.auto_auth import AutoAuthPage
from ...pages.lms.course_info import CourseInfoPage from ...pages.lms.course_info import CourseInfoPage
from ...pages.lms.learner_profile import LearnerProfilePage from ...pages.lms.learner_profile import LearnerProfilePage
from ...pages.lms.tab_nav import TabNavPage from ...pages.lms.tab_nav import TabNavPage
from ...pages.lms.teams import TeamsPage, MyTeamsPage, BrowseTopicsPage, BrowseTeamsPage, CreateTeamPage, TeamPage from ...pages.lms.teams import TeamsPage, MyTeamsPage, BrowseTopicsPage, BrowseTeamsPage, CreateOrEditTeamPage, TeamPage
TOPICS_PER_PAGE = 12 TOPICS_PER_PAGE = 12
...@@ -335,7 +335,7 @@ class BrowseTopicsTest(TeamsTabBase): ...@@ -335,7 +335,7 @@ class BrowseTopicsTest(TeamsTabBase):
browse_teams_page = BrowseTeamsPage(self.browser, self.course_id, topic) browse_teams_page = BrowseTeamsPage(self.browser, self.course_id, topic)
self.assertTrue(browse_teams_page.is_browser_on_page()) self.assertTrue(browse_teams_page.is_browser_on_page())
browse_teams_page.click_create_team_link() browse_teams_page.click_create_team_link()
create_team_page = CreateTeamPage(self.browser, self.course_id, topic) create_team_page = CreateOrEditTeamPage(self.browser, self.course_id, topic)
create_team_page.value_for_text_field(field_id='name', value='Team Name', press_enter=False) create_team_page.value_for_text_field(field_id='name', value='Team Name', press_enter=False)
create_team_page.value_for_textarea_field( create_team_page.value_for_textarea_field(
field_id='description', field_id='description',
...@@ -629,78 +629,124 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase): ...@@ -629,78 +629,124 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
@attr('shard_5') @attr('shard_5')
class CreateTeamTest(TeamsTabBase): class TeamFormActions(TeamsTabBase):
""" """
Tests for creating a new Team within a Topic on the Teams page. Base class for create & edit team.
""" """
TEAM_DESCRIPTION = 'The Avengers are a fictional team of superheroes.'
def setUp(self): topic = {'name': 'Example Topic', 'id': 'example_topic', 'description': 'Description'}
super(CreateTeamTest, self).setUp() TEAMS_NAME = 'Avengers'
self.topic = {'name': 'Example Topic', 'id': 'example_topic', 'description': 'Description'}
self.set_team_configuration({'course_id': self.course_id, 'max_team_size': 10, 'topics': [self.topic]})
self.browse_teams_page = BrowseTeamsPage(self.browser, self.course_id, self.topic)
self.browse_teams_page.visit()
self.create_team_page = CreateTeamPage(self.browser, self.course_id, self.topic)
self.team_name = 'Avengers'
def verify_page_header(self): def verify_page_header(self, title, description, breadcrumbs):
""" """
Verify that the page header correctly reflects the Verify that the page header correctly reflects the
create team header, description and breadcrumb. create team header, description and breadcrumb.
""" """
self.assertEqual(self.create_team_page.header_page_name, 'Create a New Team') self.assertEqual(self.create_or_edit_team_page.header_page_name, title)
self.assertEqual( self.assertEqual(self.create_or_edit_team_page.header_page_description, description)
self.create_team_page.header_page_description, self.assertEqual(self.create_or_edit_team_page.header_page_breadcrumbs, breadcrumbs)
'Create a new team if you can\'t find existing teams to join, '
'or if you would like to learn with friends you know.'
)
self.assertEqual(self.create_team_page.header_page_breadcrumbs, self.topic['name'])
def verify_and_navigate_to_create_team_page(self): def verify_and_navigate_to_create_team_page(self):
"""Navigates to the create team page and verifies.""" """Navigates to the create team page and verifies."""
self.browse_teams_page.click_create_team_link() self.browse_teams_page.click_create_team_link()
self.verify_page_header() self.verify_page_header(
title='Create a New Team',
description='Create a new team if you can\'t find existing teams to '
'join, or if you would like to learn with friends you know.',
breadcrumbs=self.topic['name']
)
def verify_and_navigate_to_edit_team_page(self):
"""Navigates to the edit team page and verifies."""
# pylint: disable=no-member
self.assertEqual(self.team_page.team_name, self.team['name'])
self.assertTrue(self.team_page.edit_team_button_present)
self.team_page.click_edit_team_button()
self.create_or_edit_team_page.wait_for_page()
def fill_create_form(self): # Edit page header.
"""Fill the create team form fields with appropriate values.""" self.verify_page_header(
self.create_team_page.value_for_text_field(field_id='name', value=self.team_name, press_enter=False) title='Edit Team',
self.create_team_page.value_for_textarea_field( description='If you make significant changes, make sure you notify '
'members of the team before making these changes.',
breadcrumbs='All Topics {topic_name} {team_name}'.format(
topic_name=self.topic['name'],
team_name=self.team['name']
)
)
def verify_team_info(self, name, description, location, language):
"""Verify the team information on team page."""
# pylint: disable=no-member
self.assertEqual(self.team_page.team_name, name)
self.assertEqual(self.team_page.team_description, description)
self.assertEqual(self.team_page.team_location, location)
self.assertEqual(self.team_page.team_language, language)
def fill_create_or_edit_form(self):
"""Fill the create/edit team form fields with appropriate values."""
self.create_or_edit_team_page.value_for_text_field(field_id='name', value=self.TEAMS_NAME, press_enter=False)
self.create_or_edit_team_page.value_for_textarea_field(
field_id='description', field_id='description',
value='The Avengers are a fictional team of superheroes.' value=self.TEAM_DESCRIPTION
) )
self.create_team_page.value_for_dropdown_field(field_id='language', value='English') self.create_or_edit_team_page.value_for_dropdown_field(field_id='language', value='English')
self.create_team_page.value_for_dropdown_field(field_id='country', value='Pakistan') self.create_or_edit_team_page.value_for_dropdown_field(field_id='country', value='Pakistan')
def test_user_can_see_create_team_page(self): def verify_all_fields_exist(self):
""" """
Scenario: The user should be able to see the create team page via teams list page. Verify the fields for create/edit page.
Given I am enrolled in a course with a team configuration and a topic
When I visit the Teams page for that topic
Then I should see the Create Team page link on bottom
And When I click create team link
Then I should see the create team page.
And I should see the create team header
And I should also see the help messages for fields.
""" """
self.verify_and_navigate_to_create_team_page()
self.assertEqual( self.assertEqual(
self.create_team_page.message_for_field('name'), self.create_or_edit_team_page.message_for_field('name'),
'A name that identifies your team (maximum 255 characters).' 'A name that identifies your team (maximum 255 characters).'
) )
self.assertEqual( self.assertEqual(
self.create_team_page.message_for_textarea_field('description'), self.create_or_edit_team_page.message_for_textarea_field('description'),
'A short description of the team to help other learners understand ' 'A short description of the team to help other learners understand '
'the goals or direction of the team (maximum 300 characters).' 'the goals or direction of the team (maximum 300 characters).'
) )
self.assertEqual( self.assertEqual(
self.create_team_page.message_for_field('country'), self.create_or_edit_team_page.message_for_field('country'),
'The country that team members primarily identify with.' 'The country that team members primarily identify with.'
) )
self.assertEqual( self.assertEqual(
self.create_team_page.message_for_field('language'), self.create_or_edit_team_page.message_for_field('language'),
'The language that team members primarily use to communicate with each other.' 'The language that team members primarily use to communicate with each other.'
) )
@ddt.ddt
class CreateTeamTest(TeamFormActions):
"""
Tests for creating a new Team within a Topic on the Teams page.
"""
def setUp(self):
super(CreateTeamTest, self).setUp()
self.set_team_configuration({'course_id': self.course_id, 'max_team_size': 10, 'topics': [self.topic]})
self.create_or_edit_team_page = CreateOrEditTeamPage(self.browser, self.course_id, self.topic)
self.browse_teams_page = BrowseTeamsPage(self.browser, self.course_id, self.topic)
self.browse_teams_page.visit()
def test_user_can_see_create_team_page(self):
"""
Scenario: The user should be able to see the create team page via teams list page.
Given I am enrolled in a course with a team configuration and a topic
When I visit the Teams page for that topic
Then I should see the Create Team page link on bottom
And When I click create team link
Then I should see the create team page.
And I should see the create team header
And I should also see the help messages for fields.
"""
self.verify_and_navigate_to_create_team_page()
self.verify_all_fields_exist()
def test_user_can_see_error_message_for_missing_data(self): def test_user_can_see_error_message_for_missing_data(self):
""" """
Scenario: The user should be able to see error message in case of missing required field. Scenario: The user should be able to see error message in case of missing required field.
...@@ -711,14 +757,14 @@ class CreateTeamTest(TeamsTabBase): ...@@ -711,14 +757,14 @@ class CreateTeamTest(TeamsTabBase):
Then I should see the error message and highlighted fields. Then I should see the error message and highlighted fields.
""" """
self.verify_and_navigate_to_create_team_page() self.verify_and_navigate_to_create_team_page()
self.create_team_page.submit_form() self.create_or_edit_team_page.submit_form()
self.assertEqual( self.assertEqual(
self.create_team_page.validation_message_text, self.create_or_edit_team_page.validation_message_text,
'Check the highlighted fields below and try again.' 'Check the highlighted fields below and try again.'
) )
self.assertTrue(self.create_team_page.error_for_field(field_id='name')) self.assertTrue(self.create_or_edit_team_page.error_for_field(field_id='name'))
self.assertTrue(self.create_team_page.error_for_field(field_id='description')) self.assertTrue(self.create_or_edit_team_page.error_for_field(field_id='description'))
def test_user_can_see_error_message_for_incorrect_data(self): def test_user_can_see_error_message_for_incorrect_data(self):
""" """
...@@ -733,7 +779,7 @@ class CreateTeamTest(TeamsTabBase): ...@@ -733,7 +779,7 @@ class CreateTeamTest(TeamsTabBase):
self.verify_and_navigate_to_create_team_page() self.verify_and_navigate_to_create_team_page()
# Fill the name field with >255 characters to see validation message. # Fill the name field with >255 characters to see validation message.
self.create_team_page.value_for_text_field( self.create_or_edit_team_page.value_for_text_field(
field_id='name', field_id='name',
value='EdX is a massive open online course (MOOC) provider and online learning platform. ' value='EdX is a massive open online course (MOOC) provider and online learning platform. '
'It hosts online university-level courses in a wide range of disciplines to a worldwide ' 'It hosts online university-level courses in a wide range of disciplines to a worldwide '
...@@ -745,13 +791,13 @@ class CreateTeamTest(TeamsTabBase): ...@@ -745,13 +791,13 @@ class CreateTeamTest(TeamsTabBase):
'edX has more than 4 million users taking more than 500 courses online.', 'edX has more than 4 million users taking more than 500 courses online.',
press_enter=False press_enter=False
) )
self.create_team_page.submit_form() self.create_or_edit_team_page.submit_form()
self.assertEqual( self.assertEqual(
self.create_team_page.validation_message_text, self.create_or_edit_team_page.validation_message_text,
'Check the highlighted fields below and try again.' 'Check the highlighted fields below and try again.'
) )
self.assertTrue(self.create_team_page.error_for_field(field_id='name')) self.assertTrue(self.create_or_edit_team_page.error_for_field(field_id='name'))
def test_user_can_create_new_team_successfully(self): def test_user_can_create_new_team_successfully(self):
""" """
...@@ -767,16 +813,19 @@ class CreateTeamTest(TeamsTabBase): ...@@ -767,16 +813,19 @@ class CreateTeamTest(TeamsTabBase):
And the number of teams should be updated on the topic card And the number of teams should be updated on the topic card
And if I switch to "My Team", the newly created team is displayed And if I switch to "My Team", the newly created team is displayed
""" """
AutoAuthPage(self.browser, course_id=self.course_id).visit()
self.browse_teams_page.visit()
self.verify_and_navigate_to_create_team_page() self.verify_and_navigate_to_create_team_page()
self.fill_create_form() self.fill_create_or_edit_form()
self.create_team_page.submit_form() self.create_or_edit_team_page.submit_form()
# Verify that the page is shown for the new team # Verify that the page is shown for the new team
team_page = TeamPage(self.browser, self.course_id) team_page = TeamPage(self.browser, self.course_id)
team_page.wait_for_page() team_page.wait_for_page()
self.assertEqual(team_page.team_name, self.team_name) self.assertEqual(team_page.team_name, self.TEAMS_NAME)
self.assertEqual(team_page.team_description, 'The Avengers are a fictional team of superheroes.') self.assertEqual(team_page.team_description, self.TEAM_DESCRIPTION)
self.assertEqual(team_page.team_user_membership_text, 'You are a member of this team.') self.assertEqual(team_page.team_user_membership_text, 'You are a member of this team.')
# Verify the new team was added to the topic list # Verify the new team was added to the topic list
...@@ -802,7 +851,7 @@ class CreateTeamTest(TeamsTabBase): ...@@ -802,7 +851,7 @@ class CreateTeamTest(TeamsTabBase):
self.assertEqual(self.browse_teams_page.get_pagination_header_text(), 'Showing 0 out of 0 total') self.assertEqual(self.browse_teams_page.get_pagination_header_text(), 'Showing 0 out of 0 total')
self.verify_and_navigate_to_create_team_page() self.verify_and_navigate_to_create_team_page()
self.create_team_page.cancel_team() self.create_or_edit_team_page.cancel_team()
self.assertTrue(self.browse_teams_page.is_browser_on_page()) self.assertTrue(self.browse_teams_page.is_browser_on_page())
self.assertEqual(self.browse_teams_page.get_pagination_header_text(), 'Showing 0 out of 0 total') self.assertEqual(self.browse_teams_page.get_pagination_header_text(), 'Showing 0 out of 0 total')
...@@ -813,6 +862,157 @@ class CreateTeamTest(TeamsTabBase): ...@@ -813,6 +862,157 @@ class CreateTeamTest(TeamsTabBase):
self.verify_my_team_count(0) self.verify_my_team_count(0)
@ddt.ddt
class EditTeamTest(TeamFormActions):
"""
Tests for editing the team.
"""
def setUp(self):
super(EditTeamTest, self).setUp()
self.set_team_configuration(
{'course_id': self.course_id, 'max_team_size': 10, 'topics': [self.topic]},
global_staff=True
)
self.create_or_edit_team_page = CreateOrEditTeamPage(self.browser, self.course_id, self.topic)
self.team = self.create_teams(self.topic, num_teams=1)[0]
self.team_page = TeamPage(self.browser, self.course_id, team=self.team)
self.team_page.visit()
def test_staff_can_navigate_to_edit_team_page(self):
"""
Scenario: The user should be able to see and navigate to the edit team page.
Given I am staff user for a course with a team
When I visit the Team profile page
Then I should see the Edit Team button
And When I click edit team button
Then I should see the edit team page
And I should see the edit team header
And I should also see the help messages for fields
"""
self.verify_and_navigate_to_edit_team_page()
self.verify_all_fields_exist()
def test_staff_can_edit_team_successfully(self):
"""
Scenario: The staff should be able to edit team successfully.
Given I am staff user for a course with a team
When I visit the Team profile page
Then I should see the Edit Team button
And When I click edit team button
Then I should see the edit team page
When I edit all the fields with appropriate data
And I click Update button
Then I should see the page for my team with updated data
"""
self.verify_team_info(
name=self.team['name'],
description=self.team['description'],
location='Afghanistan',
language='Afar'
)
self.verify_and_navigate_to_edit_team_page()
self.fill_create_or_edit_form()
self.create_or_edit_team_page.submit_form()
self.team_page.wait_for_page()
self.verify_team_info(
name=self.TEAMS_NAME,
description=self.TEAM_DESCRIPTION,
location='Pakistan',
language='English'
)
def test_staff_can_cancel_the_team_edit(self):
"""
Scenario: The user should be able to cancel the editing of team.
Given I am staff user for a course with a team
When I visit the Team profile page
Then I should see the Edit Team button
And When I click edit team button
Then I should see the edit team page
Then I should see the Edit Team header
When I click Cancel button
Then I should see team page page without changes.
"""
self.verify_team_info(
name=self.team['name'],
description=self.team['description'],
location='Afghanistan',
language='Afar'
)
self.verify_and_navigate_to_edit_team_page()
self.fill_create_or_edit_form()
self.create_or_edit_team_page.cancel_team()
self.team_page.wait_for_page()
self.verify_team_info(
name=self.team['name'],
description=self.team['description'],
location='Afghanistan',
language='Afar'
)
def test_student_cannot_see_edit_button(self):
"""
Scenario: The student should not see the edit team button.
Given I am student for a course with a team
When I visit the Team profile page
Then I should not see the Edit Team button
"""
AutoAuthPage(self.browser, course_id=self.course_id).visit()
self.team_page.visit()
self.assertFalse(self.team_page.edit_team_button_present)
@ddt.data('Moderator', 'Community TA', 'Administrator')
def test_discussion_privileged_user_can_edit_team(self, role):
"""
Scenario: The user with specified role should see the edit team button.
Given I am user with privileged role for a course with a team
When I visit the Team profile page
Then I should see the Edit Team button
"""
kwargs = {
'course_id': self.course_id,
'staff': False
}
if role is not None:
kwargs['roles'] = role
AutoAuthPage(self.browser, **kwargs).visit()
self.team_page.visit()
self.teams_page.wait_for_page()
self.assertTrue(self.team_page.edit_team_button_present)
self.verify_team_info(
name=self.team['name'],
description=self.team['description'],
location='Afghanistan',
language='Afar'
)
self.verify_and_navigate_to_edit_team_page()
self.fill_create_or_edit_form()
self.create_or_edit_team_page.submit_form()
self.team_page.wait_for_page()
self.verify_team_info(
name=self.TEAMS_NAME,
description=self.TEAM_DESCRIPTION,
location='Pakistan',
language='English'
)
@attr('shard_5') @attr('shard_5')
@ddt.ddt @ddt.ddt
class TeamPageTest(TeamsTabBase): class TeamPageTest(TeamsTabBase):
......
...@@ -4,13 +4,14 @@ define([ ...@@ -4,13 +4,14 @@ define([
'backbone', 'backbone',
'common/js/spec_helpers/ajax_helpers', 'common/js/spec_helpers/ajax_helpers',
'teams/js/views/edit_team', 'teams/js/views/edit_team',
'teams/js/models/team',
'teams/js/spec_helpers/team_spec_helpers' 'teams/js/spec_helpers/team_spec_helpers'
], function ($, _, Backbone, AjaxHelpers, TeamEditView, TeamSpecHelpers) { ], function ($, _, Backbone, AjaxHelpers, TeamEditView, TeamModel, TeamSpecHelpers) {
'use strict'; 'use strict';
describe('EditTeam', function () { describe('CreateEditTeam', function() {
var teamsUrl = '/api/team/v0/teams/', var teamsUrl = '/api/team/v0/teams/',
teamsData = { createTeamData = {
id: null, id: null,
name: "TeamName", name: "TeamName",
is_active: null, is_active: null,
...@@ -18,11 +19,17 @@ define([ ...@@ -18,11 +19,17 @@ define([
topic_id: "awesomeness", topic_id: "awesomeness",
date_created: "", date_created: "",
description: "TeamDescription", description: "TeamDescription",
country: "c", country: "US",
language: "a", language: "en",
membership: [], membership: [],
last_activity_at: '' last_activity_at: ''
}, },
editTeamData = {
name: "UpdatedAvengers",
description: "We do not discuss about avengers.",
country: "US",
language: "en"
},
verifyValidation = function (requests, teamEditView, fieldsData) { verifyValidation = function (requests, teamEditView, fieldsData) {
_.each(fieldsData, function (fieldData) { _.each(fieldsData, function (fieldData) {
teamEditView.$(fieldData[0]).val(fieldData[1]); teamEditView.$(fieldData[0]).val(fieldData[1]);
...@@ -32,33 +39,57 @@ define([ ...@@ -32,33 +39,57 @@ define([
var message = teamEditView.$('.wrapper-msg'); var message = teamEditView.$('.wrapper-msg');
expect(message.hasClass('is-hidden')).toBeFalsy(); expect(message.hasClass('is-hidden')).toBeFalsy();
expect(message.find('.title').text().trim()).toBe("Your team could not be created!"); var actionMessage = (teamAction === 'create' ? 'Your team could not be created.' : 'Your team could not be updated.');
expect(message.find('.title').text().trim()).toBe(actionMessage);
expect(message.find('.copy').text().trim()).toBe( expect(message.find('.copy').text().trim()).toBe(
"Check the highlighted fields below and try again." "Check the highlighted fields below and try again."
); );
_.each(fieldsData, function (fieldData) { _.each(fieldsData, function (fieldData) {
if(fieldData[2] === 'error') { if (fieldData[2] === 'error') {
expect(teamEditView.$(fieldData[0].split(" ")[0] + '.error').length).toBe(1); expect(teamEditView.$(fieldData[0].split(" ")[0] + '.error').length).toBe(1);
} else if(fieldData[2] === 'success') { } else if (fieldData[2] === 'success') {
expect(teamEditView.$(fieldData[0].split(" ")[0] + '.error').length).toBe(0); expect(teamEditView.$(fieldData[0].split(" ")[0] + '.error').length).toBe(0);
} }
}); });
expect(requests.length).toBe(0); expect(requests.length).toBe(0);
}; },
editTeamID = 'av',
teamAction;
var createEditTeamView = function () {
var teamModel = {};
if (teamAction === 'edit') {
teamModel = new TeamModel(
{
id: editTeamID,
name: 'Avengers',
description: 'Team of dumbs',
language: 'en',
country: 'US',
membership: [],
url: '/api/team/v0/teams/' + editTeamID
},
{
parse: true
}
);
}
var createTeamEditView = function() {
return new TeamEditView({ return new TeamEditView({
teamEvents: TeamSpecHelpers.teamEvents, teamEvents: TeamSpecHelpers.teamEvents,
el: $('.teams-content'), el: $('.teams-content'),
action: teamAction,
model: teamModel,
teamParams: { teamParams: {
teamsUrl: teamsUrl, teamsUrl: teamsUrl,
courseID: "a/b/c", courseID: "a/b/c",
topicID: 'awesomeness', topicID: 'awesomeness',
topicName: 'Awesomeness', topicName: 'Awesomeness',
languages: [['a', 'aaa'], ['b', 'bbb']], languages: [['aa', 'Afar'], ['fr', 'French'], ['en', 'English']],
countries: [['c', 'ccc'], ['d', 'ddd']] countries: [['af', 'Afghanistan'], ['CA', 'Canada'], ['US', 'United States']],
teamsDetailUrl: teamModel.url
} }
}).render(); }).render();
}; };
...@@ -68,7 +99,7 @@ define([ ...@@ -68,7 +99,7 @@ define([
spyOn(Backbone.history, 'navigate'); spyOn(Backbone.history, 'navigate');
}); });
it('can render itself correctly', function () { var assertFormRendersCorrectly = function() {
var fieldClasses = [ var fieldClasses = [
'.u-field-name', '.u-field-name',
'.u-field-description', '.u-field-description',
...@@ -76,7 +107,7 @@ define([ ...@@ -76,7 +107,7 @@ define([
'.u-field-language', '.u-field-language',
'.u-field-country' '.u-field-country'
], ],
teamEditView = createTeamEditView(); teamEditView = createEditTeamView();
_.each(fieldClasses, function (fieldClass) { _.each(fieldClasses, function (fieldClass) {
expect(teamEditView.$el.find(fieldClass).length).toBe(1); expect(teamEditView.$el.find(fieldClass).length).toBe(1);
...@@ -84,32 +115,46 @@ define([ ...@@ -84,32 +115,46 @@ define([
expect(teamEditView.$('.create-team.form-actions .action-primary').length).toBe(1); expect(teamEditView.$('.create-team.form-actions .action-primary').length).toBe(1);
expect(teamEditView.$('.create-team.form-actions .action-cancel').length).toBe(1); expect(teamEditView.$('.create-team.form-actions .action-cancel').length).toBe(1);
});
it('can create a team', function () { if (teamAction === 'edit') {
var requests = AjaxHelpers.requests(this), expect(teamEditView.$el.find('.u-field-name input').val()).toBe('Avengers');
teamEditView = createTeamEditView(); expect(teamEditView.$el.find('.u-field-description textarea').val()).toBe('Team of dumbs');
expect(teamEditView.$el.find('.u-field-language select option:selected').text()).toBe('English');
expect(teamEditView.$el.find('.u-field-country select option:selected').text()).toBe('United States');
}
};
var requestMethod = function() {
return teamAction === 'create' ? 'POST' : 'PATCH';
};
var assertTeamCreateUpdateInfo = function(that, teamsData, teamsUrl, expectedUrl) {
var requests = AjaxHelpers.requests(that),
teamEditView = createEditTeamView();
teamEditView.$('.u-field-name input').val(teamsData.name); teamEditView.$('.u-field-name input').val(teamsData.name);
teamEditView.$('.u-field-textarea textarea').val(teamsData.description); teamEditView.$('.u-field-textarea textarea').val(teamsData.description);
teamEditView.$('.u-field-language select').val('a').attr("selected", "selected"); teamEditView.$('.u-field-language select').val(teamsData.language).attr("selected", "selected");
teamEditView.$('.u-field-country select').val('c').attr("selected", "selected"); teamEditView.$('.u-field-country select').val(teamsData.country).attr("selected", "selected");
teamEditView.$('.create-team.form-actions .action-primary').click(); teamEditView.$('.create-team.form-actions .action-primary').click();
AjaxHelpers.expectJsonRequest(requests, 'POST', teamsUrl, teamsData);
AjaxHelpers.respondWithJson(requests, _.extend(_.extend({}, teamsData), { id: '123'})); AjaxHelpers.expectJsonRequest(requests, requestMethod(), teamsUrl, teamsData);
AjaxHelpers.respondWithJson(requests, _.extend(_.extend({}, teamsData), teamAction === 'create' ? {id: '123'} : {}));
expect(teamEditView.$('.create-team.wrapper-msg .copy').text().trim().length).toBe(0); expect(teamEditView.$('.create-team.wrapper-msg .copy').text().trim().length).toBe(0);
expect(Backbone.history.navigate.calls[0].args).toContain('teams/awesomeness/123'); expect(Backbone.history.navigate.calls[0].args).toContain(expectedUrl);
}); };
var assertValidationMessagesWhenFieldsEmpty = function(that) {
var requests = AjaxHelpers.requests(that),
teamEditView = createEditTeamView();
it('shows validation error message when field is empty', function () {
var requests = AjaxHelpers.requests(this),
teamEditView = createTeamEditView();
verifyValidation(requests, teamEditView, [ verifyValidation(requests, teamEditView, [
['.u-field-name input', 'Name', 'success'], ['.u-field-name input', 'Name', 'success'],
['.u-field-textarea textarea', '', 'error'] ['.u-field-textarea textarea', '', 'error']
]); ]);
teamEditView.render(); teamEditView.render();
verifyValidation(requests, teamEditView, [ verifyValidation(requests, teamEditView, [
['.u-field-name input', '', 'error'], ['.u-field-name input', '', 'error'],
...@@ -120,13 +165,13 @@ define([ ...@@ -120,13 +165,13 @@ define([
['.u-field-name input', '', 'error'], ['.u-field-name input', '', 'error'],
['.u-field-textarea textarea', '', 'error'] ['.u-field-textarea textarea', '', 'error']
]); ]);
}); };
it('shows validation error message when field value length exceeded the limit', function () { var assertValidationMessagesWhenInvalidData = function(that) {
var requests = AjaxHelpers.requests(this), var requests = AjaxHelpers.requests(that),
teamEditView = createTeamEditView(), teamEditView = createEditTeamView(),
teamName = new Array(500 + 1).join( '$'), teamName = new Array(500 + 1).join('$'),
teamDescription = new Array(500 + 1).join( '$' ); teamDescription = new Array(500 + 1).join('$');
verifyValidation(requests, teamEditView, [ verifyValidation(requests, teamEditView, [
['.u-field-name input', teamName, 'error'], ['.u-field-name input', teamName, 'error'],
...@@ -142,48 +187,114 @@ define([ ...@@ -142,48 +187,114 @@ define([
['.u-field-name input', teamName, 'error'], ['.u-field-name input', teamName, 'error'],
['.u-field-textarea textarea', teamDescription, 'error'] ['.u-field-textarea textarea', teamDescription, 'error']
]); ]);
}); };
it("shows an error message for HTTP 500", function () { var assertShowMessageOnError = function(that, teamsData, teamsUrl, errorCode) {
var teamEditView = createTeamEditView(), var teamEditView = createEditTeamView(),
requests = AjaxHelpers.requests(this); requests = AjaxHelpers.requests(that);
teamEditView.$('.u-field-name input').val(teamsData.name); teamEditView.$('.u-field-name input').val(teamsData.name);
teamEditView.$('.u-field-textarea textarea').val(teamsData.description); teamEditView.$('.u-field-textarea textarea').val(teamsData.description);
teamEditView.$('.create-team.form-actions .action-primary').click(); teamEditView.$('.create-team.form-actions .action-primary').click();
if (teamAction === 'create') {
teamsData.country = ''; teamsData.country = '';
teamsData.language = ''; teamsData.language = '';
AjaxHelpers.expectJsonRequest(requests, 'POST', teamsUrl, teamsData); }
AjaxHelpers.respondWithError(requests); AjaxHelpers.expectJsonRequest(requests, requestMethod(), teamsUrl, teamsData);
if (errorCode < 500) {
AjaxHelpers.respondWithError(
requests,
errorCode,
{'user_message': 'User message', 'developer_message': 'Developer message'}
);
expect(teamEditView.$('.wrapper-msg .copy').text().trim()).toBe("User message");
} else {
AjaxHelpers.respondWithError(requests);
expect(teamEditView.$('.wrapper-msg .copy').text().trim()).toBe("An error occurred. Please try again."); expect(teamEditView.$('.wrapper-msg .copy').text().trim()).toBe("An error occurred. Please try again.");
}
};
var assertRedirectsToCorrectUrlOnCancel = function(expectedUrl) {
var teamEditView = createEditTeamView();
teamEditView.$('.create-team.form-actions .action-cancel').click();
expect(Backbone.history.navigate.calls[0].args).toContain(expectedUrl);
};
describe('NewTeam', function () {
beforeEach(function() {
teamAction = 'create';
});
it('can render itself correctly', function () {
assertFormRendersCorrectly();
});
it('can create a team', function () {
assertTeamCreateUpdateInfo(this, createTeamData, teamsUrl, 'teams/awesomeness/123');
});
it('shows validation error message when field is empty', function () {
assertValidationMessagesWhenFieldsEmpty(this);
});
it('shows validation error message when field value length exceeded the limit', function () {
assertValidationMessagesWhenInvalidData(this);
});
it("shows an error message for HTTP 500", function () {
assertShowMessageOnError(this, createTeamData, teamsUrl, 500);
}); });
it("shows correct error message when server returns an error", function () { it("shows correct error message when server returns an error", function () {
var requests = AjaxHelpers.requests(this), assertShowMessageOnError(this, createTeamData, teamsUrl, 400);
teamEditView = createTeamEditView(); });
teamEditView.$('.u-field-name input').val(teamsData.name); it("changes route on cancel click", function () {
teamEditView.$('.u-field-textarea textarea').val(teamsData.description); assertRedirectsToCorrectUrlOnCancel('topics/awesomeness');
});
});
teamEditView.$('.create-team.form-actions .action-primary').click(); describe('EditTeam', function () {
teamsData.country = '';
teamsData.language = '';
AjaxHelpers.expectJsonRequest(requests, 'POST', teamsUrl, teamsData);
AjaxHelpers.respondWithError(
requests,
400,
{'user_message': 'User message', 'developer_message': 'Developer message'}
);
expect(teamEditView.$('.wrapper-msg .copy').text().trim()).toBe("User message"); beforeEach(function() {
teamAction = 'edit';
});
it('can render itself correctly', function () {
assertFormRendersCorrectly();
});
it('can edit a team', function () {
var copyTeamsData = _.clone(editTeamData);
copyTeamsData.country = 'CA';
copyTeamsData.language = 'fr';
assertTeamCreateUpdateInfo(this, copyTeamsData, teamsUrl + editTeamID + '?expand=user', 'teams/awesomeness/' + editTeamID);
});
it('shows validation error message when field is empty', function () {
assertValidationMessagesWhenFieldsEmpty(this);
});
it('shows validation error message when field value length exceeded the limit', function () {
assertValidationMessagesWhenInvalidData(this);
});
it("shows an error message for HTTP 500", function () {
assertShowMessageOnError(this, editTeamData, teamsUrl + editTeamID + '?expand=user', 500);
});
it("shows correct error message when server returns an error", function () {
assertShowMessageOnError(this, editTeamData, teamsUrl + editTeamID + '?expand=user', 400);
}); });
it("changes route on cancel click", function () { it("changes route on cancel click", function () {
var teamEditView = createTeamEditView(); assertRedirectsToCorrectUrlOnCancel('teams/awesomeness/' + editTeamID);
teamEditView.$('.create-team.form-actions .action-cancel').click(); });
expect(Backbone.history.navigate.calls[0].args).toContain('topics/awesomeness');
}); });
}); });
}); });
define([ define([
'backbone', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/models/team', 'backbone', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/models/team',
'teams/js/views/team_join', 'teams/js/spec_helpers/team_spec_helpers' 'teams/js/views/team_profile_header_actions', 'teams/js/spec_helpers/team_spec_helpers'
], function (Backbone, _, AjaxHelpers, TeamModel, TeamJoinView, TeamSpecHelpers) { ], function (Backbone, _, AjaxHelpers, TeamModel, TeamProfileHeaderActionsView, TeamSpecHelpers) {
'use strict'; 'use strict';
describe('TeamJoinView', function () {
describe('TeamProfileHeaderActionsView', function () {
var createTeamsUrl, var createTeamsUrl,
createTeamModelData, createTeamModelData,
createMembershipData, createMembershipData,
createJoinView, createHeaderActionsView,
verifyErrorMessage, verifyErrorMessage,
ACCOUNTS_API_URL = '/api/user/v1/accounts/', ACCOUNTS_API_URL = '/api/user/v1/accounts/',
TEAMS_URL = '/api/team/v0/teams/', TEAMS_URL = '/api/team/v0/teams/',
TEAMS_MEMBERSHIP_URL = '/api/team/v0/team_membership/'; TEAMS_MEMBERSHIP_URL = '/api/team/v0/team_membership/';
beforeEach(function () {
setFixtures(
'<div class="teams-content"><div class="msg-content"><div class="copy"></div></div><div class="header-action-view"></div></div>'
);
});
verifyErrorMessage = function (requests, errorMessage, expectedMessage, joinTeam) {
var view = createJoinView(1, 'ma', createTeamModelData('teamA', 'teamAlpha', []));
if (joinTeam) {
// if we want the error to return when user try to join team, respond with no membership
AjaxHelpers.respondWithJson(requests, {"count": 0});
view.$('.action.action-primary').click();
}
AjaxHelpers.respondWithTextError(requests, 400, errorMessage);
expect($('.msg-content .copy').text().trim()).toBe(expectedMessage);
};
createTeamsUrl = function (teamId) { createTeamsUrl = function (teamId) {
return TEAMS_URL + teamId + '?expand=user'; return TEAMS_URL + teamId + '?expand=user';
}; };
...@@ -38,10 +22,31 @@ define([ ...@@ -38,10 +22,31 @@ define([
return { return {
id: teamId, id: teamId,
name: teamName, name: teamName,
membership: membership membership: membership,
url: createTeamsUrl(teamId)
}; };
}; };
createHeaderActionsView = function(maxTeamSize, currentUsername, teamModelData, showEditButton) {
var teamId = 'teamA';
var model = new TeamModel(teamModelData, { parse: true });
return new TeamProfileHeaderActionsView(
{
courseID: TeamSpecHelpers.testCourseID,
teamEvents: TeamSpecHelpers.teamEvents,
model: model,
teamsUrl: createTeamsUrl(teamId),
maxTeamSize: maxTeamSize,
currentUsername: currentUsername,
teamMembershipsUrl: TEAMS_MEMBERSHIP_URL,
topicID: '',
showEditButton: showEditButton
}
).render();
};
createMembershipData = function (username) { createMembershipData = function (username) {
return [ return [
{ {
...@@ -53,29 +58,28 @@ define([ ...@@ -53,29 +58,28 @@ define([
]; ];
}; };
createJoinView = function(maxTeamSize, currentUsername, teamModelData, teamId) { describe('JoinButton', function () {
teamId = teamId || 'teamA';
var model = new TeamModel(teamModelData, { parse: true }); beforeEach(function () {
model.url = createTeamsUrl(teamId); setFixtures(
'<div class="teams-content"><div class="msg-content"><div class="copy"></div></div><div class="header-action-view"></div></div>'
);
});
var teamJoinView = new TeamJoinView( verifyErrorMessage = function (requests, errorMessage, expectedMessage, joinTeam) {
{ var view = createHeaderActionsView(1, 'ma', createTeamModelData('teamA', 'teamAlpha', []));
courseID: TeamSpecHelpers.testCourseID, if (joinTeam) {
teamEvents: TeamSpecHelpers.teamEvents, // if we want the error to return when user try to join team, respond with no membership
model: model, AjaxHelpers.respondWithJson(requests, {"count": 0});
teamsUrl: createTeamsUrl(teamId), view.$('.action.action-primary').click();
maxTeamSize: maxTeamSize,
currentUsername: currentUsername,
teamMembershipsUrl: TEAMS_MEMBERSHIP_URL
} }
); AjaxHelpers.respondWithTextError(requests, 400, errorMessage);
return teamJoinView.render(); expect($('.msg-content .copy').text().trim()).toBe(expectedMessage);
}; };
it('can render itself', function () { it('can render itself', function () {
var teamModelData = createTeamModelData('teamA', 'teamAlpha', createMembershipData('ma')); var teamModelData = createTeamModelData('teamA', 'teamAlpha', createMembershipData('ma'));
var view = createJoinView(1, 'ma', teamModelData); var view = createHeaderActionsView(1, 'ma', teamModelData);
expect(view.$('.join-team').length).toEqual(1); expect(view.$('.join-team').length).toEqual(1);
}); });
...@@ -86,7 +90,7 @@ define([ ...@@ -86,7 +90,7 @@ define([
var teamId = 'teamA'; var teamId = 'teamA';
var teamName = 'teamAlpha'; var teamName = 'teamAlpha';
var teamModelData = createTeamModelData(teamId, teamName, []); var teamModelData = createTeamModelData(teamId, teamName, []);
var view = createJoinView(1, currentUsername, teamModelData); var view = createHeaderActionsView(1, currentUsername, teamModelData);
// a get request will be sent to get user membership info // a get request will be sent to get user membership info
// because current user is not member of current team // because current user is not member of current team
...@@ -131,7 +135,7 @@ define([ ...@@ -131,7 +135,7 @@ define([
it('shows already member message', function () { it('shows already member message', function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this);
var currentUsername = 'ma1'; var currentUsername = 'ma1';
var view = createJoinView(1, currentUsername, createTeamModelData('teamA', 'teamAlpha', [])); var view = createHeaderActionsView(1, currentUsername, createTeamModelData('teamA', 'teamAlpha', []));
// a get request will be sent to get user membership info // a get request will be sent to get user membership info
// because current user is not member of current team // because current user is not member of current team
...@@ -151,7 +155,7 @@ define([ ...@@ -151,7 +155,7 @@ define([
it('shows team full message', function () { it('shows team full message', function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this);
var view = createJoinView( var view = createHeaderActionsView(
1, 1,
'ma1', 'ma1',
createTeamModelData('teamA', 'teamAlpha', createMembershipData('ma')) createTeamModelData('teamA', 'teamAlpha', createMembershipData('ma'))
...@@ -215,4 +219,36 @@ define([ ...@@ -215,4 +219,36 @@ define([
); );
}); });
}); });
describe('EditButton', function() {
var teamModelData,
view,
createAndAssertView;
createAndAssertView = function(showEditButton) {
teamModelData = createTeamModelData('aveA', 'avengers', createMembershipData('ma'));
view = createHeaderActionsView(1, 'ma', teamModelData, showEditButton);
expect(view.$('.action-edit-team').length).toEqual(showEditButton ? 1 : 0);
};
it('renders when option showEditButton is true', function () {
createAndAssertView(true);
});
it('does not render when option showEditButton is false', function () {
createAndAssertView(false);
});
it("can navigate to correct url", function () {
spyOn(Backbone.history, 'navigate');
createAndAssertView(true);
var editButton = view.$('.action-edit-team');
expect(editButton.length).toEqual(1);
$(editButton).click();
expect(Backbone.history.navigate.calls[0].args[0]).toContain('/edit-team');
});
});
});
}); });
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
maxTeamDescriptionLength: 300, maxTeamDescriptionLength: 300,
events: { events: {
'click .action-primary': 'createTeam', 'click .action-primary': 'createOrUpdateTeam',
'submit form': 'createTeam', 'submit form': 'createOrUpdateTeam',
'click .action-cancel': 'goBackToTopic' 'click .action-cancel': 'cancelAndGoBack'
}, },
initialize: function(options) { initialize: function(options) {
...@@ -27,12 +27,20 @@ ...@@ -27,12 +27,20 @@
this.teamsUrl = options.teamParams.teamsUrl; this.teamsUrl = options.teamParams.teamsUrl;
this.languages = options.teamParams.languages; this.languages = options.teamParams.languages;
this.countries = options.teamParams.countries; this.countries = options.teamParams.countries;
this.primaryButtonTitle = options.primaryButtonTitle || 'Submit'; this.teamsDetailUrl = options.teamParams.teamsDetailUrl;
this.action = options.action;
_.bindAll(this, 'goBackToTopic', 'createTeam'); _.bindAll(this, 'cancelAndGoBack', 'createOrUpdateTeam');
if (this.action === 'create') {
this.teamModel = new TeamModel({}); this.teamModel = new TeamModel({});
this.teamModel.url = this.teamsUrl; this.teamModel.url = this.teamsUrl;
this.primaryButtonTitle = 'Create';
} else if(this.action === 'edit' ) {
this.teamModel = options.model;
this.teamModel.url = this.teamsDetailUrl.replace('team_id', options.model.get('id')) + '?expand=user';
this.primaryButtonTitle = 'Update';
}
this.teamNameField = new FieldViews.TextFieldView({ this.teamNameField = new FieldViews.TextFieldView({
model: this.teamModel, model: this.teamModel,
...@@ -74,7 +82,11 @@ ...@@ -74,7 +82,11 @@
}, },
render: function() { render: function() {
this.$el.html(_.template(editTeamTemplate)({primaryButtonTitle: this.primaryButtonTitle})); this.$el.html(_.template(editTeamTemplate) ({
primaryButtonTitle: this.primaryButtonTitle,
action: this.action,
totalMembers: _.isUndefined(this.teamModel) ? 0 : this.teamModel.get('membership').length
}));
this.set(this.teamNameField, '.team-required-fields'); this.set(this.teamNameField, '.team-required-fields');
this.set(this.teamDescriptionField, '.team-required-fields'); this.set(this.teamDescriptionField, '.team-required-fields');
this.set(this.teamLanguageField, '.team-optional-fields'); this.set(this.teamLanguageField, '.team-optional-fields');
...@@ -91,31 +103,39 @@ ...@@ -91,31 +103,39 @@
} }
}, },
createTeam: function (event) { createOrUpdateTeam: function (event) {
event.preventDefault(); event.preventDefault();
var view = this, var view = this,
teamLanguage = this.teamLanguageField.fieldValue(), teamLanguage = this.teamLanguageField.fieldValue(),
teamCountry = this.teamCountryField.fieldValue(); teamCountry = this.teamCountryField.fieldValue(),
data = {
var data = {
course_id: this.courseID,
topic_id: this.topicID,
name: this.teamNameField.fieldValue(), name: this.teamNameField.fieldValue(),
description: this.teamDescriptionField.fieldValue(), description: this.teamDescriptionField.fieldValue(),
language: _.isNull(teamLanguage) ? '' : teamLanguage, language: _.isNull(teamLanguage) ? '' : teamLanguage,
country: _.isNull(teamCountry) ? '' : teamCountry country: _.isNull(teamCountry) ? '' : teamCountry
},
saveOptions = {
wait: true
}; };
if (this.action === 'create') {
data.course_id = this.courseID;
data.topic_id = this.topicID;
} else if (this.action === 'edit' ) {
saveOptions.patch = true;
saveOptions.contentType = 'application/merge-patch+json';
}
var validationResult = this.validateTeamData(data); var validationResult = this.validateTeamData(data);
if (validationResult.status === false) { if (validationResult.status === false) {
this.showMessage(validationResult.message, validationResult.srMessage); this.showMessage(validationResult.message, validationResult.srMessage);
return; return;
} }
this.teamModel.save(data, { wait: true }) this.teamModel.save(data, saveOptions)
.done(function(result) { .done(function(result) {
view.teamEvents.trigger('teams:update', { view.teamEvents.trigger('teams:update', {
action: 'create', action: view.action,
team: result team: result
}); });
Backbone.history.navigate( Backbone.history.navigate(
...@@ -186,8 +206,15 @@ ...@@ -186,8 +206,15 @@
} }
}, },
goBackToTopic: function () { cancelAndGoBack: function (event) {
Backbone.history.navigate('topics/' + this.topicID, {trigger: true}); event.preventDefault();
var url;
if (this.action === 'create') {
url = 'topics/' + this.topicID;
} else if (this.action === 'edit' ) {
url = 'teams/' + this.topicID + '/' + this.teamModel.get('id');
}
Backbone.history.navigate(url, {trigger: true});
} }
}); });
}); });
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
'underscore', 'underscore',
'gettext', 'gettext',
'teams/js/views/team_utils', 'teams/js/views/team_utils',
'text!teams/templates/team-join.underscore'], 'text!teams/templates/team-profile-header-actions.underscore'],
function (Backbone, _, gettext, TeamUtils, teamJoinTemplate) { function (Backbone, _, gettext, TeamUtils, teamProfileHeaderActionsTemplate) {
return Backbone.View.extend({ return Backbone.View.extend({
errorMessage: gettext("An error occurred. Try again."), errorMessage: gettext("An error occurred. Try again."),
...@@ -14,31 +14,34 @@ ...@@ -14,31 +14,34 @@
teamFullMessage: gettext("This team is full."), teamFullMessage: gettext("This team is full."),
events: { events: {
"click .action-primary": "joinTeam" "click .action-primary": "joinTeam",
"click .action-edit-team": "editTeam"
}, },
initialize: function(options) { initialize: function(options) {
this.teamEvents = options.teamEvents; this.teamEvents = options.teamEvents;
this.template = _.template(teamJoinTemplate); this.template = _.template(teamProfileHeaderActionsTemplate);
this.courseID = options.courseID; this.courseID = options.courseID;
this.maxTeamSize = options.maxTeamSize; this.maxTeamSize = options.maxTeamSize;
this.currentUsername = options.currentUsername; this.currentUsername = options.currentUsername;
this.teamMembershipsUrl = options.teamMembershipsUrl; this.teamMembershipsUrl = options.teamMembershipsUrl;
_.bindAll(this, 'render', 'joinTeam', 'getUserTeamInfo'); this.showEditButton = options.showEditButton;
this.topicID = options.topicID;
_.bindAll(this, 'render', 'joinTeam','editTeam', 'getUserTeamInfo');
this.listenTo(this.model, "change", this.render); this.listenTo(this.model, "change", this.render);
}, },
render: function() { render: function() {
var view = this, var view = this,
message, message,
showButton, showJoinButton,
teamHasSpace; teamHasSpace;
this.getUserTeamInfo(this.currentUsername, view.maxTeamSize).done(function (info) { this.getUserTeamInfo(this.currentUsername, view.maxTeamSize).done(function (info) {
teamHasSpace = info.teamHasSpace; teamHasSpace = info.teamHasSpace;
// if user is the member of current team then we wouldn't show anything // if user is the member of current team then we wouldn't show anything
if (!info.memberOfCurrentTeam) { if (!info.memberOfCurrentTeam) {
showButton = !info.alreadyMember && teamHasSpace; showJoinButton = !info.alreadyMember && teamHasSpace;
if (info.alreadyMember) { if (info.alreadyMember) {
message = info.memberOfCurrentTeam ? '' : view.alreadyMemberMessage; message = info.memberOfCurrentTeam ? '' : view.alreadyMemberMessage;
...@@ -47,7 +50,11 @@ ...@@ -47,7 +50,11 @@
} }
} }
view.$el.html(view.template({showButton: showButton, message: message})); view.$el.html(view.template({
showJoinButton: showJoinButton,
message: message,
showEditButton: view.showEditButton
}));
}); });
return view; return view;
}, },
...@@ -108,6 +115,10 @@ ...@@ -108,6 +115,10 @@
} }
return deferred.promise(); return deferred.promise();
},
editTeam: function (event) {
event.preventDefault();
Backbone.history.navigate('topics/' + this.topicID + '/' + this.model.get('id') +'/edit-team', {trigger: true});
} }
}); });
}); });
......
...@@ -17,12 +17,12 @@ ...@@ -17,12 +17,12 @@
'teams/js/views/my_teams', 'teams/js/views/my_teams',
'teams/js/views/topic_teams', 'teams/js/views/topic_teams',
'teams/js/views/edit_team', 'teams/js/views/edit_team',
'teams/js/views/team_join', 'teams/js/views/team_profile_header_actions',
'text!teams/templates/teams_tab.underscore'], 'text!teams/templates/teams_tab.underscore'],
function (Backbone, _, gettext, HeaderView, HeaderModel, TabbedView, function (Backbone, _, gettext, HeaderView, HeaderModel, TabbedView,
TopicModel, TopicCollection, TeamModel, TeamCollection, TeamMembershipCollection, TopicModel, TopicCollection, TeamModel, TeamCollection, TeamMembershipCollection,
TopicsView, TeamProfileView, MyTeamsView, TopicTeamsView, TeamEditView, TopicsView, TeamProfileView, MyTeamsView, TopicTeamsView, TeamEditView,
TeamJoinView, teamsTemplate) { TeamProfileHeaderActionsView, teamsTemplate) {
var TeamsHeaderModel = HeaderModel.extend({ var TeamsHeaderModel = HeaderModel.extend({
initialize: function (attributes) { initialize: function (attributes) {
_.extend(this.defaults, {nav_aria_label: gettext('teams')}); _.extend(this.defaults, {nav_aria_label: gettext('teams')});
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
this.topics = options.topics; this.topics = options.topics;
this.topicUrl = options.topicUrl; this.topicUrl = options.topicUrl;
this.teamsUrl = options.teamsUrl; this.teamsUrl = options.teamsUrl;
this.teamsDetailUrl = options.teamsDetailUrl;
this.teamMembershipsUrl = options.teamMembershipsUrl; this.teamMembershipsUrl = options.teamMembershipsUrl;
this.teamMembershipDetailUrl = options.teamMembershipDetailUrl; this.teamMembershipDetailUrl = options.teamMembershipDetailUrl;
this.maxTeamSize = options.maxTeamSize; this.maxTeamSize = options.maxTeamSize;
...@@ -74,6 +75,7 @@ ...@@ -74,6 +75,7 @@
}, this)], }, this)],
['topics/:topic_id(/)', _.bind(this.browseTopic, this)], ['topics/:topic_id(/)', _.bind(this.browseTopic, this)],
['topics/:topic_id/create-team(/)', _.bind(this.newTeam, this)], ['topics/:topic_id/create-team(/)', _.bind(this.newTeam, this)],
['topics/:topic_id/:team_id/edit-team(/)', _.bind(this.editTeam, this)],
['teams/:topic_id/:team_id(/)', _.bind(this.browseTeam, this)], ['teams/:topic_id/:team_id(/)', _.bind(this.browseTeam, this)],
[new RegExp('^(browse)\/?$'), _.bind(this.goToTab, this)], [new RegExp('^(browse)\/?$'), _.bind(this.goToTab, this)],
[new RegExp('^(my-teams)\/?$'), _.bind(this.goToTab, this)] [new RegExp('^(my-teams)\/?$'), _.bind(this.goToTab, this)]
...@@ -208,10 +210,9 @@ ...@@ -208,10 +210,9 @@
}) })
}), }),
main: new TeamEditView({ main: new TeamEditView({
action: 'create',
teamEvents: self.teamEvents, teamEvents: self.teamEvents,
tagName: 'create-new-team', teamParams: teamsView.main.teamParams
teamParams: teamsView.main.teamParams,
primaryButtonTitle: 'Create'
}) })
}); });
self.render(); self.render();
...@@ -219,6 +220,44 @@ ...@@ -219,6 +220,44 @@
}, },
/** /**
* Render the edit team form.
*/
editTeam: function (topicID, teamID) {
var self = this,
editViewWithHeader;
this.getTopic(topicID).done(function (topic) {
self.getTeam(teamID, false).done(function(team) {
var view = new TeamEditView({
action: 'edit',
teamEvents: self.teamEvents,
teamParams: {
courseID: self.courseID,
topicID: topic.get('id'),
teamsUrl: self.teamsUrl,
topicName: topic.get('name'),
languages: self.languages,
countries: self.countries,
teamsDetailUrl: self.teamsDetailUrl
},
model: team
});
editViewWithHeader = self.createViewWithHeader({
mainView: view,
subject: {
name: gettext("Edit Team"),
description: gettext("If you make significant changes, make sure you notify members of the team before making these changes.")
},
parentTeam: team,
parentTopic: topic
}
);
self.mainView = editViewWithHeader;
self.render();
});
});
},
/**
* Return a promise for the TeamsView for the given topic ID. * Return a promise for the TeamsView for the given topic ID.
*/ */
getTeamsView: function (topicID) { getTeamsView: function (topicID) {
...@@ -227,7 +266,7 @@ ...@@ -227,7 +266,7 @@
var self = this, var self = this,
router = this.router, router = this.router,
deferred = $.Deferred(); deferred = $.Deferred();
if (this.teamsCollection && this.teamsCollection.topic_id === topicID) { if (this.teamsCollection && this.teamsCollection.topic_id === topicID && this.teamsView) {
deferred.resolve(this.teamsView); deferred.resolve(this.teamsView);
} else { } else {
this.getTopic(topicID) this.getTopic(topicID)
...@@ -254,7 +293,8 @@ ...@@ -254,7 +293,8 @@
teamsUrl: self.teamsUrl, teamsUrl: self.teamsUrl,
topicName: topic.get('name'), topicName: topic.get('name'),
languages: self.languages, languages: self.languages,
countries: self.countries countries: self.countries,
teamsDetailUrl: self.teamsDetailUrl
} }
}); });
deferred.resolve( deferred.resolve(
...@@ -311,14 +351,17 @@ ...@@ -311,14 +351,17 @@
teamMembershipDetailUrl: self.teamMembershipDetailUrl, teamMembershipDetailUrl: self.teamMembershipDetailUrl,
setFocusToHeaderFunc: self.setFocusToHeader setFocusToHeaderFunc: self.setFocusToHeader
}); });
var teamJoinView = new TeamJoinView({
var TeamProfileActionsView = new TeamProfileHeaderActionsView({
teamEvents: self.teamEvents, teamEvents: self.teamEvents,
courseID: courseID, courseID: courseID,
model: team, model: team,
teamsUrl: self.teamsUrl, teamsUrl: self.teamsUrl,
maxTeamSize: self.maxTeamSize, maxTeamSize: self.maxTeamSize,
currentUsername: self.userInfo.username, currentUsername: self.userInfo.username,
teamMembershipsUrl: self.teamMembershipsUrl teamMembershipsUrl: self.teamMembershipsUrl,
topicID: topicID,
showEditButton: self.userInfo.privileged || self.userInfo.staff
}); });
deferred.resolve( deferred.resolve(
self.createViewWithHeader( self.createViewWithHeader(
...@@ -326,7 +369,7 @@ ...@@ -326,7 +369,7 @@
mainView: view, mainView: view,
subject: team, subject: team,
parentTopic: topic, parentTopic: topic,
headerActionsView: teamJoinView headerActionsView: TeamProfileActionsView
} }
) )
); );
...@@ -337,7 +380,8 @@ ...@@ -337,7 +380,8 @@
createViewWithHeader: function (options) { createViewWithHeader: function (options) {
var router = this.router, var router = this.router,
breadcrumbs, headerView; breadcrumbs, headerView,
viewDescription, viewTitle;
breadcrumbs = [{ breadcrumbs = [{
title: gettext('All Topics'), title: gettext('All Topics'),
url: '#browse' url: '#browse'
...@@ -348,10 +392,25 @@ ...@@ -348,10 +392,25 @@
url: '#topics/' + options.parentTopic.id url: '#topics/' + options.parentTopic.id
}); });
} }
if (options.parentTeam) {
breadcrumbs.push({
title: options.parentTeam.get('name'),
url: '#teams/' + options.parentTopic.id + '/' + options.parentTeam.id
});
}
if (options.subject instanceof Backbone.Model) {
viewDescription = options.subject.get('description');
viewTitle = options.subject.get('name');
} else if (options.subject) {
viewDescription = options.subject.description;
viewTitle = options.subject.name;
}
headerView = new HeaderView({ headerView = new HeaderView({
model: new TeamsHeaderModel({ model: new TeamsHeaderModel({
description: options.subject.get('description'), description: viewDescription,
title: options.subject.get('name'), title: viewTitle,
breadcrumbs: breadcrumbs breadcrumbs: breadcrumbs
}), }),
headerActionsView: options.headerActionsView, headerActionsView: options.headerActionsView,
......
<form> <form>
<div class="create-team wrapper-msg is-incontext urgency-low warning is-hidden" tabindex="-1"> <div class="create-team wrapper-msg is-incontext urgency-low error is-hidden" tabindex="-1">
<div class="msg"> <div class="msg">
<div class="msg-content"> <div class="msg-content">
<h3 class="title"><%- gettext("Your team could not be created!") %></h3> <h3 class="title">
<% if (action === 'create') { %>
<%- gettext("Your team could not be created.") %>
<% } else if (action === 'edit') { %>
<%- gettext("Your team could not be updated.") %>
<% } %>
</h3>
<span class="screen-reader-message sr"></span> <span class="screen-reader-message sr"></span>
<div class="copy"> <div class="copy">
<p></p> <p></p>
...@@ -11,15 +17,16 @@ ...@@ -11,15 +17,16 @@
</div> </div>
</div> </div>
<div class="form-instructions create-team-instructions"> <% if (action === 'create') { %>
<div class="form-instructions create-team-instructions">
<p class="copy"> <p class="copy">
<%- gettext("Enter information to describe your team. You cannot change these details after you create the team.") %></p> <%- gettext("Enter information to describe your team. You cannot change these details after you create the team.") %></p>
</div> </div>
<% } %>
<div class="team-edit-fields"> <div class="team-edit-fields">
<div class="team-required-fields"> <div class="team-required-fields">
</div> </div>
<div class="team-optional-fields"> <div class="team-optional-fields">
<fieldset> <fieldset>
<div class="u-field u-field-optional_description"> <div class="u-field u-field-optional_description">
...@@ -38,7 +45,7 @@ ...@@ -38,7 +45,7 @@
<button class="action action-primary"> <button class="action action-primary">
<%= <%=
interpolate_text( interpolate_text(
_.escape(gettext("{primaryButtonTitle} {span_start}a new team{span_end}")), _.escape(gettext("{primaryButtonTitle} {span_start}a team{span_end}")),
{ {
'primaryButtonTitle': primaryButtonTitle, 'span_start': '<span class="sr">', 'span_end': '</span>' 'primaryButtonTitle': primaryButtonTitle, 'span_start': '<span class="sr">', 'span_end': '</span>'
} }
...@@ -48,9 +55,10 @@ ...@@ -48,9 +55,10 @@
<button class="action action-cancel"> <button class="action action-cancel">
<%= <%=
interpolate_text( interpolate_text(
_.escape(gettext("Cancel {span_start}a new team{span_end}")), _.escape(gettext("Cancel {span_start} {action} team {span_end}")),
{ {
'span_start': '<span class="sr">', 'span_end': '</span>' 'span_start': '<span class="sr">', 'span_end': '</span>',
'action': action === 'create' ? 'creating' : 'updating'
} }
) )
%> %>
......
<div class="join-team form-actions"> <div class="join-team form-actions">
<% if (showButton) {%> <% if (showJoinButton) {%>
<button class="action action-primary"> <button class="action action-primary">
<%- gettext("Join Team") %> <%- gettext("Join Team") %>
</button> </button>
<% } else if (message) { %> <% } else if (message) { %>
<p class="join-team-message"><%- message %></p> <p class="join-team-message"><%- message %></p>
<% } %> <% } %>
<% if (showEditButton) { %>
<button class="btn btn-secondary action-edit-team"><%- gettext("Edit Team") %></button>
<% } %>
</div> </div>
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
<% if (isMember) { %> <% if (isMember) { %>
<div class="leave-team"> <div class="leave-team">
<button class="btn btn-link btn-base btn-secondary leave-team-link"><%- gettext("Leave Team") %></button> <button class="btn btn-link leave-team-link"><%- gettext("Leave Team") %></button>
</div> </div>
<div class="divider-lv1"></div> <div class="divider-lv1"></div>
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
topicUrl: '${ topic_url }', topicUrl: '${ topic_url }',
topicsUrl: '${ topics_url }', topicsUrl: '${ topics_url }',
teamsUrl: '${ teams_url }', teamsUrl: '${ teams_url }',
teamsDetailUrl: '${ teams_detail_url }',
teamMembershipsUrl: '${ team_memberships_url }', teamMembershipsUrl: '${ team_memberships_url }',
teamMembershipDetailUrl: '${ team_membership_detail_url }', teamMembershipDetailUrl: '${ team_membership_detail_url }',
maxTeamSize: ${ course.teams_max_size }, maxTeamSize: ${ course.teams_max_size },
......
...@@ -117,6 +117,7 @@ class TeamsDashboardView(View): ...@@ -117,6 +117,7 @@ class TeamsDashboardView(View):
), ),
"topics_url": reverse('topics_list', request=request), "topics_url": reverse('topics_list', request=request),
"teams_url": reverse('teams_list', request=request), "teams_url": reverse('teams_list', request=request),
"teams_detail_url": reverse('teams_detail', args=['team_id']),
"team_memberships_url": reverse('team_membership_list', request=request), "team_memberships_url": reverse('team_membership_list', request=request),
"team_membership_detail_url": reverse('team_membership_detail', args=['team_id', user.username]), "team_membership_detail_url": reverse('team_membership_detail', args=['team_id', user.username]),
"languages": settings.ALL_LANGUAGES, "languages": settings.ALL_LANGUAGES,
......
...@@ -802,7 +802,7 @@ ...@@ -802,7 +802,7 @@
'lms/include/teams/js/spec/views/topic_card_spec.js', 'lms/include/teams/js/spec/views/topic_card_spec.js',
'lms/include/teams/js/spec/views/topic_teams_spec.js', 'lms/include/teams/js/spec/views/topic_teams_spec.js',
'lms/include/teams/js/spec/views/topics_spec.js', 'lms/include/teams/js/spec/views/topics_spec.js',
'lms/include/teams/js/spec/views/team_join_spec.js' 'lms/include/teams/js/spec/views/team_profile_header_actions_spec.js'
]); ]);
}).call(this, requirejs, define); }).call(this, requirejs, define);
...@@ -404,7 +404,7 @@ ...@@ -404,7 +404,7 @@
} }
} }
.btn-link { .btn-secondary {
@extend %btn-pl-secondary-base; @extend %btn-pl-secondary-base;
background-image: none; background-image: none;
...@@ -416,3 +416,24 @@ ...@@ -416,3 +416,24 @@
color: $link-color; color: $link-color;
} }
} }
.btn-link {
@extend %shame-link-text;
// reset of inherited buttons
border-radius: 0;
border-color: $transparent;
padding: 1px;
background: $transparent;
background-image: none;
@extend %t-action3;
@extend %t-strong;
&:focus,
&:hover {
background-image: none !important;
background-color: $transparent !important;
box-shadow: none !important;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment