diff --git a/Gemfile b/Gemfile index 0ef1dfc..337d6d0 100644 --- a/Gemfile +++ b/Gemfile @@ -19,9 +19,9 @@ gem 'turbolinks' gem 'friendly_id', '~> 5.0.0' # Note: You MUST use 5.0.0 or greater for Rails 4.0+ gem 'acts-as-taggable-on', '~> 3.4' -gem 'rails4-autocomplete' gem 'i18n_country_select' gem 'i18n-country-translations' +gem 'select2-rails' gem 'redcarpet' gem 'bcrypt', '~> 3.1.7' diff --git a/Gemfile.lock b/Gemfile.lock index ba74778..bb3befa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -115,8 +115,6 @@ GEM bundler (>= 1.3.0, < 2.0) railties (= 4.1.6) sprockets-rails (~> 2.0) - rails4-autocomplete (1.1.1) - rails (>= 3.0) railties (4.1.6) actionpack (= 4.1.6) activesupport (= 4.1.6) @@ -146,6 +144,8 @@ GEM sass (~> 3.2.2) sprockets (~> 2.8, < 3.0) sprockets-rails (~> 2.0) + select2-rails (3.5.9.1) + thor (~> 0.14) slop (3.6.0) spring (1.2.0) sprockets (2.12.3) @@ -194,10 +194,10 @@ DEPENDENCIES pg quiet_assets rails (= 4.1.6) - rails4-autocomplete redcarpet rspec-rails sass-rails (~> 4.0.3) + select2-rails spring sqlite3 turbolinks diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 25e6422..2aad3b5 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -15,7 +15,7 @@ //= require jquery-ui/tooltip //= require jquery_ujs //= require tipsy -//= require autocomplete-rails //= require slidebars +//= require select2 //= require turbolinks //= require_tree . diff --git a/app/assets/javascripts/general.js.coffee b/app/assets/javascripts/general.js.coffee index fdb30c1..85101cc 100644 --- a/app/assets/javascripts/general.js.coffee +++ b/app/assets/javascripts/general.js.coffee @@ -1,11 +1,31 @@ -$( "#donation_project_name" ).autocomplete - source: [ "c++", "java", "php", "coldfusion", "javascript", "asp", "ruby" ] - $(document).on "page:change", -> $(".popup").click (event) -> event.preventDefault() window.open $(this).attr("href"), "popupWindow", "width=600,height=600,scrollbars=yes" return + $('#donation_project_attributes_name').select2 + placeholder: 'Project' + ajax: + url: '/projects' + dataType: 'json' + quietMillis: 250, + results: (data, page) -> + return { results: $.map data, (obj) -> {id: obj.name, text: obj.name} } + cache: true + data: (term, page) -> + return { q: term } + # query: (query) -> + # data = {results: [{id: 'Wadus', text: 'Wadus'}, {id: 'Wadus 2', text: 'Wadus 2'}]} + # query.callback data + allowClear: 'true' + createSearchChoice: (term, data) -> + return {id:term, text: term + ' (Add project)'} + createSearchChoicePosition: 'bottom' + $('#donation_project_attributes_name').on "select2-selecting", (e) -> + if e.choice.text.indexOf('(Add project)') > 0 + $('#project_attributes').slideDown() + else + $('#project_attributes').slideUp() $('.tipsit').tipsy({fade: true; gravity: 's'}) my_slidebars = new $.slidebars(); return diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index e1a0ec5..3dcbb6e 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -15,6 +15,7 @@ *= require jquery-ui/autocomplete *= require tipsy *= require slidebars + *= require select2 *= */ @@ -135,9 +136,10 @@ h2 { font-size: 24px; } .main_form { clear: both; margin: 0 0 20px 0;} .track_don_project, .track_don_quantity, .track_don_date { display: inline-block; } -.track_don_project { width: 540px; margin-bottom: 20px; overflow: hidden;} +.track_don_project { width: 540px; overflow: hidden;} .track_don_quantity { width: 90px; margin-right: 10px; } -.track_don_quantity_B { width: 375px; margin-bottom: 20px; float: right; } +.track_don_quantity_B { width: 375px; float: right; } +.main_form .track_don_quantity_B input { width: 90px; margin: 0;} .track_don_quantity_B_option { background: #D5D7A3; margin-bottom: 4px; } .track_don_quantity_B_option .hint { display: inline-block; } .main_form .track_don_quantity_B_option_hint { display: inline-block; width: auto; font-size: 12px; vertical-align: top; padding: 6px 0 0 0;} @@ -147,9 +149,13 @@ h2 { font-size: 24px; } .track_don_quantity input { width: 74px; } .track_don_date input { width: 100%; font-size: 12px;} .track_don_options { margin: 0 0 20px 0; clear: both;} -.hint { font-size: 12px} +.hint { font-size: 12px; margin-bottom: 20px; } #i_want_to_explain_content { display: none; } #i_want_to_explain_content textarea { width: 97%; height: 100px; font-size: 13px; padding-top: 10px; margin: 10px 0;} +#project_attributes { display:none; + input, textarea { width: 96.5%; font-size: 13px; border: 1px dashed $main-color; font-weight:bold;} + textarea { width:99%; padding-top: 10px; height: 100px; } +} .track_don_quantity_B { @@ -258,7 +264,7 @@ hr { height: 1px; border:0; background-color: #D9DAAA; margin: 60px 0px 15px; wi padding: 0; li { - width: 30%; + width: 29%; margin-right: 26px; background-color: $main-color; text-align: center; @@ -320,6 +326,14 @@ hr { height: 1px; border:0; background-color: #D9DAAA; margin: 60px 0px 15px; wi .ui-autocomplete { border: 1px solid red; } +.select2-container { width: 540px; font-size: 22px; font-weight: bold; font-family: Raleway; height: 40px; margin-bottom: 8px !important; + a.select2-choice { line-height: 32px; display: block; height: 35px; border: 1px dashed #7c9200; padding: 4px 6px 0px; + + } +} +.select2-results .select2-highlighted { background: #7c9200 !important; } +.select2-drop-active { border: 1px dashed #7c9200 !important; border-top: none !important; } +.select2-search input[type=text] { font-family: Raleway; font-size: 18px; } #first_donation_pending { padding-top: 1em; padding-bottom: 1em; margin-bottom: 2em; } #footer { text-align: center; font-size: 12px } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2235a9c..5a03941 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -7,7 +7,6 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception include SessionsHelper include ProjectsHelper - include DonationsHelper before_action :set_locale @@ -27,7 +26,25 @@ def extract_locale_from_subdomain def set_new_donation new_donation_currency = logged_in? ? current_user.currency : 'EUR' - @donation = Donation.new currency: new_donation_currency + @donation = Donation.new currency: new_donation_currency, + project: (@project.nil? ? Project.new : @project) end + def donation_save(donation_params) + @donation = current_user.donations.build(donation_params) + if donation_params[:project_id] and project = Project.find_by(id: donation_params[:project_id]) + @donation.project = project + end + if @donation.save + redirect_to donation_path(@donation, :share_links => true) + else + render 'new' + end + end + + def cookie_donation + JSON.parse(cookies[:donation]).with_indifferent_access + end + helper_method :cookie_donation + end diff --git a/app/controllers/donations_controller.rb b/app/controllers/donations_controller.rb index 1204942..2edce93 100644 --- a/app/controllers/donations_controller.rb +++ b/app/controllers/donations_controller.rb @@ -20,8 +20,7 @@ def show def create unless logged_in? save_donation_to_cookie(donation_params) - cookie_donation - redirect_to root_url + redirect_to signup_path else donation_save(donation_params) if cookies[:donation] @@ -33,20 +32,12 @@ def create private def donation_params - params.require(:donation).permit(:quantity, :currency, :date, :project_id, :comment, :quantity_privacy) + params.require(:donation).permit(:quantity, :currency, :date, :comment, :quantity_privacy, + :project_id, project_attributes: [:name, :description, :url, :id]) end def save_donation_to_cookie(donation_params) - cookies[:donation] = { - :quantity => donation_params[:quantity], - :currency => donation_params[:currency], - :date => donation_params[:date], - #:tag_list => donation_params[:tag_list], - :project_id => donation_params[:project_id], - :comment => donation_params[:comment], - :quantity_privacy => donation_params[:quantity_privacy], - :user_id => donation_params[:user_id] - }.to_json + cookies[:donation] = donation_params.to_json end end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 2675c94..d711147 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,10 +1,12 @@ class ProjectsController < ApplicationController before_filter :set_new_donation, only: :show - autocomplete :project, :name - def index - @projects = Project.all + @projects = Project.search(params[:q]) + respond_to do |format| + format.html + format.json { render json: @projects} + end end def show @@ -16,7 +18,6 @@ def new end def create - # render plain: params[:project].inspect @project = Project.new(project_params) if @project.save flash[:success] = "Project created. Share the word and start donation-saving!" @@ -27,7 +28,6 @@ def create end private - def project_params params.require(:project).permit(:name, :description, :url, :twitter) end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index ac0e55f..6ad4966 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -10,8 +10,6 @@ def index def show @user = User.find(params[:id]) - @donations = @user.donations - @projects = @user.projects end def new @@ -36,14 +34,7 @@ def create @user = User.new(user_params) if @user.save log_in @user - if cookies[:donation] - donation_save(cookie_donation) - flash[:success] = "Hey, donation tracked, and you have your profile ready to keep tracking donations! Now this is a great day." - cookies.delete(:donation) - else - flash[:success] = "Welcome to TrackDons. Hope you track a lot of dons!" - redirect_to @user - end + save_pending_donations || redirect_to(@user, success: "Welcome to TrackDons. Hope you track a lot of dons!") else render 'new' end @@ -77,4 +68,12 @@ def admin_user redirect_to(root_url) unless current_user.admin? end + def save_pending_donations + if cookies[:donation] + donation_save(cookie_donation) + flash[:success] = "Hey, donation tracked, and you have your profile ready to keep tracking donations! Now this is a great day." + cookies.delete(:donation) + end + end + end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 1600618..ae955e0 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -38,9 +38,14 @@ def markdown(text) markdown.render(text).html_safe end - + private + def language_name_for(locale) I18n.backend.send(:translations)[locale][:language_name] end + + def current_user_profile? + @user == current_user + end end diff --git a/app/helpers/donations_helper.rb b/app/helpers/donations_helper.rb index f3f5b1b..ed92220 100644 --- a/app/helpers/donations_helper.rb +++ b/app/helpers/donations_helper.rb @@ -1,22 +1,9 @@ module DonationsHelper - def donation_save(donation_params) - @donation = current_user.donations.build(donation_params) - if @donation.save - redirect_to donation_path(@donation, :share_links => true) - else - render 'new' - end + def temp_donations_exist? + cookies[:donation].present? end - def cookie_donation - cookie_donation = JSON.parse(cookies[:donation]).with_indifferent_access - end - - def temp_donations_exist - cookies[:donation] # check if the cookie donation is set - end - def in_projects_page? controller_name == 'projects' && action_name == 'show' end diff --git a/app/models/donation.rb b/app/models/donation.rb index ab883fb..3c87b0a 100644 --- a/app/models/donation.rb +++ b/app/models/donation.rb @@ -1,20 +1,27 @@ class Donation < ActiveRecord::Base belongs_to :project + accepts_nested_attributes_for :project + belongs_to :user + before_validation :set_project monetize :quantity_cents, as: :quantity, with_model_currency: :currency default_scope -> { order('created_at DESC') } scope :last_month, -> { where('date >= ?', 1.month.ago) } - - attr_accessor :project_name # acts_as_taggable_on :tags - #validates :quantity_cents, presence: true - #validates :currency, presence: true validates :project_id, presence: true validates :user_id, presence: true validates :date, presence: true + def set_project + if self.project && self.project.new_record? + self.project = Project.create_with({ + description: self.project.description, + url: self.project.url}).find_or_create_by(name: self.project.name) + end + end + end diff --git a/app/models/project.rb b/app/models/project.rb index 64a9214..5adb0e5 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,13 +1,18 @@ class Project < ActiveRecord::Base - + has_many :donations has_many :users, through: :donations - extend FriendlyId + extend FriendlyId friendly_id :name, :use => [:slugged] - validates :name, presence: true, length: { minimum: 5 } + validates :name, presence: true, length: { minimum: 5 }, uniqueness: true validates :description, presence: true, length: { minimum: 25 } validates :url, presence: true, length: { minimum: 5 } + def self.search(query) + return Project.where(["name like ?", "%#{query}%"]) if query.present? + Project.all + end + end diff --git a/app/views/donations/_form.html.erb b/app/views/donations/_form.html.erb index 3dbabb9..4da62ca 100644 --- a/app/views/donations/_form.html.erb +++ b/app/views/donations/_form.html.erb @@ -3,18 +3,25 @@
- <% if controller_name == 'projects' %> + <% if @project %>
<%= @project.name %>
+
+ <%= link_to t('need_to_trackdon_for_another_project'), root_path(anchor: 'track_donation') %> +
+ <%= f.hidden_field :project_id, value: @project.id %> <% else %> - <%= f.autocomplete_field :project_name, autocomplete_project_name_projects_path, :id_element => '#donation_project_id', placeholder: 'Project', :"data-autocomplete-label" => "Sorry, nothing found." %> - <% end %> - - <% if params[:controller] == 'projects' %> -
<%= link_to t('need_to_trackdon_for_another_project'), track_donation_link %>
- <% else %> -
<%= f.label(:project_name, 'ie. Wikipedia, Redd Cross, UNR') %>
+ <%= f.fields_for(:project) do |project_form| %> + <%= project_form.hidden_field :name %> +
<%= project_form.label(:name, 'ie. Wikipedia, Redd Cross, UNR') %>
+
+ <%= project_form.text_area :description %> +
<%= project_form.label(:description, 'Project Description') %>
+ <%= project_form.text_field :url %> +
<%= project_form.label(:url, 'Project URL') %>
+
+ <% end %> <% end %>
@@ -58,11 +65,6 @@
- <% if params[:controller] == 'projects' %> - <%= f.hidden_field :project_id, :value => @project.id %> - <% else %> - <%= f.hidden_field :project_id %> - <% end %> <%= f.submit('TrackDon', class: 'big' ) %> <% end %> diff --git a/app/views/donations/_temp_save.html.erb b/app/views/donations/_temp_save.html.erb deleted file mode 100644 index a107587..0000000 --- a/app/views/donations/_temp_save.html.erb +++ /dev/null @@ -1,8 +0,0 @@ - -
-

