diff --git a/Gemfile b/Gemfile
index 61dc001..f223eed 100644
--- a/Gemfile
+++ b/Gemfile
@@ -26,6 +26,7 @@ gem 'redcarpet'
gem 'pygments.rb'
gem "twitter-bootstrap-rails"
+gem 'bootstrap-glyphicons'
gem 'asset_sync'
gem 'unicorn'
gem 'newrelic_rpm'
diff --git a/Gemfile.lock b/Gemfile.lock
index 777fd81..8461318 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -34,6 +34,9 @@ GEM
better_errors (1.0.1)
coderay (>= 1.0.0)
erubis (>= 2.6.6)
+ bootstrap-glyphicons (0.0.1)
+ railties (>= 3.0)
+ sass (>= 3.2)
builder (3.1.4)
cancan (1.6.10)
capistrano (2.15.5)
@@ -265,6 +268,7 @@ PLATFORMS
DEPENDENCIES
asset_sync
better_errors
+ bootstrap-glyphicons
cancan
capistrano
capybara
diff --git a/app/assets/javascripts/meeting_requests.js b/app/assets/javascripts/meeting_requests.js
new file mode 100644
index 0000000..83a7f93
--- /dev/null
+++ b/app/assets/javascripts/meeting_requests.js
@@ -0,0 +1,23 @@
+$(function() {
+ $('.concept-search').click(function() {
+ $(this).toggleClass('badge-success');
+ if ($('.badge-success').length === 0) {
+ $('.request').show();
+ } else {
+ $('#open-requests').children('.request').hide();
+ showRelated(getSelectedConceptNames());
+ }
+ });
+});
+
+function getSelectedConceptNames() {
+ return $('.badge-success').map(function() {
+ return $(this).attr('data-name').toLowerCase();
+ });
+}
+
+function showRelated(tagNames) {
+ tagNames.each(function() {
+ $('[data-' + this + '="true"]').show();
+ });
+}
diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss
index a4324e5..3bb0756 100644
--- a/app/assets/stylesheets/application.css.scss
+++ b/app/assets/stylesheets/application.css.scss
@@ -12,6 +12,8 @@
*= require_tree .
*/
+ @import 'bootstrap/glyphicons';
+
footer {
position: relative;
width: 370px;
diff --git a/app/assets/stylesheets/layouts.css.scss b/app/assets/stylesheets/layouts.css.scss
index 94be697..b300963 100644
--- a/app/assets/stylesheets/layouts.css.scss
+++ b/app/assets/stylesheets/layouts.css.scss
@@ -72,3 +72,28 @@ $mercury: #d1d1d1;
#location-map {
display: none;
}
+
+.request {
+ border: solid;
+ border-color: grey;
+ margin-bottom: 5px;
+ padding: 2px;
+}
+
+.no-left-margin {
+ margin-left: 0px;
+}
+
+.concept-tag {
+ cursor: pointer;
+ &:hover {
+ background-color: blue;
+ }
+}
+
+.concept-search {
+ cursor: pointer;
+ &:hover {
+ background-color: green;
+ }
+}
diff --git a/app/controllers/meeting_requests_controller.rb b/app/controllers/meeting_requests_controller.rb
index d84002b..55a9b10 100644
--- a/app/controllers/meeting_requests_controller.rb
+++ b/app/controllers/meeting_requests_controller.rb
@@ -1,6 +1,7 @@
class MeetingRequestsController < ApplicationController
def new
@meeting_request = MeetingRequest.new(member_uuid: current_user.uuid)
+ @concepts = Concept.all
authorize! :create, @meeting_request
end
@@ -17,6 +18,7 @@ def create
def edit
@meeting_request = MeetingRequest.find(params[:id])
+ @concepts = Concept.all
authorize! :update, @meeting_request
end
@@ -37,6 +39,7 @@ def index
claimed_uuids = current_user.claimed_meeting_requests.map(&:member_uuid)
@open_users = User.fetch_from_uuids(open_uuids)
@claimed_users = User.fetch_from_uuids(claimed_uuids)
+ @concepts = Concept.all
end
def show
@@ -58,6 +61,6 @@ def destroy
private
def meeting_request_params
- params.require(:meeting_request).permit(:title, :content, :contact_info, :member_uuid)
+ params.require(:meeting_request).permit(:title, :content, :contact_info, :member_uuid, :concept_ids => [])
end
end
\ No newline at end of file
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 2103104..e1a4a4d 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -8,6 +8,10 @@ def sponsors
]
end
+ def escape_attribute_name(string)
+ string.gsub(/\W|_/, '-').downcase
+ end
+
class HTMLwithPygments < Redcarpet::Render::HTML
def block_code(code, language)
Pygments.highlight(code, lexer:language)
diff --git a/app/views/meeting_requests/_concept.html.erb b/app/views/meeting_requests/_concept.html.erb
new file mode 100644
index 0000000..e592cdc
--- /dev/null
+++ b/app/views/meeting_requests/_concept.html.erb
@@ -0,0 +1 @@
+
<%= concept.name %>
\ No newline at end of file
diff --git a/app/views/meeting_requests/_mentor_requests_index.html.erb b/app/views/meeting_requests/_mentor_requests_index.html.erb
index a2da7b6..1a8aac1 100644
--- a/app/views/meeting_requests/_mentor_requests_index.html.erb
+++ b/app/views/meeting_requests/_mentor_requests_index.html.erb
@@ -1,17 +1,18 @@
-
-
-
My Claimed Requests
- <%= render 'requests_list', meeting_requests: current_user.claimed_meeting_requests, users: @claimed_users %>
-
-
-
-
-
+
+ My Claimed Requests
+ <%= render 'requests_list', meeting_requests: current_user.claimed_meeting_requests, users: @claimed_users %>
+
+
+
Open Requests
<%= render 'requests_list', meeting_requests: current_user.open_meeting_requests, users: @open_users %>
-
-
-
Concepts
+
+
Concepts
+
Click on a concept to see related requests
+
+ <%= render partial: "concept", collection: @concepts %>
+
-
\ No newline at end of file
+
+
diff --git a/app/views/meeting_requests/_request_form.html.erb b/app/views/meeting_requests/_request_form.html.erb
index c745498..431abd1 100644
--- a/app/views/meeting_requests/_request_form.html.erb
+++ b/app/views/meeting_requests/_request_form.html.erb
@@ -12,16 +12,32 @@
<%= render 'shared/form_errors', object: @meeting_request %>
-
\ No newline at end of file
diff --git a/app/views/meeting_requests/untitled b/app/views/meeting_requests/untitled
new file mode 100644
index 0000000..e69de29
diff --git a/app/views/shared/_concept_tags.html.erb b/app/views/shared/_concept_tags.html.erb
new file mode 100644
index 0000000..0a0f9f6
--- /dev/null
+++ b/app/views/shared/_concept_tags.html.erb
@@ -0,0 +1,7 @@
+<% if object.concepts.any? %>
+
+ <% object.concepts.each do |concept| %>
+ - <%= link_to concept.name, concept_path(concept), class: 'label concept-tag' %>
+ <% end %>
+
+<% end %>
diff --git a/spec/features/request_features_spec.rb b/spec/features/request_features_spec.rb
index 975a024..9cd3d6a 100644
--- a/spec/features/request_features_spec.rb
+++ b/spec/features/request_features_spec.rb
@@ -17,6 +17,17 @@
page.should have_content 'successfully'
end
+ scenario 'a member creates a valid request and tags it with concepts' do
+ concept = FactoryGirl.create(:concept)
+ click_link 'Create a request'
+ fill_in 'meeting_request_title', with: 'need help with rails'
+ fill_in 'meeting_request_content', with: 'understanding the basics'
+ fill_in 'meeting_request_contact_info', with: 'my cell phone for sure'
+ check(concept.name)
+ click_button 'Submit'
+ within('#related-concepts') { page.should have_content concept.name }
+ end
+
scenario 'a member attempts to create an invalid request' do
click_link 'Create a request'
click_button 'Submit'
@@ -47,14 +58,22 @@
scenario 'a member edits a request with valid information' do
click_link 'Edit Request'
- fill_in 'Title', with: 'new request title'
+ fill_in 'meeting_request_title', with: 'new request title'
click_button 'Submit'
page.should have_content 'new request title'
end
+ scenario 'they add a concept tag' do
+ concept = FactoryGirl.create(:concept)
+ click_link 'Edit Request'
+ check(concept.name)
+ click_button 'Submit'
+ within('#related-concepts') { page.should have_content concept.name }
+ end
+
scenario 'a member attempts to edit a request with invalid information' do
click_link 'Edit Request'
- fill_in 'Title', with: ''
+ fill_in 'meeting_request_title', with: ''
click_button 'Submit'
page.should have_content 'error'
end
@@ -191,30 +210,65 @@
@meeting_request4 = FactoryGirl.create(:meeting_request, member_uuid: @user.uuid)
end
- scenario 'a member visits the page' do
- stub_user_fetch_from_uuid
- stub_user_fetch_from_uuids
- stub_application_controller
- visit meeting_requests_path
- page.should_not have_content @meeting_request1.title
- page.should_not have_content @meeting_request2.title
- page.should have_content @meeting_request3.title
- page.should have_content @meeting_request4.title
+ context 'as a member' do
+ scenario 'a member visits the page' do
+ stub_user_fetch_from_uuid
+ stub_user_fetch_from_uuids
+ stub_application_controller
+ visit meeting_requests_path
+ page.should_not have_content @meeting_request1.title
+ page.should_not have_content @meeting_request2.title
+ page.should have_content @meeting_request3.title
+ page.should have_content @meeting_request4.title
+ end
end
- scenario 'a mentor visits the page' do
- @user = new_mentor
- @user2 = new_member
- @meeting_request1.update(mentor_uuid: @user.uuid)
- @meeting_request3.update(mentor_uuid: 'other-mentor-uuid')
- stub_user_fetch_from_uuid
- User.stub(:fetch_from_uuids).and_return({@meeting_request3.member_uuid => @user2, @user.uuid => @user, 'member-uuid' => @user2})
- stub_application_controller
- visit meeting_requests_path
- page.should have_content @meeting_request1.title
- page.should have_content @meeting_request2.title
- page.should_not have_content @meeting_request3.title
- page.should have_content @meeting_request4.title
+ context 'as a mentor' do
+ before do
+ @user = new_mentor
+ @user2 = new_member
+ @meeting_request1.update(mentor_uuid: @user.uuid)
+ @meeting_request3.update(mentor_uuid: 'other-mentor-uuid')
+ stub_user_fetch_from_uuid
+ User.stub(:fetch_from_uuids).and_return({@meeting_request3.member_uuid => @user2, @user.uuid => @user, 'member-uuid' => @user2})
+ stub_application_controller
+ end
+
+ scenario 'a mentor visits the page' do
+ visit meeting_requests_path
+ page.should have_content @meeting_request1.title
+ page.should have_content @meeting_request2.title
+ page.should_not have_content @meeting_request3.title
+ page.should have_content @meeting_request4.title
+ end
+
+ scenario 'they filter requests by concepts', js: true do
+ concept = FactoryGirl.create(:concept)
+ @meeting_request4.concepts << concept
+ visit meeting_requests_path
+ within('.concepts') { find('.concept-search').click }
+ within('#open-requests') { page.should_not have_content @meeting_request2.title }
+ end
+
+ scenario 'they unfilter requests', js: true do
+ concept = FactoryGirl.create(:concept)
+ @meeting_request4.concepts << concept
+ visit meeting_requests_path
+ within('.concepts') { find('.concept-search').click }
+ within('.concepts') { find('.concept-search').click }
+ within('#open-requests') { page.should have_content @meeting_request2.title }
+ end
+
+ scenario 'they filter multiple concepts', js: true do
+ concept = FactoryGirl.create(:concept)
+ concept2 = FactoryGirl.create(:concept, name: 'Javascript')
+ @meeting_request4.concepts << concept
+ @meeting_request3.concepts << concept2
+ visit meeting_requests_path
+ within('.concepts') { find('.concept-search:first-of-type').click }
+ within('.concepts') { find('.concept-search:nth-of-type(2)').click }
+ within('#open-requests') { page.should have_content @meeting_request4.title }
+ end
end
end