Woooa! Congratulations

-

You have tracked your first donation. Wasn't that easy? But... you wouldn't want to loose it, right? Add your email and a password and you'll have your account created.

-

<%= cookie_donation[:project_name] %>

- <% @user = User.new # TODO solve this ñapa %> - <%= render 'users/new.html.erb' %> -
diff --git a/app/views/donations/new.html.erb b/app/views/donations/new.html.erb index 2d37a9c..e174764 100644 --- a/app/views/donations/new.html.erb +++ b/app/views/donations/new.html.erb @@ -1,24 +1,19 @@ -

New Donation

<% if @donation.errors.any? %> - - <%= @donation.inspect %> - -
-

<%= pluralize(@donation.errors.count, "error") %> prohibited - this article from being saved:

- -
+
+

<%= pluralize(@donation.errors.count, "error") %> prohibited + this article from being saved:

+ +
<% end %> <%= render 'donations/form' %> - -
+ diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 72d9b14..d0a1f84 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -50,15 +50,10 @@
- <% flash.each do |message_type, message| %>
<%= message %>
<% end %> - - <% if temp_donations_exist %> - <%= render 'donations/temp_save' %> - <% end %> - + <%= yield %>
diff --git a/app/views/pages/index.html.erb b/app/views/pages/index.html.erb index 052b7f4..8f310d2 100644 --- a/app/views/pages/index.html.erb +++ b/app/views/pages/index.html.erb @@ -9,8 +9,6 @@
  • <%= t 'main_bullet_3' %>
  • <%= link_to t('read_more_about_this_project'), {controller: 'pages', action: 'about'}, class: 'button' %> - <%# link_to t('read_more_about_this_project'), class: 'button' %> -
    diff --git a/app/views/users/_new.html.erb b/app/views/users/_new.html.erb index f46cce1..4bfe7a3 100644 --- a/app/views/users/_new.html.erb +++ b/app/views/users/_new.html.erb @@ -1,3 +1,10 @@ +<% if temp_donations_exist? %> +

    Woooa! Congratulations

    +

    You have tracked your first donation. Wasn't that easy? But... you wouldn't want to loose it, right? Add your email and a password and you'll have your account created.

    +

    <%= cookie_donation[:project_name] %>

    +<% else %> +

    Sign up

    +<% end %> <%= form_for(@user, html: {class: "simple_form"} ) do |f| %> @@ -43,4 +50,4 @@ <%= f.submit "Create my account" %>

    - <% end %> \ No newline at end of file + <% end %> diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index 8ae9c9f..99ca475 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb @@ -1,8 +1,6 @@ -
    - - <% provide(:title, 'Sign up') %> -

    Sign up

    +<% provide(:title, 'Sign up') %> +<%= content_tag :section, :class => 'content_column', :id => (temp_donations_exist? ? "first_donation_pending" : "user") do -%> <%= render 'new' %> - -
    \ No newline at end of file +<% end -%> +
    diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 649df36..26b0eb7 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -1,30 +1,26 @@ -
    - <%# provide(:title, @user.name) %> - <%= render 'header' %> - +
    - <% if @user == current_user %> -
    <%= link_to "Edit your profile", edit_user_path(current_user) %>
    + <% if current_user_profile? %> +
    <%= link_to t('.edit_your_profile'), edit_user_path(current_user) %>
    <% end %> - Donations (<%= @user.donations.count %>) - Projects (<%= @user.projects.distinct.count %>) + + Donations (<%= @user.donations.length %>) + Projects (<%= @user.projects.distinct.length %>)
    <% if @user.donations.any? %> - <%= render @donations %> + <%= render @user.donations %> <% end %>
    - - -
    \ No newline at end of file + diff --git a/config/locales/en.yml b/config/locales/en.yml index 60219b4..4a088aa 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -84,3 +84,5 @@ en: donated: donated in_the_last_month: in the last month in_total: in total + show: + edit_your_profile: Edit your profile diff --git a/config/locales/es.yml b/config/locales/es.yml index 044016f..3ad697f 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -50,3 +50,5 @@ es: donated: donado in_the_last_month: en el último mes in_total: en total + show: + edit_your_profile: Edita tu perfil diff --git a/config/routes.rb b/config/routes.rb index f447456..f0c9e8c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,7 +16,6 @@ resources :donations resources :projects do resources :donations - get :autocomplete_project_name, :on => :collection end diff --git a/spec/features/creating_project_while_tracking_don_spec.rb b/spec/features/creating_project_while_tracking_don_spec.rb new file mode 100644 index 0000000..2957218 --- /dev/null +++ b/spec/features/creating_project_while_tracking_don_spec.rb @@ -0,0 +1,58 @@ +require 'rails_helper' + +RSpec.feature 'Adding projects while tracking donations. When I create a donation' do + background do + @project = create_project(:name => 'Wikiwadus') + @user = create_user(name: 'Yorch', password: 'wadusm4n', :email => "yorch@example.com") + end + + scenario 'As a logged in user, I should be able to create a new project on the fly' do + visit '/login' + + fill_in 'Email', :with => "yorch@example.com" + fill_in 'Password', :with => "wadusm4n" + + click_button 'Log in' + + visit '/' + + find('#donation_project_attributes_name').set 'Ngrok' + + fill_in 'Project Description', :with => 'Introspected tunnels to localhost' + fill_in 'URL', :with => 'https://ngrok.com/' + + fill_in 'When did you donate?', :with => '2014-10-10' + fill_in 'How much?', :with => '25' + + click_button 'TrackDon' + + expect(page).to have_content 'Hooray!' + expect(page).to have_content '25€ to Ngrok by Yorch' + + end + + scenario 'As an anonymous user, I should be able to create a new project on the fly' do + visit '/' + + find('#donation_project_attributes_name').set 'Ngrok' + + fill_in 'Project Description', :with => 'Introspected tunnels to localhost' + fill_in 'URL', :with => 'https://ngrok.com/' + + fill_in 'When did you donate?', :with => '2014-10-10' + fill_in 'How much?', :with => '25' + + click_button 'TrackDon' + + expect(page).to have_content 'Woooa! Congratulations' + fill_in 'Name', :with => "Luke Skywalker" + fill_in 'Email', :with => "luke@example.com" + fill_in 'Password', :with => 'lukeskywalk3r' + fill_in 'Confirmation', :with => 'lukeskywalk3r' + select 'Spain', :from => 'Country' + + click_button 'Create my account' + + expect(page).to have_content 'Hey, donation tracked, and you have your profile ready to keep tracking donations!' + end +end